Every workflow turn that needed a quality gate either let it drop
silently or bulk-stamped it at closeout. Q8 was the worst case: seeded
as scope:"slice" by plan-slice, treated as a blocker for the
evaluating-gates phase by state.ts, then filtered out of the
gate-evaluate prompt via `if (!meta) continue;` and never closed by
complete-slice — a guaranteed auto-loop stall once slice gates were
enabled.
Introduce gate-registry.ts as the single source of truth for which
turn owns which gate (Q3/Q4 → gate-evaluate, Q5/Q6/Q7 → execute-task,
Q8 → complete-slice, MV01–MV04 → validate-milestone). Every layer of
the prompt system now consults it:
- state.ts derives pending counts by owner turn, not scope, so Q8
never stalls evaluating-gates again.
- auto-prompts.ts builders call assertGateCoverage() and render a
"Gates to Close" block from the registry instead of a hand-rolled
GATE_QUESTIONS table.
- complete-slice and complete-task handlers saveGateResult for every
gate they own, mapping gate id → params field so empty sections
become `omitted` and populated sections become `pass`.
- milestone-validation-gates sources its MV id list from the registry.
- prompt-validation.ts adds validateSliceSummaryOutput /
validateTaskSummaryOutput / validateMilestoneValidationOutput
schema checks.
- gsd_save_gate_result accepts MV01–MV04 (via the registry keys) in
the MCP server and bootstrap tool registration.
Tests: new gate-registry + prompt-system-gate-coverage +
complete-slice-gate-closure suites, plus a Q8 regression case in
gate-dispatch.test.ts. 161 related tests pass end-to-end.
https://claude.ai/code/session_019PT3EmrkMxr4TsgGGLSYK3
Audit-driven fixes across the two MCP server surfaces and the Claude Code
streaming adapter:
- src/mcp-server.ts: propagate `extra.signal` into `tool.execute` so MCP
clients can actually cancel long-running Bash/WebFetch/grep calls, and
route the remaining `/server` subpath import through `createRequire`
for #3603 consistency.
- src/tests/mcp-createRequire.test.ts: extend regression coverage to the
`/server` subpath.
- claude-code-cli/stream-adapter.ts: (a) classify aborts as `aborted`
instead of the retry-eligible `stream_exhausted_without_result`,
(b) merge final-turn toolCall blocks from the builder into the
AssistantMessage via the new `mergePendingToolCalls` helper so a turn
ending in `tool_use` stop_reason no longer drops its tool calls, and
(c) resolve the SDK permission mode via `resolveClaudePermissionMode`
(auto-mode → bypass, interactive → acceptEdits, env override).
- packages/mcp-server/src/server.ts: make `gsd_query` actually respect
its `query` argument with known categories + forward-compatible
fallback, and thread `extra.signal` into `gsd_execute` so an aborted
RPC request cancels the newly-created session instead of leaking a
background RpcClient process.
- stream-adapter test suite: add regression tests for abort
classification, final-turn tool-call merging, and permission mode
resolution.
Verified via: mcp-createRequire, stream-adapter (27), partial-builder,
mcp-server package (31), workflow-tools (13) — 83 tests green.
https://claude.ai/code/session_0174sYny3VvdwYTdCNTmY4Do
Exposes secure_env_collect as an MCP tool so any MCP client (Claude Code,
Cursor, etc.) can collect secrets through form-based input. Values are
written directly to .env/Vercel/Convex and never appear in LLM context —
only key names and applied/skipped status are returned.
- New env-writer.ts with writeEnvKey, detectDestination, checkExistingEnvKeys, applySecrets
- Uses server.server.elicitInput() to present form fields to the MCP client
- Pre-checks existing keys to skip already-set env vars
- Auto-detects destination from project files (vercel.json, convex/ dir)
- 27 tests covering utilities and tool integration
Closes#3975
importLocalModule() resolved paths relative to import.meta.url. When
running from dist/, paths like ../../../src/.../foo.js pointed to source
where no .js files exist. Now tries src/<->dist/ swap and .ts fallback
so the same code works in both dev (tsx) and prod (compiled) contexts.
Also adds dist/ candidates to write-gate and workflow-executor lookups.
Fixes#3954
Change /^[a-z]+:/i to /^[a-z]{2,}:/i in getWriteGateModuleCandidates()
and getWorkflowExecutorModuleCandidates() so single-letter drive prefixes
(C:, D:) are not rejected as URL schemes. All IANA-registered schemes are
2+ characters, so this is a safe narrowing.
Adds regression tests for the regex fix.
Fixes#3942
- Stream tool results in real-time during Claude Code SDK sessions
instead of deferring until session end. Tool calls (read, bash, write,
etc.) now show their output as they complete, not collapsed as "..."
- Stop suppressing toolcall_start/delta/end events from stream adapter
so the TUI can render tool call progress during streaming
- On SDK turn boundary (user message with tool results), push synthetic
toolcall_end events with externalResult attached for immediate rendering
- Chat controller checks for externalResult on toolcall_end message
updates and calls updateResult on pending ToolExecutionComponents
- Fix case-sensitive tool name matching (Read vs read, Bash vs bash)
in TUI ToolExecutionComponent rendering
- Auto-discover and pass GSD_WORKFLOW_EXECUTORS_MODULE and
GSD_WORKFLOW_WRITE_GATE_MODULE env vars in MCP server launch config
- Add /gsd mcp init command and auto-bootstrap .mcp.json for Claude
Code provider during auto-start
- Add tool_execution_update event type for web UI streaming updates
- Add setStderrLoggingEnabled toggle for workflow logger
Add gsd_progress, gsd_roadmap, gsd_history, gsd_doctor, gsd_captures,
and gsd_knowledge tools that parse .gsd/ on disk — no session needed.
Inline lightweight readers in src/readers/ keep the package standalone
(zero new dependencies). 33 new tests, 64 total passing.
* feat: Migrated headless orchestrator to use execution_complete events,…
- "src/headless.ts"
- "src/headless-ui.ts"
- "src/tests/headless-v2-migration.test.ts"
GSD-Task: S06/T02
* test: Wired pi-coding-agent to re-export JSONL utils from @gsd/rpc-clie…
- "packages/pi-coding-agent/src/modes/rpc/jsonl.ts"
- "packages/pi-coding-agent/package.json"
- "packages/rpc-client/src/index.ts"
- "packages/rpc-client/src/jsonl.ts"
- "packages/rpc-client/src/rpc-client.ts"
- "packages/rpc-client/src/rpc-types.ts"
- "packages/rpc-client/src/rpc-client.test.ts"
- "packages/rpc-client/package.json"
GSD-Task: S06/T03
* feat: Wire --resume flag to resolve session IDs via prefix matching and…
- "src/headless.ts"
- "dist/headless.js"
GSD-Task: S01/T01
* test: Added 5 e2e integration tests proving headless JSON batch, SIGINT…
- "src/tests/integration/e2e-headless.test.ts"
GSD-Task: S01/T02
* test: Updated @gsd/rpc-client and @gsd/mcp-server to 2.52.0 with publis…
- "packages/rpc-client/package.json"
- "packages/mcp-server/package.json"
- "packages/rpc-client/.npmignore"
- "packages/mcp-server/.npmignore"
GSD-Task: S02/T01
* chore: auto-commit after complete-milestone
GSD-Unit: M002-gzq23a
* fix: revert jsonl.ts to inline implementation — @gsd-build/rpc-client not available at source-level test time in CI
The re-export from @gsd-build/rpc-client fails in CI because tests run against
TypeScript source (--experimental-strip-types) before any build step. The npm
dependency resolves to node_modules/ which requires dist/ to exist. Reverting
to the original inline implementation eliminates the cross-package dependency
for source-level imports.