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.
- package/README.md +41 -31
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +121 -8
- package/dist/resources/extensions/gsd/auto/phases.js +17 -0
- package/dist/resources/extensions/gsd/auto/session.js +6 -0
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +12 -0
- package/dist/resources/extensions/gsd/auto-start.js +12 -0
- package/dist/resources/extensions/gsd/auto.js +27 -0
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +11 -435
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +1 -4
- package/dist/resources/extensions/gsd/bootstrap/query-tools.js +7 -64
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +88 -8
- package/dist/resources/extensions/gsd/commands/catalog.js +2 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +39 -25
- package/dist/resources/extensions/gsd/commands/index.js +8 -1
- package/dist/resources/extensions/gsd/commands-mcp-status.js +43 -7
- package/dist/resources/extensions/gsd/guided-flow.js +16 -0
- package/dist/resources/extensions/gsd/init-wizard.js +37 -0
- package/dist/resources/extensions/gsd/mcp-project-config.js +83 -0
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +508 -0
- package/dist/resources/extensions/gsd/workflow-logger.js +18 -3
- package/dist/resources/extensions/gsd/workflow-mcp.js +261 -0
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +15 -15
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +15 -15
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/6502.5dcdcf1e1432e20d.js +9 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-b49b09f97429b5d0.js → webpack-42a66876b763aa26.js} +1 -1
- package/package.json +4 -2
- package/packages/mcp-server/README.md +38 -0
- package/packages/mcp-server/dist/cli.d.ts +9 -0
- package/packages/mcp-server/dist/cli.d.ts.map +1 -0
- package/packages/mcp-server/dist/cli.js +58 -0
- package/packages/mcp-server/dist/cli.js.map +1 -0
- package/packages/mcp-server/dist/index.d.ts +20 -0
- package/packages/mcp-server/dist/index.d.ts.map +1 -0
- package/packages/mcp-server/dist/index.js +14 -0
- package/packages/mcp-server/dist/index.js.map +1 -0
- package/packages/mcp-server/dist/readers/captures.d.ts +25 -0
- package/packages/mcp-server/dist/readers/captures.d.ts.map +1 -0
- package/packages/mcp-server/dist/readers/captures.js +67 -0
- package/packages/mcp-server/dist/readers/captures.js.map +1 -0
- package/packages/mcp-server/dist/readers/doctor-lite.d.ts +20 -0
- package/packages/mcp-server/dist/readers/doctor-lite.d.ts.map +1 -0
- package/packages/mcp-server/dist/readers/doctor-lite.js +173 -0
- package/packages/mcp-server/dist/readers/doctor-lite.js.map +1 -0
- package/packages/mcp-server/dist/readers/index.d.ts +14 -0
- package/packages/mcp-server/dist/readers/index.d.ts.map +1 -0
- package/packages/mcp-server/dist/readers/index.js +10 -0
- package/packages/mcp-server/dist/readers/index.js.map +1 -0
- package/packages/mcp-server/dist/readers/knowledge.d.ts +18 -0
- package/packages/mcp-server/dist/readers/knowledge.d.ts.map +1 -0
- package/packages/mcp-server/dist/readers/knowledge.js +82 -0
- package/packages/mcp-server/dist/readers/knowledge.js.map +1 -0
- package/packages/mcp-server/dist/readers/metrics.d.ts +32 -0
- package/packages/mcp-server/dist/readers/metrics.d.ts.map +1 -0
- package/packages/mcp-server/dist/readers/metrics.js +74 -0
- package/packages/mcp-server/dist/readers/metrics.js.map +1 -0
- package/packages/mcp-server/dist/readers/paths.d.ts +42 -0
- package/packages/mcp-server/dist/readers/paths.d.ts.map +1 -0
- package/packages/mcp-server/dist/readers/paths.js +199 -0
- package/packages/mcp-server/dist/readers/paths.js.map +1 -0
- package/packages/mcp-server/dist/readers/roadmap.d.ts +26 -0
- package/packages/mcp-server/dist/readers/roadmap.d.ts.map +1 -0
- package/packages/mcp-server/dist/readers/roadmap.js +194 -0
- package/packages/mcp-server/dist/readers/roadmap.js.map +1 -0
- package/packages/mcp-server/dist/readers/state.d.ts +43 -0
- package/packages/mcp-server/dist/readers/state.d.ts.map +1 -0
- package/packages/mcp-server/dist/readers/state.js +184 -0
- package/packages/mcp-server/dist/readers/state.js.map +1 -0
- package/packages/mcp-server/dist/server.d.ts +28 -0
- package/packages/mcp-server/dist/server.d.ts.map +1 -0
- package/packages/mcp-server/dist/server.js +319 -0
- package/packages/mcp-server/dist/server.js.map +1 -0
- package/packages/mcp-server/dist/session-manager.d.ts +54 -0
- package/packages/mcp-server/dist/session-manager.d.ts.map +1 -0
- package/packages/mcp-server/dist/session-manager.js +284 -0
- package/packages/mcp-server/dist/session-manager.js.map +1 -0
- package/packages/mcp-server/dist/types.d.ts +61 -0
- package/packages/mcp-server/dist/types.d.ts.map +1 -0
- package/packages/mcp-server/dist/types.js +11 -0
- package/packages/mcp-server/dist/types.js.map +1 -0
- package/packages/mcp-server/dist/workflow-tools.d.ts +9 -0
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -0
- package/packages/mcp-server/dist/workflow-tools.js +532 -0
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -0
- package/packages/mcp-server/src/server.ts +6 -2
- package/packages/mcp-server/src/workflow-tools.test.ts +976 -0
- package/packages/mcp-server/src/workflow-tools.ts +997 -0
- package/packages/mcp-server/tsconfig.json +1 -1
- package/packages/pi-agent-core/dist/agent-loop.js +14 -6
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/src/agent-loop.test.ts +53 -0
- package/packages/pi-agent-core/src/agent-loop.ts +20 -6
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +28 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +17 -12
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +19 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +54 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +18 -12
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +21 -0
- package/packages/rpc-client/dist/index.d.ts +10 -0
- package/packages/rpc-client/dist/index.d.ts.map +1 -0
- package/packages/rpc-client/dist/index.js +9 -0
- package/packages/rpc-client/dist/index.js.map +1 -0
- package/packages/rpc-client/dist/jsonl.d.ts +17 -0
- package/packages/rpc-client/dist/jsonl.d.ts.map +1 -0
- package/packages/rpc-client/dist/jsonl.js +54 -0
- package/packages/rpc-client/dist/jsonl.js.map +1 -0
- package/packages/rpc-client/dist/rpc-client.d.ts +259 -0
- package/packages/rpc-client/dist/rpc-client.d.ts.map +1 -0
- package/packages/rpc-client/dist/rpc-client.js +541 -0
- package/packages/rpc-client/dist/rpc-client.js.map +1 -0
- package/packages/rpc-client/dist/rpc-client.test.d.ts +2 -0
- package/packages/rpc-client/dist/rpc-client.test.d.ts.map +1 -0
- package/packages/rpc-client/dist/rpc-client.test.js +477 -0
- package/packages/rpc-client/dist/rpc-client.test.js.map +1 -0
- package/packages/rpc-client/dist/rpc-types.d.ts +566 -0
- package/packages/rpc-client/dist/rpc-types.d.ts.map +1 -0
- package/packages/rpc-client/dist/rpc-types.js +12 -0
- package/packages/rpc-client/dist/rpc-types.js.map +1 -0
- package/scripts/ensure-workspace-builds.cjs +2 -0
- package/scripts/link-workspace-packages.cjs +21 -14
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +157 -8
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +182 -0
- package/src/resources/extensions/gsd/auto/phases.ts +25 -0
- package/src/resources/extensions/gsd/auto/session.ts +6 -0
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +20 -0
- package/src/resources/extensions/gsd/auto-start.ts +15 -1
- package/src/resources/extensions/gsd/auto.ts +29 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +22 -435
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +1 -5
- package/src/resources/extensions/gsd/bootstrap/query-tools.ts +7 -72
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +122 -6
- package/src/resources/extensions/gsd/commands/catalog.ts +2 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +53 -26
- package/src/resources/extensions/gsd/commands/index.ts +7 -1
- package/src/resources/extensions/gsd/commands-mcp-status.ts +53 -7
- package/src/resources/extensions/gsd/guided-flow.ts +24 -0
- package/src/resources/extensions/gsd/init-wizard.ts +40 -0
- package/src/resources/extensions/gsd/mcp-project-config.ts +128 -0
- package/src/resources/extensions/gsd/tests/auto-project-root-env.test.ts +29 -0
- package/src/resources/extensions/gsd/tests/core-overlay-fallback.test.ts +101 -0
- package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +85 -0
- package/src/resources/extensions/gsd/tests/mcp-status.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +500 -0
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +625 -0
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +629 -0
- package/src/resources/extensions/gsd/workflow-logger.ts +19 -3
- package/src/resources/extensions/gsd/workflow-mcp.ts +320 -0
- package/dist/web/standalone/.next/static/chunks/6502.b804e48b7919f55e.js +0 -9
- /package/dist/web/standalone/.next/static/{NllX5BEOLdTXS9ypf1i3i → gbSATDX4Jt2ufxzUr5nYm}/_buildManifest.js +0 -0
- /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.
|
|
30
|
+
## What's New in v2.67
|
|
31
31
|
|
|
32
|
-
###
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
41
|
-
- **Stop/backtrack capture classifications** — context optimization with model routing and masking.
|
|
43
|
+
### Safety & Data Integrity
|
|
42
44
|
|
|
43
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
60
|
-
|
|
61
|
-
- **
|
|
62
|
-
- **
|
|
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.
|
|
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
|
-
|
|
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
|
}
|