Skip to content

fix(coding-agent): expand slash commands in non-interactive runs - #3898

Merged
Yeachan-Heo merged 3 commits into
Yeachan-Heo:devfrom
yazzang-homelab:fix/print-mode-slash-commands
Aug 6, 2026
Merged

fix(coding-agent): expand slash commands in non-interactive runs#3898
Yeachan-Heo merged 3 commits into
Yeachan-Heo:devfrom
yazzang-homelab:fix/print-mode-slash-commands

Conversation

@yazzang-homelab

Copy link
Copy Markdown
Contributor

What

gjc -p "/init" (and any other slash command in non-interactive mode) reached the model as literal text. This loads the same slash-command list interactive mode uses, before print mode sends its first prompt.

Why

AgentSession#prompt expands leading-slash input from #slashCommands, which is populated only by setSlashCommands(). The single caller is interactive-mode.ts:refreshSlashCommandState(), invoked while building autocomplete. Print mode has no autocomplete, so the list stayed at its [] default and expandSlashCommand() returned the raw text.

The failure is silent and misreports success. Measured before the fix, in a temp repo containing an AGENTS.md:

$ gjc -p "/init"
Repository initialized.
- **Project:** OrderFlow, Bun/TypeScript order-intake service
...

Session log for that run: init.md body injected 0 times, write/edit calls 0, AGENTS.md md5 unchanged. Nothing ran; the model improvised an answer from the literal string /init.

After the fix, same repo and prompt: command body injected, 3 task + 4 subagent dispatches (the /init prompt asks for parallel role agents), AGENTS.md regenerated 1,257B → 3,699B. The hand-written section I planted (<!-- SENTINEL-DO-NOT-LOSE-8f3a2b --> plus a Korean deployment rule) survived at lines 65/67, so this does not turn /init into a destructive overwrite in practice.

Two failure modes were checked explicitly and do not apply:

  • A broken project command file cannot kill a -p run in CI. loadSlashCommands parses user/project templates at level: "warn" (logs, recovers); only in-binary native/embedded content is "fatal". So a malformed repo-local commands/*.md degrades, it does not throw.
  • Prose that happens to start with / is unaffected. expandSlashCommand takes the token up to the first space as the command name, so gjc -p "/tmp/x.txt 를 읽어줘" finds no match and passes through unchanged.

Cost: loadSlashCommands measured at 23–64ms cold, 2ms warm, against a ~7s minimal -p run.

Testing

  • bun test packages/coding-agent/test/silent-abort-print-mode.test.ts — 19 pass. New case asserts the handover happens exactly once, before the first prompt, and that the handed-over list contains the embedded init command. Reverting the source change makes it fail (18 pass / 1 fail), so it pins the regression rather than the implementation.
  • The existing 18 cases in that file previously constructed session fakes without sessionManager.getCwd() or setSlashCommands; both are now modelled, since the real contract needs them. Ordering is asserted in the new test rather than in lifecycle, which the disposal/EPIPE cases compare byte-for-byte.
  • bun test packages/coding-agent/test/modes packages/coding-agent/test/silent-abort-print-mode.test.ts — 410 pass / 0 fail.
  • Default-surface gates: check-visible-definitions exit 0, verify-g002-gates exit 0, default-gjc-definitions.test.ts 28 pass.
  • bunx biome check clean on all three touched files.
  • bun run check:types NOT completed: tsc (typescript-go) aborts with fatal error: runtime: name offset out of range on this host at unmodified dev as well, so it is an environment fault, not this change. Left to CI.

GJC verdict

gajae.pr-review-verdict.v1 needs-human sha256:54867c2b5c7013ce9bcc02baf8f48fc74a60d422 reviewer:human evidence:bun test .../silent-abort-print-mode.test.ts (19 pass; 18/1 fail with fix reverted) + bun test .../test/modes (410 pass) + /init e2e before/after above

  • Target branch is dev
  • bun check passes — biome clean, targeted + mode suites green; tsgo typecheck crashes at baseline on this host, left to CI
  • Tested locally
  • CHANGELOG updated (if user-facing)
  • Verdict above matches the exact PR head, not an earlier commit

`gjc -p "/init"` reached the model as the literal string `/init`: no command
body was injected, no AGENTS.md was written, and the model still answered
"Repository initialized." A silent no-op that reports success is worse than a
refusal.

AgentSession#prompt expands leading-slash text from the list installed by
setSlashCommands, and only interactive mode called it — it does so while
building autocomplete, which print mode has none of. Print mode now performs the
same load before its first prompt, so bundled (`/init`) and file-based project
commands behave identically in both modes.

Lore-id: 4b91e7c2
Constraint: a broken project command file must not kill a non-interactive run -- user/project templates parse at "warn", only in-binary content is "fatal"
Constraint: load once before the first prompt, so follow-up messages in the same run share the list
Rejected: expand only for known bundled names | project commands would stay silently inert in -p
Rejected: swallow load failures | hides genuine config errors and interactive mode does not
Confidence: high
Scope-risk: narrow
Reversibility: easy
Tested: /init from source in a temp repo -- command body injected, subagents dispatched, AGENTS.md regenerated with hand-written rules preserved; new unit test fails with the fix reverted
Not-tested: --mode json event-stream consumers that assume no pre-prompt filesystem access (410 mode tests pass)
@yazzang-homelab
yazzang-homelab force-pushed the fix/print-mode-slash-commands branch from 54867c2 to 7fe8031 Compare August 5, 2026 23:24
@yazzang-homelab

Copy link
Copy Markdown
Contributor Author

Rebased onto current dev (11e48d5bc, #3901) — the previous head was CONFLICTING/DIRTY on the CHANGELOG ## [Unreleased] section. New head 7fe803158; rebase was CHANGELOG-only, no code merges, and the diff is otherwise unchanged.

Re-verified on the new base: bun test packages/coding-agent/test/silent-abort-print-mode.test.ts → 19 pass, 0 fail.

@Yeachan-Heo
Yeachan-Heo merged commit 4d21cf3 into Yeachan-Heo:dev Aug 6, 2026
21 checks passed
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