Skip to content

Replace queue-request minibuffer with gfm-mode compose buffer#9

Merged
timvisher-dd merged 6 commits into
mainfrom
queue-via-temp-gfm-compose-buffer
May 12, 2026
Merged

Replace queue-request minibuffer with gfm-mode compose buffer#9
timvisher-dd merged 6 commits into
mainfrom
queue-via-temp-gfm-compose-buffer

Conversation

@timvisher
Copy link
Copy Markdown
Collaborator

M-x agent-shell-queue-request now pops a dedicated gfm-mode compose buffer instead of reading a single line from the minibuffer. C-c C-c queues (when the shell is busy) or submits (when idle) and kills the compose buffer. C-c C-k cancels — silently when the buffer is empty/unmodified, otherwise with a y-or-n-p confirmation, matching magit-commit's feel.

The new compose flow is intentionally separate from the existing agent-shell-viewport compose buffer. Viewport's compose-send interrupts when busy; queue-request must enqueue. Same end-user motion, different semantics — so agent-shell-prompt-compose, agent-shell-viewport-edit-mode, and the rest of the viewport subsystem are untouched.

Programmatic callers passing a PROMPT argument keep the direct submit/queue path; only interactive invocations open the compose buffer.

Notable implementation details:

  • agent-shell-compose-mode is a minor mode layered over gfm-mode, so its C-c C-c / C-c C-k bindings naturally win over major-mode bindings.
  • New private helper agent-shell--queue-or-submit consolidates the busy-check + enqueue/submit dispatch so the compose-submit handler and the programmatic path share one implementation.
  • Compose buffer name (*agent-shell-compose: <shell-buffer-name>*) includes the originating shell buffer to disambiguate when several shells are open.
  • markdown-mode is added to Package-Requires with a 2.5 lower bound.
  • bin/test defaults markdown_mode_root to the newest ~/.emacs.d/elpa/markdown-mode-* install; CI checks out jrblevin/markdown-mode@v2.6 alongside the other deps.

Out of scope (intentionally): an editable full-buffer queue view, replacing viewport's compose entry, or reusing viewport's edit mode.

Test plan

  • bin/test byte-compiles cleanly with no warnings
  • 144/145 ERT tests pass; the one failure (agent-shell-restart-preserves-default-directory) predates this branch and is tracked separately
  • Manual: M-x agent-shell-queue-request while idle → type → C-c C-c submits and kills the compose buffer
  • Manual: M-x agent-shell-queue-request while busy → type → C-c C-c queues and kills the compose buffer
  • Manual: C-c C-k on empty buffer kills silently; on non-empty asks confirmation
  • Manual: viewport behaviors (C-c C-o, agent-shell-prompt-compose) unchanged

@timvisher-dd timvisher-dd force-pushed the queue-via-temp-gfm-compose-buffer branch from dc8dc31 to 888ec94 Compare April 28, 2026 19:35
@timvisher-dd timvisher-dd reopened this Apr 29, 2026
@timvisher-dd timvisher-dd marked this pull request as ready for review April 29, 2026 12:58
@timvisher-dd timvisher-dd force-pushed the queue-via-temp-gfm-compose-buffer branch 3 times, most recently from 94892d7 to 5bb5388 Compare April 29, 2026 14:53
@timvisher-dd timvisher-dd force-pushed the queue-via-temp-gfm-compose-buffer branch 3 times, most recently from 3379057 to d8d0980 Compare May 11, 2026 13:42
timvisher-dd and others added 5 commits May 12, 2026 10:28
GitHub Actions workflow with four jobs: readme-updated (PR-only,
guards the soft-fork features list), agent-symlinks (verifies the
multi-IDE plumbing), dependency-dag (require graph must be acyclic),
and test (byte-compile + ERT under emacs 29.4 with acp.el and
shell-maker as checkout deps).

bin/test parses ci.yml with yq and dispatches each step locally, so
CI changes are picked up automatically.  adapt_for_local rewrites
GitHub PR sha context to a single @{u}... three-dot range that the
git wrapper accepts.  CONTRIBUTING.org documents the runner and the
acp_root / shell_maker_root overrides.

.claude / .codex / .gemini and CODEX.md are symlinks pointing at
.agents and AGENTS.md so the same config works across Claude Code,
Codex, and Gemini CLI.  .agents/commands/live-validate.md describes
the live rendering-validation workflow.

README.org gets a "Features on top of agent-shell" section
enumerating the streaming-dedup work and follow-on polish.

agent-shell-devcontainer.el declares agent-shell-text-file-capabilities
to suppress a byte-compile warning for the cross-file reference.

Three send-command tests in tests/agent-shell-tests.el get :title
and :last-activity-time pre-seeded on their hand-rolled state alists
so the local runner produces a clean baseline.  Without the
placeholders, agent-shell--set-session-title's map-put! call fails
with map-not-inplace because the alists lack the keys.

Quote the keymap argument to shell-maker-define-major-mode.  Under
shell-maker 0.91.2 the macro expects a symbol it can resolve at mode
activation; passing the unquoted variable evaluates to the keymap
value before the macro can use it, and agent-shell-mode signals
(void-function keymap) when any test creates a fresh buffer.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three tests cover the markdown table overlay pipeline end-to-end:
overlay structure for a static buffer, mid-stream cleanup so stale
overlays disappear when a row is rewritten, and a regression that
guards against table rows being split across visual lines.

The helpers inject ACP traffic via agent-shell--on-notification
and fire pending debounce timers when present, so the tests reflect
the real streaming path rather than direct markdown-overlays-put
calls.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…lpers

Three new modules and the agent-shell.el integration that wires them
together:

- agent-shell-meta.el extracts toolResponse and terminal_output from
  the ACP meta envelope so streaming code can fold mixed-source tool
  output (terminal stream + final meta.toolResponse) without showing
  duplicate content.

- agent-shell-invariants.el is a runtime tracing and assertion
  library: a ring of recent ACP/UI events, process-mark and
  fragment-update guard wrappers, and a long-buffer head/tail
  snapshot included in violation reports.

- agent-shell-streaming.el is the streaming tool_call_update handler
  with dedup, including a label cache cleared on completion and the
  generalized title upgrade path that survives buffer-kill races.

agent-shell.el wires these in (require, on-notification dispatch,
process-mark/fragment guards, insert-cursor reset, defcustom for the
markdown-overlay debounce delay, and dropping session/update
handlers when the shell buffer has been killed).  agent-shell-ui.el
gains the invariants require and the UI plumbing the streaming
handler relies on.

Tests cover the dedup logic across mixed sources, the invariants
library's event ring and guard wrappers, and additional regression
coverage in agent-shell-tests.el (cancel with nil transcript-file,
markdown-overlay debounce buffer-kill race, "Thinking" label
restoration on agent_thought_chunk).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace the read-string minibuffer prompt for the interactive form
of `agent-shell-queue-request' with a `gfm-mode' compose buffer
layered with the new `agent-shell-queue-compose-mode' minor mode:

  C-c C-c → agent-shell-queue-compose-submit
  C-c C-k → agent-shell-queue-compose-cancel

The compose buffer (`*agent-shell-queue-compose: <shell>*') is bound
to its originating shell via two buffer-locals — the compose buffer
holds a back-reference to the shell, and the shell holds a forward
reference so re-popping reuses the same buffer.  An in-progress draft
therefore survives a re-invocation (declined cancel or buried buffer).
The forward reference is cleared via a buffer-local
`kill-buffer-hook' on the compose buffer so submit/cancel don't leave
a stale ref.  On reuse, the modified flag resets so the modeline
doesn't carry the `**' indicator from a kept draft.

Submit hands the raw `(buffer-string)' to a small dispatcher,
`agent-shell--queue-or-submit', which enqueues to the pending-request
queue when the shell is busy and otherwise inserts and submits
directly.  Trimming is applied only for the empty-buffer guard so a
trailing newline in a pasted code block isn't silently dropped.
Whitespace-only PROMPT in the non-interactive form is rejected
symmetrically with `user-error'.

Both submit and cancel route through
`agent-shell-queue-compose--quit-or-kill', which prefers `(quit-window
t)' when the buffer is displayed and falls back to `kill-buffer' when
it isn't (M-x after switching away).

Other touches:
- Add markdown-mode to Package-Requires (>= 2.5).
- Wire markdown-mode into `bin/test' (XDG and ~/.emacs.d elpa
  auto-discovery via `mapfile' over a directory-only glob; v2.5
  example in the not-found error) and CI (pin to v2.5 — the
  Package-Requires floor — with a comment noting the divergence
  from local auto-discovery).
- Switch `(error "Not in a shell")' to `(user-error ...)' and add
  `(declare (modes agent-shell-mode))' for M-x discoverability.
- Update README features list and key-binding table; fix the
  `agent-shell-queue-compose-cancel' description to say "modified"
  rather than "non-empty".
- ERT tests for the entire flow: pop fresh-creation, alive-buffer
  reuse, post-submit fresh-creation, dead-shell errors, busy/idle
  dispatch, busy-branch end-to-end, submit empty/dispatch/dead-shell,
  cancel silent-kill / declined / confirmed, queue-request not-in-
  shell / non-interactive bypass / empty-PROMPT rejection, the
  --quit-or-kill helper branches, header-line presence, and keymap
  bindings.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The `agent-shell-restart-preserves-default-directory' test calls
`make-frame' on a hidden frame to drive an interactive restart flow,
which fails with "Unknown terminal type" under emacs --batch.
Upstream guards the body with `(skip-unless (not noninteractive))';
add a comment above it explaining the constraint so a future reader
doesn't mistake the skip for an unfinished test.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@timvisher-dd timvisher-dd force-pushed the queue-via-temp-gfm-compose-buffer branch from d8d0980 to 9f25b9f Compare May 12, 2026 15:01
Whitespace-only fix in agent-shell--send-command-emits-turn-complete-event-test
so the (cons :title nil) row lines up with (cons :id ...) inside the
(list ...) form, matching the other send-command test fixtures.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@timvisher-dd timvisher-dd force-pushed the queue-via-temp-gfm-compose-buffer branch from 9f25b9f to 4b261b3 Compare May 12, 2026 15:11
@timvisher-dd timvisher-dd merged commit 4b261b3 into main May 12, 2026
4 checks passed
@timvisher-dd timvisher-dd deleted the queue-via-temp-gfm-compose-buffer branch May 12, 2026 15:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants