aboutsummaryrefslogtreecommitdiff
path: root/tests
Commit message (Collapse)AuthorAgeFilesLines
* refactor: split video-audio-recording.el into layered modulesCraig Jennings12 hours1-0/+2
| | | | | | | | | | | | | Break the 1025-line video-audio-recording.el into a thin public face plus two layered libraries, moving every function verbatim so behavior and public names are unchanged: - video-audio-recording-devices.el — base layer: PulseAudio source and sink discovery, the pactl output parsers, device labeling and sort/status helpers for completing-read, and the lookup predicates. Pure string and shell-query helpers with no dependency on recording state, config, or the engine. This is the heavily-tested core. - video-audio-recording-capture.el — engine: ffmpeg/wf-recorder command construction, the recording process lifecycle (sentinel, producer-first shutdown, exit polling), the modeline indicator, dependency checks, device acquisition and validation, and the start/stop entry points. Requires the devices layer. video-audio-recording.el keeps configuration and the recording process-handle state, the device-diagnostic and device-test commands, the toggle commands, and the C-; r keymap, and requires the two layers. The engine reads and updates the config and process-handle variables, which the top module owns, through forward declarations, so no layer requires the top module back. No function call crosses from a layer up into the top module, so the split needs no forward-declared functions. Every public name is preserved, so all 323 existing video-audio-recording tests pass unchanged through the require chain. The two new modules carry the load-graph and package headers and join the header-contract allowlist. Claude-Session: https://claude.ai/code/session_014fyKMTTqLrZpL3rDF3dYc3
* refactor: split calendar-sync.el into layered modulesCraig Jennings12 hours1-0/+4
| | | | | | | | | | | | | | | Break the 1724-line calendar-sync.el into a thin public face plus four layered libraries, moving every function verbatim so behavior and public names are unchanged: - calendar-sync-ics.el — base parsing: RFC 5545 text cleaning, VEVENT property extraction, attendee/organizer/URL parsing, timezone and timestamp conversion, date arithmetic, single-event parsing. Depends on neither of the other new modules. - calendar-sync-recurrence.el — RRULE/EXDATE/RECURRENCE-ID expansion. - calendar-sync-org.el — Org rendering and atomic file output. - calendar-sync-source.el — sync state and persistence, async .ics fetch, the batch conversion worker, and the Google Calendar API path. calendar-sync.el keeps configuration, the parse orchestrator, sync dispatch, the user commands, the timer, and the C-; g keymap, and requires the four layers. Each layer forward-declares the config defvars it reads, so no layer requires the top module back. The batch worker loads the whole graph, so source forward-declares the two functions it calls there. Every public name is preserved, so all 574 existing calendar-sync tests pass unchanged through the require chain. The four new modules carry the load-graph and package headers and join the header-contract allowlist. Claude-Session: https://claude.ai/code/session_014fyKMTTqLrZpL3rDF3dYc3
* test: fix restart-emacs no-service mock to survive native-compCraig Jennings13 hours1-2/+8
| | | | | | test-system-cmd-restart-emacs-no-service-aborts mocked cj/system-cmd--emacs-service-available-p directly, but cj/system-cmd-restart-emacs reaches that helper through a native-comp intra-file direct call that bypasses the symbol-function redefinition. The mock silently no-opped, the real check ran, and on any machine that has emacs.service it returned non-nil, so restart proceeded and the should-error saw no error. I mock executable-find to nil instead, driving the real helper to nil at a boundary its subr trampoline honors, matching the passing sibling tests. The test now passes whether or not emacs.service is installed.
* refactor: split custom-misc.el into focused modulesCraig Jennings13 hours7-54/+56
| | | | | | custom-misc.el was an incoherent grab-bag, so anything small defaulted to landing there. I split its eight commands by concern. Three moved into new modules: custom-format (region/buffer reformat), custom-counts (word and character counts), and custom-text-transform (fraction glyphs). The other three went to existing homes: the previous-buffer toggle to custom-buffer-file, the delimiter jump to custom-line-paragraph, and the align-regexp space advice with its alignment and fill bindings to custom-whitespace. The C-; bindings, which-key labels, and the six test files moved with their functions, and custom-misc.el is deleted. No behavior change: every command keeps its name and its C-; key.
* refactor: prefix two collision-prone helpers, document naming auditCraig Jennings13 hours3-25/+25
| | | | | | Two owned helpers carried unprefixed generic names that risk colliding in the single Emacs namespace: car-member (local-repository.el) and unpropertize-kill-ring (system-defaults.el). I renamed them to localrepo--car-member and cj/--unpropertize-kill-ring and updated their callers and tests. Both are non-interactive and contained, so no alias was needed. docs/design/naming-audit.org records the rest of the scan: the allowlist of deliberate module prefixes, the foreign forward-declarations that aren't owned definitions, and a deferred list (keybound commands, the with-timer macro, the ui-theme defcustoms, the user-constants paths) that each want a focused pass rather than an unattended rename.
* refactor: normalize module package headers and enforce themCraig Jennings13 hours1-0/+98
| | | | | | The first-line header on 33 modules named the file without its .el extension (;;; font-config --- ... rather than ;;; font-config.el --- ...), the form checkdoc and package-lint expect and the other modules already use. I normalized all 33 to the canonical ;;; name.el --- summary shape. The change is line 1 only. A new test, test-meta-package-headers.el, locks the convention. It checks every module for the canonical first line, Commentary before Code, a provide footer, and no BOM, and unit-tests the checker against each malformed shape so the guard itself is proven.
* fix(music): define the playlist-header facesCraig Jennings18 hours1-0/+25
| | | | The route-colors pass dropped the literal cj/music-* face definitions but left the playlist header referencing them, so every header render spammed "Invalid face reference". I restored the five as deffaces that inherit themed base faces, so the theme still owns their colors. A test asserts each referenced face is defined.
* fix(ai-term): keep agent buffers alive through the kill-all sweepCraig Jennings26 hours1-0/+52
| | | | | | F1 (cj/dashboard-only) kills every other buffer, burying only those on the undead list. Agent buffers were never registered, so the sweep killed live agents and detached their sessions. Agent buffers are a dynamic family ("agent [<project>]") that an exact-name list can't pre-enumerate, so undead-buffers gains a regexp list (cj/undead-buffer-regexps) and a centralized cj/--buffer-undead-p predicate. Both kill paths route through it. ai-term registers the "agent [" pattern, so every agent -- current or future, however created -- is buried rather than killed.
* feat(calibre): open calibredb filtered to the in-progress booksCraig Jennings27 hours1-0/+57
| | | | | | Every calibredb launch (the dashboard "b", M-x, anywhere) now opens filtered to the in-progress books rather than the whole library, via an :after advice on calibredb. Clear with L or x to see everything. The filter scopes to the tag field (calibredb-tag-filter-p), not a bare keyword search. A bare keyword matches any field, which surfaced books that only mention "in-progress" in their description.
* feat(reading): reformat PDF bookmark names like EPUBsCraig Jennings27 hours1-37/+57
| | | | | | Bookmark reformatting to "Author, Title" was nov-only, so PDF bookmarks kept the raw filename. PDFs open in pdf-view-mode, whose pdf-view-bookmark-make-record carried no advice. I added a parallel :filter-return advice there, reusing the same extension-agnostic filename parser, and renamed the helpers off the nov- prefix to reading- since they now serve both EPUB and PDF. New tests cover a PDF filename and a PDF-shaped record.
* feat(dashboard): add a weather launcher (wttrin)Craig Jennings28 hours1-12/+18
| | | | | | A Weather launcher joins the dashboard's top row after Agenda, on key w, drawn with the nf-weather-day_sunny_overcast Weather Icons glyph. It opens the wttrin forecast through call-interactively so wttrin's location prompt runs. A bare (wttrin) call errors, since the command takes the location as a required argument that its interactive form supplies. Row sizes move from 4-4-3-3 to 5-4-3-3. The launcher table stays the single source for both the navigator icons and the keymap.
* fix(ai-term): summon restores the agent's last fullscreen stateCraig Jennings28 hours1-0/+114
| | | | | | Summoning the agent (M-SPC) into a single-window frame docked it at the default fraction even when it was last fullscreen, because the size-memory model only captured split geometry at toggle-off and a sole window has no dock size to record. A window-configuration-change-hook tracker now records whether the displayed agent fills its frame (cj/--ai-term-last-fullscreen), and display-saved restores it in place when that flag and a single-window frame both hold. The tracker records only that flag, not dock geometry: re-capturing the dock size on every window change fed a capture/replay loop that drifted the dock height a couple rows per cycle. The restore guard uses (one-window-p t) so an active minibuffer (a picker prompt mid-summon) isn't counted as a second window, which otherwise misfired the restore into a dock and cascaded.
* feat(windows): bind M-arrow to the window pull-away and resizeCraig Jennings30 hours1-0/+45
| | | | | | M-<arrow> now mirrors C-; b <arrow>. From a sole window it pulls a sliver split open on the opposite edge, revealing the previous buffer. In a multi-window layout it nudges the divider via windsize. cj/window-resize-sticky derives the arrow with event-basic-type, so one command serves both chords. M-up/down were unbound, and M-left/right shed word-motion, which stays on C-left/right. org and other modes that own M-arrow still shadow it, so C-; b remains the universal binding.
* docs: fix blank package summaries and normalize more module headersCraig Jennings38 hours2-2/+2
| | | | More of the commentary/comment audit. The custom-* command modules, weather-config, and mousetrap-mode had empty package summary lines and verbose summary paragraphs. I filled the summaries and condensed the prose while keeping each module's load-contract metadata. dwim-shell-config and auth-config had malformed ;; headers (now ;;;), local-repository had a leading BOM, and two test files had blank summaries.
* refactor(system-commands): bind C-; ! to the menu, drop the leaf keysCraig Jennings38 hours1-19/+18
| | | | C-; ! was a prefix map with per-command leaf keys (s/r/e/l/L/E/S) I rarely use. I bound C-; ! directly to the completing-read menu instead and removed the leaf keys, reclaiming the real-estate. Every command stays reachable through the menu. Updated the commentary and the two keymap tests to the new contract.
* fix(transcription): write stderr to the error log instead of a phantom bufferCraig Jennings39 hours1-3/+47
| | | | | | make-process :stderr was a file path, but :stderr takes a buffer, so Emacs made a buffer named after the path instead of writing the file. The "Errored. Logs in <file>" notification pointed at a log with no error text, and that hidden buffer leaked one per transcription. I now route stderr through an explicit, erased buffer: passed to :stderr, threaded to the sentinel, drained into the log, then killed. That keeps stderr off the stdout :buffer, so the transcript stays clean.
* feat(eat): reset SGR at newline to contain unterminated-color bleedCraig Jennings3 days1-0/+11
| | | | Claude Code and similar inline TUIs sometimes truncate a colored span without emitting a reset; the unterminated color then bleeds onto every following line in the EAT buffer. Advise eat-term-process-output to inject an SGR reset before each newline, containing the bleed to its own line. Validated in real EAT and via an ansi-color proxy: it contains the bleed and leaves per-line coloring intact, since programs re-open their color on each line. Gated by cj/eat-reset-sgr-at-newline (default on) so it can be disabled if a program ever carries one color across newlines without re-opening it.
* feat(eat): tame the viewport bounce from full-frame inline redrawsCraig Jennings3 days1-0/+9
| | | | Claude Code (and any Ink-style inline TUI) moves the terminal cursor up to redraw its whole block and back to the bottom on every tick; EAT follows the cursor with point, so the Emacs window chases it up and down -- the bounce. Add cj/--eat-tame-scroll on eat-mode-hook: scroll-conservatively 101, scroll-margin 0, and auto-window-vscroll nil, so the window line-scrolls minimally instead of recentering. It doesn't remove the bounce (the inline redraw is the root) but makes each jump gentler.
* feat(dirvish): make dired d=diff and D=delete to match the conventionCraig Jennings3 days1-0/+23
| | | | dired's d was dired-flag-file-deletion and D was dired-do-delete, while the ediff diff sat on e. Bind d to the ediff diff and keep D as delete, so the d=diff / D=delete pair is consistent with C-; b and ibuffer. d no longer flags for deletion -- mark with m for batch deletes, then D. Fix the stale commentary (it called d "delete" and D "duplicate") and add which-key labels for the pair.
* fix(eat): forward word-motion arrows to the terminal in agent buffersCraig Jennings3 days1-0/+8
| | | | C-/M-left/right were in EAT's default eat-semi-char-non-bound-keys, so they fell through to Emacs and ran left-word/right-word, moving point in the EAT buffer instead of being sent to the program. The terminal's own cursor never moved, so the next keystroke snapped point back to the real cursor -- the "cursor jumps back" symptom when editing claude's input. Bind them to eat-self-input so they forward as word motion, the way ghostel did. Window arrows (S-, C-M-) still reach Emacs for windmove and buffer-move.
* fix(eat): make Escape the unified copy-mode exitCraig Jennings4 days1-0/+15
| | | | EAT's semi-char mode left the bare escape key unbound and treated ESC only as the Meta prefix, so a lone Escape never reached the pty. That is why C-<up>'s tmux copy-mode could not be exited with Escape: tmux's own Escape=cancel binding never saw the key. Bind <escape> to forward ESC to the terminal, so it cancels tmux copy-mode and still works in TUIs like vim. Also bind <escape> in eat-mode-map to return to semi-char, so the same key exits EAT's own emacs and char modes. One exit key for both copy views; q is no longer required.
* chore(ibuffer): put diff on d and delete on DCraig Jennings4 days1-0/+9
| | | | In the ibuffer buffer list, d now diffs the buffer at point against its saved file (ibuffer-diff-with-file, was on =) and D marks it for deletion (was on d; x still executes the marks).
* refactor(term): finish ghostel retirement (phase 5)Craig Jennings4 days16-44/+32
| | | | Remove the dead ghostel app from theme-studio: the GHOSTEL_FACES/SEED data, the registry row, the renderGhostelPreview previewer, and the package_seed test, then regenerate the tool. ansi-color stays since eat inherits it. Rename testutil-ghostel-buffers to testutil-terminal-buffers and drop make-fake-ghostel-buffer; the toggle-filter test now uses the eat fixture, since agents are eat. Fix the comments that still called the agent buffers ghostel (they're eat now) in eat-config and the ai-term and auto-dim test docstrings. I also package-deleted the unused ghostel ELPA package. Full suite green; the remaining ghostel mentions are accurate migration history.
* feat(external-open): open videos in a looping playerCraig Jennings4 days1-4/+81
| | | | Opening a video from dirvish routed through cj/xdg-open to the OS default handler, which plays it once. I pulled the video extensions into their own cj/video-extensions list and route them through a new cj/open-video-looping, which launches mpv with --loop-file=inf (the player and its args are both customizable) detached, so the video plays on repeat. Audio and office docs still use the OS default handler. The find-file advice already covers dirvish RET, so this applies wherever a video is opened.
* test(init): drop deleted term-config from the classified-modules list; mark ↵Craig Jennings4 days1-1/+0
| | | | consolidation phase 4 done
* refactor(term): retire ghostel, migrate copy-mode and tmux-history to eat-configCraig Jennings4 days3-293/+74
| | | | Complete the EAT consolidation by removing ghostel. ai-term and F12 already run on EAT, so ghostel's only remaining users were the dashboard launcher and term-config itself. Migrate the terminal-generic pieces into eat-config: the tmux copy-mode (C-<up> enters it, the same UX and keybinding as before, since agents run EAT over tmux) and the tmux-history capture, swapping ghostel-send-string for a pty write and the mode checks to eat-mode. Repoint the dashboard "Launch Terminal" to the eshell/EAT toggle, swap the face-diagnostic terminal-mode check to eat-mode, and refresh auto-dim's comment. Delete term-config.el and its init require. EAT's default semi-char non-bound-keys already lets windmove, buffer-move, and the Emacs essentials reach the terminal. Tests retargeted; the obsolete ghostel-keymap-exceptions tests are dropped.
* feat(ai-term): run agents through EAT instead of ghostelCraig Jennings4 days2-67/+59
| | | | Port ai-term from ghostel to EAT. Agents spawn in an EAT terminal running the same tmux session (tmux new-session -A -s aiv-<project>), so the persistence and detach/reattach model is unchanged. A spike confirmed EAT + tmux detach and reattach exactly like ghostel + tmux. The swaps: (ghostel) becomes (eat) with eat-buffer-name carrying the agent name, ghostel-send-string becomes a process-send-string helper, and the M-SPC swap chord is bound directly in eat-semi-char-mode-map (no exception-list plus rebuild dance). Buffer detection was already name-based, so the dispatch, next, and cycle logic is unchanged. Dropped the now-unused suppress-tmux variable. Tests updated to mock eat.
* feat(eshell): zsh-parity prompt segments and zoxideCraig Jennings4 days1-0/+75
| | | | Bring eshell closer to the zsh terminal it replaces. The prompt now shows the git branch (read from .git/HEAD, no subprocess, skipped on remote so TRAMP stays fast) and a [N] exit-status segment when the last command failed, matching the zsh prompt's info. Add a zoxide z command and an eshell-directory-change hook that feeds zoxide add, sharing the same frecency database as the zsh shell. New tests cover the pure prompt helpers.
* refactor(term): F12 opens eshell-through-EAT, retire eshell-toggle and ↵Craig Jennings4 days2-21/+31
| | | | | | xterm-color Point the F12 dock-and-remember toggle at eshell instead of a standalone EAT zsh shell, so the primary terminal is eshell running through EAT (eat-eshell-mode): elisp functions as commands, TRAMP transparency, and EAT rendering visual commands. Drop the eshell-toggle package and its C-<f12> binding, since F12 covers it now. Drop xterm-color from eshell, since EAT handles ANSI color natively and its TERM=xterm-256color fought EAT's own. The toggle's buffer predicate now matches eshell-mode; the toggle tests and fixture are updated.
* refactor(term): extract eat-config.el from term-config.elCraig Jennings4 days3-3/+3
| | | | Move the eat use-package, the F12/C-; keymap wiring, and the F12 dock-and-remember toggle out of term-config.el into a dedicated eat-config.el. term-config.el keeps ghostel (ai-term's backend) and requires eat-config for cj/term-toggle and cj/turn-off-chrome-for-term. Pure relocation, no behavior change. First step toward consolidating on EAT and retiring ghostel. The toggle tests now require eat-config.
* feat(term): toggle EAT instead of ghostel on F12Craig Jennings4 days2-20/+40
| | | | F12 now creates and toggles a single EAT terminal (pure-elisp, fully themeable) instead of a ghostel one, reusing the existing dock-and-remember geometry toggle. ghostel stays for ai-term on M-SPC. The EAT terminal runs a plain shell with no tmux. F12 and C-; are bound in EAT's semi-char and mode keymaps so they reach Emacs from inside the terminal (EAT forwards unbound keys to the shell otherwise). Retargeted the toggle's buffer predicate and create-new path from ghostel to EAT, and updated the buffer-filter tests to the EAT semantics.
* fix(transcription): land video transcripts beside the source, not in /tmpCraig Jennings4 days1-0/+22
| | | | The video flow extracts audio to a temp .mp3 in /tmp, then derived the .txt/.log from that temp path, so transcripts landed in /tmp and died on reboot, contradicting the "alongside the source" docstring. Thread the source video through cj/--start-transcription-process as an optional output base so the outputs derive from it (talk.mp4 -> talk.txt beside the video). Audio is unchanged. New regression test pins the output base to the source video.
* fix(calendar-sync): atomic writes, curl --fail, and zero-event vs garbageCraig Jennings4 days2-3/+76
| | | | Three robustness fixes from the config audit. (1) calendar-sync--write-file and --save-state now write a temp file in the same directory and rename it into place, so org-agenda or chime reading mid-write never sees a half-written calendar. (2) The two curl fetches gain --fail, so an HTTP 404/500 error page exits non-zero instead of flowing its HTML into conversion. (3) calendar-sync--parse-ics distinguishes a healthy zero-event calendar (a real iCalendar with BEGIN:VCALENDAR and no in-window events returns the header) from garbage (no VCALENDAR returns nil), so a near-empty calendar no longer reports "parse failed". New robustness tests; the empty-calendar boundary test updated to the corrected behavior. Verified against the live feed: all three calendars fetch and write cleanly.
* chore(dashboard): use the nf-cod-library codicon for the Calibre launcherCraig Jennings4 days1-1/+2
| | | | Closer to the actual Calibre logo than the faicon book-open. Switches the launcher's icon function to nerd-icons-codicon, adds the matching declare-function, and adds nerd-icons-codicon to the test's icon mock.
* test(ai-term): isolate layout-capture globals in collapse-split testsCraig Jennings4 days1-2/+12
| | | | The multi-window and single-window collapse tests call cj/ai-term, which captures the current layout into cj/--ai-term-last-direction / cj/--ai-term-last-size on toggle-off, but only let-bound cj/--ai-term-last-was-bury. They leaked last-direction into the display-rule test, whose display-saved action reads those globals to choose the split direction, so its agent buffer split below instead of right and the assertion failed. Let-bind last-direction and last-size to nil, matching the roundtrip test in the same file. Full ai-term suite is green.
* feat(ai-term): step into detached sessions too, attaching themCraig Jennings4 days4-75/+100
| | | | The next-agent step (C-; a n / M-SPC) cycled only live agent buffers, so a detached session (alive in tmux, no Emacs buffer) was reachable only through the picker. Now the queue is every active agent, live buffer or live session, keyed on the project dir and ordered by buffer name. Stepping onto a detached one attaches it: show-or-create recreates the terminal, which reattaches the tmux session. The live-buffer swap path is unchanged. I replaced the buffer-rotation helper with a dir-based one and added an active-agent enumerator, with 10 tests.
* test(lsp): narrow startup smoke test for prog-lsp config resolutionCraig Jennings5 days1-0/+66
| | | | Pins the load-time invariants of the central LSP module: lsp-enable-remote stays nil (no auto-start on TRAMP files), the file-watch-ignore defaults live in one idempotent helper, the eldoc provider is stripped from the global hook, and no mode accrues a duplicate lsp-deferred entry. Tests the top-level :init and helper surface, since :config defaults defer to lsp-mode's own load under make test.
* feat(google-keep): org-page renderer, refresh command, keybindings (Phase 2-3)Craig Jennings5 days1-0/+142
| | | | The elisp side of the Keep integration: a pure JSON-to-org core (parse, tag/heading/render helpers) kept free of .emacs.d specifics for later extraction, plus the IO runner cj/keep-refresh (async make-process + sentinel, atomic temp-then-rename write to keep-file, stderr-token to display-warning) and the glue (C-c k prefix, executable warning, require in init.el). 15 ERT tests over the core and the parse-render-write chain. Read-only v1; live fetch needs the one-time gkeepapi + token setup.
* fix(calendar-sync): re-derive status from a declined occurrence overrideCraig Jennings5 days1-0/+37
| | | | A recurring event declined for one occurrence still synced with :STATUS: accepted, because apply-single-exception merged the override attendees but never re-derived the user's status from them, so filter-declined never dropped it. Re-derive :status via find-user-status when the exception overrides :attendees, leaving the inherited status when the override doesn't name the user. Four new tests cover declined, accepted, no-attendee, and user-absent overrides.
* fix(dirvish): point the bg wallpaper command at set-wallpaper on WaylandCraig Jennings5 days1-2/+2
| | | | The Wayland branch of cj/--wallpaper-program-for returned swww, but this system's wallpaper daemon is awww, so dirvish "bg" silently no-opped. Point it at the set-wallpaper script (on PATH via dotfiles), which wraps awww img and persists the choice to waypaper's config. X11 still uses feh. Updated the wallpaper-program test to match.
* chore(elisp): clear byte-compile warnings (org, music, org-roam)Craig Jennings5 days1-3/+3
| | | | | | Move own-command bindings out of use-package :bind to keymap-global-set / with-eval-after-load (C-c C-a org-appear-toggle, R music radio-station, C-c n r/t roam recipe/topic) — same keys, verified live. Pull music-config helper defuns out of :config/with-eval-after-load to top level (their proper home; emms referenced only at call time via declare-function). Swap obsolete org-show-all for org-fold-show-all (9.6). Plus declare-function/defvar for lazy symbols. No behavior change; full suite + launch smoke green. Claude-Session: https://claude.ai/code/session_01BqrdWUo9GcznYX2pZr76gZ
* chore(elisp): clear byte-compile warnings (mail, dashboard, eshell, erc)Craig Jennings5 days1-4/+5
| | | | | | Add declare-function/defvar declarations for lazily-loaded package functions and variables so each module compiles cleanly standalone, reflow over-long docstrings, and swap the obsolete erc-server-buffer-p for its named replacement erc-server-or-unjoined-channel-buffer-p (obsolete since 30.1). No behavior change. Two erc setq targets (erc-unique-buffers, erc-generate-buffer-name-function) appear not to be real ERC variables — declared to silence the warning with a NOTE flagging that the intended buffer-naming may not be taking effect. Claude-Session: https://claude.ai/code/session_01BqrdWUo9GcznYX2pZr76gZ
* refactor(org-refile): drop roam Project notes as refile targetsCraig Jennings5 days1-5/+6
| | | | | | Stop scanning org-roam notes tagged "Project" for refile targets; keep the "Topic" scan. Behavior change by decision: roam Projects are no longer pulled in anywhere (the agenda never scanned them either — that was a stale doc claim, corrected separately). Refiling into Topic notes and into per-project todo.org files is unchanged. Test reworked to assert Topic is included and Project is not. Claude-Session: https://claude.ai/code/session_01BqrdWUo9GcznYX2pZr76gZ
* fix(org-agenda): filter missing base files; drop the roam-source doc claimCraig Jennings5 days1-17/+40
| | | | | | cj/--org-agenda-base-files now drops files that do not exist (a fresh machine may lack the synced calendars or the inbox), and org-agenda-skip-unavailable-files is set as a backstop, so org-agenda never prompts to create a missing path — the interactive-prompt class that once hung the chime daemon. The filter lives in the one shared helper, so the agenda builders, single-project view, and the chime initializer all get the existence check. Also correct the docs: the commentary and docstrings claimed org-roam nodes tagged "Project" are agenda sources, but they were never scanned; roam Project/Topic notes are refile targets (org-refile-config.el), not agenda sources. Claude-Session: https://claude.ai/code/session_01BqrdWUo9GcznYX2pZr76gZ
* feat(ai-term): wrap-teardown + shutdown entry points for rulesetsCraig Jennings5 days3-0/+198
| | | | | | Add the three headless functions the rulesets wrap-it-up workflow calls via emacsclient -e, since this module owns the aiv- session naming, the agent buffer, and the geometry restore. cj/ai-term-quit kills a project's tmux session and agent buffer and restores the layout, idempotent and safe when already gone. cj/ai-term-live-count returns the integer count of live aiv- sessions for the shutdown safety gate. cj/ai-term-shutdown-countdown re-checks that gate, then runs an abort-able run-at-time countdown in the echo area and, uncancelled, runs the shutdown command (a defcustom so tests stub it). Reuses the existing kill/close helpers. 13 ERT tests cover the live-count parsing, the quit kill-and-idempotency, and the gate-abort/cancel/tick logic; the tmux and shutdown side effects are manual. Claude-Session: https://claude.ai/code/session_01BqrdWUo9GcznYX2pZr76gZ
* test(nerd-icons): dir-precedence probe + legend round-trip (phase 4)Craig Jennings5 days1-0/+15
| | | | | | Lock the dir-precedence decision with an ERT probe: when a dir icon already carries nerd-icons-completion-dir-face, the advice's prepended nerd-icons-yellow is first in the face list and wins. Extend the #nerdiconstest browser gate with an export/import round-trip over an assigned nerd-icons color, asserting it re-imports to the same state and that the separate nerd-icons-completion dir-face stays out of the nerd-icons app. Claude-Session: https://claude.ai/code/session_01BqrdWUo9GcznYX2pZr76gZ
* feat(nerd-icons): drop the runtime tint so the theme drives icon color (phase 3)Craig Jennings5 days1-63/+0
| | | | | | Remove cj/nerd-icons-tint-color, cj/--nerd-icons-color-faces, cj/nerd-icons-apply-tint and its two call sites, so the 34 nerd-icons color faces are no longer force-set to one darkgoldenrod foreground at load time. The WIP theme already owns those faces (theme-studio auto-discovered them), so with the tint gone their per-filetype colors come from the theme and are editable in theme-studio's new nerd-icons pane. The dir-icon advice (cj/--nerd-icons-color-dir) stays — it points at a theme-owned face now. Delete the apply-tint test, which covered removed code. Claude-Session: https://claude.ai/code/session_01BqrdWUo9GcznYX2pZr76gZ
* fix(term): scope copy-mode to C-<up> and don't re-enter mid-copyCraig Jennings6 days1-62/+76
| | | | | | Today's modified-arrow work bound every C-arrow and M-arrow to copy-mode, which swallowed C-<left>/C-<right> — readline word-motion at the shell prompt. Bind only C-<up> (enter copy-mode and scroll up); the other arrows pass through to the terminal again. C-<up> pressed while already in copy-mode now just moves up: cj/term-copy-mode-up checks tmux pane_in_mode (and ghostel--input-mode without tmux) and skips re-entry, which would otherwise reset the cursor to the start of the line. Claude-Session: https://claude.ai/code/session_01BqrdWUo9GcznYX2pZr76gZ
* fix(latex): activate the latexmk workflowCraig Jennings6 days1-0/+62
| | | | | | Two breaks kept latexmk from ever engaging. The :hook key TeX-mode-hook expanded to the unbound TeX-mode-hook-hook, since use-package appends -hook to any symbol not ending in -mode, so TeX-command-default was never set; name the mode TeX-mode instead. Separately auctex-latexmk was :defer t with no trigger, so auctex-latexmk-setup never ran and latexmk never joined TeX-command-list; load it :after tex. Claude-Session: https://claude.ai/code/session_01BqrdWUo9GcznYX2pZr76gZ
* feat(face-diagnostic): make report face names describe-face buttonsCraig Jennings6 days2-0/+26
| | | | | | Render each real face name in the Face Diagnosis report as a button that runs describe-face on it, carrying the face as button data; anonymous specs and non-faces stay plain text. Also add face-diagnostic to the module-header allowlist now that it is required in init.el and carries the header contract. Claude-Session: https://claude.ai/code/session_01BqrdWUo9GcznYX2pZr76gZ