gsd-pi 2.67.0-dev.a5b1d8f → 2.67.0-dev.fe39184

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. package/README.md +41 -31
  2. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +121 -8
  3. package/dist/resources/extensions/gsd/auto/phases.js +17 -0
  4. package/dist/resources/extensions/gsd/auto/session.js +6 -0
  5. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +12 -0
  6. package/dist/resources/extensions/gsd/auto-start.js +12 -0
  7. package/dist/resources/extensions/gsd/auto.js +27 -0
  8. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +11 -435
  9. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +1 -4
  10. package/dist/resources/extensions/gsd/bootstrap/query-tools.js +7 -64
  11. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +88 -8
  12. package/dist/resources/extensions/gsd/commands/catalog.js +2 -1
  13. package/dist/resources/extensions/gsd/commands/handlers/core.js +39 -25
  14. package/dist/resources/extensions/gsd/commands/index.js +8 -1
  15. package/dist/resources/extensions/gsd/commands-mcp-status.js +43 -7
  16. package/dist/resources/extensions/gsd/guided-flow.js +16 -0
  17. package/dist/resources/extensions/gsd/init-wizard.js +37 -0
  18. package/dist/resources/extensions/gsd/mcp-project-config.js +83 -0
  19. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +508 -0
  20. package/dist/resources/extensions/gsd/workflow-logger.js +18 -3
  21. package/dist/resources/extensions/gsd/workflow-mcp.js +261 -0
  22. package/dist/web/standalone/.next/BUILD_ID +1 -1
  23. package/dist/web/standalone/.next/app-path-routes-manifest.json +15 -15
  24. package/dist/web/standalone/.next/build-manifest.json +3 -3
  25. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  26. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  27. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  28. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  29. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  30. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  31. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  32. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  33. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  34. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  35. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  36. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  37. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  38. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  39. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  40. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  41. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  42. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  43. package/dist/web/standalone/.next/server/app/index.html +1 -1
  44. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  45. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  46. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  47. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  48. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  49. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  50. package/dist/web/standalone/.next/server/app-paths-manifest.json +15 -15
  51. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  52. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  53. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  54. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  55. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  56. package/dist/web/standalone/.next/static/chunks/6502.5dcdcf1e1432e20d.js +9 -0
  57. package/dist/web/standalone/.next/static/chunks/{webpack-b49b09f97429b5d0.js → webpack-42a66876b763aa26.js} +1 -1
  58. package/package.json +4 -2
  59. package/packages/mcp-server/README.md +38 -0
  60. package/packages/mcp-server/dist/cli.d.ts +9 -0
  61. package/packages/mcp-server/dist/cli.d.ts.map +1 -0
  62. package/packages/mcp-server/dist/cli.js +58 -0
  63. package/packages/mcp-server/dist/cli.js.map +1 -0
  64. package/packages/mcp-server/dist/index.d.ts +20 -0
  65. package/packages/mcp-server/dist/index.d.ts.map +1 -0
  66. package/packages/mcp-server/dist/index.js +14 -0
  67. package/packages/mcp-server/dist/index.js.map +1 -0
  68. package/packages/mcp-server/dist/readers/captures.d.ts +25 -0
  69. package/packages/mcp-server/dist/readers/captures.d.ts.map +1 -0
  70. package/packages/mcp-server/dist/readers/captures.js +67 -0
  71. package/packages/mcp-server/dist/readers/captures.js.map +1 -0
  72. package/packages/mcp-server/dist/readers/doctor-lite.d.ts +20 -0
  73. package/packages/mcp-server/dist/readers/doctor-lite.d.ts.map +1 -0
  74. package/packages/mcp-server/dist/readers/doctor-lite.js +173 -0
  75. package/packages/mcp-server/dist/readers/doctor-lite.js.map +1 -0
  76. package/packages/mcp-server/dist/readers/index.d.ts +14 -0
  77. package/packages/mcp-server/dist/readers/index.d.ts.map +1 -0
  78. package/packages/mcp-server/dist/readers/index.js +10 -0
  79. package/packages/mcp-server/dist/readers/index.js.map +1 -0
  80. package/packages/mcp-server/dist/readers/knowledge.d.ts +18 -0
  81. package/packages/mcp-server/dist/readers/knowledge.d.ts.map +1 -0
  82. package/packages/mcp-server/dist/readers/knowledge.js +82 -0
  83. package/packages/mcp-server/dist/readers/knowledge.js.map +1 -0
  84. package/packages/mcp-server/dist/readers/metrics.d.ts +32 -0
  85. package/packages/mcp-server/dist/readers/metrics.d.ts.map +1 -0
  86. package/packages/mcp-server/dist/readers/metrics.js +74 -0
  87. package/packages/mcp-server/dist/readers/metrics.js.map +1 -0
  88. package/packages/mcp-server/dist/readers/paths.d.ts +42 -0
  89. package/packages/mcp-server/dist/readers/paths.d.ts.map +1 -0
  90. package/packages/mcp-server/dist/readers/paths.js +199 -0
  91. package/packages/mcp-server/dist/readers/paths.js.map +1 -0
  92. package/packages/mcp-server/dist/readers/roadmap.d.ts +26 -0
  93. package/packages/mcp-server/dist/readers/roadmap.d.ts.map +1 -0
  94. package/packages/mcp-server/dist/readers/roadmap.js +194 -0
  95. package/packages/mcp-server/dist/readers/roadmap.js.map +1 -0
  96. package/packages/mcp-server/dist/readers/state.d.ts +43 -0
  97. package/packages/mcp-server/dist/readers/state.d.ts.map +1 -0
  98. package/packages/mcp-server/dist/readers/state.js +184 -0
  99. package/packages/mcp-server/dist/readers/state.js.map +1 -0
  100. package/packages/mcp-server/dist/server.d.ts +28 -0
  101. package/packages/mcp-server/dist/server.d.ts.map +1 -0
  102. package/packages/mcp-server/dist/server.js +319 -0
  103. package/packages/mcp-server/dist/server.js.map +1 -0
  104. package/packages/mcp-server/dist/session-manager.d.ts +54 -0
  105. package/packages/mcp-server/dist/session-manager.d.ts.map +1 -0
  106. package/packages/mcp-server/dist/session-manager.js +284 -0
  107. package/packages/mcp-server/dist/session-manager.js.map +1 -0
  108. package/packages/mcp-server/dist/types.d.ts +61 -0
  109. package/packages/mcp-server/dist/types.d.ts.map +1 -0
  110. package/packages/mcp-server/dist/types.js +11 -0
  111. package/packages/mcp-server/dist/types.js.map +1 -0
  112. package/packages/mcp-server/dist/workflow-tools.d.ts +9 -0
  113. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -0
  114. package/packages/mcp-server/dist/workflow-tools.js +532 -0
  115. package/packages/mcp-server/dist/workflow-tools.js.map +1 -0
  116. package/packages/mcp-server/src/server.ts +6 -2
  117. package/packages/mcp-server/src/workflow-tools.test.ts +976 -0
  118. package/packages/mcp-server/src/workflow-tools.ts +997 -0
  119. package/packages/mcp-server/tsconfig.json +1 -1
  120. package/packages/pi-agent-core/dist/agent-loop.js +14 -6
  121. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  122. package/packages/pi-agent-core/src/agent-loop.test.ts +53 -0
  123. package/packages/pi-agent-core/src/agent-loop.ts +20 -6
  124. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.d.ts +2 -0
  125. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.d.ts.map +1 -0
  126. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +28 -0
  127. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -0
  128. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +1 -0
  129. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  130. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +17 -12
  131. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  132. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  133. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +19 -0
  134. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  135. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +54 -0
  136. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +18 -12
  137. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +21 -0
  138. package/packages/rpc-client/dist/index.d.ts +10 -0
  139. package/packages/rpc-client/dist/index.d.ts.map +1 -0
  140. package/packages/rpc-client/dist/index.js +9 -0
  141. package/packages/rpc-client/dist/index.js.map +1 -0
  142. package/packages/rpc-client/dist/jsonl.d.ts +17 -0
  143. package/packages/rpc-client/dist/jsonl.d.ts.map +1 -0
  144. package/packages/rpc-client/dist/jsonl.js +54 -0
  145. package/packages/rpc-client/dist/jsonl.js.map +1 -0
  146. package/packages/rpc-client/dist/rpc-client.d.ts +259 -0
  147. package/packages/rpc-client/dist/rpc-client.d.ts.map +1 -0
  148. package/packages/rpc-client/dist/rpc-client.js +541 -0
  149. package/packages/rpc-client/dist/rpc-client.js.map +1 -0
  150. package/packages/rpc-client/dist/rpc-client.test.d.ts +2 -0
  151. package/packages/rpc-client/dist/rpc-client.test.d.ts.map +1 -0
  152. package/packages/rpc-client/dist/rpc-client.test.js +477 -0
  153. package/packages/rpc-client/dist/rpc-client.test.js.map +1 -0
  154. package/packages/rpc-client/dist/rpc-types.d.ts +566 -0
  155. package/packages/rpc-client/dist/rpc-types.d.ts.map +1 -0
  156. package/packages/rpc-client/dist/rpc-types.js +12 -0
  157. package/packages/rpc-client/dist/rpc-types.js.map +1 -0
  158. package/scripts/ensure-workspace-builds.cjs +2 -0
  159. package/scripts/link-workspace-packages.cjs +21 -14
  160. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +157 -8
  161. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +182 -0
  162. package/src/resources/extensions/gsd/auto/phases.ts +25 -0
  163. package/src/resources/extensions/gsd/auto/session.ts +6 -0
  164. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +20 -0
  165. package/src/resources/extensions/gsd/auto-start.ts +15 -1
  166. package/src/resources/extensions/gsd/auto.ts +29 -1
  167. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +22 -435
  168. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +1 -5
  169. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +7 -72
  170. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +122 -6
  171. package/src/resources/extensions/gsd/commands/catalog.ts +2 -1
  172. package/src/resources/extensions/gsd/commands/handlers/core.ts +53 -26
  173. package/src/resources/extensions/gsd/commands/index.ts +7 -1
  174. package/src/resources/extensions/gsd/commands-mcp-status.ts +53 -7
  175. package/src/resources/extensions/gsd/guided-flow.ts +24 -0
  176. package/src/resources/extensions/gsd/init-wizard.ts +40 -0
  177. package/src/resources/extensions/gsd/mcp-project-config.ts +128 -0
  178. package/src/resources/extensions/gsd/tests/auto-project-root-env.test.ts +29 -0
  179. package/src/resources/extensions/gsd/tests/core-overlay-fallback.test.ts +101 -0
  180. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +66 -0
  181. package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +85 -0
  182. package/src/resources/extensions/gsd/tests/mcp-status.test.ts +15 -0
  183. package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +16 -0
  184. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +500 -0
  185. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +625 -0
  186. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +629 -0
  187. package/src/resources/extensions/gsd/workflow-logger.ts +19 -3
  188. package/src/resources/extensions/gsd/workflow-mcp.ts +320 -0
  189. package/dist/web/standalone/.next/static/chunks/6502.b804e48b7919f55e.js +0 -9
  190. /package/dist/web/standalone/.next/static/{NllX5BEOLdTXS9ypf1i3i → gbSATDX4Jt2ufxzUr5nYm}/_buildManifest.js +0 -0
  191. /package/dist/web/standalone/.next/static/{NllX5BEOLdTXS9ypf1i3i → gbSATDX4Jt2ufxzUr5nYm}/_ssgManifest.js +0 -0
package/README.md CHANGED
@@ -27,56 +27,66 @@ One command. Walk away. Come back to a built project with clean git history.
27
27
 
28
28
  ---
29
29
 
30
- ## What's New in v2.63.0
30
+ ## What's New in v2.67
31
31
 
32
- ### MCP Server & Integrations
32
+ ### Context Engineering
33
+
34
+ - **Tiered Context Injection (M005)** — relevance-scoped context with 65%+ token reduction. Decision scope cascade derives context from slice metadata instead of blanket injection.
35
+ - **Resilient transient error recovery** — defers to Core RetryHandler and fixes cmdCtx race conditions for more reliable auto-mode sessions.
33
36
 
34
- - **MCP server** 6 read-only project state tools for external integrations, auto-wrapup guard, and question dedup.
35
- - **Ollama extension** — first-class local LLM support via Ollama, with dynamic routing enabled by default.
36
- - **Discord bot & daemon** — dedicated daemon package, Discord bot with 6 discord.js shard event listeners, and headless text mode with tool calls.
37
+ ### Provider & Model Improvements
37
38
 
38
- ### Intelligent Model Routing
39
+ - **Anthropic subscription routing** — users with Anthropic subscriptions are automatically routed through Claude Code CLI provider with proper display names across all UI surfaces.
40
+ - **Claude Code provider hardening** — native Windows claude lookup, fallback guards, and `out of extra usage` error matching.
41
+ - **XML parameter recovery** — pi-ai recovers XML parameters trapped in JSON strings from providers.
39
42
 
40
- - **Capability-aware model routing (ADR-004)** — capability scoring, `before_model_select` hook, and task metadata extraction replace pattern-based model selection.
41
- - **Stop/backtrack capture classifications** — context optimization with model routing and masking.
43
+ ### Safety & Data Integrity
42
44
 
43
- ### VS Code & TUI
45
+ - **LLM safety harness** — auto-mode damage control prevents the LLM from running destructive operations or querying `gsd.db` directly via bash.
46
+ - **5-wave state machine hardening** — critical data integrity fixes across atomic writes, randomized tmp paths, event log reconciliation, session recovery, and consistency enforcement. 86+ regression tests added.
47
+ - **Discussion gate enforcement** — mechanical enforcement for discussion question gates with fail-closed behavior.
48
+ - **Enhanced verification** — pre-execution plan verification checks, post-execution cross-task consistency checks, blocking behavior and strict mode.
44
49
 
45
- - **VS Code sidebar redesign** — SCM provider, checkpoints, diagnostics panel, activity feed, workflow controls, session forking, and enhanced code lens.
46
- - **`/gsd parallel watch`** — native TUI overlay for real-time worker monitoring.
47
- - **Real-time TUI monitor dashboard** — self-healing dashboard with colorized headless verbose output.
50
+ ### Parallel Execution & Dispatch
48
51
 
49
- ### Agent & Auto-Mode
52
+ - **Slice-level parallelism** — dependency-aware parallel dispatch within a milestone, not just across milestones.
53
+ - **Parallel research slices** — research and milestone validation run in parallel.
54
+ - **Worker model override** — configure different models for parallel milestone workers.
50
55
 
51
- - **`/btw` skill** — ephemeral side questions without interrupting the main workflow.
52
- - **Codebase map** — automatic codebase map injection for fresh agent contexts.
53
- - **`--resume` flag** — resume previous sessions from the CLI.
54
- - **Concurrent invocation guard** — prevents overlapping auto-mode runs with parallel worker reliability improvements.
55
- - **Safety mechanisms on by default** — snapshots and pre-merge checks enabled out of the box.
56
+ ### TUI & Notifications
56
57
 
57
- ### Infrastructure & Performance
58
+ - **Persistent notification panel** — TUI overlay, widget, and web API for real-time notifications.
59
+ - **Remote questions race** — local TUI races against remote channel (Slack/Discord) instead of remote-only routing.
60
+ - **OS-specific keyboard shortcuts** — shortcut hints now adapt to macOS/Linux/Windows.
61
+ - **`/gsd show-config`** — inspect active configuration at a glance.
58
62
 
59
- - **Topological sort for extensions** — correct load ordering for dependent extensions.
60
- - **Headless integration hardening** — real-time streaming, verbose output, and observability improvements across v2.54–v2.55.
61
- - **GLM-5.1 model** — new model support added.
62
- - **80+ bug fixes** — worktree safety, parallel mode scoping, state corruption, and more.
63
+ ### Infrastructure
64
+
65
+ - **Ollama native provider** — `/api/chat` provider with full option exposure, `apiKey` auth mode, and headless probe.
66
+ - **MCP OAuth** — MCP client supports OAuth auth provider for HTTP transport.
67
+ - **WAL-safe migration backup** — database migrations create WAL-safe backups with stronger regression tests.
68
+ - **Xcode/xcodegen detection** — project detection now supports Xcode bundles and xcodegen.
69
+ - **170+ bug fixes** — state machine resilience, worktree safety, prompt injection, session recovery, and more.
63
70
 
64
71
  See the full [Changelog](./CHANGELOG.md) for details on every release.
65
72
 
66
73
  <details>
67
- <summary>Previous highlights (v2.52 and earlier)</summary>
68
-
74
+ <summary>Previous highlights (v2.63 and earlier)</summary>
75
+
76
+ - **MCP server** — 6 read-only project state tools for external integrations, auto-wrapup guard, and question dedup
77
+ - **Ollama extension** — first-class local LLM support via Ollama, with dynamic routing enabled by default
78
+ - **Discord bot & daemon** — dedicated daemon package, Discord bot, and headless text mode with tool calls
79
+ - **Capability-aware model routing (ADR-004)** — capability scoring, `before_model_select` hook, and task metadata extraction
80
+ - **VS Code sidebar redesign** — SCM provider, checkpoints, diagnostics panel, activity feed, workflow controls, session forking
81
+ - **`/gsd parallel watch`** — native TUI overlay for real-time worker monitoring
82
+ - **Codebase map** — automatic codebase map injection for fresh agent contexts
83
+ - **`--resume` flag** — resume previous sessions from the CLI
84
+ - **Concurrent invocation guard** — prevents overlapping auto-mode runs
69
85
  - **VS Code integration** — status bar, file decorations, bash terminal, session tree, conversation history, and code lens
70
- - **Capability-based model selection** — replaced model-ID pattern matching with capability metadata
71
86
  - **Skills overhaul** — 30+ skill packs covering major frameworks, databases, and cloud platforms
72
- - **Quality gates** — 8-question quality gates for planning and completion templates
73
87
  - **Single-writer state engine** — disciplined state transitions with machine guards and TOCTOU hardening
74
- - **`/gsd rethink`** — conversational project reorganization
75
- - **Complete offline mode** — fully offline with local models
76
- - **Browser-based web interface** — run GSD from the browser with `gsd --web`
77
88
  - **DB-backed planning tools** — atomic SQLite tool calls for state transitions
78
89
  - **Declarative workflow engine** — YAML workflows through auto-loop
79
- - **7 data-loss prevention fixes** — hallucination guard, merge anchor verification, dirty tree detection, and more
80
90
  - **Doctor: worktree lifecycle checks** — validates worktree health, detects orphans, consolidates cleanup
81
91
 
82
92
  </details>
@@ -9,6 +9,7 @@
9
9
  import { EventStream } from "@gsd/pi-ai";
10
10
  import { execSync } from "node:child_process";
11
11
  import { PartialMessageBuilder, ZERO_USAGE, mapUsage } from "./partial-builder.js";
12
+ import { buildWorkflowMcpServers } from "../gsd/workflow-mcp.js";
12
13
  // ---------------------------------------------------------------------------
13
14
  // Stream factory
14
15
  // ---------------------------------------------------------------------------
@@ -133,6 +134,7 @@ export function makeStreamExhaustedErrorMessage(model, lastTextContent) {
133
134
  * beta flags, and other configuration without mocking the full SDK.
134
135
  */
135
136
  export function buildSdkOptions(modelId, prompt) {
137
+ const mcpServers = buildWorkflowMcpServers();
136
138
  return {
137
139
  pathToClaudeCodeExecutable: getClaudePath(),
138
140
  model: modelId,
@@ -143,9 +145,98 @@ export function buildSdkOptions(modelId, prompt) {
143
145
  allowDangerouslySkipPermissions: true,
144
146
  settingSources: ["project"],
145
147
  systemPrompt: { type: "preset", preset: "claude_code" },
148
+ ...(mcpServers ? { mcpServers } : {}),
146
149
  betas: modelId.includes("sonnet") ? ["context-1m-2025-08-07"] : [],
147
150
  };
148
151
  }
152
+ function normalizeToolResultContent(content) {
153
+ if (typeof content === "string") {
154
+ return [{ type: "text", text: content }];
155
+ }
156
+ if (!Array.isArray(content)) {
157
+ if (content == null)
158
+ return [{ type: "text", text: "" }];
159
+ return [{ type: "text", text: JSON.stringify(content) }];
160
+ }
161
+ const blocks = [];
162
+ for (const item of content) {
163
+ if (typeof item === "string") {
164
+ blocks.push({ type: "text", text: item });
165
+ continue;
166
+ }
167
+ if (!item || typeof item !== "object") {
168
+ blocks.push({ type: "text", text: String(item) });
169
+ continue;
170
+ }
171
+ const block = item;
172
+ if (block.type === "text") {
173
+ blocks.push({ type: "text", text: typeof block.text === "string" ? block.text : "" });
174
+ continue;
175
+ }
176
+ if (block.type === "image"
177
+ && typeof block.data === "string"
178
+ && typeof block.mimeType === "string") {
179
+ blocks.push({ type: "image", data: block.data, mimeType: block.mimeType });
180
+ continue;
181
+ }
182
+ blocks.push({ type: "text", text: JSON.stringify(block) });
183
+ }
184
+ return blocks.length > 0 ? blocks : [{ type: "text", text: "" }];
185
+ }
186
+ export function extractToolResultsFromSdkUserMessage(message) {
187
+ const extracted = [];
188
+ const seen = new Set();
189
+ const rawMessage = message.message;
190
+ const content = Array.isArray(rawMessage?.content) ? rawMessage.content : [];
191
+ for (const item of content) {
192
+ if (!item || typeof item !== "object")
193
+ continue;
194
+ const block = item;
195
+ const type = typeof block.type === "string" ? block.type : "";
196
+ if (type !== "tool_result" && type !== "mcp_tool_result")
197
+ continue;
198
+ const toolUseId = typeof block.tool_use_id === "string" ? block.tool_use_id : "";
199
+ if (!toolUseId || seen.has(toolUseId))
200
+ continue;
201
+ seen.add(toolUseId);
202
+ extracted.push({
203
+ toolUseId,
204
+ result: {
205
+ content: normalizeToolResultContent(block.content),
206
+ details: {},
207
+ isError: block.is_error === true,
208
+ },
209
+ });
210
+ }
211
+ if (extracted.length === 0) {
212
+ const fallback = message.tool_use_result;
213
+ if (fallback && typeof fallback === "object") {
214
+ const toolResult = fallback;
215
+ const toolUseId = typeof toolResult.tool_use_id === "string" ? toolResult.tool_use_id : "";
216
+ if (toolUseId) {
217
+ extracted.push({
218
+ toolUseId,
219
+ result: {
220
+ content: normalizeToolResultContent(toolResult.content),
221
+ details: {},
222
+ isError: toolResult.is_error === true,
223
+ },
224
+ });
225
+ }
226
+ }
227
+ }
228
+ return extracted;
229
+ }
230
+ function attachExternalResultsToToolCalls(toolCalls, toolResultsById) {
231
+ for (const block of toolCalls) {
232
+ if (block.type !== "toolCall")
233
+ continue;
234
+ const externalResult = toolResultsById.get(block.id);
235
+ if (!externalResult)
236
+ continue;
237
+ block.externalResult = externalResult;
238
+ }
239
+ }
149
240
  // ---------------------------------------------------------------------------
150
241
  // streamSimple implementation
151
242
  // ---------------------------------------------------------------------------
@@ -169,6 +260,8 @@ async function pumpSdkMessages(model, context, options, stream) {
169
260
  let lastThinkingContent = "";
170
261
  /** Collect tool calls from intermediate SDK turns for tool_execution events. */
171
262
  const intermediateToolCalls = [];
263
+ /** Preserve real external tool results from Claude Code's synthetic user messages. */
264
+ const toolResultsById = new Map();
172
265
  try {
173
266
  // Dynamic import — the SDK is an optional dependency.
174
267
  const sdkModule = "@anthropic-ai/claude-agent-sdk";
@@ -221,14 +314,7 @@ async function pumpSdkMessages(model, context, options, stream) {
221
314
  break;
222
315
  const assistantEvent = builder.handleEvent(event);
223
316
  if (assistantEvent) {
224
- // Skip toolcall events — the agent loop's externalToolExecution
225
- // path emits tool_execution_start/end events after streamSimple
226
- // returns. Streaming toolcall events would render tool calls
227
- // out of order in the TUI's accumulated message content.
228
- const t = assistantEvent.type;
229
- if (t !== "toolcall_start" && t !== "toolcall_delta" && t !== "toolcall_end") {
230
- stream.push(assistantEvent);
231
- }
317
+ stream.push(assistantEvent);
232
318
  }
233
319
  break;
234
320
  }
@@ -263,6 +349,32 @@ async function pumpSdkMessages(model, context, options, stream) {
263
349
  }
264
350
  }
265
351
  }
352
+ // Extract tool results from the SDK's synthetic user message
353
+ // and attach to corresponding tool call blocks immediately.
354
+ for (const { toolUseId, result } of extractToolResultsFromSdkUserMessage(msg)) {
355
+ toolResultsById.set(toolUseId, result);
356
+ }
357
+ attachExternalResultsToToolCalls(intermediateToolCalls, toolResultsById);
358
+ // Push a synthetic toolcall_end for each tool call from this turn
359
+ // so the TUI can render tool results in real-time during the SDK
360
+ // session instead of waiting until the entire session completes.
361
+ if (builder) {
362
+ for (const block of builder.message.content) {
363
+ if (block.type !== "toolCall")
364
+ continue;
365
+ const extResult = block.externalResult;
366
+ if (!extResult)
367
+ continue;
368
+ // Push a toolcall_end with result attached so the chat-controller
369
+ // can call updateResult on the pending ToolExecutionComponent.
370
+ stream.push({
371
+ type: "toolcall_end",
372
+ contentIndex: builder.message.content.indexOf(block),
373
+ toolCall: block,
374
+ partial: builder.message,
375
+ });
376
+ }
377
+ }
266
378
  builder = null;
267
379
  break;
268
380
  }
@@ -274,6 +386,7 @@ async function pumpSdkMessages(model, context, options, stream) {
274
386
  // events for proper TUI rendering, followed by the text response.
275
387
  const finalContent = [];
276
388
  // Add tool calls from intermediate turns first (renders above text)
389
+ attachExternalResultsToToolCalls(intermediateToolCalls, toolResultsById);
277
390
  finalContent.push(...intermediateToolCalls);
278
391
  // Add text/thinking from the last turn
279
392
  if (builder && builder.message.content.length > 0) {
@@ -27,6 +27,7 @@ import { isDbAvailable, getMilestoneSlices } from "../gsd-db.js";
27
27
  import { resetEvidence } from "../safety/evidence-collector.js";
28
28
  import { createCheckpoint, cleanupCheckpoint, rollbackToCheckpoint } from "../safety/git-checkpoint.js";
29
29
  import { resolveSafetyHarnessConfig } from "../safety/safety-harness.js";
30
+ import { getWorkflowTransportSupportError, getRequiredWorkflowToolsForAutoUnit, } from "../workflow-mcp.js";
30
31
  // ─── generateMilestoneReport ──────────────────────────────────────────────────
31
32
  /**
32
33
  * Resolve the base path for milestone reports.
@@ -886,6 +887,22 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
886
887
  s.currentDispatchedModelId = s.currentUnitModel
887
888
  ? `${s.currentUnitModel.provider ?? ""}/${s.currentUnitModel.id ?? ""}`
888
889
  : null;
890
+ const compatibilityError = getWorkflowTransportSupportError(s.currentUnitModel?.provider ?? ctx.model?.provider, getRequiredWorkflowToolsForAutoUnit(unitType), {
891
+ projectRoot: s.basePath,
892
+ surface: "auto-mode",
893
+ unitType,
894
+ authMode: s.currentUnitModel?.provider
895
+ ? ctx.modelRegistry.getProviderAuthMode(s.currentUnitModel.provider)
896
+ : ctx.model?.provider
897
+ ? ctx.modelRegistry.getProviderAuthMode(ctx.model.provider)
898
+ : undefined,
899
+ baseUrl: s.currentUnitModel?.baseUrl ?? ctx.model?.baseUrl,
900
+ });
901
+ if (compatibilityError) {
902
+ ctx.ui.notify(compatibilityError, "error");
903
+ await deps.stopAuto(ctx, pi, compatibilityError);
904
+ return { action: "break", reason: "workflow-capability" };
905
+ }
889
906
  // Progress widget + preconditions — deferred to after model selection so the
890
907
  // widget's first render tick shows the correct model (#2899).
891
908
  deps.updateProgressWidget(ctx, unitType, unitId, state);
@@ -33,6 +33,9 @@ export class AutoSession {
33
33
  // ── Paths ────────────────────────────────────────────────────────────────
34
34
  basePath = "";
35
35
  originalBasePath = "";
36
+ previousProjectRootEnv = null;
37
+ hadProjectRootEnv = false;
38
+ projectRootEnvCaptured = false;
36
39
  gitService = null;
37
40
  // ── Dispatch counters ────────────────────────────────────────────────────
38
41
  unitDispatchCount = new Map();
@@ -132,6 +135,9 @@ export class AutoSession {
132
135
  // Paths
133
136
  this.basePath = "";
134
137
  this.originalBasePath = "";
138
+ this.previousProjectRootEnv = null;
139
+ this.hadProjectRootEnv = false;
140
+ this.projectRootEnvCaptured = false;
135
141
  this.gitService = null;
136
142
  // Dispatch
137
143
  this.unitDispatchCount.clear();
@@ -10,6 +10,7 @@ import { resolveMilestoneFile, resolveSliceFile, relSliceFile, } from "./paths.j
10
10
  import { buildResearchSlicePrompt, buildResearchMilestonePrompt, buildPlanSlicePrompt, buildPlanMilestonePrompt, buildExecuteTaskPrompt, buildCompleteSlicePrompt, buildCompleteMilestonePrompt, buildReassessRoadmapPrompt, buildRunUatPrompt, buildReplanSlicePrompt, } from "./auto-prompts.js";
11
11
  import { loadEffectiveGSDPreferences } from "./preferences.js";
12
12
  import { pauseAuto } from "./auto.js";
13
+ import { getWorkflowTransportSupportError, getRequiredWorkflowToolsForAutoUnit, } from "./workflow-mcp.js";
13
14
  export async function dispatchDirectPhase(ctx, pi, phase, base) {
14
15
  const state = await deriveState(base);
15
16
  const mid = state.activeMilestone?.id;
@@ -202,6 +203,17 @@ export async function dispatchDirectPhase(ctx, pi, phase, base) {
202
203
  ctx.ui.notify(`Unknown phase "${phase}". Valid phases: research, plan, execute, complete, reassess, uat, replan.`, "warning");
203
204
  return;
204
205
  }
206
+ const compatibilityError = getWorkflowTransportSupportError(ctx.model?.provider, getRequiredWorkflowToolsForAutoUnit(unitType), {
207
+ projectRoot: base,
208
+ surface: "direct phase dispatch",
209
+ unitType,
210
+ authMode: ctx.model?.provider ? ctx.modelRegistry.getProviderAuthMode(ctx.model.provider) : undefined,
211
+ baseUrl: ctx.model?.baseUrl,
212
+ });
213
+ if (compatibilityError) {
214
+ ctx.ui.notify(compatibilityError, "error");
215
+ return;
216
+ }
205
217
  ctx.ui.notify(`Dispatching ${unitType} for ${unitId}...`, "info");
206
218
  const result = await ctx.newSession();
207
219
  if (result.cancelled) {
@@ -250,6 +250,18 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
250
250
  logWarning("engine", `mkdir failed: ${err instanceof Error ? err.message : String(err)}`);
251
251
  }
252
252
  }
253
+ if (ctx.model?.provider === "claude-code") {
254
+ try {
255
+ const { ensureProjectWorkflowMcpConfig } = await import("./mcp-project-config.js");
256
+ const result = ensureProjectWorkflowMcpConfig(base);
257
+ if (result.status !== "unchanged") {
258
+ ctx.ui.notify(`Claude Code MCP prepared at ${result.configPath}`, "info");
259
+ }
260
+ }
261
+ catch (err) {
262
+ ctx.ui.notify(`Claude Code MCP prep failed: ${err instanceof Error ? err.message : String(err)}`, "warning");
263
+ }
264
+ }
253
265
  // Initialize GitServiceImpl
254
266
  s.gitService = new GitServiceImpl(s.basePath, loadEffectiveGSDPreferences()?.preferences?.git ?? {});
255
267
  // Check for crash from previous session. Skip our own fresh bootstrap lock.
@@ -79,6 +79,27 @@ export { MAX_UNIT_DISPATCHES, STUB_RECOVERY_THRESHOLD, MAX_LIFETIME_DISPATCHES,
79
79
  const s = new AutoSession();
80
80
  /** Throttle STATE.md rebuilds — at most once per 30 seconds */
81
81
  const STATE_REBUILD_MIN_INTERVAL_MS = 30_000;
82
+ function captureProjectRootEnv(projectRoot) {
83
+ if (!s.projectRootEnvCaptured) {
84
+ s.hadProjectRootEnv = Object.prototype.hasOwnProperty.call(process.env, "GSD_PROJECT_ROOT");
85
+ s.previousProjectRootEnv = process.env.GSD_PROJECT_ROOT ?? null;
86
+ s.projectRootEnvCaptured = true;
87
+ }
88
+ process.env.GSD_PROJECT_ROOT = projectRoot;
89
+ }
90
+ function restoreProjectRootEnv() {
91
+ if (!s.projectRootEnvCaptured)
92
+ return;
93
+ if (s.hadProjectRootEnv && s.previousProjectRootEnv !== null) {
94
+ process.env.GSD_PROJECT_ROOT = s.previousProjectRootEnv;
95
+ }
96
+ else {
97
+ delete process.env.GSD_PROJECT_ROOT;
98
+ }
99
+ s.previousProjectRootEnv = null;
100
+ s.hadProjectRootEnv = false;
101
+ s.projectRootEnvCaptured = false;
102
+ }
82
103
  export function shouldUseWorktreeIsolation() {
83
104
  const prefs = loadEffectiveGSDPreferences()?.preferences?.git;
84
105
  if (prefs?.isolation === "worktree")
@@ -315,6 +336,7 @@ function handleLostSessionLock(ctx, lockStatus) {
315
336
  s.active = false;
316
337
  s.paused = false;
317
338
  clearUnitTimeout();
339
+ restoreProjectRootEnv();
318
340
  deregisterSigtermHandler();
319
341
  clearCmuxSidebar(loadEffectiveGSDPreferences()?.preferences);
320
342
  const base = lockBase();
@@ -345,6 +367,7 @@ function cleanupAfterLoopExit(ctx) {
345
367
  s.currentUnit = null;
346
368
  s.active = false;
347
369
  clearUnitTimeout();
370
+ restoreProjectRootEnv();
348
371
  // Clear crash lock and release session lock so the next `/gsd next` does
349
372
  // not see a stale lock with the current PID and treat it as a "remote"
350
373
  // session (which would cause it to SIGTERM itself). (#2730)
@@ -601,6 +624,7 @@ export async function stopAuto(ctx, pi, reason) {
601
624
  ctx?.ui.setStatus("gsd-auto", undefined);
602
625
  ctx?.ui.setWidget("gsd-progress", undefined);
603
626
  ctx?.ui.setFooter(undefined);
627
+ restoreProjectRootEnv();
604
628
  // Reset all session state in one call
605
629
  s.reset();
606
630
  }
@@ -674,6 +698,7 @@ export async function pauseAuto(ctx, _pi, _errorContext) {
674
698
  _resetPendingResolve();
675
699
  s.active = false;
676
700
  s.paused = true;
701
+ restoreProjectRootEnv();
677
702
  s.pendingVerificationRetry = null;
678
703
  s.verificationRetryCount.clear();
679
704
  ctx?.ui.setStatus("gsd-auto", "paused");
@@ -981,6 +1006,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
981
1006
  updateSessionLock(lockBase(), "resuming", s.currentMilestoneId ?? "unknown");
982
1007
  writeLock(lockBase(), "resuming", s.currentMilestoneId ?? "unknown");
983
1008
  logCmuxEvent(loadEffectiveGSDPreferences()?.preferences, s.stepMode ? "Step-mode resumed." : "Auto-mode resumed.", "progress");
1009
+ captureProjectRootEnv(s.originalBasePath || s.basePath);
984
1010
  await autoLoop(ctx, pi, s, buildLoopDeps());
985
1011
  cleanupAfterLoopExit(ctx);
986
1012
  return;
@@ -995,6 +1021,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
995
1021
  const ready = await bootstrapAutoSession(s, ctx, pi, base, verboseMode, requestedStepMode, bootstrapDeps);
996
1022
  if (!ready)
997
1023
  return;
1024
+ captureProjectRootEnv(s.originalBasePath || s.basePath);
998
1025
  try {
999
1026
  syncCmuxSidebar(loadEffectiveGSDPreferences()?.preferences, await deriveState(s.basePath));
1000
1027
  }