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
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* link-workspace-packages.cjs
|
|
4
4
|
*
|
|
5
|
-
* Creates node_modules/@gsd/* symlinks pointing
|
|
5
|
+
* Creates node_modules/@gsd/* and node_modules/@gsd-build/* symlinks pointing
|
|
6
|
+
* to shipped packages/* directories.
|
|
6
7
|
*
|
|
7
8
|
* During development, npm workspaces creates these automatically. But in the
|
|
8
9
|
* published tarball, workspace packages are shipped under packages/ (via the
|
|
@@ -20,27 +21,33 @@ const { resolve, join } = require('path')
|
|
|
20
21
|
|
|
21
22
|
const root = resolve(__dirname, '..')
|
|
22
23
|
const packagesDir = join(root, 'packages')
|
|
23
|
-
const
|
|
24
|
+
const scopeDirs = {
|
|
25
|
+
'@gsd': join(root, 'node_modules', '@gsd'),
|
|
26
|
+
'@gsd-build': join(root, 'node_modules', '@gsd-build'),
|
|
27
|
+
}
|
|
24
28
|
|
|
25
|
-
// Map directory names to package names
|
|
29
|
+
// Map directory names to scoped package names
|
|
26
30
|
const packageMap = {
|
|
27
|
-
'native': 'native',
|
|
28
|
-
'pi-agent-core': 'pi-agent-core',
|
|
29
|
-
'pi-ai': 'pi-ai',
|
|
30
|
-
'pi-coding-agent': 'pi-coding-agent',
|
|
31
|
-
'pi-tui': 'pi-tui',
|
|
31
|
+
'native': { scope: '@gsd', name: 'native' },
|
|
32
|
+
'pi-agent-core': { scope: '@gsd', name: 'pi-agent-core' },
|
|
33
|
+
'pi-ai': { scope: '@gsd', name: 'pi-ai' },
|
|
34
|
+
'pi-coding-agent': { scope: '@gsd', name: 'pi-coding-agent' },
|
|
35
|
+
'pi-tui': { scope: '@gsd', name: 'pi-tui' },
|
|
36
|
+
'rpc-client': { scope: '@gsd-build', name: 'rpc-client' },
|
|
32
37
|
}
|
|
33
38
|
|
|
34
|
-
|
|
35
|
-
if (!existsSync(
|
|
36
|
-
|
|
39
|
+
for (const scopeDir of Object.values(scopeDirs)) {
|
|
40
|
+
if (!existsSync(scopeDir)) {
|
|
41
|
+
mkdirSync(scopeDir, { recursive: true })
|
|
42
|
+
}
|
|
37
43
|
}
|
|
38
44
|
|
|
39
45
|
let linked = 0
|
|
40
46
|
let copied = 0
|
|
41
|
-
for (const [dir,
|
|
47
|
+
for (const [dir, pkg] of Object.entries(packageMap)) {
|
|
42
48
|
const source = join(packagesDir, dir)
|
|
43
|
-
const
|
|
49
|
+
const scopeDir = scopeDirs[pkg.scope]
|
|
50
|
+
const target = join(scopeDir, pkg.name)
|
|
44
51
|
|
|
45
52
|
if (!existsSync(source)) continue
|
|
46
53
|
|
|
@@ -50,7 +57,7 @@ for (const [dir, name] of Object.entries(packageMap)) {
|
|
|
50
57
|
const stat = lstatSync(target)
|
|
51
58
|
if (stat.isSymbolicLink()) {
|
|
52
59
|
const linkTarget = readlinkSync(target)
|
|
53
|
-
if (resolve(join(
|
|
60
|
+
if (resolve(join(scopeDir, linkTarget)) === source || linkTarget === source) {
|
|
54
61
|
continue // Already correct
|
|
55
62
|
}
|
|
56
63
|
unlinkSync(target) // Wrong target, relink
|
|
@@ -14,17 +14,37 @@ import type {
|
|
|
14
14
|
Context,
|
|
15
15
|
Model,
|
|
16
16
|
SimpleStreamOptions,
|
|
17
|
+
ToolCall,
|
|
17
18
|
} from "@gsd/pi-ai";
|
|
18
19
|
import { EventStream } from "@gsd/pi-ai";
|
|
19
20
|
import { execSync } from "node:child_process";
|
|
20
21
|
import { PartialMessageBuilder, ZERO_USAGE, mapUsage } from "./partial-builder.js";
|
|
22
|
+
import { buildWorkflowMcpServers } from "../gsd/workflow-mcp.js";
|
|
21
23
|
import type {
|
|
22
24
|
SDKAssistantMessage,
|
|
23
25
|
SDKMessage,
|
|
24
26
|
SDKPartialAssistantMessage,
|
|
25
27
|
SDKResultMessage,
|
|
28
|
+
SDKUserMessage,
|
|
26
29
|
} from "./sdk-types.js";
|
|
27
30
|
|
|
31
|
+
export interface ExternalToolResultContentBlock {
|
|
32
|
+
type: string;
|
|
33
|
+
text?: string;
|
|
34
|
+
data?: string;
|
|
35
|
+
mimeType?: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface ExternalToolResultPayload {
|
|
39
|
+
content: ExternalToolResultContentBlock[];
|
|
40
|
+
details?: Record<string, unknown>;
|
|
41
|
+
isError: boolean;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
type ToolCallWithExternalResult = ToolCall & {
|
|
45
|
+
externalResult?: ExternalToolResultPayload;
|
|
46
|
+
};
|
|
47
|
+
|
|
28
48
|
// ---------------------------------------------------------------------------
|
|
29
49
|
// Stream factory
|
|
30
50
|
// ---------------------------------------------------------------------------
|
|
@@ -163,6 +183,7 @@ export function makeStreamExhaustedErrorMessage(model: string, lastTextContent:
|
|
|
163
183
|
* beta flags, and other configuration without mocking the full SDK.
|
|
164
184
|
*/
|
|
165
185
|
export function buildSdkOptions(modelId: string, prompt: string): Record<string, unknown> {
|
|
186
|
+
const mcpServers = buildWorkflowMcpServers();
|
|
166
187
|
return {
|
|
167
188
|
pathToClaudeCodeExecutable: getClaudePath(),
|
|
168
189
|
model: modelId,
|
|
@@ -173,10 +194,115 @@ export function buildSdkOptions(modelId: string, prompt: string): Record<string,
|
|
|
173
194
|
allowDangerouslySkipPermissions: true,
|
|
174
195
|
settingSources: ["project"],
|
|
175
196
|
systemPrompt: { type: "preset", preset: "claude_code" },
|
|
197
|
+
...(mcpServers ? { mcpServers } : {}),
|
|
176
198
|
betas: modelId.includes("sonnet") ? ["context-1m-2025-08-07"] : [],
|
|
177
199
|
};
|
|
178
200
|
}
|
|
179
201
|
|
|
202
|
+
function normalizeToolResultContent(content: unknown): ExternalToolResultContentBlock[] {
|
|
203
|
+
if (typeof content === "string") {
|
|
204
|
+
return [{ type: "text", text: content }];
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (!Array.isArray(content)) {
|
|
208
|
+
if (content == null) return [{ type: "text", text: "" }];
|
|
209
|
+
return [{ type: "text", text: JSON.stringify(content) }];
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const blocks: ExternalToolResultContentBlock[] = [];
|
|
213
|
+
|
|
214
|
+
for (const item of content) {
|
|
215
|
+
if (typeof item === "string") {
|
|
216
|
+
blocks.push({ type: "text", text: item });
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
if (!item || typeof item !== "object") {
|
|
220
|
+
blocks.push({ type: "text", text: String(item) });
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const block = item as Record<string, unknown>;
|
|
225
|
+
if (block.type === "text") {
|
|
226
|
+
blocks.push({ type: "text", text: typeof block.text === "string" ? block.text : "" });
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
if (
|
|
230
|
+
block.type === "image"
|
|
231
|
+
&& typeof block.data === "string"
|
|
232
|
+
&& typeof block.mimeType === "string"
|
|
233
|
+
) {
|
|
234
|
+
blocks.push({ type: "image", data: block.data, mimeType: block.mimeType });
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
blocks.push({ type: "text", text: JSON.stringify(block) });
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return blocks.length > 0 ? blocks : [{ type: "text", text: "" }];
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export function extractToolResultsFromSdkUserMessage(message: SDKUserMessage): Array<{
|
|
245
|
+
toolUseId: string;
|
|
246
|
+
result: ExternalToolResultPayload;
|
|
247
|
+
}> {
|
|
248
|
+
const extracted: Array<{ toolUseId: string; result: ExternalToolResultPayload }> = [];
|
|
249
|
+
const seen = new Set<string>();
|
|
250
|
+
const rawMessage = message.message as Record<string, unknown> | null | undefined;
|
|
251
|
+
const content = Array.isArray(rawMessage?.content) ? rawMessage.content : [];
|
|
252
|
+
|
|
253
|
+
for (const item of content) {
|
|
254
|
+
if (!item || typeof item !== "object") continue;
|
|
255
|
+
const block = item as Record<string, unknown>;
|
|
256
|
+
const type = typeof block.type === "string" ? block.type : "";
|
|
257
|
+
if (type !== "tool_result" && type !== "mcp_tool_result") continue;
|
|
258
|
+
|
|
259
|
+
const toolUseId = typeof block.tool_use_id === "string" ? block.tool_use_id : "";
|
|
260
|
+
if (!toolUseId || seen.has(toolUseId)) continue;
|
|
261
|
+
seen.add(toolUseId);
|
|
262
|
+
|
|
263
|
+
extracted.push({
|
|
264
|
+
toolUseId,
|
|
265
|
+
result: {
|
|
266
|
+
content: normalizeToolResultContent(block.content),
|
|
267
|
+
details: {},
|
|
268
|
+
isError: block.is_error === true,
|
|
269
|
+
},
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (extracted.length === 0) {
|
|
274
|
+
const fallback = message.tool_use_result;
|
|
275
|
+
if (fallback && typeof fallback === "object") {
|
|
276
|
+
const toolResult = fallback as Record<string, unknown>;
|
|
277
|
+
const toolUseId = typeof toolResult.tool_use_id === "string" ? toolResult.tool_use_id : "";
|
|
278
|
+
if (toolUseId) {
|
|
279
|
+
extracted.push({
|
|
280
|
+
toolUseId,
|
|
281
|
+
result: {
|
|
282
|
+
content: normalizeToolResultContent(toolResult.content),
|
|
283
|
+
details: {},
|
|
284
|
+
isError: toolResult.is_error === true,
|
|
285
|
+
},
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return extracted;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function attachExternalResultsToToolCalls(
|
|
295
|
+
toolCalls: AssistantMessage["content"],
|
|
296
|
+
toolResultsById: ReadonlyMap<string, ExternalToolResultPayload>,
|
|
297
|
+
): void {
|
|
298
|
+
for (const block of toolCalls) {
|
|
299
|
+
if (block.type !== "toolCall") continue;
|
|
300
|
+
const externalResult = toolResultsById.get(block.id);
|
|
301
|
+
if (!externalResult) continue;
|
|
302
|
+
(block as ToolCallWithExternalResult).externalResult = externalResult;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
180
306
|
// ---------------------------------------------------------------------------
|
|
181
307
|
// streamSimple implementation
|
|
182
308
|
// ---------------------------------------------------------------------------
|
|
@@ -213,6 +339,8 @@ async function pumpSdkMessages(
|
|
|
213
339
|
let lastThinkingContent = "";
|
|
214
340
|
/** Collect tool calls from intermediate SDK turns for tool_execution events. */
|
|
215
341
|
const intermediateToolCalls: AssistantMessage["content"] = [];
|
|
342
|
+
/** Preserve real external tool results from Claude Code's synthetic user messages. */
|
|
343
|
+
const toolResultsById = new Map<string, ExternalToolResultPayload>();
|
|
216
344
|
|
|
217
345
|
try {
|
|
218
346
|
// Dynamic import — the SDK is an optional dependency.
|
|
@@ -282,14 +410,7 @@ async function pumpSdkMessages(
|
|
|
282
410
|
|
|
283
411
|
const assistantEvent = builder.handleEvent(event);
|
|
284
412
|
if (assistantEvent) {
|
|
285
|
-
|
|
286
|
-
// path emits tool_execution_start/end events after streamSimple
|
|
287
|
-
// returns. Streaming toolcall events would render tool calls
|
|
288
|
-
// out of order in the TUI's accumulated message content.
|
|
289
|
-
const t = assistantEvent.type;
|
|
290
|
-
if (t !== "toolcall_start" && t !== "toolcall_delta" && t !== "toolcall_end") {
|
|
291
|
-
stream.push(assistantEvent);
|
|
292
|
-
}
|
|
413
|
+
stream.push(assistantEvent);
|
|
293
414
|
}
|
|
294
415
|
break;
|
|
295
416
|
}
|
|
@@ -324,6 +445,33 @@ async function pumpSdkMessages(
|
|
|
324
445
|
}
|
|
325
446
|
}
|
|
326
447
|
}
|
|
448
|
+
|
|
449
|
+
// Extract tool results from the SDK's synthetic user message
|
|
450
|
+
// and attach to corresponding tool call blocks immediately.
|
|
451
|
+
for (const { toolUseId, result } of extractToolResultsFromSdkUserMessage(msg as SDKUserMessage)) {
|
|
452
|
+
toolResultsById.set(toolUseId, result);
|
|
453
|
+
}
|
|
454
|
+
attachExternalResultsToToolCalls(intermediateToolCalls, toolResultsById);
|
|
455
|
+
|
|
456
|
+
// Push a synthetic toolcall_end for each tool call from this turn
|
|
457
|
+
// so the TUI can render tool results in real-time during the SDK
|
|
458
|
+
// session instead of waiting until the entire session completes.
|
|
459
|
+
if (builder) {
|
|
460
|
+
for (const block of builder.message.content) {
|
|
461
|
+
if (block.type !== "toolCall") continue;
|
|
462
|
+
const extResult = (block as ToolCallWithExternalResult).externalResult;
|
|
463
|
+
if (!extResult) continue;
|
|
464
|
+
// Push a toolcall_end with result attached so the chat-controller
|
|
465
|
+
// can call updateResult on the pending ToolExecutionComponent.
|
|
466
|
+
stream.push({
|
|
467
|
+
type: "toolcall_end",
|
|
468
|
+
contentIndex: builder.message.content.indexOf(block),
|
|
469
|
+
toolCall: block,
|
|
470
|
+
partial: builder.message,
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
327
475
|
builder = null;
|
|
328
476
|
break;
|
|
329
477
|
}
|
|
@@ -338,6 +486,7 @@ async function pumpSdkMessages(
|
|
|
338
486
|
const finalContent: AssistantMessage["content"] = [];
|
|
339
487
|
|
|
340
488
|
// Add tool calls from intermediate turns first (renders above text)
|
|
489
|
+
attachExternalResultsToToolCalls(intermediateToolCalls, toolResultsById);
|
|
341
490
|
finalContent.push(...intermediateToolCalls);
|
|
342
491
|
|
|
343
492
|
// Add text/thinking from the last turn
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
import { describe, test } from "node:test";
|
|
2
2
|
import assert from "node:assert/strict";
|
|
3
|
+
import { mkdirSync, mkdtempSync, realpathSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { join, resolve } from "node:path";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
3
6
|
import {
|
|
4
7
|
makeStreamExhaustedErrorMessage,
|
|
5
8
|
buildPromptFromContext,
|
|
6
9
|
buildSdkOptions,
|
|
10
|
+
extractToolResultsFromSdkUserMessage,
|
|
7
11
|
getClaudeLookupCommand,
|
|
8
12
|
parseClaudeLookupOutput,
|
|
9
13
|
} from "../stream-adapter.ts";
|
|
10
14
|
import type { Context, Message } from "@gsd/pi-ai";
|
|
15
|
+
import type { SDKUserMessage } from "../sdk-types.ts";
|
|
11
16
|
|
|
12
17
|
// ---------------------------------------------------------------------------
|
|
13
18
|
// Existing tests — exhausted stream fallback (#2575)
|
|
@@ -103,6 +108,65 @@ describe("stream-adapter — full context prompt (#2859)", () => {
|
|
|
103
108
|
});
|
|
104
109
|
});
|
|
105
110
|
|
|
111
|
+
describe("stream-adapter — Claude Code external tool results", () => {
|
|
112
|
+
test("extractToolResultsFromSdkUserMessage maps tool_result content to tool payloads", () => {
|
|
113
|
+
const message: SDKUserMessage = {
|
|
114
|
+
type: "user",
|
|
115
|
+
session_id: "sess-1",
|
|
116
|
+
parent_tool_use_id: "tool-bash-1",
|
|
117
|
+
message: {
|
|
118
|
+
role: "user",
|
|
119
|
+
content: [
|
|
120
|
+
{
|
|
121
|
+
type: "tool_result",
|
|
122
|
+
tool_use_id: "tool-bash-1",
|
|
123
|
+
content: "line 1\nline 2",
|
|
124
|
+
is_error: false,
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const results = extractToolResultsFromSdkUserMessage(message);
|
|
131
|
+
assert.deepEqual(results, [
|
|
132
|
+
{
|
|
133
|
+
toolUseId: "tool-bash-1",
|
|
134
|
+
result: {
|
|
135
|
+
content: [{ type: "text", text: "line 1\nline 2" }],
|
|
136
|
+
details: {},
|
|
137
|
+
isError: false,
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
]);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
test("extractToolResultsFromSdkUserMessage falls back to tool_use_result", () => {
|
|
144
|
+
const message: SDKUserMessage = {
|
|
145
|
+
type: "user",
|
|
146
|
+
session_id: "sess-1",
|
|
147
|
+
parent_tool_use_id: "tool-read-1",
|
|
148
|
+
message: { role: "user", content: [] },
|
|
149
|
+
tool_use_result: {
|
|
150
|
+
tool_use_id: "tool-read-1",
|
|
151
|
+
content: "file contents",
|
|
152
|
+
is_error: true,
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
const results = extractToolResultsFromSdkUserMessage(message);
|
|
157
|
+
assert.deepEqual(results, [
|
|
158
|
+
{
|
|
159
|
+
toolUseId: "tool-read-1",
|
|
160
|
+
result: {
|
|
161
|
+
content: [{ type: "text", text: "file contents" }],
|
|
162
|
+
details: {},
|
|
163
|
+
isError: true,
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
]);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
106
170
|
describe("stream-adapter — session persistence (#2859)", () => {
|
|
107
171
|
test("buildSdkOptions enables persistSession by default", () => {
|
|
108
172
|
const options = buildSdkOptions("claude-sonnet-4-20250514", "test prompt");
|
|
@@ -127,6 +191,124 @@ describe("stream-adapter — session persistence (#2859)", () => {
|
|
|
127
191
|
"non-sonnet models should have empty betas",
|
|
128
192
|
);
|
|
129
193
|
});
|
|
194
|
+
|
|
195
|
+
test("buildSdkOptions includes workflow MCP server config when env is set", () => {
|
|
196
|
+
const prev = {
|
|
197
|
+
GSD_WORKFLOW_MCP_COMMAND: process.env.GSD_WORKFLOW_MCP_COMMAND,
|
|
198
|
+
GSD_WORKFLOW_MCP_NAME: process.env.GSD_WORKFLOW_MCP_NAME,
|
|
199
|
+
GSD_WORKFLOW_MCP_ARGS: process.env.GSD_WORKFLOW_MCP_ARGS,
|
|
200
|
+
GSD_WORKFLOW_MCP_ENV: process.env.GSD_WORKFLOW_MCP_ENV,
|
|
201
|
+
GSD_WORKFLOW_MCP_CWD: process.env.GSD_WORKFLOW_MCP_CWD,
|
|
202
|
+
};
|
|
203
|
+
try {
|
|
204
|
+
process.env.GSD_WORKFLOW_MCP_COMMAND = "node";
|
|
205
|
+
process.env.GSD_WORKFLOW_MCP_NAME = "gsd-workflow";
|
|
206
|
+
process.env.GSD_WORKFLOW_MCP_ARGS = JSON.stringify(["packages/mcp-server/dist/cli.js"]);
|
|
207
|
+
process.env.GSD_WORKFLOW_MCP_ENV = JSON.stringify({ GSD_CLI_PATH: "/tmp/gsd" });
|
|
208
|
+
process.env.GSD_WORKFLOW_MCP_CWD = "/tmp/project";
|
|
209
|
+
|
|
210
|
+
const options = buildSdkOptions("claude-sonnet-4-20250514", "test");
|
|
211
|
+
const mcpServers = options.mcpServers as Record<string, any>;
|
|
212
|
+
assert.ok(mcpServers?.["gsd-workflow"], "expected gsd-workflow server config");
|
|
213
|
+
const srv = mcpServers["gsd-workflow"];
|
|
214
|
+
assert.equal(srv.command, "node");
|
|
215
|
+
assert.deepEqual(srv.args, ["packages/mcp-server/dist/cli.js"]);
|
|
216
|
+
assert.equal(srv.cwd, "/tmp/project");
|
|
217
|
+
assert.equal(srv.env.GSD_CLI_PATH, "/tmp/gsd");
|
|
218
|
+
assert.equal(srv.env.GSD_PERSIST_WRITE_GATE_STATE, "1");
|
|
219
|
+
assert.equal(srv.env.GSD_WORKFLOW_PROJECT_ROOT, "/tmp/project");
|
|
220
|
+
} finally {
|
|
221
|
+
process.env.GSD_WORKFLOW_MCP_COMMAND = prev.GSD_WORKFLOW_MCP_COMMAND;
|
|
222
|
+
process.env.GSD_WORKFLOW_MCP_NAME = prev.GSD_WORKFLOW_MCP_NAME;
|
|
223
|
+
process.env.GSD_WORKFLOW_MCP_ARGS = prev.GSD_WORKFLOW_MCP_ARGS;
|
|
224
|
+
process.env.GSD_WORKFLOW_MCP_ENV = prev.GSD_WORKFLOW_MCP_ENV;
|
|
225
|
+
process.env.GSD_WORKFLOW_MCP_CWD = prev.GSD_WORKFLOW_MCP_CWD;
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
test("buildSdkOptions auto-discovers bundled MCP server even without env hints", () => {
|
|
230
|
+
const prev = {
|
|
231
|
+
GSD_WORKFLOW_MCP_COMMAND: process.env.GSD_WORKFLOW_MCP_COMMAND,
|
|
232
|
+
GSD_WORKFLOW_MCP_NAME: process.env.GSD_WORKFLOW_MCP_NAME,
|
|
233
|
+
GSD_WORKFLOW_MCP_ARGS: process.env.GSD_WORKFLOW_MCP_ARGS,
|
|
234
|
+
GSD_WORKFLOW_MCP_ENV: process.env.GSD_WORKFLOW_MCP_ENV,
|
|
235
|
+
GSD_WORKFLOW_MCP_CWD: process.env.GSD_WORKFLOW_MCP_CWD,
|
|
236
|
+
};
|
|
237
|
+
try {
|
|
238
|
+
delete process.env.GSD_WORKFLOW_MCP_COMMAND;
|
|
239
|
+
delete process.env.GSD_WORKFLOW_MCP_NAME;
|
|
240
|
+
delete process.env.GSD_WORKFLOW_MCP_ARGS;
|
|
241
|
+
delete process.env.GSD_WORKFLOW_MCP_ENV;
|
|
242
|
+
delete process.env.GSD_WORKFLOW_MCP_CWD;
|
|
243
|
+
|
|
244
|
+
const originalCwd = process.cwd();
|
|
245
|
+
const emptyDir = mkdtempSync(join(tmpdir(), "claude-mcp-none-"));
|
|
246
|
+
process.chdir(emptyDir);
|
|
247
|
+
const options = buildSdkOptions("claude-sonnet-4-20250514", "test");
|
|
248
|
+
process.chdir(originalCwd);
|
|
249
|
+
// The bundled CLI may or may not be discoverable depending on
|
|
250
|
+
// whether the build output exists relative to import.meta.url.
|
|
251
|
+
// Either outcome is valid — the key invariant is no crash.
|
|
252
|
+
const mcpServers = (options as any).mcpServers;
|
|
253
|
+
if (mcpServers) {
|
|
254
|
+
assert.ok(mcpServers["gsd-workflow"], "if present, must be gsd-workflow");
|
|
255
|
+
}
|
|
256
|
+
rmSync(emptyDir, { recursive: true, force: true });
|
|
257
|
+
} finally {
|
|
258
|
+
process.env.GSD_WORKFLOW_MCP_COMMAND = prev.GSD_WORKFLOW_MCP_COMMAND;
|
|
259
|
+
process.env.GSD_WORKFLOW_MCP_NAME = prev.GSD_WORKFLOW_MCP_NAME;
|
|
260
|
+
process.env.GSD_WORKFLOW_MCP_ARGS = prev.GSD_WORKFLOW_MCP_ARGS;
|
|
261
|
+
process.env.GSD_WORKFLOW_MCP_ENV = prev.GSD_WORKFLOW_MCP_ENV;
|
|
262
|
+
process.env.GSD_WORKFLOW_MCP_CWD = prev.GSD_WORKFLOW_MCP_CWD;
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
test("buildSdkOptions auto-detects local workflow MCP dist CLI when present", () => {
|
|
267
|
+
const prev = {
|
|
268
|
+
GSD_WORKFLOW_MCP_COMMAND: process.env.GSD_WORKFLOW_MCP_COMMAND,
|
|
269
|
+
GSD_WORKFLOW_MCP_NAME: process.env.GSD_WORKFLOW_MCP_NAME,
|
|
270
|
+
GSD_WORKFLOW_MCP_ARGS: process.env.GSD_WORKFLOW_MCP_ARGS,
|
|
271
|
+
GSD_WORKFLOW_MCP_ENV: process.env.GSD_WORKFLOW_MCP_ENV,
|
|
272
|
+
GSD_WORKFLOW_MCP_CWD: process.env.GSD_WORKFLOW_MCP_CWD,
|
|
273
|
+
GSD_CLI_PATH: process.env.GSD_CLI_PATH,
|
|
274
|
+
};
|
|
275
|
+
const originalCwd = process.cwd();
|
|
276
|
+
const repoDir = mkdtempSync(join(tmpdir(), "claude-mcp-detect-"));
|
|
277
|
+
try {
|
|
278
|
+
delete process.env.GSD_WORKFLOW_MCP_COMMAND;
|
|
279
|
+
delete process.env.GSD_WORKFLOW_MCP_NAME;
|
|
280
|
+
delete process.env.GSD_WORKFLOW_MCP_ARGS;
|
|
281
|
+
delete process.env.GSD_WORKFLOW_MCP_ENV;
|
|
282
|
+
delete process.env.GSD_WORKFLOW_MCP_CWD;
|
|
283
|
+
process.env.GSD_CLI_PATH = "/tmp/gsd";
|
|
284
|
+
|
|
285
|
+
const distDir = join(repoDir, "packages", "mcp-server", "dist");
|
|
286
|
+
mkdirSync(distDir, { recursive: true });
|
|
287
|
+
writeFileSync(join(distDir, "cli.js"), "#!/usr/bin/env node\n");
|
|
288
|
+
process.chdir(repoDir);
|
|
289
|
+
const resolvedRepoDir = realpathSync(repoDir);
|
|
290
|
+
|
|
291
|
+
const options = buildSdkOptions("claude-sonnet-4-20250514", "test");
|
|
292
|
+
const mcpServers = options.mcpServers as Record<string, any>;
|
|
293
|
+
assert.ok(mcpServers?.["gsd-workflow"], "expected gsd-workflow server config");
|
|
294
|
+
const srv = mcpServers["gsd-workflow"];
|
|
295
|
+
assert.equal(srv.command, process.execPath);
|
|
296
|
+
assert.deepEqual(srv.args, [realpathSync(resolve(repoDir, "packages", "mcp-server", "dist", "cli.js"))]);
|
|
297
|
+
assert.equal(srv.cwd, resolvedRepoDir);
|
|
298
|
+
assert.equal(srv.env.GSD_CLI_PATH, "/tmp/gsd");
|
|
299
|
+
assert.equal(srv.env.GSD_PERSIST_WRITE_GATE_STATE, "1");
|
|
300
|
+
assert.equal(srv.env.GSD_WORKFLOW_PROJECT_ROOT, resolvedRepoDir);
|
|
301
|
+
} finally {
|
|
302
|
+
process.chdir(originalCwd);
|
|
303
|
+
rmSync(repoDir, { recursive: true, force: true });
|
|
304
|
+
process.env.GSD_WORKFLOW_MCP_COMMAND = prev.GSD_WORKFLOW_MCP_COMMAND;
|
|
305
|
+
process.env.GSD_WORKFLOW_MCP_NAME = prev.GSD_WORKFLOW_MCP_NAME;
|
|
306
|
+
process.env.GSD_WORKFLOW_MCP_ARGS = prev.GSD_WORKFLOW_MCP_ARGS;
|
|
307
|
+
process.env.GSD_WORKFLOW_MCP_ENV = prev.GSD_WORKFLOW_MCP_ENV;
|
|
308
|
+
process.env.GSD_WORKFLOW_MCP_CWD = prev.GSD_WORKFLOW_MCP_CWD;
|
|
309
|
+
process.env.GSD_CLI_PATH = prev.GSD_CLI_PATH;
|
|
310
|
+
}
|
|
311
|
+
});
|
|
130
312
|
});
|
|
131
313
|
|
|
132
314
|
describe("stream-adapter — Windows Claude path lookup (#3770)", () => {
|
|
@@ -41,6 +41,10 @@ import { isDbAvailable, getMilestoneSlices } from "../gsd-db.js";
|
|
|
41
41
|
import { resetEvidence } from "../safety/evidence-collector.js";
|
|
42
42
|
import { createCheckpoint, cleanupCheckpoint, rollbackToCheckpoint } from "../safety/git-checkpoint.js";
|
|
43
43
|
import { resolveSafetyHarnessConfig } from "../safety/safety-harness.js";
|
|
44
|
+
import {
|
|
45
|
+
getWorkflowTransportSupportError,
|
|
46
|
+
getRequiredWorkflowToolsForAutoUnit,
|
|
47
|
+
} from "../workflow-mcp.js";
|
|
44
48
|
|
|
45
49
|
// ─── generateMilestoneReport ──────────────────────────────────────────────────
|
|
46
50
|
|
|
@@ -1216,6 +1220,27 @@ export async function runUnitPhase(
|
|
|
1216
1220
|
? `${(s.currentUnitModel as any).provider ?? ""}/${(s.currentUnitModel as any).id ?? ""}`
|
|
1217
1221
|
: null;
|
|
1218
1222
|
|
|
1223
|
+
const compatibilityError = getWorkflowTransportSupportError(
|
|
1224
|
+
s.currentUnitModel?.provider ?? ctx.model?.provider,
|
|
1225
|
+
getRequiredWorkflowToolsForAutoUnit(unitType),
|
|
1226
|
+
{
|
|
1227
|
+
projectRoot: s.basePath,
|
|
1228
|
+
surface: "auto-mode",
|
|
1229
|
+
unitType,
|
|
1230
|
+
authMode: s.currentUnitModel?.provider
|
|
1231
|
+
? ctx.modelRegistry.getProviderAuthMode(s.currentUnitModel.provider)
|
|
1232
|
+
: ctx.model?.provider
|
|
1233
|
+
? ctx.modelRegistry.getProviderAuthMode(ctx.model.provider)
|
|
1234
|
+
: undefined,
|
|
1235
|
+
baseUrl: (s.currentUnitModel as any)?.baseUrl ?? ctx.model?.baseUrl,
|
|
1236
|
+
},
|
|
1237
|
+
);
|
|
1238
|
+
if (compatibilityError) {
|
|
1239
|
+
ctx.ui.notify(compatibilityError, "error");
|
|
1240
|
+
await deps.stopAuto(ctx, pi, compatibilityError);
|
|
1241
|
+
return { action: "break", reason: "workflow-capability" };
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1219
1244
|
// Progress widget + preconditions — deferred to after model selection so the
|
|
1220
1245
|
// widget's first render tick shows the correct model (#2899).
|
|
1221
1246
|
deps.updateProgressWidget(ctx, unitType, unitId, state);
|
|
@@ -84,6 +84,9 @@ export class AutoSession {
|
|
|
84
84
|
// ── Paths ────────────────────────────────────────────────────────────────
|
|
85
85
|
basePath = "";
|
|
86
86
|
originalBasePath = "";
|
|
87
|
+
previousProjectRootEnv: string | null = null;
|
|
88
|
+
hadProjectRootEnv = false;
|
|
89
|
+
projectRootEnvCaptured = false;
|
|
87
90
|
gitService: GitServiceImpl | null = null;
|
|
88
91
|
|
|
89
92
|
// ── Dispatch counters ────────────────────────────────────────────────────
|
|
@@ -192,6 +195,9 @@ export class AutoSession {
|
|
|
192
195
|
// Paths
|
|
193
196
|
this.basePath = "";
|
|
194
197
|
this.originalBasePath = "";
|
|
198
|
+
this.previousProjectRootEnv = null;
|
|
199
|
+
this.hadProjectRootEnv = false;
|
|
200
|
+
this.projectRootEnvCaptured = false;
|
|
195
201
|
this.gitService = null;
|
|
196
202
|
|
|
197
203
|
// Dispatch
|
|
@@ -29,6 +29,10 @@ import {
|
|
|
29
29
|
} from "./auto-prompts.js";
|
|
30
30
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
31
31
|
import { pauseAuto } from "./auto.js";
|
|
32
|
+
import {
|
|
33
|
+
getWorkflowTransportSupportError,
|
|
34
|
+
getRequiredWorkflowToolsForAutoUnit,
|
|
35
|
+
} from "./workflow-mcp.js";
|
|
32
36
|
|
|
33
37
|
export async function dispatchDirectPhase(
|
|
34
38
|
ctx: ExtensionCommandContext,
|
|
@@ -243,6 +247,22 @@ export async function dispatchDirectPhase(
|
|
|
243
247
|
return;
|
|
244
248
|
}
|
|
245
249
|
|
|
250
|
+
const compatibilityError = getWorkflowTransportSupportError(
|
|
251
|
+
ctx.model?.provider,
|
|
252
|
+
getRequiredWorkflowToolsForAutoUnit(unitType),
|
|
253
|
+
{
|
|
254
|
+
projectRoot: base,
|
|
255
|
+
surface: "direct phase dispatch",
|
|
256
|
+
unitType,
|
|
257
|
+
authMode: ctx.model?.provider ? ctx.modelRegistry.getProviderAuthMode(ctx.model.provider) : undefined,
|
|
258
|
+
baseUrl: ctx.model?.baseUrl,
|
|
259
|
+
},
|
|
260
|
+
);
|
|
261
|
+
if (compatibilityError) {
|
|
262
|
+
ctx.ui.notify(compatibilityError, "error");
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
|
|
246
266
|
ctx.ui.notify(`Dispatching ${unitType} for ${unitId}...`, "info");
|
|
247
267
|
const result = await ctx.newSession();
|
|
248
268
|
if (result.cancelled) {
|
|
@@ -340,6 +340,21 @@ export async function bootstrapAutoSession(
|
|
|
340
340
|
}
|
|
341
341
|
}
|
|
342
342
|
|
|
343
|
+
if (ctx.model?.provider === "claude-code") {
|
|
344
|
+
try {
|
|
345
|
+
const { ensureProjectWorkflowMcpConfig } = await import("./mcp-project-config.js");
|
|
346
|
+
const result = ensureProjectWorkflowMcpConfig(base);
|
|
347
|
+
if (result.status !== "unchanged") {
|
|
348
|
+
ctx.ui.notify(`Claude Code MCP prepared at ${result.configPath}`, "info");
|
|
349
|
+
}
|
|
350
|
+
} catch (err) {
|
|
351
|
+
ctx.ui.notify(
|
|
352
|
+
`Claude Code MCP prep failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
353
|
+
"warning",
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
343
358
|
// Initialize GitServiceImpl
|
|
344
359
|
s.gitService = new GitServiceImpl(
|
|
345
360
|
s.basePath,
|
|
@@ -909,4 +924,3 @@ export async function bootstrapAutoSession(
|
|
|
909
924
|
throw err;
|
|
910
925
|
}
|
|
911
926
|
}
|
|
912
|
-
|