aboutsummaryrefslogtreecommitdiff
path: root/.ai/scripts/todo-cleanup.el
diff options
context:
space:
mode:
Diffstat (limited to '.ai/scripts/todo-cleanup.el')
-rw-r--r--.ai/scripts/todo-cleanup.el34
1 files changed, 34 insertions, 0 deletions
diff --git a/.ai/scripts/todo-cleanup.el b/.ai/scripts/todo-cleanup.el
index c4a87de..cb333e2 100644
--- a/.ai/scripts/todo-cleanup.el
+++ b/.ai/scripts/todo-cleanup.el
@@ -100,6 +100,12 @@
;; --check-child-priority is the report-only alias for --sync-child-priority
;; --check.
+;; Before any modification a backup is copied to
+;; /tmp/<basename>.before-todo-cleanup.<YYYYMMDD-HHMMSS>
+;; matching lint-org.el and wrap-org-table.el. Skipped under --check, which
+;; writes nothing.
+;;
+
(require 'org)
(require 'cl-lib)
(require 'calendar)
@@ -832,9 +838,37 @@ event-log entry, pulling the timestamp from its CLOSED cookie. Honors
;;; ---------------------------------------------------------------------------
;;; Driver + reporting
+(defun tc--backup (file)
+ "Copy FILE to /tmp before any modification. Skipped in --check mode.
+
+Matches `lint-org.el' and `wrap-org-table.el', the other tools that rewrite
+these org files. todo-cleanup runs the most often of the three (every wrap,
+every sentry fire), and Emacs's own backup does not fire under --batch -q, so
+without this a mechanical rewrite has no undo short of git — which recovers
+only to the last commit and loses intra-session work."
+ (let* ((base (format "%s%s.before-todo-cleanup.%s"
+ temporary-file-directory
+ (file-name-nondirectory file)
+ (format-time-string "%Y%m%d-%H%M%S")))
+ (backup base)
+ (n 2))
+ ;; Never overwrite an earlier backup. A second-resolution stamp collides
+ ;; when two invocations run back to back, which the shipped workflow does
+ ;; (open-tasks.org runs --convert-subtasks then --archive-done, each a
+ ;; sub-second batch run). Overwriting there replaces the true pre-session
+ ;; original with already-mutated content — losing exactly what the backup
+ ;; exists to preserve. Suffix instead, so every invocation keeps its own.
+ (while (file-exists-p backup)
+ (setq backup (format "%s-%d" base n))
+ (setq n (1+ n)))
+ (copy-file file backup nil)
+ backup))
+
(defun tc-process-file (file)
(setq tc-current-file (file-name-nondirectory file))
(setq tc-current-dir (file-name-directory (expand-file-name file)))
+ (unless tc-check-only
+ (tc--backup file))
(with-current-buffer (find-file-noselect file)
(org-mode)
(cond