Commits
Pulls project-manager aeb6325, which fixes the pm-sidebar overlay/marker
leak + render storm that wedged the Emacs daemon (23GB RSS runaway).
The per-terminal reader thread held term_mutex while doing a blocking
write() to the Emacs event pipe. When the display client stopped draining
that pipe -- e.g. an emacsclient suspended inside an Eternal Terminal
session that was slept -- the 64 KiB pipe filled, the reader blocked in
the write holding term_mutex, and the main thread deadlocked waiting for
term_mutex (needed for redisplay / the event filter), wedging the whole
daemon. Reproduced live; draining the pipe was the only recovery.
Carry a local patch (nix/ghostel/event-pipe-nonblocking-flush.patch),
applied to ghostelSrc via pkgs.applyPatches, that:
- flushes events OUTSIDE term_mutex with non-blocking writes, so the
reader never blocks while holding the lock the main loop needs to drain
the pipe, and keeps draining the child PTY while the client is slow;
- backs events with a pooled FIFO of fixed blocks (one form per node, new
src/event_buffer.zig) so the hot path stays allocation-free and the
backlog can be dropped form-aware -- never truncating a form mid-wire,
which would desync Emacs' incremental reader -- when a suspended client
falls far behind;
- restores blocking mode for the reaper's final exit-status write.
Builds clean under zig 0.15.2 (ReleaseFast); EventBuffer unit tests pass.
Runtime suspend repro still pending a daemon running the new module.
Adds the pm-sidebar package (renamed from pm-serve): a toggleable,
point-preserving live agent-session sidebar scoped to the launching
Emacs instance, with RET on a project heading opening the project
dispatch. Bumps the pm flake inputs (flake.lock + lock/flake.lock) to
project-manager c2b7049.
The documented recipe (generate-new-buffer + ghostel--init-buffer) no
longer starts a rendered shell in ghostel 0.36.0 — the buffer comes up
blank and the agent never launches, with no error. Switch the canonical,
background, worktree, and bare-shell spawns to (ghostel t), which creates,
starts, displays, and returns the terminal buffer (honoring a let-bound
ghostel-buffer-name and default-directory). Background spawn now wraps it
in save-window-excursion. Update the API table and tripping hazards.
Update both the pm-src override input and twist's lock/ pm pin (the
latter drives the package's compiled file list). The new revision adds
pm-stacker.el, so the twist pin must advance too or pm-status.el's
(require 'pm-stacker) fails to compile against the stale file list.
Build verified: .#packages.x86_64-linux.default.
Adopt features from the 0.36 bump:
- ghostel-point-leave-input-mode / ghostel-mark-activation-input-mode
('copy): isearch/consult-line/minibuffer nav landing in scrollback,
and keyboard region selection, switch to a read-only mode so the
next redraw can't clobber point or the region.
- ghostel-comint-mode on comint-mode-hook: libghostty VT parser as the
comint preoutput filter for shell / inferior-REPL / ielm buffers
(truecolor SGR, full underline styles, clickable OSC 8 links).
eshell is not comint-derived, so it is unaffected.
- ghostel-compile-global-mode: route compile / recompile /
project-compile through a real ghostel TTY (progress bars, colour,
curses tools); the buffer finalizes into a compilation-mode subclass
with working next-error. grep-mode excluded by default.
Verified end to end: compile routes through ghostel and the finished
buffer parses gnu-style errors and jumps via next-error.
ghostel 0.35+ defaults local buffers to a native PTY (a pipe process
whose process-id is nil), so my/ghostel-buffer-busy-info silently
stopped detecting foreground children, and kill-emacs/kill-buffer no
longer warned about a running Claude Code / cargo build / REPL.
Read the buffer-local ghostel--pid (the shell's OS pid, set for both
the Emacs and native PTY backends) instead, and skip remote TRAMP
buffers whose pid lives on another host. Verified end to end against a
live daemon: idle shell -> nil, running command -> (pid . name).
Update the emacs-unstable input (nix-community/emacs-overlay) and its
transitive nixpkgs pins. emacs-git-pgtk goes 20260421.0 -> 20260620.0.
Both local patches (eln-cache-correct-spot, tty-synchronized-output)
still apply.
Build verified: .#packages.x86_64-linux.default (emacs-jd).
Upstream rewrote cursor handling, moving control to Elisp
(ghostel--apply-cursor-style); a hidden cursor now maps to
cursor-type nil, structurally avoiding the TTY inverse-cell
double-inversion the local patch worked around. The patched Zig
code path no longer exists, so drop the patch entirely.
- flake.lock: ghostel -> 2479c15 (0.36.0); bump zig2nix
- flake.nix: ghostelModule.version -> 0.36.0; ghostelSrc is now
plain inputs.ghostel (no applyPatches); refresh comments
- lock/flake.lock: bump twist's separate ghostel pin so the new
lisp/*.el (ghostel-comint/ime/kitty) are resolved and compiled
- nix/ghostel/build.zig.zon2json-lock: regenerate for the
libghostty bump
- init.org: drop stale ghostel--scroll-positions comment reference
Builds verified: .#ghostelModule and .#packages.x86_64-linux.default.
Upstream picked up a lot since 0.21.0 — most notably the new
ghostel-query-before-killing defcustom and PTY-based password input
detection — and refactored src/render.zig into src/Renderer.zig.
Re-rolled the local patch onto the new Renderer.zig and trimmed it
down to just the inverse-cell stripping for TTY Emacs. The
blinking/password-input cursor-state tracking the old patch added is
unused by this config; upstream's PTY heuristic supersedes it.
Set ghostel-query-before-killing to nil so Emacs's built-in
process-kill prompt doesn't fire alongside the /proc-based handlers,
which already name the foreground command and work through raw-TTY
apps that don't emit OSC 133.
- pm-agent ghostel dispatcher now passes a non-numeric prefix so
every launch lands in a freshly named buffer (no more pasting
argv into a live agent's REPL on the second launch).
- pm-process renames the per-verb stderr buffer to a leading-space
name so the "Process … stderr finished" trailer no longer shows
up in the buffer list after `pm-refresh` on init.
Reframe the skill around its user-facing purpose — launching pm agents
inside the running Emacs daemon — rather than the ghostel terminal that
backs it. Ghostel is now treated as an implementation detail.
Other tweaks bundled in:
- Default `default-directory` to the project root, not a worktree.
Worktree-scoped spawn is now an explicit variation, used only when
the user named one or the task is worktree-bound (stacker, branches).
- Broaden triggers so the skill fires on bare "run/start/spawn an
agent" phrasing — Emacs need not be mentioned, since launching in
the daemon is the user's default.
- Point at the pm-workflow skill for project/worktree discovery
instead of guessing pm subcommands inline.
Plugin packaging the ghostel-agent skill — reference for spawning
coding agents (claude/codex/cursor) into the running Emacs daemon
via emacsclient + ghostel + pm agent. Skill source mirrors the
pm/integrations/claude-code layout so it can be exposed through
the experimental plugin marketplace.
pm-src 1c844ea → 3b6d5e4 (emacs: set default-directory on pm
buffers). Set pm-manager-project to "manager" so global pm
buffers (list, pool, repos, all-projects agent-list) cwd into
the manager container instead of falling back to ~.
- Bump `ghostel` flake input from e8eb2f8 to upstream HEAD (0.21.0
release; 43 commits, including rendering refactor and the Zigify
rewrite). Re-rolled the cursor-render patch onto the new
render.zig API (gt.rs.getMulti / gt.rs_row.read / readCellStyle
taking cells+raw, env.call4).
- Drop the `ghostel-link-map' RET workaround. Upstream c145c5e
(skip link detection on the active prompt and prompt prefix)
fixes the underlying bug — `cd src/main.rs' at the prompt no
longer hijacks RET into ghostel-open-link-at-point.
- Fix bare-ESC translator install gate. The earlier
`(unless (display-graphic-p))' silently no-op'd on pgtk daemons
whose initial frame reports graphic, so every later
`emacsclient -t' inherited the stock xterm CSI prefix decoder
for ESC. Trigger on `daemonp' too.
- Disable jinx in ghostel buffers. Spell-check on live terminal
output thrashes its overlays.
Drops the submodules/ghostel git submodule. Upstream is now pulled in as
a flake input pinned to a github commit, and our local changes live as
patches under patches/ghostel applied via pkgs.applyPatches. Single
patched src is shared between the Zig module build and the elisp
package override.
Keeps the cursor-render TTY fix (b3196b7); drops the debug tooling
commit (b8079ad) — that scaffolding was only useful while diagnosing
the cursor issue.
Magit master uses `transient--get-format' (transient 0.13+); Emacs 31
ships transient 0.12. Add a twist recipe pointing at magit/transient
plus a root `use-package' so `nix run .#lock --impure' resolves it.
Drop monet and websocket inputs — no longer referenced.
Add `bookmark-make-record-function' support for ghostel buffers. A
mode-hook sets `my/ghostel-bookmark-make-record' buffer-locally; the
record captures `default-directory' (kept current via OSC 7, TRAMP-
aware) and the buffer's canonical identity (`ghostel--buffer-identity',
the original name from before title-tracking renames).
The handler `my/ghostel-bookmark-jump' rebinds `default-directory' and
`ghostel-buffer-name' and calls `(ghostel)', which reuses a live buffer
with the same identity if one exists — otherwise spawns a fresh shell
at the recorded directory under the original name. Project-prefixed
identities round-trip because we restore the literal name rather than
re-deriving it from `project-current'.
`ghostel-buffer-name' is `defvar'-declared so the `let' creates a
dynamic binding `ghostel' can see; the file is `lexical-binding' and
the autoload may not have fired before the first jump.
PTY, scrollback, and child process are not persisted — only the intent
to recreate.
Add a ghostel-aware $VISUAL/$EDITOR wrapper exposed via flake output
homeManagerModules.ghostel-editor. The wrapper branches on
EMACS_GHOSTEL_PATH: inside a ghostel-managed terminal it forwards the
file to the running Emacs daemon via emacsclient (so e.g. Ctrl+G in
Claude Code pops the buffer into the user's existing Emacs frame);
elsewhere it falls back to $EDITOR. The module wires it through
$VISUAL so the user's $EDITOR remains untouched and naturally serves
as the fallback.
Move the always-on emacs-daemon unit out of integrations/systemd/ (a
hand-installed user service) into integrations/home-manager/ as a
home-manager module exposed via flake output
homeManagerModules.emacs-daemon. Lets the home-manager flake import
it directly instead of dropping a unit file by hand.
Adds `nix/patches/tty-synchronized-output.patch' (a local term.c patch
wrapping each TTY redraw in DEC mode 2026 BSU/ESU markers) to the
`emacs-git-pgtk' override, and turns it on in init.org's Display block
via `(setq tty-synchronized-output t)' so Ghostty presents frames
atomically and TTY Emacs stops flickering during heavy redraws.
Patch summary: install a `tty_update_begin' hook (term.c) that emits
`ESC[?2026h' when the variable is non-nil, modify `tty_update_end' to
emit `ESC[?2026l' before its existing fflush, add a recursion guard
bitfield to `struct tty_display_info' (termchar.h), and emit a defensive
ESU on `tty_reset_terminal_modes' so suspend/exit doesn't strand the
terminal in synchronized-update mode.
Bundled side changes:
- flake input `pm-src' (github:jordan-isaacs_data/project-manager) +
pmSrc plumbing into nix/packageOverrides.nix, which overrides the
`pm' package's src to that input.
- init.org: switch `monet' use-package block to `:tangle no'.
7 commits, mostly the magit-section rewrite of pm's status/list buffers:
each render is wrapped in a root section, bookkeeping resets on
re-render, the root section's region carries a `magit-section' text
property, and `pm-agent-list' defaults to --all. pm-pool now renders
the real CLI slot fields (uuid/branch/status).
Refactor the foreground-child probe so the (BUFFER, PID, COMM) chain
flows through one helper:
my/ghostel--foreground-child SHELL-PID → (PID . COMM) | nil
my/ghostel-buffer-busy-info BUFFER → (PID . COMM) | nil
my/ghostel-busy-buffers → ((BUFFER . COMM) ...)
`my/ghostel--foreground-child' resolves the PTY foreground process
group leader (tpgid in /proc/SHELL-PID/stat) and reads its
/proc/PID/comm, so prompts now name the offender — `claude in *ghostel:
foo*' rather than just the buffer name.
Add a `kill-buffer-query-functions' hook so killing a single ghostel
buffer with a busy child also prompts. The kill-emacs hook keeps the
same scope but now lists each busy buffer with its command.
Rebase the submodule onto upstream tip (e8eb2f8 + 2 patches; was on
v0.17.0 + 3). cd13a03 "fix meta" is dropped — superseded by upstream
c42451e, which adds the same TTY ESC-prefix re-injection plus an
explicit M-DEL binding and a regression test. The other two local
patches replay cleanly:
b8079ad Expand debug tooling with VT log mirroring and cursor probes
b3196b7 Track cursor render state and strip inverse cell for TTY Emacs
Upstream's repo reorg (266e3e9) moves Lisp under lisp/, the bundled
terminfo to etc/terminfo/, and shell-integration shims to etc/shell/.
The previous nix wiring papered over that with a custom files map in
inputOverrides; the new layout lines up with twist's MELPA :defaults,
so collapse the override entirely and let the recipe carry the diff:
recipes/ghostel : :files (:defaults "etc")
inputOverrides : ghostel block removed (was a no-op)
packageOverrides: drop `rm -f evil-ghostel.el ghostel-evil.el`
(recipe doesn't pull them in any more)
flake.nix : ghostel-module version 0.17.0 → 0.18.1
Init.org cleanups, all driven by upstream commits already in our base:
- Remove the 16-face `ghostel-color-* → ansi-color-*' remap.
a27f2fa already inherits from `ansi-color-*' natively, which is
what the remap was working around.
- Drop the `M-DEL' :bind entry; c42451e binds it upstream.
- Override `ghostel-link-map' RET back to `ghostel--send-event'.
Plain-link detection (3c61db6) attaches a `keymap' text property
on every detected path, including paths typed at the prompt; the
text-property keymap wins over `ghostel-mode-map', so RET on a
line like `cd submodules/ghostel/' opens dired instead of running
the command. Mouse-1 still opens links.
- Fix the monet ZDOTDIR chain target: 266e3e9 renamed
`etc/shell-integration/zsh' to `etc/shell/bootstrap/zsh'. The
chain was silently failing (path didn't exist), which prevented
ghostel's own zsh integration from sourcing — no OSC 7 cwd
updates, so `default-directory' in ghostel buffers stayed pinned
to the spawn directory and project.el couldn't bucket them by
project.
Drops the local-path use-package in favor of `recipes/pm` pointing at
github.com/jordan-isaacs_data/project-manager with a :files spec
mapping the elisp out of integrations/emacs/. Twist now treats pm
like any other MELPA-style dependency: lockfile-pinned, nix-built,
no manual checkout required.
The user-systemd environment doesn't include ~/.local/bin by default,
so executable-find / process-file in the daemon couldn't resolve `pm`
(installed via `uv pip install --user`). Setting Environment=PATH=
in the unit fixes this without requiring absolute paths in package
defcustoms.
~/.nix-profile/bin is included for the same reason — `nix` and other
nix-installed CLIs become directly invokable from Emacs.
The pm repo's `extensions/` was renamed to `integrations/' for
consistency with this repo's own `integrations/' convention.
Always-on Emacs daemon service (tmux/zellij-style) with notify type,
on-failure restart, and a clean kill-emacs shutdown. Same file I had
under ~/startup/emacs-daemon/ locally; moving it into the repo so
install is `ln -sf` + daemon-reload.
README documents install / verify / uninstall.
Wires the standalone Emacs package shipped from
~/.repos/project-manager/extensions/emacs/. Hooks the pm container
finder into project.el, binds C-x p P (pm-dispatch) and C-x p .
(pm-project-dispatch), and registers pm-project-dispatch as the post-
project-switch entry "PM". Initial pm-refresh runs on an idle timer
out of after-init-hook.
* Switch to yasnippet and fix the broken autocomplete chars. cape super
doesn't work.
* Lower stealth jit lock time
* Run treesit--pre-display in an idle timer
* Tune jit-lock settings.
* Adds claude-code and a CLAUDE.md
* Updates packages/inputs
* Remove and re-add (aka update) lock directory
* Elpa is broken for subpackages (files within a parent package). Add
recipes for them
* Update all flake inputs. Some minor build changes
* Disable go-mod-ts-mode. Get a file not found error. Will figure out
later.
The per-terminal reader thread held term_mutex while doing a blocking
write() to the Emacs event pipe. When the display client stopped draining
that pipe -- e.g. an emacsclient suspended inside an Eternal Terminal
session that was slept -- the 64 KiB pipe filled, the reader blocked in
the write holding term_mutex, and the main thread deadlocked waiting for
term_mutex (needed for redisplay / the event filter), wedging the whole
daemon. Reproduced live; draining the pipe was the only recovery.
Carry a local patch (nix/ghostel/event-pipe-nonblocking-flush.patch),
applied to ghostelSrc via pkgs.applyPatches, that:
- flushes events OUTSIDE term_mutex with non-blocking writes, so the
reader never blocks while holding the lock the main loop needs to drain
the pipe, and keeps draining the child PTY while the client is slow;
- backs events with a pooled FIFO of fixed blocks (one form per node, new
src/event_buffer.zig) so the hot path stays allocation-free and the
backlog can be dropped form-aware -- never truncating a form mid-wire,
which would desync Emacs' incremental reader -- when a suspended client
falls far behind;
- restores blocking mode for the reaper's final exit-status write.
Builds clean under zig 0.15.2 (ReleaseFast); EventBuffer unit tests pass.
Runtime suspend repro still pending a daemon running the new module.
The documented recipe (generate-new-buffer + ghostel--init-buffer) no
longer starts a rendered shell in ghostel 0.36.0 — the buffer comes up
blank and the agent never launches, with no error. Switch the canonical,
background, worktree, and bare-shell spawns to (ghostel t), which creates,
starts, displays, and returns the terminal buffer (honoring a let-bound
ghostel-buffer-name and default-directory). Background spawn now wraps it
in save-window-excursion. Update the API table and tripping hazards.
Update both the pm-src override input and twist's lock/ pm pin (the
latter drives the package's compiled file list). The new revision adds
pm-stacker.el, so the twist pin must advance too or pm-status.el's
(require 'pm-stacker) fails to compile against the stale file list.
Build verified: .#packages.x86_64-linux.default.
Adopt features from the 0.36 bump:
- ghostel-point-leave-input-mode / ghostel-mark-activation-input-mode
('copy): isearch/consult-line/minibuffer nav landing in scrollback,
and keyboard region selection, switch to a read-only mode so the
next redraw can't clobber point or the region.
- ghostel-comint-mode on comint-mode-hook: libghostty VT parser as the
comint preoutput filter for shell / inferior-REPL / ielm buffers
(truecolor SGR, full underline styles, clickable OSC 8 links).
eshell is not comint-derived, so it is unaffected.
- ghostel-compile-global-mode: route compile / recompile /
project-compile through a real ghostel TTY (progress bars, colour,
curses tools); the buffer finalizes into a compilation-mode subclass
with working next-error. grep-mode excluded by default.
Verified end to end: compile routes through ghostel and the finished
buffer parses gnu-style errors and jumps via next-error.
ghostel 0.35+ defaults local buffers to a native PTY (a pipe process
whose process-id is nil), so my/ghostel-buffer-busy-info silently
stopped detecting foreground children, and kill-emacs/kill-buffer no
longer warned about a running Claude Code / cargo build / REPL.
Read the buffer-local ghostel--pid (the shell's OS pid, set for both
the Emacs and native PTY backends) instead, and skip remote TRAMP
buffers whose pid lives on another host. Verified end to end against a
live daemon: idle shell -> nil, running command -> (pid . name).
Upstream rewrote cursor handling, moving control to Elisp
(ghostel--apply-cursor-style); a hidden cursor now maps to
cursor-type nil, structurally avoiding the TTY inverse-cell
double-inversion the local patch worked around. The patched Zig
code path no longer exists, so drop the patch entirely.
- flake.lock: ghostel -> 2479c15 (0.36.0); bump zig2nix
- flake.nix: ghostelModule.version -> 0.36.0; ghostelSrc is now
plain inputs.ghostel (no applyPatches); refresh comments
- lock/flake.lock: bump twist's separate ghostel pin so the new
lisp/*.el (ghostel-comint/ime/kitty) are resolved and compiled
- nix/ghostel/build.zig.zon2json-lock: regenerate for the
libghostty bump
- init.org: drop stale ghostel--scroll-positions comment reference
Builds verified: .#ghostelModule and .#packages.x86_64-linux.default.
Upstream picked up a lot since 0.21.0 — most notably the new
ghostel-query-before-killing defcustom and PTY-based password input
detection — and refactored src/render.zig into src/Renderer.zig.
Re-rolled the local patch onto the new Renderer.zig and trimmed it
down to just the inverse-cell stripping for TTY Emacs. The
blinking/password-input cursor-state tracking the old patch added is
unused by this config; upstream's PTY heuristic supersedes it.
Set ghostel-query-before-killing to nil so Emacs's built-in
process-kill prompt doesn't fire alongside the /proc-based handlers,
which already name the foreground command and work through raw-TTY
apps that don't emit OSC 133.
- pm-agent ghostel dispatcher now passes a non-numeric prefix so
every launch lands in a freshly named buffer (no more pasting
argv into a live agent's REPL on the second launch).
- pm-process renames the per-verb stderr buffer to a leading-space
name so the "Process … stderr finished" trailer no longer shows
up in the buffer list after `pm-refresh` on init.
Reframe the skill around its user-facing purpose — launching pm agents
inside the running Emacs daemon — rather than the ghostel terminal that
backs it. Ghostel is now treated as an implementation detail.
Other tweaks bundled in:
- Default `default-directory` to the project root, not a worktree.
Worktree-scoped spawn is now an explicit variation, used only when
the user named one or the task is worktree-bound (stacker, branches).
- Broaden triggers so the skill fires on bare "run/start/spawn an
agent" phrasing — Emacs need not be mentioned, since launching in
the daemon is the user's default.
- Point at the pm-workflow skill for project/worktree discovery
instead of guessing pm subcommands inline.
- Bump `ghostel` flake input from e8eb2f8 to upstream HEAD (0.21.0
release; 43 commits, including rendering refactor and the Zigify
rewrite). Re-rolled the cursor-render patch onto the new
render.zig API (gt.rs.getMulti / gt.rs_row.read / readCellStyle
taking cells+raw, env.call4).
- Drop the `ghostel-link-map' RET workaround. Upstream c145c5e
(skip link detection on the active prompt and prompt prefix)
fixes the underlying bug — `cd src/main.rs' at the prompt no
longer hijacks RET into ghostel-open-link-at-point.
- Fix bare-ESC translator install gate. The earlier
`(unless (display-graphic-p))' silently no-op'd on pgtk daemons
whose initial frame reports graphic, so every later
`emacsclient -t' inherited the stock xterm CSI prefix decoder
for ESC. Trigger on `daemonp' too.
- Disable jinx in ghostel buffers. Spell-check on live terminal
output thrashes its overlays.
Drops the submodules/ghostel git submodule. Upstream is now pulled in as
a flake input pinned to a github commit, and our local changes live as
patches under patches/ghostel applied via pkgs.applyPatches. Single
patched src is shared between the Zig module build and the elisp
package override.
Keeps the cursor-render TTY fix (b3196b7); drops the debug tooling
commit (b8079ad) — that scaffolding was only useful while diagnosing
the cursor issue.
Add `bookmark-make-record-function' support for ghostel buffers. A
mode-hook sets `my/ghostel-bookmark-make-record' buffer-locally; the
record captures `default-directory' (kept current via OSC 7, TRAMP-
aware) and the buffer's canonical identity (`ghostel--buffer-identity',
the original name from before title-tracking renames).
The handler `my/ghostel-bookmark-jump' rebinds `default-directory' and
`ghostel-buffer-name' and calls `(ghostel)', which reuses a live buffer
with the same identity if one exists — otherwise spawns a fresh shell
at the recorded directory under the original name. Project-prefixed
identities round-trip because we restore the literal name rather than
re-deriving it from `project-current'.
`ghostel-buffer-name' is `defvar'-declared so the `let' creates a
dynamic binding `ghostel' can see; the file is `lexical-binding' and
the autoload may not have fired before the first jump.
PTY, scrollback, and child process are not persisted — only the intent
to recreate.
Add a ghostel-aware $VISUAL/$EDITOR wrapper exposed via flake output
homeManagerModules.ghostel-editor. The wrapper branches on
EMACS_GHOSTEL_PATH: inside a ghostel-managed terminal it forwards the
file to the running Emacs daemon via emacsclient (so e.g. Ctrl+G in
Claude Code pops the buffer into the user's existing Emacs frame);
elsewhere it falls back to $EDITOR. The module wires it through
$VISUAL so the user's $EDITOR remains untouched and naturally serves
as the fallback.
Adds `nix/patches/tty-synchronized-output.patch' (a local term.c patch
wrapping each TTY redraw in DEC mode 2026 BSU/ESU markers) to the
`emacs-git-pgtk' override, and turns it on in init.org's Display block
via `(setq tty-synchronized-output t)' so Ghostty presents frames
atomically and TTY Emacs stops flickering during heavy redraws.
Patch summary: install a `tty_update_begin' hook (term.c) that emits
`ESC[?2026h' when the variable is non-nil, modify `tty_update_end' to
emit `ESC[?2026l' before its existing fflush, add a recursion guard
bitfield to `struct tty_display_info' (termchar.h), and emit a defensive
ESU on `tty_reset_terminal_modes' so suspend/exit doesn't strand the
terminal in synchronized-update mode.
Bundled side changes:
- flake input `pm-src' (github:jordan-isaacs_data/project-manager) +
pmSrc plumbing into nix/packageOverrides.nix, which overrides the
`pm' package's src to that input.
- init.org: switch `monet' use-package block to `:tangle no'.
7 commits, mostly the magit-section rewrite of pm's status/list buffers:
each render is wrapped in a root section, bookkeeping resets on
re-render, the root section's region carries a `magit-section' text
property, and `pm-agent-list' defaults to --all. pm-pool now renders
the real CLI slot fields (uuid/branch/status).
Refactor the foreground-child probe so the (BUFFER, PID, COMM) chain
flows through one helper:
my/ghostel--foreground-child SHELL-PID → (PID . COMM) | nil
my/ghostel-buffer-busy-info BUFFER → (PID . COMM) | nil
my/ghostel-busy-buffers → ((BUFFER . COMM) ...)
`my/ghostel--foreground-child' resolves the PTY foreground process
group leader (tpgid in /proc/SHELL-PID/stat) and reads its
/proc/PID/comm, so prompts now name the offender — `claude in *ghostel:
foo*' rather than just the buffer name.
Add a `kill-buffer-query-functions' hook so killing a single ghostel
buffer with a busy child also prompts. The kill-emacs hook keeps the
same scope but now lists each busy buffer with its command.
Rebase the submodule onto upstream tip (e8eb2f8 + 2 patches; was on
v0.17.0 + 3). cd13a03 "fix meta" is dropped — superseded by upstream
c42451e, which adds the same TTY ESC-prefix re-injection plus an
explicit M-DEL binding and a regression test. The other two local
patches replay cleanly:
b8079ad Expand debug tooling with VT log mirroring and cursor probes
b3196b7 Track cursor render state and strip inverse cell for TTY Emacs
Upstream's repo reorg (266e3e9) moves Lisp under lisp/, the bundled
terminfo to etc/terminfo/, and shell-integration shims to etc/shell/.
The previous nix wiring papered over that with a custom files map in
inputOverrides; the new layout lines up with twist's MELPA :defaults,
so collapse the override entirely and let the recipe carry the diff:
recipes/ghostel : :files (:defaults "etc")
inputOverrides : ghostel block removed (was a no-op)
packageOverrides: drop `rm -f evil-ghostel.el ghostel-evil.el`
(recipe doesn't pull them in any more)
flake.nix : ghostel-module version 0.17.0 → 0.18.1
Init.org cleanups, all driven by upstream commits already in our base:
- Remove the 16-face `ghostel-color-* → ansi-color-*' remap.
a27f2fa already inherits from `ansi-color-*' natively, which is
what the remap was working around.
- Drop the `M-DEL' :bind entry; c42451e binds it upstream.
- Override `ghostel-link-map' RET back to `ghostel--send-event'.
Plain-link detection (3c61db6) attaches a `keymap' text property
on every detected path, including paths typed at the prompt; the
text-property keymap wins over `ghostel-mode-map', so RET on a
line like `cd submodules/ghostel/' opens dired instead of running
the command. Mouse-1 still opens links.
- Fix the monet ZDOTDIR chain target: 266e3e9 renamed
`etc/shell-integration/zsh' to `etc/shell/bootstrap/zsh'. The
chain was silently failing (path didn't exist), which prevented
ghostel's own zsh integration from sourcing — no OSC 7 cwd
updates, so `default-directory' in ghostel buffers stayed pinned
to the spawn directory and project.el couldn't bucket them by
project.
The user-systemd environment doesn't include ~/.local/bin by default,
so executable-find / process-file in the daemon couldn't resolve `pm`
(installed via `uv pip install --user`). Setting Environment=PATH=
in the unit fixes this without requiring absolute paths in package
defcustoms.
~/.nix-profile/bin is included for the same reason — `nix` and other
nix-installed CLIs become directly invokable from Emacs.
Wires the standalone Emacs package shipped from
~/.repos/project-manager/extensions/emacs/. Hooks the pm container
finder into project.el, binds C-x p P (pm-dispatch) and C-x p .
(pm-project-dispatch), and registers pm-project-dispatch as the post-
project-switch entry "PM". Initial pm-refresh runs on an idle timer
out of after-init-hook.