;;; org-json-bridge.el --- Bridge for LLM agents to manipulate Org-mode via JSON (require 'org-element) (require 'json) (require 'cl-lib) (defun org-json-bridge--clean-tree (element) "Recursively convert an Org ELEMENT into a JSON-serializable format." (cond ((listp element) (let* ((type (car element)) (props (nth 1 element)) (children (nthcdr 2 element)) (cleaned-props nil)) (cl-loop for (key val) on props by 'cddr do (unless (member key '(:standard-properties :parent)) (let ((json-key (substring (symbol-name key) 1))) (push (cons json-key (cond ((stringp val) val) ((numberp val) val) ((booleanp val) val) (t (format "%s" val)))) cleaned-props)))) (list (cons 'type (symbol-name type)) (cons 'properties cleaned-props) (cons 'contents (mapcar #'org-json-bridge--clean-tree children))))) ((stringp element) element) (t (format "%s" element)))) (defun org-to-json (file-path) "Parse an Org file and output its structure as JSON." (with-current-buffer (find-file-noselect file-path) (let* ((tree (org-element-parse-buffer)) (cleaned (org-json-bridge--clean-tree tree))) (princ (json-encode cleaned))))) (defun json-to-org (json-string output-file) "Take a JSON representation of an Org tree and write it back to a file." (let ((data (json-read-from-string json-string))) (with-temp-file output-file (insert (org-element-interpret-data data))))) ;; Entry point for batch mode (message "DEBUG: Entry point reached") ;; Sometimes -- is left in command-line-args-left (when (string= (car command-line-args-left) "--") (pop command-line-args-left)) (let ((command (pop command-line-args-left))) (message "DEBUG: Command is %s" command) (cond ((string= command "org-to-json") (let ((file (pop command-line-args-left))) (org-to-json file))) ((string= command "json-to-org") (let ((json-str (pop command-line-args-left)) (out-file (pop command-line-args-left))) (json-to-org json-str out-file)))))