aboutsummaryrefslogtreecommitdiff
Commit message (Collapse)AuthorAgeFilesLines
* feat(theme-selector): show every ui face in the mock frameCraig Jennings2026-06-082-20/+36
| | | | The live buffer preview was incomplete. It skipped highlight, isearch-fail, show-paren-mismatch, and vertical-border, and the fringe was painted its ground-colored default so it read as absent. The mock now renders all twenty ui faces: a highlighted line, a failing isearch in the echo area, a mismatched paren, and a vertical-border strip down the buffer's right edge. The fringe column is wider with a hairline edge so the gutter is locatable even at ground color, and the buffer runs a dozen lines to fit everything.
* feat(theme-selector): add package-face state and schema (tier-3 phase 1)Craig Jennings2026-06-083-8/+72
| | | | | | I laid the tier-3 foundation: an APPS registry (org starter for now) and a PKGMAP holding {fg,bg,bold,italic,inherit,source} per face. Pure helpers seed PKGMAP from APPS defaults, build the export per the state policy, and merge an import back in. Export gains a packages key when any package face is present, and import reads it while old JSON with no packages key still loads cleanly onto the seeded defaults. No UI yet — that's phase 3. A #selftest harness, guarded by the URL hash so it never shows in normal use, runs seed to export to import and checks the round-trip, old-JSON merge, and inherit/source survival. Headless Chrome reports PASS, which is how I verified the schema end-to-end against the real emitted code rather than a copy.
* docs(theme-selector): finalize package-faces spec and emit implementation tasksCraig Jennings2026-06-082-8/+49
| | | | | | Craig resolved the last two opens: hybrid-and-split inventory (org/magit/elfeed bespoke first, the generated all-package inventory as a later phase) and the custom color picker built after tier 3. With inheritance already settled, the rubric moves to Ready. I emitted the phase breakdown into todo.org under Emacs Open Work: one task per implementation phase plus a test-surface task, all marked solo since each builds and self-verifies through node, headless screenshots, and import/export round-trips. A Manual testing task collects the two human judgments that aren't solo: whether the seeded package defaults look right and whether the large org and magit tables stay usable.
* docs(theme-selector): settle inheritance as model-and-override in the specCraig Jennings2026-06-071-22/+29
| | | | Craig settled the inheritance question: model it rather than flatten it. Each face's resolved color shows in the table marked as inherited, the mock preview paints every face with its effective color, and overriding any face is one assignment that flips it from inherited to explicit. Export keeps the :inherit relationship for faces left alone and writes explicit attributes only for the ones overridden. Seeded defaults open showing org's real cascade. That clears one of the three open decisions; inventory split and picker timing remain.
* docs(theme-selector): incorporate Codex review into the package-faces specCraig Jennings2026-06-071-11/+154
| | | | | | I ran spec-response against Codex's review. Added implementation phases, acceptance criteria, the package-face inventory source, and state/export semantics with a source field that distinguishes seeded defaults from user edits from deliberate clears. The inventory is hybrid and split: the generated all-package path is its own phase after org, magit, and elfeed, so the three bespoke apps don't wait on it and the scope-explosion risk Codex flagged stays contained. Two findings I modified with reasons in the dispositions section, the rest accepted. Renamed the spec to -spec.org for the workflow precondition. The rubric is now Ready with caveats, and three decisions stay open for me: the inheritance representation, hybrid-vs-curated-only inventory, and the custom picker timing.
* fix(theme-selector): stop accidental duplicate colors when editing a valueCraig Jennings2026-06-072-16/+32
| | | | Editing a color's value could create a new color instead of updating it. Enter in the hex or name field now applies to the selected color rather than adding, and Add color refuses a name that already exists with a noticeable inline notice, so re-saving an existing color can't silently spawn a duplicate. Picking from the native swatch focuses the hex field so Enter applies right after, and both add and update report what happened in the same notice line.
* docs(theme-selector): fold first-round answers into the package-faces specCraig Jennings2026-06-071-38/+186
| | | | I folded the first-round answers into the tier-3 spec. org now carries its complete defface set instead of an 18-face sample, v1 apps are org, magit, and elfeed, and the generic fallback is a fully editable table so any package can be themed. I answered the inheritance question with an optional inherit field (absolute default, opt-in cascade) and added a custom-color-picker proposal. Two decisions stay open: confirming the inheritance representation and when to build the picker.
* feat(theme-selector): click a preview token to flash its assignment rowCraig Jennings2026-06-072-30/+48
| | | | | | I added the reverse lookup. Clicking a token in the code sample flashes the matching code/color assignment row and scrolls it into view; clicking an element in the mock frame flashes its ui-faces row, or the assignment row when it's a code token. Each token carries its category and each mock element its face as a data attribute, so the lookup survives sorting, reassignment, and palette edits. Going color-first can't tell you which category owns a shared color, since operator, function, and punctuation all read as silver. Clicking the token answers it directly.
* docs(theme-selector): spec the tier-3 package-faces sectionCraig Jennings2026-06-071-0/+220
| | | | I spec'd a third tier for the tool: package-specific faces, edited one application at a time, org-mode first. It covers the app dropdown, a per-app face table, a bespoke org-document preview, the theme.json packages schema, and how the build step consumes it. It's awaiting review and ends with five open questions.
* feat(theme-selector): edit palette colors in place, taller mock frameCraig Jennings2026-06-072-30/+58
| | | | | | I made palette colors editable. Click a chip and its hex and name load into the editor and the chip is selected. "Update selected" rewrites that entry and remaps every syntax and ui assignment from the old hex to the new, so nudging a color no longer means redoing the assignments that used it. "Add color" still appends a fresh one. The ui-faces mock frame now stretches to the height of its face table, with the buffer filling and the mode-line pinned to the bottom like a real window. I also renamed "interface faces" to "ui faces."
* feat(theme-selector): add a live mock Emacs frame for the interface facesCraig Jennings2026-06-072-4/+100
| | | | | | I split the interface-faces row into the face table on the left and a mock Emacs buffer on the right. The mock paints the faces in context: line numbers and fringe, a current line with hl-line and the current-line number, a region selection, an isearch match, a lazy-highlight, a show-paren match, a block cursor, active and inactive mode-lines, and a minibuffer prompt with an echo line for link, error, warning, and success. It rebuilds whenever a syntax or interface color changes, so it always reflects the current theme. The face table told you each color. The mock shows what they look like together in a real buffer.
* feat(theme-selector): two-column layout, contrast ratings, taller samplesCraig Jennings2026-06-073-75/+165
| | | | | | | | I restructured the page into ordered rows. The top row splits palette on the left and save / load theme on the right. The next row, "code/color assignments," puts the assignment table on the left and a single code sample on the right, picked by a language dropdown and recolored live from the assignments. The last row is the interface faces. I added a contrast column to the assignment table: each color's WCAG ratio on the current background plus an AAA / AA / FAIL rating, recomputed live and re-rated when the background changes. I also replaced the six-language scroll with the one-language picker, lengthened every sample to roughly the height of the assignment table, and renamed the title suffix to "theme."
* feat(theme-selector): add browser-based theme design toolCraig Jennings2026-06-074-0/+604
| | | | | | | | A self-contained tool for building Emacs color themes by eye. generate.py emits one HTML page with six languages of tree-sitter-tokenized code, a category-to-color assignment table, a UI-faces table, and an editable palette. Reassign colors from the palette, toggle weight and slant per category, set foreground and background per UI face, then export a theme.json a later build step turns into theme files. The export carries the name, palette, syntax assignments, bold and italic sets, and a ui object of per-face foreground and background. The theme name is both the json name field and the download filename. samples.py holds the language samples and the default color map. theme-selector.html is the generated output. The json-to-theme converter is the next piece, and the part worth TDD.
* docs(design): spec the dupre-clear contrast-first theme, add taskCraig Jennings2026-06-072-0/+93
| | | | A plan for a contrast-first AAA sibling of the dupre theme. It keeps dupre's hues but builds them Prot's way, with contrast as the founding constraint, where the in-progress dupre revision is mood-first and lands at AA. The spec records the modus methodology analysis, the AA-to-AAA starting palette, the hard blue-keyword decision, and enough context to resume cold months from now. The task in Emacs Open Work links to it.
* chore(todo): log dupre-theme test failures as a tracked bugCraig Jennings2026-06-071-0/+8
| | | | A full make test run is green except four tests in test-dupre-theme.el. Logged with the two root causes (a stale #151311 background assertion across three tests, and an org-todo color mismatch) so the red baseline is tracked instead of tolerated.
* chore(hooks): sync validate-el.sh compact test output from the bundleCraig Jennings2026-06-071-3/+13
| | | | The bundle hook now prints a short test summary to the terminal on a red test (the run tally and the failing test names) and keeps the full ERT backtrace in the agent's context. Synced the project copy to match.
* fix(dupre): make diff-changed and diff-refine-changed legibleCraig Jennings2026-06-073-3/+37
| | | | | | diff-refine-changed rendered the default foreground (#f0fef0) on the bright-gold yellow-1 (#ffd700) at WCAG contrast 1.35, unreadable wherever the face is a plain background, not inside diff-mode's own foreground overlay. diff-changed was weak too at 2.78. Both now use the default foreground on the dark amber yellow-2 (#875f00), already in dupre's palette, for a contrast of 5.49. diff-refine-changed keeps its bold weight so it stays stronger than diff-changed. A WCAG-contrast test guards both faces from dropping below 4.5.
* chore(todo): file dupre diff-face legibility bug from pearl handoffCraig Jennings2026-06-072-0/+10
| | | | dupre's diff-refine-changed is bright gold under near-white text (WCAG ~1.35), unreadable as a plain background. Filed with the side-by-side comparison render from the pearl session that surfaced it.
* feat(pearl): add multi-account config, rename module to pearl-configCraig Jennings2026-06-065-61/+69
| | | | | | The pearl package moved from a single Linear workspace to multi-account, so the config follows. pearl-accounts now declares two workspaces, one for work and one personal, each resolving its own API key from authinfo and rendering to its own Org file. pearl-default-account picks which one opens, and pearl-switch-account swaps at runtime. This replaces the old single-account setup (pearl-org-file-path plus one pearl-api-key lookup). The module file moves from linear-config.el to pearl-config.el to match the package name. init.el, the module-headers allowlist, and the module-inventory row follow the rename.
* chore(todo): reorder open work, restamp reviews, close M-F9 split taskCraig Jennings2026-06-061-69/+85
| | | | Reorder the Emacs Open Work section: Calibre pulled to the top, the message-client and localrepo tasks regrouped. Stamp 7 task-review tasks with today's date and regrade the dashboard-keybinding task to B. Mark the M-F9 close-removes-split bug DONE now that the fix shipped in 1a097b7e.
* fix(ai-term): keep the window split when closing an agentCraig Jennings2026-06-062-7/+45
| | | | M-F9 close deleted the agent's window, collapsing the layout. Close now swaps that window to the working buffer and kills the agent buffer, so the split stays put. F9 hide still collapses the split. Close no longer does.
* chore(todo): group Calibre work, file new feature and convention tasksCraig Jennings2026-06-061-135/+208
| | | | Created a Calibre parent grouping the bookmark-title, keybindings, and metadata-embed children. Relocated the project-aware capture and Calibre-keybindings items out of the global capture inbox. Added tasks for project-aware capture, the "? = curated help menu" convention survey, and embedding Calibre's DB metadata into the book files. Flipped the in-progress tasks to DOING and added manual-verify checklist items for the shipped features.
* feat(calibredb): curated ? menu, docked description, filter-preserving sortCraig Jennings2026-06-062-1/+136
| | | | | | | | | | | | Three things in the calibredb search buffer. A curated transient on ? exposes just my frequent workflows (switch library, filter by format or author, sort by author/title/pubdate/format, open, describe) instead of leaving me to remember calibredb's top-level single keys. calibredb's own full dispatch moves to H. which-key can't help here: these are mode-map single keys, not a prefix. So a curated menu on ? is the discoverable entry point. The transient is defined in :config rather than top-level: its macro expands against the elpa transient, but a batch Emacs loads the older built-in transient and breaks the load. The book-detail view (d, or v) now docks to the bottom 30% and q dismisses it. calibredb-show-entry-switch goes to pop-to-buffer so a display-buffer-alist rule applies. The default switch-to-buffer-other-window ignores it. It's the same bottom-dock pattern as the signal chat buffer. Sorting kept dropping the active filter. calibredb's macro-generated sort commands all end in calibredb-search-refresh-and-clear-filter, which nulls every filter flag. I override each to refresh via calibredb-search-refresh-or-resume, which re-applies the filter, so a sort over a filtered list keeps it. I used named advice, so reloading the module doesn't stack it. Tests cover the describe command and the sort helper. The transient, bindings, dock, and advice wiring need the elpa transient and a live calibredb, so they're verified in the running daemon.
* fix(nov): name EPUB bookmarks "Author, Title" from the filenameCraig Jennings2026-06-062-0/+135
| | | | | | | | | | In a nov buffer m is bound to bookmark-set. nov's nov-bookmark-make-record names the record after the buffer name, the raw EPUB filename. So bookmarks read like "Frege_ A Guide for the Perplexed - Edward Kanterian.epub". I advise nov-bookmark-make-record to rebuild the name from the record's filename: split on the last " - " into title and author per Calibre's "<Title> - <Author>.epub" naming, restore the colon Calibre sanitized to "_ ", and reorder to "Author, Title". That book becomes "Edward Kanterian, Frege: A Guide for the Perplexed". I pulled the name from the filename rather than the embedded EPUB metadata on purpose. In real books the embedded metadata is the worse copy (truncated titles, authors in "Last, First" sort form, lost punctuation), while the filenames come from Calibre's curated database. A separate task tracks embedding the good metadata back into the files. cj/--nov-clean-title and cj/--nov-bookmark-name-from-file are pure and carry the logic. The advice is a thin wrapper. 10 ERT tests cover colon restoration, the last-separator split, and the no-separator fallback.
* feat(capture): project-aware Task and Bug capture targetsCraig Jennings2026-06-062-1/+262
| | | | | | | | C-c c t (Task) and a new C-c c b (Bug) now file into the current projectile project's todo.org under its "... Open Work" heading instead of always landing in the global inbox. Bug stamps the entry [#C]. Task stays a plain TODO. Both share one function target, cj/--org-capture-project-location. It matches an existing top-level "... Open Work" heading when there is one, so a directory like .emacs.d resolves to the existing "Emacs Open Work" rather than a name derived from the basename. It only creates "<Project> Open Work" when the file has none. Outside a project, or in a project whose root has no todo.org, it falls back to the global inbox under "Inbox". In the no-todo.org case it also warns, naming the project. It never creates a project's todo.org. I split the logic into pure helpers (project name, target decision, find-or-create heading) so they test directly, with the impure buffer-positioning left thin. 15 ERT tests cover the helpers and the wiring. I confirmed a real capture lands the entry under Open Work at the right level in the running daemon.
* chore(todo): add Calibre bookmark-title taskCraig Jennings2026-06-061-0/+8
|
* fix(term): land copy-mode cursor at column 0Craig Jennings2026-06-062-15/+32
| | | | | | | | Entering copy-mode from C-; x c left the cursor at the live column, far right after a prompt, so scrolling up ran the cursor up the right edge instead of the left. In the tmux branch I append C-a after C-b [, which tmux's emacs copy-mode reads as start-of-line. It has to go after C-b [: before copy-mode is active, C-a would hit the shell's readline instead. In the non-tmux ghostel-copy-mode branch I call beginning-of-line after entering the view, for the same column-0 result. Both branches now run the cursor up the left edge. The non-tmux test asserts ghostel-copy-mode runs before beginning-of-line, since the move only repositions inside an active copy view. Its tracker variable is dwim-order, not calls, to avoid clashing with the variable the tmux mock macro binds.
* fix(signal): register C-; M prefix via canonical helperCraig Jennings2026-06-063-6/+20
| | | | | | | | The C-; M Signal prefix didn't take effect on a fresh Emacs launch. signal-config.el was the only feature module that bound into cj/custom-keymap directly, wrapped in (with-eval-after-load 'keybindings (when (boundp 'cj/custom-keymap) ...)). The boundp guard turned a load-order miss into a silent no-op, so the binding never landed at startup. A later live-reload always papered over it because keybindings was loaded by then. I switched to the documented cj/register-prefix-map helper and added (require 'keybindings) at the top, matching every other prefix map. The require guarantees keybindings loads before registration, so the guard is gone. I verified at a full emacs --batch init.el launch, the actual failing scenario, that C-; M resolves to the signel prefix. I added a contract test asserting the registration, since the boundp guard was robust under unit timings and only failed at full launch.
* chore: spin Duet out into its own project; add config stubCraig Jennings2026-06-062-3/+22
| | | | The Duet design work graduated into a standalone package, so its task moved out of this todo. modules/duet-config.el is a use-package stub for it, inert until wired into init.el. Daily task-review also synced three ghostel follow-up priorities to their parent.
* chore(todo): cancel ghostel auto-dim revisit taskCraig Jennings2026-06-051-2/+2
| | | | The shipped no-dim behavior works fine, which is the measured decision the task asked for, so the revisit is unneeded. Rewrote it to a dated cancellation log entry per the sub-task close rule.
* fix(term): forward F10 and C-F10 to Emacs in ghostel buffersCraig Jennings2026-06-052-2/+16
| | | | Inside a ghostel terminal or agent buffer, semi-char mode forwarded F10 and C-F10 to the pty, so the music-playlist toggle and the server-shutdown command never ran. Both are global bindings with no ghostel-mode-map entry, so I added them to ghostel-keymap-exceptions and rebuilt the semi-char map. The lookup then falls through to the global map. Same shape as the earlier F9, F12, and window-nav fixes.
* chore(claude): add patterns-catalog pointer rule from bundleCraig Jennings2026-06-051-0/+29
| | | | Synced into .claude/rules/ by the startup language-bundle drift check. Points at the rulesets pattern catalog for interaction-design decisions.
* chore(todo): re-stamp task-review batch, tag two quick tasksCraig Jennings2026-06-051-6/+15
| | | | Daily task-review pass over the seven oldest-unreviewed tasks: all kept as-is and re-stamped to 2026-06-05. Tagged the TTY C-; keymap task :solo:quick: and the Slack popup task :quick:.
* chore(todo): file slack-popup and ghostel selection-color tasksCraig Jennings2026-06-051-0/+6
|
* fix(term): forward C-SPC and window-nav keys in ghostel buffersCraig Jennings2026-06-052-6/+43
| | | | | | | | | | Two keystrokes weren't reaching Emacs inside a ghostel terminal, both because of how ghostel routes keys in semi-char mode. C-SPC was the worse one. ghostel forwards the `C-@' event but not the distinct `C-SPC' event GUI Emacs produces, so C-Space fell through to the global `set-mark-command' and set an Emacs region in the terminal buffer. That region followed point as output streamed (a stuck "selection" Escape and C-g couldn't clear), and it meant tmux copy-mode's begin-selection never started, so M-w copied nothing. I bind C-SPC to cj/term-send-C-SPC, which forwards NUL like a terminal key. The C-M-arrows (buffer-move, window swap) were being forwarded to the terminal program the same way the F9 family was. I added the windmove S-arrows and buffer-move C-M-arrows to ghostel-keymap-exceptions and rebuilt the semi-char map. The S-arrows already reached Emacs by keymap precedence, but listing them makes the window-nav contract explicit rather than accidental. Regression tests cover all three: C-SPC bound to the forwarder, and the window-nav keys in the exceptions with the semi-char map no longer forwarding them.
* fix(term): make F9 and F12 reach Emacs inside ghostel buffersCraig Jennings2026-06-056-6/+52
| | | | | | | | F9 did nothing in an agent buffer: ghostel's semi-char mode forwards every key not in ghostel-keymap-exceptions to the pty, and ghostel-semi-char-mode-map outranks the major-mode map, so the F9-family and F12 bindings I'd put in ghostel-mode-map never fired. The keys went to Claude/the shell, which ignored them. I added the F9 family (in ai-term) and F12 plus C-; (in term-config) to ghostel-keymap-exceptions and rebuilt the semi-char map with ghostel--rebuild-semi-char-keymap. add-to-list updates the list but not the already-built map, so the rebuild is what actually lets the keys through. C-; had the same latent bug for the same reason. Two regression tests assert the keys are in the exceptions and that the rebuilt semi-char map no longer forwards them. I also corrected the spec note that claimed binding in ghostel-mode-map was enough (true for vterm, wrong for ghostel) and codified the gotcha.
* feat(term): replace vterm with ghostel as the terminal engineCraig Jennings2026-06-0558-3027/+2796
| | | | | | | | I swapped the terminal engine from vterm to ghostel (libghostty-vt) everywhere. term-config replaces vterm-config (the F12 terminal, the C-; x menu, tmux history capture), and ai-term replaces ai-vterm (the F9 Claude-agent launcher). ghostel renders the agent TUI without vterm's flicker under heavy streaming, and one engine now covers every terminal workflow. Two behavior changes fall out of the swap. F9 launches in a terminal frame now: ghostel renders in TTY frames, so the old GUI-only guard is gone. Terminal windows no longer dim when unfocused: ghostel resolves its palette into the native module per-terminal, so there's no per-window color hook to dim through the way vterm had. auto-dim drops its vterm color-advice path, the dashboard Terminal button launches ghostel, and the vterm and vterm-toggle packages are removed. The tmux pane-history and copy-mode machinery carried over unchanged. It keys on the pty tty, which ghostel exposes.
* chore(todo): restore orphaned heading, file TTY keymap taskCraig Jennings2026-06-031-1/+13
| | | | | | I restored the heading "Color dashboard navigator independently of list items" above its PROPERTIES drawer. The 2026-06-02 archive cleanup dropped the heading, which orphaned the drawer and body into the preceding DONE task and tripped org-lint's obsolete-properties-drawer check. org-lint is clean again. I also filed "TTY-accessible personal C-; keymap" [#B]: C-; is GUI-only, so the whole custom prefix family is unreachable in a terminal. The task records the single-point fix in keybindings.el and the candidate TTY-safe mirror prefixes.
* feat(linear): add global C-; L prefix and short assignee tagsCraig Jennings2026-06-031-8/+15
| | | | | | | | I bound pearl-prefix-map globally under C-; L with :bind-keymap, so the full command surface is reachable from any buffer instead of only inside a pearl-rendered one or through M-x. The first press autoloads pearl. It's the same map pearl-mode binds in-buffer, so behavior is identical everywhere. I also set pearl-assignee-tag-short, so the assignee @-tag renders as the first name only (@first instead of @first_last), trading disambiguation for a tighter tag line. Both layer onto the prior vanilla setup after dogfooding the out-of-box experience. I updated the commentary to match.
* chore(todo): drop keybinding-display.md item from pearl follow-upsCraig Jennings2026-06-021-1/+0
|
* chore(todo): archive resolved tasks and file pearl follow-upsCraig Jennings2026-06-021-41/+47
| | | | Move the f9 toggle, completing-read prompts, and GPG pinentry subtrees into Resolved, and file the pearl vanilla-config dogfooding follow-ups surfaced by the cross-project handoff.
* chore: gitignore slime-history.eldCraig Jennings2026-06-021-0/+1
|
* refactor(linear): reduce to a vanilla pearl setupCraig Jennings2026-06-022-256/+30
| | | | | | | | The config carried a full custom command surface: a hand-built C-; L keymap, which-key labels, a lazy API-key loader wired in as advice, and a pinned DeepSat team id. That's worth keeping only if the out-of-box pearl experience isn't good enough on its own, and the point now is to find out. Stripped it back to exactly what pearl's README documents for a first install: pearl owns its own keymap (pearl-mode binds the command surface under pearl-keymap-prefix, default C-; L, in any Linear buffer), no global binding, no advice. The API key comes from authinfo.gpg via auth-source-pick-first-password, and the synced file moves to gtd/linear.org under org-directory. The only deviation from the README is loading from the local checkout at ~/code/pearl instead of an archive. Deleted tests/test-linear-config.el — it covered the custom helpers (the key-loader advice, the keymap wiring) that no longer exist. What's left is declarative use-package config with nothing of its own to test.
* feat(ui): name the operation in completing-read promptsCraig Jennings2026-06-029-18/+33
| | | | | | | | A picker prompt is the last thing shown before a command commits, so a bare noun leaves a mis-keyed command ambiguous. Hitting C-f8 (project agenda) instead of C-f9 (AI-vterm picker) gave the same "Project:" prompt with no signal which one was about to run. Reworded 17 prompts across 8 modules so each names the operation rather than just the thing being chosen: "Project:" becomes "Show agenda for project:", "F6:" becomes "Run tests:", the dwim-shell sub-prompts gain their context (checksum algorithm, PDF compression quality, text-to-speech voice, run dwim-shell command), the two contact pickers split into "Find contact:" and "Insert contact email:", and the dirvish ediff, org finalize, and custom-comments length/box-style prompts get the same treatment. I audited all ~124 completing-read / read-* call sites; the rest already named their operation and were left alone. These are prompt-string changes only, no logic touched.
* chore(todo): reconcile stale tasks and re-stamp the reviewed batchCraig Jennings2026-06-021-13/+22
| | | | | | | | | | Audit reconciliation: - EAT consolidation: moved DOING back to TODO — the eval matrix has no recorded run since the 2026-05-26 direction note, so it isn't active work. - Finish terminal GPG pinentry: CANCELLED as a duplicate. The "Terminal GPG pinentry Completion" task is canonical; its audit already found the terminal-pinentry branch gone, so the work restarts from main and is tracked there. - M-F9 close: added a note that it's still a bug, distinct from the F9 toggle collapse — close should leave the surrounding layout intact, and cj/--ai-vterm-close-buffer still deletes the window. - De-linked the coverage-v1 cross-reference, which pointed at a session file that was never archived. Review: re-stamped LAST_REVIEWED on the seven oldest-unreviewed tasks (debug-profiling, org-noter, API workspace, Company-to-Corfu, F2 preview, TRAMP/dirvish, F-key Completion), all kept as-is.
* fix(ai-vterm): make F9 a faithful toggle of the agent splitCraig Jennings2026-06-024-41/+261
| | | | | | | | | | | | F9 toggle-off used quit-restore-window to dismiss the agent. With several agents alive sharing one slot, switching among them (C-F9) reuses the window via set-window-buffer, which leaves the window's quit-restore parameter pointing at the first agent shown. Once stale, quit-restore-window falls back to switch-to-prev-buffer and surfaces a different agent instead of removing the window, so F9 appeared to "show another agent" rather than hide the split. Toggle-off now collapses the split with delete-window, which is independent of the slot's buffer history, so the working buffer reclaims the frame. Geometry is captured first so the next toggle-on re-splits at the same width. Toggle-on reopens the exact agent that was hidden (new cj/--ai-vterm-last-hidden-buffer), falling back to the most-recent agent only when that buffer has been killed. Hide-then-show is now a faithful round trip, not a jump to whichever agent is most-recent in buffer-list. Sole-window toggle-off returns to the most-recent non-agent buffer instead of other-buffer, which could land on another agent. I updated the two reuse-edge-window tests that asserted the old restore-displaced-into-a-kept-slot behavior to match the new always-collapse behavior.
* docs(rules): record auth-source credential cache in live-reload caveatsCraig Jennings2026-06-011-0/+1
| | | | Updating authinfo.gpg in a running daemon does nothing until auth-source-forget-all-cached clears its two-hour result cache. I added the symptom, cause, and fix to the running-Emacs caveats so the next session reaches for the cache clear instead of re-diagnosing a "key not set" error.
* chore(todo): task-review hygiene passCraig Jennings2026-06-011-7/+13
| | | | I stamped LAST_REVIEWED on the seven oldest-unreviewed tasks and tagged the gptel-magit velox bug and the Signal dashboard task as quick.
* fix(prog-general): repoint daily-prep opener to root symlinkCraig Jennings2026-06-012-10/+9
| | | | The daily-prep workflow now keeps its stable symlink at the project root as daily-prep.org instead of inbox/today-prep.org. I repointed cj/open-project-daily-prep (C-c p d) to match, updating its docstring, not-found message, and test for the new path.
* feat(ai-vterm): gate the F9 launcher to GUI framesCraig Jennings2026-05-317-13/+128
| | | | | | AI-vterm launches a graphical vterm side window, so F9 / C-F9 / M-F9 now decline with a message in a terminal frame instead of opening a vterm. The guard checks the current frame at command time rather than at load. That matters under the daemon, which serves GUI and terminal frames both with display-graphic-p nil at load, so a load-time gate would have disabled the launcher in its GUI frames too. Routed the three window-behavior tests through a GUI-frame stub, since a batch run is itself a terminal frame.