aboutsummaryrefslogtreecommitdiff
path: root/claude-templates/.ai/scripts
Commit message (Collapse)AuthorAgeFilesLines
...
* feat(scripts): add drill-to-anki.py template script (org-drill to Anki .apkg)Craig Jennings2026-05-291-0/+214
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Generalizes the health-drill-to-anki.py converter into a template script under claude-templates/.ai/scripts/. Every project's startup rsync now picks it up at .ai/scripts/drill-to-anki.py. The converter walks an org-drill file. Top-level * Section headings become Anki tags. Each ** Card name :drill: entry becomes a card with the heading as Front and the body as Back (newlines converted to <br>). Parameterized from the original health-specific version: - Input file is a positional argument (was hardcoded health-drill.org). - Deck name defaults to the org file's #+TITLE if present, else the input basename in Title Case (was hardcoded "Health Drill"). - Output path defaults to ~/sync/org/drill/<input-basename>.apkg (was hardcoded health-drill.apkg in the same dir). - Deck and model IDs are derived from the deck name via SHA-256, so re-running against the same source produces stable IDs. Anki imports update existing cards in place rather than duplicating. Dependencies via PEP 723 inline script metadata. The shebang is #!/usr/bin/env -S uv run --script. First run resolves and caches genanki>=0.13. Subsequent runs are instant. There is no venv to maintain and no PEP 668 friction. Smoke tested against ~/projects/health/health-drill.org. The script wrote 43 cards into the Health Drill deck, matching the original script's output. Inbox source: 2026-05-29-1114-from-health-todo-b-org-drill-anki-export-updated.org. Craig confirmed all projects will likely have org-drill files, justifying template-tier promotion.
* feat(signal): page-signal CLI wrapper + workflows + cross-project broadcast ↵Craig Jennings2026-05-291-0/+155
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | helper Three coupled additions ship together. claude-templates/bin/page-signal is a bash wrapper around signal-cli send. It defaults to --note-to-self for safety. The wrapper supports --file for attachments, --to <+number> for outbound (explicit per call, no defaults, no batch), --quiet, and --json. Exit codes: 0 sent, 1 signal-cli failure, 2 usage error, 3 signal-cli not installed. claude-templates/.ai/workflows/page-signal.org carries the discrimination rules and safety rails. When desktop notify covers it, don't reach for Signal. Long-running task completion is the canonical case. Outbound to other contacts requires explicit Craig instruction per send. A known-limitation note covers the current notification gap. signal-cli registered on Craig's primary number means messages don't fire notifications until the pending Google Voice registration lands. claude-templates/.ai/workflows/cross-project-broadcast.org and its helper cross-project-broadcast.py fan out a single message file to every AI project's inbox in one operation. Discovery is fingerprint-based: any directory under ~/code, ~/projects, ~/.emacs.d with both .ai/protocols.org and a top-level inbox/ is broadcastable. Senders are auto-excluded. Verified discovery against 23 broadcastable targets. Makefile's install target gains a general bin/ loop. The previous version hardcoded bin/ai. The new version iterates over every executable under claude-templates/bin/ and symlinks each into ~/.local/bin/. install-hooks (existing Claude hook installer) is unchanged. install-githooks (sync-check pre-commit hook setup, added earlier today) is unchanged. The bin/ loop now picks up bin/page-signal automatically. INDEX entries for both new workflows landed under Tools and meta. No bats tests on the new scripts. page-signal was smoke-tested with a live send. The send succeeded. The notification gap is covered by the workflow's known-limitation note. cross-project-broadcast.py was smoke-tested via --list against the live project set. Tests can be added when the broadcast pattern proves out across multiple use cases.
* feat(notify): default page notifications to --persistCraig Jennings2026-05-262-2/+4
| | | | | | I default page notifications to --persist so a page that fires while I'm away from the desk waits for me instead of auto-dismissing after a few seconds. page-me and status-check already persisted every page. I added --persist to the rest: the alarm, reminder, and meeting-alert examples in protocols.org, the long-running-process completion ping, and the cross-agent-watch message notification. I documented --persist as the default for any page meant to get attention, with a low-value informational ping as the only exception.
* fix(inbox-send): preserve dots in copied filenamesCraig Jennings2026-05-262-1/+55
| | | | | | send_file ran filenames through slugify(), which flattens dots to hyphens. That corrupts the engine.plugin.org plugin-namespace convention: triage-intake.personal-gmail.org arrived as triage-intake-personal-gmail.org, which breaks the engine's triage-intake.*.org glob and the routing that depends on the first dot. I added slugify_filename() for filename stems. It keeps dots, hyphens, underscores, and case, collapses only whitespace runs to hyphens, and truncates on a separator boundary. The prose --text path still uses slugify().
* feat(scripts): add off-screen launch capture, layout/size, and tests to ↵Craig Jennings2026-05-222-38/+259
| | | | | | | | screenshot.py Extends screenshot.py with --launch CMD, which runs a command on a transient headless Hyprland output, captures it, and tears the output down, so a UI can be verified without touching the visible workspace. --layout (tiled/monocle/floating) and --size control placement: output resolution for tiled/monocle, window size plus centering for floating. Refactors the testable logic (size parsing, geometry strings, window matching, the exec-rule body, centering) into pure helpers and adds test_screenshot.py covering them across normal, boundary, and error cases. The grim/hyprctl wrappers and the capture orchestration stay thin and are verified functionally.
* feat(scripts): add screenshot.py for visual verification on WaylandCraig Jennings2026-05-221-0/+142
| | | | Adds a grim + hyprctl wrapper so a session can capture the screen or a single window and read the resulting PNG, turning "does this look right?" into an inspectable artifact. Modes: --full (all outputs), --active (focused window), --window REGEX (matched against class or title), and --list to enumerate open windows. Output goes to a chosen path (default a timestamped file in /tmp) and the saved path is printed on stdout so the caller can read it back; the parent directory is created if it does not exist. Syncs into every project's .ai/scripts/ via the startup rsync.
* feat(workflows): add task-review list-hygiene habitCraig Jennings2026-05-202-27/+122
| | | | | | | | | | The new task-review.org workflow is the daily habit that retires the old date-coverage scan. It surfaces the oldest-unreviewed top-level tasks, walks them one at a time, and records each outcome — keep, re-grade, kill, mark DOING, or edit — stamping :LAST_REVIEWED: as it goes. It's a pure Claude workflow, no elisp. open-tasks.org displays the list; this one changes it. task-review-staleness.sh gains a --list mode that emits the N oldest-unreviewed tasks (line, review date, heading), oldest first, so the workflow walks a deterministic batch instead of eyeballing todo.org. Never-reviewed and unparseable-date tasks sort oldest. Seven new bats cases cover ordering, the count limit, exclusions, and output format; count mode is unchanged. startup.org gains the matching nudge. Phase A counts tasks unreviewed for >7 days and Phase C surfaces one line when that count is non-zero, pointing at the workflow. It lives in the template startup.org rather than the project-only startup-extras layer, so every project picks it up the same way it picks up the wrap-up health check. The INDEX entry is added with the "task review" triggers the rename freed up.
* test(scripts): add task-review-staleness.sh + bats harnessCraig Jennings2026-05-202-0/+232
| | | | | | | | First component of the daily task-review habit from docs/design/task-review.org. The staleness count is the shared primitive both the wrap-up health check (threshold 30) and the startup reminder (threshold 7) call, so it lives in one tested script rather than being reimplemented in each workflow. The script counts top-level todo.org tasks whose review has gone stale: depth-2 headings with a TODO/DOING/VERIFY keyword and an [#A]/[#B]/[#C] cookie, where LAST_REVIEWED is missing, unparseable, or older than the threshold. Age uses a strict greater-than, so a task reviewed exactly N days ago is still fresh. Today normalizes to local midnight before the diff, and the day count rounds to the nearest day, so a DST hour can't push a boundary task across the line. Twelve bats cases cover the normal, boundary, and error categories. Dates are generated relative to the current date rather than hardcoded. The script path resolves as the sibling-of-parent of the test file, so the suite runs identically from the canonical claude-templates tree and the rsync'd project mirror. Makefile test target now globs .ai/scripts/tests for bats alongside scripts/tests.
* feat(lint-org): recognize cj-comment blocks and suppress false-positive warningsCraig Jennings2026-05-162-0/+74
| | | | | | | | | | org-lint emits three warnings for every `#+begin_src cj: comment ... #+end_src` annotation block: suspicious-language-in-src-block (the language `cj:` isn't a known Babel slug), wrong-header-argument (the trailing `comment` looks like a header arg without a colon), and empty-header-argument (that same `comment` has no value). All three are false positives. The cj-comment block is a Craig-specific annotation marker, not Babel src-block syntax. I added a helper `lo--cj-comment-block-opener-p` that pattern-matches the opener line, then a short-circuit branch at the top of `lo--handle-item` that silently drops any of the three checkers when they fire on a cj-comment opener. No fix is counted, no judgment is emitted, and the warnings disappear. Two new tests cover the change. The normal case is a solo cj-comment block, which should produce zero judgments and zero fixes with all three flagged checkers absent from the issue list. The boundary case is a cj-comment block alongside a real `#+begin_src markdown` block. The markdown warning still surfaces, which scopes the suppression to cj openers only — no leak into other src blocks. Test count goes from 22 to 24, all green. I smoke-tested against rulesets/todo.org: judgment count drops from 7 to 1. Six cj-comment false positives at lines 16 and 1291 are gone, and the unrelated misplaced-heading at 2139 still surfaces correctly.
* fix(cj-scan): suppress detection inside nested non-cj begin_* blocksCraig Jennings2026-05-152-0/+140
| | | | | | cj-scan.py matched =#+begin_src cj:= / =#+end_src= line-by-line without awareness of enclosing block scopes. A cj fence embedded inside =#+begin_example= (typical when documenting what the <cj yasnippet emits) or =#+begin_src snippet= (the yasnippet definition itself) was misclassified as a live cj annotation. Two false positives surfaced from a /respond-to-cj-comments run against an org file with yasnippet docs. Track an active wrapper_type. When the scanner sees =#+begin_<type>= for any type other than cj: (the cj-open regex is checked first), enter a wrapper state where every line is content until the matching =#+end_<type>= closer fires. Inside a wrapper, both fence patterns and legacy inline cj: lines stay suppressed. Added the TestCjScanNestedFencesIgnored class with 6 tests: nesting inside example, src <other-lang>, and quote; regression guards for clean wrapper close and unclosed-wrapper non-swallow. Canonical pytest: 302 passed, 1 skipped.
* Merge commit '69c5e4ace81586c05dea6a9a3afd54dafa61a73b' as 'claude-templates'Craig Jennings2026-05-1555-0/+10648