gsd-pi 2.67.0-dev.5399650 → 2.67.0-dev.6fc2289

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 (151) hide show
  1. package/README.md +1 -1
  2. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +152 -70
  3. package/dist/resources/extensions/gsd/auto/session.js +4 -0
  4. package/dist/resources/extensions/gsd/auto-dispatch.js +1 -1
  5. package/dist/resources/extensions/gsd/auto-start.js +16 -30
  6. package/dist/resources/extensions/gsd/auto-worktree.js +62 -15
  7. package/dist/resources/extensions/gsd/auto.js +94 -59
  8. package/dist/resources/extensions/gsd/bootstrap/system-context.js +7 -2
  9. package/dist/resources/extensions/gsd/commands/catalog.js +2 -1
  10. package/dist/resources/extensions/gsd/commands/handlers/core.js +1 -1
  11. package/dist/resources/extensions/gsd/commands-mcp-status.js +43 -7
  12. package/dist/resources/extensions/gsd/doctor-git-checks.js +4 -4
  13. package/dist/resources/extensions/gsd/doctor-proactive.js +3 -3
  14. package/dist/resources/extensions/gsd/doctor.js +8 -4
  15. package/dist/resources/extensions/gsd/guided-flow.js +40 -31
  16. package/dist/resources/extensions/gsd/init-wizard.js +15 -12
  17. package/dist/resources/extensions/gsd/interrupted-session.js +146 -0
  18. package/dist/resources/extensions/gsd/mcp-project-config.js +83 -0
  19. package/dist/resources/extensions/gsd/workflow-mcp.js +64 -24
  20. package/dist/web/standalone/.next/BUILD_ID +1 -1
  21. package/dist/web/standalone/.next/app-path-routes-manifest.json +16 -16
  22. package/dist/web/standalone/.next/build-manifest.json +3 -3
  23. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  24. package/dist/web/standalone/.next/react-loadable-manifest.json +2 -2
  25. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  26. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  27. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  28. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  29. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  30. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  31. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  32. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  33. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  34. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +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 +2 -2
  45. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  46. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +2 -2
  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/page_client-reference-manifest.js +1 -1
  51. package/dist/web/standalone/.next/server/app-paths-manifest.json +16 -16
  52. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  53. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  54. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  55. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  56. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  57. package/dist/web/standalone/.next/static/chunks/2826.821e01b07d92e948.js +9 -0
  58. package/dist/web/standalone/.next/static/chunks/app/{page-0c485498795110d6.js → page-f1e30ab6bb269149.js} +1 -1
  59. package/dist/web/standalone/.next/static/chunks/{webpack-b49b09f97429b5d0.js → webpack-6e4d7e9a4f57bed4.js} +1 -1
  60. package/package.json +1 -1
  61. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  62. package/packages/mcp-server/dist/workflow-tools.js +10 -4
  63. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  64. package/packages/mcp-server/src/workflow-tools.ts +13 -2
  65. package/packages/pi-agent-core/dist/agent-loop.js +14 -6
  66. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  67. package/packages/pi-agent-core/src/agent-loop.test.ts +53 -0
  68. package/packages/pi-agent-core/src/agent-loop.ts +20 -6
  69. package/packages/pi-coding-agent/dist/core/contextual-tips.d.ts +43 -0
  70. package/packages/pi-coding-agent/dist/core/contextual-tips.d.ts.map +1 -0
  71. package/packages/pi-coding-agent/dist/core/contextual-tips.js +208 -0
  72. package/packages/pi-coding-agent/dist/core/contextual-tips.js.map +1 -0
  73. package/packages/pi-coding-agent/dist/core/contextual-tips.test.d.ts +2 -0
  74. package/packages/pi-coding-agent/dist/core/contextual-tips.test.d.ts.map +1 -0
  75. package/packages/pi-coding-agent/dist/core/contextual-tips.test.js +227 -0
  76. package/packages/pi-coding-agent/dist/core/contextual-tips.test.js.map +1 -0
  77. package/packages/pi-coding-agent/dist/core/index.d.ts +1 -0
  78. package/packages/pi-coding-agent/dist/core/index.d.ts.map +1 -1
  79. package/packages/pi-coding-agent/dist/core/index.js +1 -0
  80. package/packages/pi-coding-agent/dist/core/index.js.map +1 -1
  81. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.d.ts +2 -0
  82. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.d.ts.map +1 -0
  83. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +28 -0
  84. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -0
  85. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +1 -0
  86. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  87. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +17 -12
  88. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  89. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  90. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +19 -0
  91. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  92. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts +4 -0
  93. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  94. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +14 -0
  95. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  96. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +3 -0
  97. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  98. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +15 -12
  99. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  100. package/packages/pi-coding-agent/src/core/contextual-tips.test.ts +259 -0
  101. package/packages/pi-coding-agent/src/core/contextual-tips.ts +232 -0
  102. package/packages/pi-coding-agent/src/core/index.ts +2 -0
  103. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +54 -0
  104. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +18 -12
  105. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +21 -0
  106. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +19 -0
  107. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +19 -15
  108. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +190 -93
  109. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +89 -116
  110. package/src/resources/extensions/gsd/auto/session.ts +4 -0
  111. package/src/resources/extensions/gsd/auto-dispatch.ts +1 -1
  112. package/src/resources/extensions/gsd/auto-start.ts +23 -55
  113. package/src/resources/extensions/gsd/auto-worktree.ts +59 -15
  114. package/src/resources/extensions/gsd/auto.ts +104 -63
  115. package/src/resources/extensions/gsd/bootstrap/system-context.ts +8 -2
  116. package/src/resources/extensions/gsd/commands/catalog.ts +2 -1
  117. package/src/resources/extensions/gsd/commands/handlers/core.ts +1 -1
  118. package/src/resources/extensions/gsd/commands-mcp-status.ts +53 -7
  119. package/src/resources/extensions/gsd/doctor-git-checks.ts +4 -4
  120. package/src/resources/extensions/gsd/doctor-proactive.ts +3 -3
  121. package/src/resources/extensions/gsd/doctor.ts +9 -5
  122. package/src/resources/extensions/gsd/guided-flow.ts +42 -36
  123. package/src/resources/extensions/gsd/init-wizard.ts +17 -11
  124. package/src/resources/extensions/gsd/interrupted-session.ts +224 -0
  125. package/src/resources/extensions/gsd/mcp-project-config.ts +128 -0
  126. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +668 -2
  127. package/src/resources/extensions/gsd/tests/cold-resume-db-reopen.test.ts +14 -4
  128. package/src/resources/extensions/gsd/tests/copy-planning-artifacts-samepath.test.ts +21 -0
  129. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +380 -2
  130. package/src/resources/extensions/gsd/tests/forensics-context-persist.test.ts +30 -0
  131. package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +2 -2
  132. package/src/resources/extensions/gsd/tests/integration/doctor-fixlevel.test.ts +52 -1
  133. package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +2 -9
  134. package/src/resources/extensions/gsd/tests/integration/doctor-proactive.test.ts +0 -33
  135. package/src/resources/extensions/gsd/tests/integration/merge-cwd-restore.test.ts +169 -0
  136. package/src/resources/extensions/gsd/tests/interrupted-session-auto.test.ts +146 -0
  137. package/src/resources/extensions/gsd/tests/interrupted-session-ui.test.ts +136 -0
  138. package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +85 -0
  139. package/src/resources/extensions/gsd/tests/mcp-status.test.ts +15 -0
  140. package/src/resources/extensions/gsd/tests/verification-operational-gate.test.ts +11 -0
  141. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +178 -17
  142. package/src/resources/extensions/gsd/workflow-mcp.ts +76 -23
  143. package/dist/web/standalone/.next/static/chunks/6502.b804e48b7919f55e.js +0 -9
  144. package/packages/pi-coding-agent/dist/modes/interactive/provider-auth-setup.d.ts +0 -13
  145. package/packages/pi-coding-agent/dist/modes/interactive/provider-auth-setup.d.ts.map +0 -1
  146. package/packages/pi-coding-agent/dist/modes/interactive/provider-auth-setup.js +0 -27
  147. package/packages/pi-coding-agent/dist/modes/interactive/provider-auth-setup.js.map +0 -1
  148. package/packages/pi-coding-agent/src/modes/interactive/provider-auth-setup.ts +0 -40
  149. package/src/resources/extensions/gsd/tests/init-bootstrap-completeness.test.ts +0 -121
  150. /package/dist/web/standalone/.next/static/{6_QPFhgX0DQnDhhquheRc → yh2vT27L1E6PChb_C1N_F}/_buildManifest.js +0 -0
  151. /package/dist/web/standalone/.next/static/{6_QPFhgX0DQnDhhquheRc → yh2vT27L1E6PChb_C1N_F}/_ssgManifest.js +0 -0
@@ -1,9 +1,11 @@
1
1
  import test from "node:test";
2
2
  import assert from "node:assert/strict";
3
- import { mkdtempSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
+ import { existsSync, mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
4
4
  import { dirname, join } from "node:path";
5
5
  import { tmpdir } from "node:os";
6
6
  import { fileURLToPath } from "node:url";
7
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
8
+ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
7
9
 
8
10
  import {
9
11
  buildWorkflowMcpServers,
@@ -44,13 +46,14 @@ test("detectWorkflowMcpLaunchConfig prefers explicit env override", () => {
44
46
  command: "node",
45
47
  args: ["dist/cli.js"],
46
48
  cwd: "/tmp/project",
47
- env: {
48
- FOO: "bar",
49
- GSD_CLI_PATH: "/tmp/gsd",
50
- GSD_PERSIST_WRITE_GATE_STATE: "1",
51
- GSD_WORKFLOW_PROJECT_ROOT: "/tmp/project",
52
- },
49
+ env: launch?.env,
53
50
  });
51
+ assert.equal(launch?.env?.FOO, "bar");
52
+ assert.equal(launch?.env?.GSD_CLI_PATH, "/tmp/gsd");
53
+ assert.equal(launch?.env?.GSD_PERSIST_WRITE_GATE_STATE, "1");
54
+ assert.equal(launch?.env?.GSD_WORKFLOW_PROJECT_ROOT, "/tmp/project");
55
+ assert.match(launch?.env?.GSD_WORKFLOW_EXECUTORS_MODULE ?? "", /workflow-tool-executors\.(js|ts)$/);
56
+ assert.match(launch?.env?.GSD_WORKFLOW_WRITE_GATE_MODULE ?? "", /write-gate\.(js|ts)$/);
54
57
  });
55
58
 
56
59
  test("buildWorkflowMcpServers mirrors explicit launch config", () => {
@@ -63,12 +66,13 @@ test("buildWorkflowMcpServers mirrors explicit launch config", () => {
63
66
  "gsd-workflow": {
64
67
  command: "node",
65
68
  args: ["dist/cli.js"],
66
- env: {
67
- GSD_PERSIST_WRITE_GATE_STATE: "1",
68
- GSD_WORKFLOW_PROJECT_ROOT: "/tmp/project",
69
- },
69
+ env: servers?.["gsd-workflow"]?.env,
70
70
  },
71
71
  });
72
+ assert.equal((servers?.["gsd-workflow"]?.env as Record<string, string> | undefined)?.GSD_PERSIST_WRITE_GATE_STATE, "1");
73
+ assert.equal((servers?.["gsd-workflow"]?.env as Record<string, string> | undefined)?.GSD_WORKFLOW_PROJECT_ROOT, "/tmp/project");
74
+ assert.match((servers?.["gsd-workflow"]?.env as Record<string, string> | undefined)?.GSD_WORKFLOW_EXECUTORS_MODULE ?? "", /workflow-tool-executors\.(js|ts)$/);
75
+ assert.match((servers?.["gsd-workflow"]?.env as Record<string, string> | undefined)?.GSD_WORKFLOW_WRITE_GATE_MODULE ?? "", /write-gate\.(js|ts)$/);
72
76
  });
73
77
 
74
78
  test("detectWorkflowMcpLaunchConfig resolves the bundled server from GSD_PROJECT_ROOT", () => {
@@ -88,11 +92,41 @@ test("detectWorkflowMcpLaunchConfig resolves the bundled server from GSD_PROJECT
88
92
  command: process.execPath,
89
93
  args: [cliPath],
90
94
  cwd: repoRoot,
91
- env: {
92
- GSD_PERSIST_WRITE_GATE_STATE: "1",
93
- GSD_WORKFLOW_PROJECT_ROOT: repoRoot,
94
- },
95
+ env: launch?.env,
96
+ });
97
+ assert.equal(launch?.env?.GSD_PERSIST_WRITE_GATE_STATE, "1");
98
+ assert.equal(launch?.env?.GSD_WORKFLOW_PROJECT_ROOT, repoRoot);
99
+ assert.match(launch?.env?.GSD_WORKFLOW_EXECUTORS_MODULE ?? "", /workflow-tool-executors\.(js|ts)$/);
100
+ assert.match(launch?.env?.GSD_WORKFLOW_WRITE_GATE_MODULE ?? "", /write-gate\.(js|ts)$/);
101
+ });
102
+
103
+ test("detectWorkflowMcpLaunchConfig resolves the bundled server from GSD_BIN_PATH ancestry", () => {
104
+ const repoRoot = mkdtempSync(join(tmpdir(), "gsd-workflow-root-"));
105
+ const worktreeRoot = mkdtempSync(join(tmpdir(), "gsd-workflow-worktree-"));
106
+ const cliPath = join(repoRoot, "packages", "mcp-server", "dist", "cli.js");
107
+ const devCliPath = join(repoRoot, "scripts", "dev-cli.js");
108
+
109
+ mkdirSync(join(repoRoot, "packages", "mcp-server", "dist"), { recursive: true });
110
+ mkdirSync(join(repoRoot, "scripts"), { recursive: true });
111
+ writeFileSync(cliPath, "#!/usr/bin/env node\n", "utf-8");
112
+ writeFileSync(devCliPath, "#!/usr/bin/env node\n", "utf-8");
113
+
114
+ const launch = detectWorkflowMcpLaunchConfig(worktreeRoot, {
115
+ GSD_BIN_PATH: devCliPath,
116
+ });
117
+
118
+ assert.deepEqual(launch, {
119
+ name: "gsd-workflow",
120
+ command: process.execPath,
121
+ args: [cliPath],
122
+ cwd: worktreeRoot,
123
+ env: launch?.env,
95
124
  });
125
+ assert.equal(launch?.env?.GSD_CLI_PATH, devCliPath);
126
+ assert.equal(launch?.env?.GSD_PERSIST_WRITE_GATE_STATE, "1");
127
+ assert.equal(launch?.env?.GSD_WORKFLOW_PROJECT_ROOT, worktreeRoot);
128
+ assert.match(launch?.env?.GSD_WORKFLOW_EXECUTORS_MODULE ?? "", /workflow-tool-executors\.(js|ts)$/);
129
+ assert.match(launch?.env?.GSD_WORKFLOW_WRITE_GATE_MODULE ?? "", /write-gate\.(js|ts)$/);
96
130
  });
97
131
 
98
132
  test("detectWorkflowMcpLaunchConfig resolves the bundled server relative to the installed GSD package", () => {
@@ -104,10 +138,137 @@ test("detectWorkflowMcpLaunchConfig resolves the bundled server relative to the
104
138
  assert.equal(launch?.cwd, "/tmp/project");
105
139
  assert.equal(launch?.env?.GSD_CLI_PATH, "/tmp/gsd-loader.js");
106
140
  assert.equal(launch?.env?.GSD_WORKFLOW_PROJECT_ROOT, "/tmp/project");
141
+ assert.match(launch?.env?.GSD_WORKFLOW_EXECUTORS_MODULE ?? "", /workflow-tool-executors\.(js|ts)$/);
142
+ assert.match(launch?.env?.GSD_WORKFLOW_WRITE_GATE_MODULE ?? "", /write-gate\.(js|ts)$/);
143
+ assert.equal(typeof launch?.args?.[0], "string");
144
+ assert.match(launch?.args?.[0] ?? "", /packages[\/\\]mcp-server[\/\\]dist[\/\\]cli\.js$/);
145
+ });
146
+
147
+ test("detectWorkflowMcpLaunchConfig resolves the bundled server relative to the package without env hints", () => {
148
+ const launch = detectWorkflowMcpLaunchConfig("/tmp/project", {});
149
+
150
+ assert.equal(launch?.command, process.execPath);
151
+ assert.equal(launch?.cwd, "/tmp/project");
152
+ assert.equal(launch?.env?.GSD_CLI_PATH, undefined);
153
+ assert.equal(launch?.env?.GSD_WORKFLOW_PROJECT_ROOT, "/tmp/project");
154
+ assert.match(launch?.env?.GSD_WORKFLOW_EXECUTORS_MODULE ?? "", /workflow-tool-executors\.(js|ts)$/);
155
+ assert.match(launch?.env?.GSD_WORKFLOW_WRITE_GATE_MODULE ?? "", /write-gate\.(js|ts)$/);
107
156
  assert.equal(typeof launch?.args?.[0], "string");
108
157
  assert.match(launch?.args?.[0] ?? "", /packages[\/\\]mcp-server[\/\\]dist[\/\\]cli\.js$/);
109
158
  });
110
159
 
160
+ test("workflow MCP launch config reaches mutation tools over stdio", async () => {
161
+ const projectRoot = mkdtempSync(join(tmpdir(), "gsd-workflow-transport-"));
162
+ mkdirSync(join(projectRoot, ".gsd"), { recursive: true });
163
+
164
+ const launch = detectWorkflowMcpLaunchConfig(projectRoot, {});
165
+ assert.ok(launch, "expected a workflow MCP launch config");
166
+ assert.match(
167
+ launch.env?.GSD_WORKFLOW_EXECUTORS_MODULE ?? "",
168
+ /dist[\/\\]resources[\/\\]extensions[\/\\]gsd[\/\\]tools[\/\\]workflow-tool-executors\.js$/,
169
+ );
170
+ assert.match(
171
+ launch.env?.GSD_WORKFLOW_WRITE_GATE_MODULE ?? "",
172
+ /dist[\/\\]resources[\/\\]extensions[\/\\]gsd[\/\\]bootstrap[\/\\]write-gate\.js$/,
173
+ );
174
+
175
+ const client = new Client({ name: "workflow-mcp-transport-test", version: "1.0.0" });
176
+ const transport = new StdioClientTransport({
177
+ command: launch.command,
178
+ args: launch.args,
179
+ env: { ...process.env, ...launch.env } as Record<string, string>,
180
+ cwd: launch.cwd,
181
+ stderr: "pipe",
182
+ });
183
+
184
+ try {
185
+ await client.connect(transport, { timeout: 30_000 });
186
+
187
+ const tools = await client.listTools(undefined, { timeout: 30_000 });
188
+ assert.ok(
189
+ (tools.tools ?? []).some((tool) => tool.name === "gsd_plan_slice"),
190
+ "expected workflow MCP surface to expose gsd_plan_slice",
191
+ );
192
+
193
+ const milestoneResult = await client.callTool(
194
+ {
195
+ name: "gsd_plan_milestone",
196
+ arguments: {
197
+ projectDir: projectRoot,
198
+ milestoneId: "M001",
199
+ title: "Transport planning",
200
+ vision: "Verify stdio workflow MCP uses the executor bridge.",
201
+ slices: [
202
+ {
203
+ sliceId: "S01",
204
+ title: "Bridge path",
205
+ risk: "low",
206
+ depends: [],
207
+ demo: "Milestone planning succeeds over stdio MCP.",
208
+ goal: "Prove the executor bridge works in the spawned server.",
209
+ successCriteria: "gsd_plan_slice can write plan artifacts.",
210
+ proofLevel: "integration",
211
+ integrationClosure: "Stdio MCP client reaches the workflow executor bridge.",
212
+ observabilityImpact: "Regression test covers the spawned-server path.",
213
+ },
214
+ ],
215
+ },
216
+ },
217
+ undefined,
218
+ { timeout: 30_000 },
219
+ );
220
+ assert.equal(milestoneResult.isError, undefined);
221
+ assert.match(
222
+ ((milestoneResult.content as Array<{ text?: string }>)?.[0])?.text ?? "",
223
+ /Planned milestone M001/,
224
+ );
225
+
226
+ const sliceResult = await client.callTool(
227
+ {
228
+ name: "gsd_plan_slice",
229
+ arguments: {
230
+ projectDir: projectRoot,
231
+ milestoneId: "M001",
232
+ sliceId: "S01",
233
+ goal: "Persist slice planning over the spawned MCP transport.",
234
+ tasks: [
235
+ {
236
+ taskId: "T01",
237
+ title: "Connect the bridge",
238
+ description: "Ensure the workflow executor bridge resolves in the child process.",
239
+ estimate: "10m",
240
+ files: ["src/resources/extensions/gsd/workflow-mcp.ts"],
241
+ verify: "node --test",
242
+ inputs: ["M001-ROADMAP.md"],
243
+ expectedOutput: ["S01-PLAN.md", "T01-PLAN.md"],
244
+ },
245
+ ],
246
+ },
247
+ },
248
+ undefined,
249
+ { timeout: 30_000 },
250
+ );
251
+ assert.equal(sliceResult.isError, undefined);
252
+ assert.match(
253
+ ((sliceResult.content as Array<{ text?: string }>)?.[0])?.text ?? "",
254
+ /Planned slice S01/,
255
+ );
256
+ assert.ok(
257
+ existsSync(join(projectRoot, ".gsd", "milestones", "M001", "slices", "S01", "S01-PLAN.md")),
258
+ "expected slice plan artifact to be written through stdio MCP",
259
+ );
260
+ assert.ok(
261
+ existsSync(
262
+ join(projectRoot, ".gsd", "milestones", "M001", "slices", "S01", "tasks", "T01-PLAN.md"),
263
+ ),
264
+ "expected task plan artifact to be written through stdio MCP",
265
+ );
266
+ } finally {
267
+ await client.close().catch(() => {});
268
+ rmSync(projectRoot, { recursive: true, force: true });
269
+ }
270
+ });
271
+
111
272
  test("usesWorkflowMcpTransport matches local externalCli providers", () => {
112
273
  assert.equal(usesWorkflowMcpTransport("externalCli", "local://claude-code"), true);
113
274
  assert.equal(usesWorkflowMcpTransport("externalCli", "https://api.example.com"), false);
@@ -131,7 +292,7 @@ test("transport compatibility passes when required tools fit current MCP surface
131
292
  assert.equal(error, null);
132
293
  });
133
294
 
134
- test("transport compatibility fails cleanly when MCP server is unavailable", () => {
295
+ test("transport compatibility discovers the bundled MCP server without env overrides", () => {
135
296
  const error = getWorkflowTransportSupportError(
136
297
  "claude-code",
137
298
  ["gsd_task_complete"],
@@ -145,7 +306,7 @@ test("transport compatibility fails cleanly when MCP server is unavailable", ()
145
306
  },
146
307
  );
147
308
 
148
- assert.match(error ?? "", /workflow MCP server is not configured or discoverable/);
309
+ assert.equal(error, null);
149
310
  });
150
311
 
151
312
  test("transport compatibility now allows auto execute-task over workflow MCP surface", () => {
@@ -1,6 +1,6 @@
1
1
  import { execSync } from "node:child_process";
2
2
  import { existsSync } from "node:fs";
3
- import { resolve } from "node:path";
3
+ import { dirname, resolve } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
 
6
6
  export interface WorkflowMcpLaunchConfig {
@@ -67,8 +67,32 @@ function lookupCommand(command: string, platform: NodeJS.Platform = process.plat
67
67
  }
68
68
  }
69
69
 
70
+ function findWorkflowCliFromAncestorPath(startPath: string): string | null {
71
+ let current = resolve(startPath);
72
+
73
+ while (true) {
74
+ const candidate = resolve(current, "packages", "mcp-server", "dist", "cli.js");
75
+ if (existsSync(candidate)) return candidate;
76
+
77
+ const parent = dirname(current);
78
+ if (parent === current) break;
79
+ current = parent;
80
+ }
81
+
82
+ return null;
83
+ }
84
+
70
85
  function getBundledWorkflowMcpCliPath(env: NodeJS.ProcessEnv): string | null {
71
- if (!env.GSD_BIN_PATH?.trim() && !env.GSD_CLI_PATH?.trim()) return null;
86
+ const envAnchors = [
87
+ env.GSD_BIN_PATH?.trim(),
88
+ env.GSD_CLI_PATH?.trim(),
89
+ env.GSD_WORKFLOW_PATH?.trim(),
90
+ ].filter((value): value is string => typeof value === "string" && value.length > 0);
91
+
92
+ for (const anchor of envAnchors) {
93
+ const candidate = findWorkflowCliFromAncestorPath(anchor);
94
+ if (candidate) return candidate;
95
+ }
72
96
 
73
97
  const candidates = [
74
98
  resolve(fileURLToPath(new URL("../../../../packages/mcp-server/dist/cli.js", import.meta.url))),
@@ -82,6 +106,52 @@ function getBundledWorkflowMcpCliPath(env: NodeJS.ProcessEnv): string | null {
82
106
  return null;
83
107
  }
84
108
 
109
+ function getBundledWorkflowExecutorModulePath(): string | null {
110
+ const candidates = [
111
+ resolve(fileURLToPath(new URL("../../../../dist/resources/extensions/gsd/tools/workflow-tool-executors.js", import.meta.url))),
112
+ resolve(fileURLToPath(new URL("./tools/workflow-tool-executors.js", import.meta.url))),
113
+ resolve(fileURLToPath(new URL("./tools/workflow-tool-executors.ts", import.meta.url))),
114
+ ];
115
+
116
+ for (const candidate of candidates) {
117
+ if (existsSync(candidate)) return candidate;
118
+ }
119
+
120
+ return null;
121
+ }
122
+
123
+ function getBundledWorkflowWriteGateModulePath(): string | null {
124
+ const candidates = [
125
+ resolve(fileURLToPath(new URL("../../../../dist/resources/extensions/gsd/bootstrap/write-gate.js", import.meta.url))),
126
+ resolve(fileURLToPath(new URL("./bootstrap/write-gate.js", import.meta.url))),
127
+ resolve(fileURLToPath(new URL("./bootstrap/write-gate.ts", import.meta.url))),
128
+ ];
129
+
130
+ for (const candidate of candidates) {
131
+ if (existsSync(candidate)) return candidate;
132
+ }
133
+
134
+ return null;
135
+ }
136
+
137
+ function buildWorkflowLaunchEnv(
138
+ projectRoot: string,
139
+ gsdCliPath: string | undefined,
140
+ explicitEnv?: Record<string, string>,
141
+ ): Record<string, string> {
142
+ const executorModulePath = getBundledWorkflowExecutorModulePath();
143
+ const writeGateModulePath = getBundledWorkflowWriteGateModulePath();
144
+
145
+ return {
146
+ ...(explicitEnv ?? {}),
147
+ ...(gsdCliPath ? { GSD_CLI_PATH: gsdCliPath } : {}),
148
+ ...(executorModulePath ? { GSD_WORKFLOW_EXECUTORS_MODULE: executorModulePath } : {}),
149
+ ...(writeGateModulePath ? { GSD_WORKFLOW_WRITE_GATE_MODULE: writeGateModulePath } : {}),
150
+ GSD_PERSIST_WRITE_GATE_STATE: "1",
151
+ GSD_WORKFLOW_PROJECT_ROOT: projectRoot,
152
+ };
153
+ }
154
+
85
155
  export function detectWorkflowMcpLaunchConfig(
86
156
  projectRoot = process.cwd(),
87
157
  env: NodeJS.ProcessEnv = process.env,
@@ -101,12 +171,7 @@ export function detectWorkflowMcpLaunchConfig(
101
171
  const resolvedWorkflowProjectRoot = resolve(workflowProjectRoot);
102
172
 
103
173
  if (explicitCommand) {
104
- const launchEnv = {
105
- ...(explicitEnv ?? {}),
106
- ...(gsdCliPath ? { GSD_CLI_PATH: gsdCliPath } : {}),
107
- GSD_PERSIST_WRITE_GATE_STATE: "1",
108
- GSD_WORKFLOW_PROJECT_ROOT: resolve(workflowProjectRoot),
109
- };
174
+ const launchEnv = buildWorkflowLaunchEnv(resolve(workflowProjectRoot), gsdCliPath, explicitEnv);
110
175
  return {
111
176
  name,
112
177
  command: explicitCommand,
@@ -123,11 +188,7 @@ export function detectWorkflowMcpLaunchConfig(
123
188
  command: process.execPath,
124
189
  args: [distCli],
125
190
  cwd: resolvedWorkflowProjectRoot,
126
- env: {
127
- ...(gsdCliPath ? { GSD_CLI_PATH: gsdCliPath } : {}),
128
- GSD_PERSIST_WRITE_GATE_STATE: "1",
129
- GSD_WORKFLOW_PROJECT_ROOT: resolvedWorkflowProjectRoot,
130
- },
191
+ env: buildWorkflowLaunchEnv(resolvedWorkflowProjectRoot, gsdCliPath),
131
192
  };
132
193
  }
133
194
 
@@ -138,11 +199,7 @@ export function detectWorkflowMcpLaunchConfig(
138
199
  command: process.execPath,
139
200
  args: [bundledCli],
140
201
  cwd: resolvedWorkflowProjectRoot,
141
- env: {
142
- ...(gsdCliPath ? { GSD_CLI_PATH: gsdCliPath } : {}),
143
- GSD_PERSIST_WRITE_GATE_STATE: "1",
144
- GSD_WORKFLOW_PROJECT_ROOT: resolvedWorkflowProjectRoot,
145
- },
202
+ env: buildWorkflowLaunchEnv(resolvedWorkflowProjectRoot, gsdCliPath),
146
203
  };
147
204
  }
148
205
 
@@ -151,11 +208,7 @@ export function detectWorkflowMcpLaunchConfig(
151
208
  return {
152
209
  name,
153
210
  command: binPath,
154
- env: {
155
- ...(gsdCliPath ? { GSD_CLI_PATH: gsdCliPath } : {}),
156
- GSD_PERSIST_WRITE_GATE_STATE: "1",
157
- GSD_WORKFLOW_PROJECT_ROOT: resolvedWorkflowProjectRoot,
158
- },
211
+ env: buildWorkflowLaunchEnv(resolvedWorkflowProjectRoot, gsdCliPath),
159
212
  };
160
213
  }
161
214