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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. package/README.md +41 -31
  2. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +121 -8
  3. package/dist/resources/extensions/gsd/auto/phases.js +17 -0
  4. package/dist/resources/extensions/gsd/auto/session.js +6 -0
  5. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +12 -0
  6. package/dist/resources/extensions/gsd/auto-start.js +12 -0
  7. package/dist/resources/extensions/gsd/auto.js +27 -0
  8. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +11 -435
  9. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +1 -4
  10. package/dist/resources/extensions/gsd/bootstrap/query-tools.js +7 -64
  11. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +88 -8
  12. package/dist/resources/extensions/gsd/commands/catalog.js +2 -1
  13. package/dist/resources/extensions/gsd/commands/handlers/core.js +39 -25
  14. package/dist/resources/extensions/gsd/commands/index.js +8 -1
  15. package/dist/resources/extensions/gsd/commands-mcp-status.js +43 -7
  16. package/dist/resources/extensions/gsd/guided-flow.js +16 -0
  17. package/dist/resources/extensions/gsd/init-wizard.js +37 -0
  18. package/dist/resources/extensions/gsd/mcp-project-config.js +83 -0
  19. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +508 -0
  20. package/dist/resources/extensions/gsd/workflow-logger.js +18 -3
  21. package/dist/resources/extensions/gsd/workflow-mcp.js +261 -0
  22. package/dist/web/standalone/.next/BUILD_ID +1 -1
  23. package/dist/web/standalone/.next/app-path-routes-manifest.json +15 -15
  24. package/dist/web/standalone/.next/build-manifest.json +3 -3
  25. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  26. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  27. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  28. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  29. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  30. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  31. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  32. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  33. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  34. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  35. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  36. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  37. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  38. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  39. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  40. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  41. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  42. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  43. package/dist/web/standalone/.next/server/app/index.html +1 -1
  44. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  45. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  46. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  47. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  48. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  49. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  50. package/dist/web/standalone/.next/server/app-paths-manifest.json +15 -15
  51. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  52. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  53. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  54. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  55. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  56. package/dist/web/standalone/.next/static/chunks/6502.5dcdcf1e1432e20d.js +9 -0
  57. package/dist/web/standalone/.next/static/chunks/{webpack-b49b09f97429b5d0.js → webpack-42a66876b763aa26.js} +1 -1
  58. package/package.json +4 -2
  59. package/packages/mcp-server/README.md +38 -0
  60. package/packages/mcp-server/dist/cli.d.ts +9 -0
  61. package/packages/mcp-server/dist/cli.d.ts.map +1 -0
  62. package/packages/mcp-server/dist/cli.js +58 -0
  63. package/packages/mcp-server/dist/cli.js.map +1 -0
  64. package/packages/mcp-server/dist/index.d.ts +20 -0
  65. package/packages/mcp-server/dist/index.d.ts.map +1 -0
  66. package/packages/mcp-server/dist/index.js +14 -0
  67. package/packages/mcp-server/dist/index.js.map +1 -0
  68. package/packages/mcp-server/dist/readers/captures.d.ts +25 -0
  69. package/packages/mcp-server/dist/readers/captures.d.ts.map +1 -0
  70. package/packages/mcp-server/dist/readers/captures.js +67 -0
  71. package/packages/mcp-server/dist/readers/captures.js.map +1 -0
  72. package/packages/mcp-server/dist/readers/doctor-lite.d.ts +20 -0
  73. package/packages/mcp-server/dist/readers/doctor-lite.d.ts.map +1 -0
  74. package/packages/mcp-server/dist/readers/doctor-lite.js +173 -0
  75. package/packages/mcp-server/dist/readers/doctor-lite.js.map +1 -0
  76. package/packages/mcp-server/dist/readers/index.d.ts +14 -0
  77. package/packages/mcp-server/dist/readers/index.d.ts.map +1 -0
  78. package/packages/mcp-server/dist/readers/index.js +10 -0
  79. package/packages/mcp-server/dist/readers/index.js.map +1 -0
  80. package/packages/mcp-server/dist/readers/knowledge.d.ts +18 -0
  81. package/packages/mcp-server/dist/readers/knowledge.d.ts.map +1 -0
  82. package/packages/mcp-server/dist/readers/knowledge.js +82 -0
  83. package/packages/mcp-server/dist/readers/knowledge.js.map +1 -0
  84. package/packages/mcp-server/dist/readers/metrics.d.ts +32 -0
  85. package/packages/mcp-server/dist/readers/metrics.d.ts.map +1 -0
  86. package/packages/mcp-server/dist/readers/metrics.js +74 -0
  87. package/packages/mcp-server/dist/readers/metrics.js.map +1 -0
  88. package/packages/mcp-server/dist/readers/paths.d.ts +42 -0
  89. package/packages/mcp-server/dist/readers/paths.d.ts.map +1 -0
  90. package/packages/mcp-server/dist/readers/paths.js +199 -0
  91. package/packages/mcp-server/dist/readers/paths.js.map +1 -0
  92. package/packages/mcp-server/dist/readers/roadmap.d.ts +26 -0
  93. package/packages/mcp-server/dist/readers/roadmap.d.ts.map +1 -0
  94. package/packages/mcp-server/dist/readers/roadmap.js +194 -0
  95. package/packages/mcp-server/dist/readers/roadmap.js.map +1 -0
  96. package/packages/mcp-server/dist/readers/state.d.ts +43 -0
  97. package/packages/mcp-server/dist/readers/state.d.ts.map +1 -0
  98. package/packages/mcp-server/dist/readers/state.js +184 -0
  99. package/packages/mcp-server/dist/readers/state.js.map +1 -0
  100. package/packages/mcp-server/dist/server.d.ts +28 -0
  101. package/packages/mcp-server/dist/server.d.ts.map +1 -0
  102. package/packages/mcp-server/dist/server.js +319 -0
  103. package/packages/mcp-server/dist/server.js.map +1 -0
  104. package/packages/mcp-server/dist/session-manager.d.ts +54 -0
  105. package/packages/mcp-server/dist/session-manager.d.ts.map +1 -0
  106. package/packages/mcp-server/dist/session-manager.js +284 -0
  107. package/packages/mcp-server/dist/session-manager.js.map +1 -0
  108. package/packages/mcp-server/dist/types.d.ts +61 -0
  109. package/packages/mcp-server/dist/types.d.ts.map +1 -0
  110. package/packages/mcp-server/dist/types.js +11 -0
  111. package/packages/mcp-server/dist/types.js.map +1 -0
  112. package/packages/mcp-server/dist/workflow-tools.d.ts +9 -0
  113. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -0
  114. package/packages/mcp-server/dist/workflow-tools.js +532 -0
  115. package/packages/mcp-server/dist/workflow-tools.js.map +1 -0
  116. package/packages/mcp-server/src/server.ts +6 -2
  117. package/packages/mcp-server/src/workflow-tools.test.ts +976 -0
  118. package/packages/mcp-server/src/workflow-tools.ts +997 -0
  119. package/packages/mcp-server/tsconfig.json +1 -1
  120. package/packages/pi-agent-core/dist/agent-loop.js +14 -6
  121. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  122. package/packages/pi-agent-core/src/agent-loop.test.ts +53 -0
  123. package/packages/pi-agent-core/src/agent-loop.ts +20 -6
  124. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.d.ts +2 -0
  125. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.d.ts.map +1 -0
  126. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +28 -0
  127. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -0
  128. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +1 -0
  129. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  130. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +17 -12
  131. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  132. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  133. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +19 -0
  134. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  135. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +54 -0
  136. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +18 -12
  137. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +21 -0
  138. package/packages/rpc-client/dist/index.d.ts +10 -0
  139. package/packages/rpc-client/dist/index.d.ts.map +1 -0
  140. package/packages/rpc-client/dist/index.js +9 -0
  141. package/packages/rpc-client/dist/index.js.map +1 -0
  142. package/packages/rpc-client/dist/jsonl.d.ts +17 -0
  143. package/packages/rpc-client/dist/jsonl.d.ts.map +1 -0
  144. package/packages/rpc-client/dist/jsonl.js +54 -0
  145. package/packages/rpc-client/dist/jsonl.js.map +1 -0
  146. package/packages/rpc-client/dist/rpc-client.d.ts +259 -0
  147. package/packages/rpc-client/dist/rpc-client.d.ts.map +1 -0
  148. package/packages/rpc-client/dist/rpc-client.js +541 -0
  149. package/packages/rpc-client/dist/rpc-client.js.map +1 -0
  150. package/packages/rpc-client/dist/rpc-client.test.d.ts +2 -0
  151. package/packages/rpc-client/dist/rpc-client.test.d.ts.map +1 -0
  152. package/packages/rpc-client/dist/rpc-client.test.js +477 -0
  153. package/packages/rpc-client/dist/rpc-client.test.js.map +1 -0
  154. package/packages/rpc-client/dist/rpc-types.d.ts +566 -0
  155. package/packages/rpc-client/dist/rpc-types.d.ts.map +1 -0
  156. package/packages/rpc-client/dist/rpc-types.js +12 -0
  157. package/packages/rpc-client/dist/rpc-types.js.map +1 -0
  158. package/scripts/ensure-workspace-builds.cjs +2 -0
  159. package/scripts/link-workspace-packages.cjs +21 -14
  160. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +157 -8
  161. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +182 -0
  162. package/src/resources/extensions/gsd/auto/phases.ts +25 -0
  163. package/src/resources/extensions/gsd/auto/session.ts +6 -0
  164. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +20 -0
  165. package/src/resources/extensions/gsd/auto-start.ts +15 -1
  166. package/src/resources/extensions/gsd/auto.ts +29 -1
  167. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +22 -435
  168. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +1 -5
  169. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +7 -72
  170. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +122 -6
  171. package/src/resources/extensions/gsd/commands/catalog.ts +2 -1
  172. package/src/resources/extensions/gsd/commands/handlers/core.ts +53 -26
  173. package/src/resources/extensions/gsd/commands/index.ts +7 -1
  174. package/src/resources/extensions/gsd/commands-mcp-status.ts +53 -7
  175. package/src/resources/extensions/gsd/guided-flow.ts +24 -0
  176. package/src/resources/extensions/gsd/init-wizard.ts +40 -0
  177. package/src/resources/extensions/gsd/mcp-project-config.ts +128 -0
  178. package/src/resources/extensions/gsd/tests/auto-project-root-env.test.ts +29 -0
  179. package/src/resources/extensions/gsd/tests/core-overlay-fallback.test.ts +101 -0
  180. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +66 -0
  181. package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +85 -0
  182. package/src/resources/extensions/gsd/tests/mcp-status.test.ts +15 -0
  183. package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +16 -0
  184. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +500 -0
  185. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +625 -0
  186. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +629 -0
  187. package/src/resources/extensions/gsd/workflow-logger.ts +19 -3
  188. package/src/resources/extensions/gsd/workflow-mcp.ts +320 -0
  189. package/dist/web/standalone/.next/static/chunks/6502.b804e48b7919f55e.js +0 -9
  190. /package/dist/web/standalone/.next/static/{NllX5BEOLdTXS9ypf1i3i → gbSATDX4Jt2ufxzUr5nYm}/_buildManifest.js +0 -0
  191. /package/dist/web/standalone/.next/static/{NllX5BEOLdTXS9ypf1i3i → gbSATDX4Jt2ufxzUr5nYm}/_ssgManifest.js +0 -0
@@ -5,11 +5,7 @@ import { loadEffectiveGSDPreferences } from "../preferences.js";
5
5
  import { ensureDbOpen } from "./dynamic-tools.js";
6
6
  import { StringEnum } from "@gsd/pi-ai";
7
7
  import { logError } from "../workflow-logger.js";
8
- import { shouldBlockContextArtifactSave } from "./write-gate.js";
9
- const SUPPORTED_SUMMARY_ARTIFACT_TYPES = ["SUMMARY", "RESEARCH", "CONTEXT", "ASSESSMENT", "CONTEXT-DRAFT"];
10
- export function isSupportedSummaryArtifactType(artifactType) {
11
- return SUPPORTED_SUMMARY_ARTIFACT_TYPES.includes(artifactType);
12
- }
8
+ import { executeCompleteMilestone, executePlanMilestone, executePlanSlice, executeReplanSlice, executeReassessRoadmap, executeSaveGateResult, executeSliceComplete, executeSummarySave, executeTaskComplete, executeValidateMilestone, } from "../tools/workflow-tool-executors.js";
13
9
  /**
14
10
  * Register an alias tool that shares the same execute function as its canonical counterpart.
15
11
  * The alias description and promptGuidelines direct the LLM to prefer the canonical name.
@@ -272,59 +268,7 @@ export function registerDbTools(pi) {
272
268
  registerAlias(pi, requirementSaveTool, "gsd_save_requirement", "gsd_requirement_save");
273
269
  // ─── gsd_summary_save (formerly gsd_save_summary) ──────────────────────
274
270
  const summarySaveExecute = async (_toolCallId, params, _signal, _onUpdate, _ctx) => {
275
- const dbAvailable = await ensureDbOpen();
276
- if (!dbAvailable) {
277
- return {
278
- content: [{ type: "text", text: "Error: GSD database is not available. Cannot save artifact." }],
279
- details: { operation: "save_summary", error: "db_unavailable" },
280
- };
281
- }
282
- if (!isSupportedSummaryArtifactType(params.artifact_type)) {
283
- return {
284
- content: [{ type: "text", text: `Error: Invalid artifact_type "${params.artifact_type}". Must be one of: ${SUPPORTED_SUMMARY_ARTIFACT_TYPES.join(", ")}` }],
285
- details: { operation: "save_summary", error: "invalid_artifact_type" },
286
- };
287
- }
288
- const contextGuard = shouldBlockContextArtifactSave(params.artifact_type, params.milestone_id ?? null, params.slice_id ?? null);
289
- if (contextGuard.block) {
290
- return {
291
- content: [{ type: "text", text: `Error saving artifact: ${contextGuard.reason ?? "context write blocked"}` }],
292
- details: { operation: "save_summary", error: "context_write_blocked" },
293
- };
294
- }
295
- try {
296
- let relativePath;
297
- if (params.task_id && params.slice_id) {
298
- relativePath = `milestones/${params.milestone_id}/slices/${params.slice_id}/tasks/${params.task_id}-${params.artifact_type}.md`;
299
- }
300
- else if (params.slice_id) {
301
- relativePath = `milestones/${params.milestone_id}/slices/${params.slice_id}/${params.slice_id}-${params.artifact_type}.md`;
302
- }
303
- else {
304
- relativePath = `milestones/${params.milestone_id}/${params.milestone_id}-${params.artifact_type}.md`;
305
- }
306
- const { saveArtifactToDb } = await import("../db-writer.js");
307
- await saveArtifactToDb({
308
- path: relativePath,
309
- artifact_type: params.artifact_type,
310
- content: params.content,
311
- milestone_id: params.milestone_id,
312
- slice_id: params.slice_id,
313
- task_id: params.task_id,
314
- }, process.cwd());
315
- return {
316
- content: [{ type: "text", text: `Saved ${params.artifact_type} artifact to ${relativePath}` }],
317
- details: { operation: "save_summary", path: relativePath, artifact_type: params.artifact_type },
318
- };
319
- }
320
- catch (err) {
321
- const msg = err instanceof Error ? err.message : String(err);
322
- logError("tool", `gsd_summary_save tool failed: ${msg}`, { tool: "gsd_summary_save", error: String(err) });
323
- return {
324
- content: [{ type: "text", text: `Error saving artifact: ${msg}` }],
325
- details: { operation: "save_summary", error: msg },
326
- };
327
- }
271
+ return executeSummarySave(params, process.cwd());
328
272
  };
329
273
  const summarySaveTool = {
330
274
  name: "gsd_summary_save",
@@ -452,39 +396,7 @@ export function registerDbTools(pi) {
452
396
  registerAlias(pi, milestoneGenerateIdTool, "gsd_generate_milestone_id", "gsd_milestone_generate_id");
453
397
  // ─── gsd_plan_milestone (gsd_milestone_plan alias) ─────────────────────
454
398
  const planMilestoneExecute = async (_toolCallId, params, _signal, _onUpdate, _ctx) => {
455
- const dbAvailable = await ensureDbOpen();
456
- if (!dbAvailable) {
457
- return {
458
- content: [{ type: "text", text: "Error: GSD database is not available. Cannot plan milestone." }],
459
- details: { operation: "plan_milestone", error: "db_unavailable" },
460
- };
461
- }
462
- try {
463
- const { handlePlanMilestone } = await import("../tools/plan-milestone.js");
464
- const result = await handlePlanMilestone(params, process.cwd());
465
- if ("error" in result) {
466
- return {
467
- content: [{ type: "text", text: `Error planning milestone: ${result.error}` }],
468
- details: { operation: "plan_milestone", error: result.error },
469
- };
470
- }
471
- return {
472
- content: [{ type: "text", text: `Planned milestone ${result.milestoneId}` }],
473
- details: {
474
- operation: "plan_milestone",
475
- milestoneId: result.milestoneId,
476
- roadmapPath: result.roadmapPath,
477
- },
478
- };
479
- }
480
- catch (err) {
481
- const msg = err instanceof Error ? err.message : String(err);
482
- logError("tool", `plan_milestone tool failed: ${msg}`, { tool: "gsd_plan_milestone", error: String(err) });
483
- return {
484
- content: [{ type: "text", text: `Error planning milestone: ${msg}` }],
485
- details: { operation: "plan_milestone", error: msg },
486
- };
487
- }
399
+ return executePlanMilestone(params, process.cwd());
488
400
  };
489
401
  const planMilestoneTool = {
490
402
  name: "gsd_plan_milestone",
@@ -541,41 +453,7 @@ export function registerDbTools(pi) {
541
453
  registerAlias(pi, planMilestoneTool, "gsd_milestone_plan", "gsd_plan_milestone");
542
454
  // ─── gsd_plan_slice (gsd_slice_plan alias) ─────────────────────────────
543
455
  const planSliceExecute = async (_toolCallId, params, _signal, _onUpdate, _ctx) => {
544
- const dbAvailable = await ensureDbOpen();
545
- if (!dbAvailable) {
546
- return {
547
- content: [{ type: "text", text: "Error: GSD database is not available. Cannot plan slice." }],
548
- details: { operation: "plan_slice", error: "db_unavailable" },
549
- };
550
- }
551
- try {
552
- const { handlePlanSlice } = await import("../tools/plan-slice.js");
553
- const result = await handlePlanSlice(params, process.cwd());
554
- if ("error" in result) {
555
- return {
556
- content: [{ type: "text", text: `Error planning slice: ${result.error}` }],
557
- details: { operation: "plan_slice", error: result.error },
558
- };
559
- }
560
- return {
561
- content: [{ type: "text", text: `Planned slice ${result.sliceId} (${result.milestoneId})` }],
562
- details: {
563
- operation: "plan_slice",
564
- milestoneId: result.milestoneId,
565
- sliceId: result.sliceId,
566
- planPath: result.planPath,
567
- taskPlanPaths: result.taskPlanPaths,
568
- },
569
- };
570
- }
571
- catch (err) {
572
- const msg = err instanceof Error ? err.message : String(err);
573
- logError("tool", `plan_slice tool failed: ${msg}`, { tool: "gsd_plan_slice", error: String(err) });
574
- return {
575
- content: [{ type: "text", text: `Error planning slice: ${msg}` }],
576
- details: { operation: "plan_slice", error: msg },
577
- };
578
- }
456
+ return executePlanSlice(params, process.cwd());
579
457
  };
580
458
  const planSliceTool = {
581
459
  name: "gsd_plan_slice",
@@ -682,44 +560,7 @@ export function registerDbTools(pi) {
682
560
  registerAlias(pi, planTaskTool, "gsd_task_plan", "gsd_plan_task");
683
561
  // ─── gsd_task_complete (gsd_complete_task alias) ────────────────────────
684
562
  const taskCompleteExecute = async (_toolCallId, params, _signal, _onUpdate, _ctx) => {
685
- const dbAvailable = await ensureDbOpen();
686
- if (!dbAvailable) {
687
- return {
688
- content: [{ type: "text", text: "Error: GSD database is not available. Cannot complete task." }],
689
- details: { operation: "complete_task", error: "db_unavailable" },
690
- };
691
- }
692
- try {
693
- // Coerce string items to objects for verificationEvidence (#3541).
694
- const coerced = { ...params };
695
- coerced.verificationEvidence = (params.verificationEvidence ?? []).map((v) => typeof v === "string" ? { command: v, exitCode: -1, verdict: "unknown (coerced from string)", durationMs: 0 } : v);
696
- const { handleCompleteTask } = await import("../tools/complete-task.js");
697
- const result = await handleCompleteTask(coerced, process.cwd());
698
- if ("error" in result) {
699
- return {
700
- content: [{ type: "text", text: `Error completing task: ${result.error}` }],
701
- details: { operation: "complete_task", error: result.error },
702
- };
703
- }
704
- return {
705
- content: [{ type: "text", text: `Completed task ${result.taskId} (${result.sliceId}/${result.milestoneId})` }],
706
- details: {
707
- operation: "complete_task",
708
- taskId: result.taskId,
709
- sliceId: result.sliceId,
710
- milestoneId: result.milestoneId,
711
- summaryPath: result.summaryPath,
712
- },
713
- };
714
- }
715
- catch (err) {
716
- const msg = err instanceof Error ? err.message : String(err);
717
- logError("tool", `complete_task tool failed: ${msg}`, { tool: "gsd_task_complete", error: String(err) });
718
- return {
719
- content: [{ type: "text", text: `Error completing task: ${msg}` }],
720
- details: { operation: "complete_task", error: msg },
721
- };
722
- }
563
+ return executeTaskComplete(params, process.cwd());
723
564
  };
724
565
  const taskCompleteTool = {
725
566
  name: "gsd_task_complete",
@@ -764,90 +605,7 @@ export function registerDbTools(pi) {
764
605
  registerAlias(pi, taskCompleteTool, "gsd_complete_task", "gsd_task_complete");
765
606
  // ─── gsd_slice_complete (gsd_complete_slice alias) ─────────────────────
766
607
  const sliceCompleteExecute = async (_toolCallId, params, _signal, _onUpdate, _ctx) => {
767
- const dbAvailable = await ensureDbOpen();
768
- if (!dbAvailable) {
769
- return {
770
- content: [{ type: "text", text: "Error: GSD database is not available. Cannot complete slice." }],
771
- details: { operation: "complete_slice", error: "db_unavailable" },
772
- };
773
- }
774
- try {
775
- // Coerce string items to objects for fields where LLMs sometimes pass
776
- // plain strings instead of the expected { key, value } shape (#3541).
777
- // Parses "key — value" or "key - value" format when possible.
778
- const splitPair = (s) => {
779
- const m = s.match(/^(.+?)\s*(?:—|-)\s+(.+)$/);
780
- return m ? [m[1].trim(), m[2].trim()] : [s.trim(), ""];
781
- };
782
- const coerced = { ...params };
783
- // Coerce simple string-array fields: LLMs sometimes pass a plain string
784
- // instead of a single-element array (#3585).
785
- const wrapArray = (v) => v == null ? [] : Array.isArray(v) ? v : [v];
786
- coerced.provides = wrapArray(params.provides);
787
- coerced.keyFiles = wrapArray(params.keyFiles);
788
- coerced.keyDecisions = wrapArray(params.keyDecisions);
789
- coerced.patternsEstablished = wrapArray(params.patternsEstablished);
790
- coerced.observabilitySurfaces = wrapArray(params.observabilitySurfaces);
791
- coerced.requirementsSurfaced = wrapArray(params.requirementsSurfaced);
792
- coerced.drillDownPaths = wrapArray(params.drillDownPaths);
793
- coerced.affects = wrapArray(params.affects);
794
- coerced.filesModified = wrapArray(params.filesModified).map((f) => {
795
- if (typeof f !== "string")
796
- return f;
797
- const [path, description] = splitPair(f);
798
- return { path, description };
799
- });
800
- coerced.requires = wrapArray(params.requires).map((r) => {
801
- if (typeof r !== "string")
802
- return r;
803
- const [slice, provides] = splitPair(r);
804
- return { slice, provides };
805
- });
806
- coerced.requirementsAdvanced = wrapArray(params.requirementsAdvanced).map((r) => {
807
- if (typeof r !== "string")
808
- return r;
809
- const [id, how] = splitPair(r);
810
- return { id, how };
811
- });
812
- coerced.requirementsValidated = wrapArray(params.requirementsValidated).map((r) => {
813
- if (typeof r !== "string")
814
- return r;
815
- const [id, proof] = splitPair(r);
816
- return { id, proof };
817
- });
818
- coerced.requirementsInvalidated = wrapArray(params.requirementsInvalidated).map((r) => {
819
- if (typeof r !== "string")
820
- return r;
821
- const [id, what] = splitPair(r);
822
- return { id, what };
823
- });
824
- const { handleCompleteSlice } = await import("../tools/complete-slice.js");
825
- const result = await handleCompleteSlice(coerced, process.cwd());
826
- if ("error" in result) {
827
- return {
828
- content: [{ type: "text", text: `Error completing slice: ${result.error}` }],
829
- details: { operation: "complete_slice", error: result.error },
830
- };
831
- }
832
- return {
833
- content: [{ type: "text", text: `Completed slice ${result.sliceId} (${result.milestoneId})` }],
834
- details: {
835
- operation: "complete_slice",
836
- sliceId: result.sliceId,
837
- milestoneId: result.milestoneId,
838
- summaryPath: result.summaryPath,
839
- uatPath: result.uatPath,
840
- },
841
- };
842
- }
843
- catch (err) {
844
- const msg = err instanceof Error ? err.message : String(err);
845
- logError("tool", `complete_slice tool failed: ${msg}`, { tool: "gsd_slice_complete", error: String(err) });
846
- return {
847
- content: [{ type: "text", text: `Error completing slice: ${msg}` }],
848
- details: { operation: "complete_slice", error: msg },
849
- };
850
- }
608
+ return executeSliceComplete(params, process.cwd());
851
609
  };
852
610
  const sliceCompleteTool = {
853
611
  name: "gsd_slice_complete",
@@ -1004,42 +762,7 @@ export function registerDbTools(pi) {
1004
762
  });
1005
763
  // ─── gsd_complete_milestone ────────────────────────────────────────────
1006
764
  const milestoneCompleteExecute = async (_toolCallId, params, _signal, _onUpdate, _ctx) => {
1007
- const dbAvailable = await ensureDbOpen();
1008
- if (!dbAvailable) {
1009
- return {
1010
- content: [{ type: "text", text: "Error: GSD database is not available. Cannot complete milestone." }],
1011
- details: { operation: "complete_milestone", error: "db_unavailable" },
1012
- };
1013
- }
1014
- try {
1015
- // ── Input sanitization: normalize markdown parameters (#3013) ──────
1016
- const { sanitizeCompleteMilestoneParams } = await import("./sanitize-complete-milestone.js");
1017
- const sanitized = sanitizeCompleteMilestoneParams(params);
1018
- const { handleCompleteMilestone } = await import("../tools/complete-milestone.js");
1019
- const result = await handleCompleteMilestone(sanitized, process.cwd());
1020
- if ("error" in result) {
1021
- return {
1022
- content: [{ type: "text", text: `Error completing milestone: ${result.error}` }],
1023
- details: { operation: "complete_milestone", error: result.error },
1024
- };
1025
- }
1026
- return {
1027
- content: [{ type: "text", text: `Completed milestone ${result.milestoneId}. Summary written to ${result.summaryPath}` }],
1028
- details: {
1029
- operation: "complete_milestone",
1030
- milestoneId: result.milestoneId,
1031
- summaryPath: result.summaryPath,
1032
- },
1033
- };
1034
- }
1035
- catch (err) {
1036
- const msg = err instanceof Error ? err.message : String(err);
1037
- logError("tool", `complete_milestone tool failed: ${msg}`, { tool: "gsd_complete_milestone", error: String(err) });
1038
- return {
1039
- content: [{ type: "text", text: `Error completing milestone: ${msg}` }],
1040
- details: { operation: "complete_milestone", error: msg },
1041
- };
1042
- }
765
+ return executeCompleteMilestone(params, process.cwd());
1043
766
  };
1044
767
  const milestoneCompleteTool = {
1045
768
  name: "gsd_complete_milestone",
@@ -1076,40 +799,7 @@ export function registerDbTools(pi) {
1076
799
  registerAlias(pi, milestoneCompleteTool, "gsd_milestone_complete", "gsd_complete_milestone");
1077
800
  // ─── gsd_validate_milestone (gsd_milestone_validate alias) ─────────────
1078
801
  const milestoneValidateExecute = async (_toolCallId, params, _signal, _onUpdate, _ctx) => {
1079
- const dbAvailable = await ensureDbOpen();
1080
- if (!dbAvailable) {
1081
- return {
1082
- content: [{ type: "text", text: "Error: GSD database is not available. Cannot validate milestone." }],
1083
- details: { operation: "validate_milestone", error: "db_unavailable" },
1084
- };
1085
- }
1086
- try {
1087
- const { handleValidateMilestone } = await import("../tools/validate-milestone.js");
1088
- const result = await handleValidateMilestone(params, process.cwd());
1089
- if ("error" in result) {
1090
- return {
1091
- content: [{ type: "text", text: `Error validating milestone: ${result.error}` }],
1092
- details: { operation: "validate_milestone", error: result.error },
1093
- };
1094
- }
1095
- return {
1096
- content: [{ type: "text", text: `Validated milestone ${result.milestoneId} — verdict: ${result.verdict}. Written to ${result.validationPath}` }],
1097
- details: {
1098
- operation: "validate_milestone",
1099
- milestoneId: result.milestoneId,
1100
- verdict: result.verdict,
1101
- validationPath: result.validationPath,
1102
- },
1103
- };
1104
- }
1105
- catch (err) {
1106
- const msg = err instanceof Error ? err.message : String(err);
1107
- logError("tool", `validate_milestone tool failed: ${msg}`, { tool: "gsd_validate_milestone", error: String(err) });
1108
- return {
1109
- content: [{ type: "text", text: `Error validating milestone: ${msg}` }],
1110
- details: { operation: "validate_milestone", error: msg },
1111
- };
1112
- }
802
+ return executeValidateMilestone(params, process.cwd());
1113
803
  };
1114
804
  const milestoneValidateTool = {
1115
805
  name: "gsd_validate_milestone",
@@ -1141,41 +831,7 @@ export function registerDbTools(pi) {
1141
831
  registerAlias(pi, milestoneValidateTool, "gsd_milestone_validate", "gsd_validate_milestone");
1142
832
  // ─── gsd_replan_slice (gsd_slice_replan alias) ─────────────────────────
1143
833
  const replanSliceExecute = async (_toolCallId, params, _signal, _onUpdate, _ctx) => {
1144
- const dbAvailable = await ensureDbOpen();
1145
- if (!dbAvailable) {
1146
- return {
1147
- content: [{ type: "text", text: "Error: GSD database is not available. Cannot replan slice." }],
1148
- details: { operation: "replan_slice", error: "db_unavailable" },
1149
- };
1150
- }
1151
- try {
1152
- const { handleReplanSlice } = await import("../tools/replan-slice.js");
1153
- const result = await handleReplanSlice(params, process.cwd());
1154
- if ("error" in result) {
1155
- return {
1156
- content: [{ type: "text", text: `Error replanning slice: ${result.error}` }],
1157
- details: { operation: "replan_slice", error: result.error },
1158
- };
1159
- }
1160
- return {
1161
- content: [{ type: "text", text: `Replanned slice ${result.sliceId} (${result.milestoneId})` }],
1162
- details: {
1163
- operation: "replan_slice",
1164
- milestoneId: result.milestoneId,
1165
- sliceId: result.sliceId,
1166
- replanPath: result.replanPath,
1167
- planPath: result.planPath,
1168
- },
1169
- };
1170
- }
1171
- catch (err) {
1172
- const msg = err instanceof Error ? err.message : String(err);
1173
- logError("tool", `replan_slice tool failed: ${msg}`, { tool: "gsd_replan_slice", error: String(err) });
1174
- return {
1175
- content: [{ type: "text", text: `Error replanning slice: ${msg}` }],
1176
- details: { operation: "replan_slice", error: msg },
1177
- };
1178
- }
834
+ return executeReplanSlice(params, process.cwd());
1179
835
  };
1180
836
  const replanSliceTool = {
1181
837
  name: "gsd_replan_slice",
@@ -1214,41 +870,7 @@ export function registerDbTools(pi) {
1214
870
  registerAlias(pi, replanSliceTool, "gsd_slice_replan", "gsd_replan_slice");
1215
871
  // ─── gsd_reassess_roadmap (gsd_roadmap_reassess alias) ─────────────────
1216
872
  const reassessRoadmapExecute = async (_toolCallId, params, _signal, _onUpdate, _ctx) => {
1217
- const dbAvailable = await ensureDbOpen();
1218
- if (!dbAvailable) {
1219
- return {
1220
- content: [{ type: "text", text: "Error: GSD database is not available. Cannot reassess roadmap." }],
1221
- details: { operation: "reassess_roadmap", error: "db_unavailable" },
1222
- };
1223
- }
1224
- try {
1225
- const { handleReassessRoadmap } = await import("../tools/reassess-roadmap.js");
1226
- const result = await handleReassessRoadmap(params, process.cwd());
1227
- if ("error" in result) {
1228
- return {
1229
- content: [{ type: "text", text: `Error reassessing roadmap: ${result.error}` }],
1230
- details: { operation: "reassess_roadmap", error: result.error },
1231
- };
1232
- }
1233
- return {
1234
- content: [{ type: "text", text: `Reassessed roadmap for milestone ${result.milestoneId} after ${result.completedSliceId}` }],
1235
- details: {
1236
- operation: "reassess_roadmap",
1237
- milestoneId: result.milestoneId,
1238
- completedSliceId: result.completedSliceId,
1239
- assessmentPath: result.assessmentPath,
1240
- roadmapPath: result.roadmapPath,
1241
- },
1242
- };
1243
- }
1244
- catch (err) {
1245
- const msg = err instanceof Error ? err.message : String(err);
1246
- logError("tool", `reassess_roadmap tool failed: ${msg}`, { tool: "gsd_reassess_roadmap", error: String(err) });
1247
- return {
1248
- content: [{ type: "text", text: `Error reassessing roadmap: ${msg}` }],
1249
- details: { operation: "reassess_roadmap", error: msg },
1250
- };
1251
- }
873
+ return executeReassessRoadmap(params, process.cwd());
1252
874
  };
1253
875
  const reassessRoadmapTool = {
1254
876
  name: "gsd_reassess_roadmap",
@@ -1292,53 +914,7 @@ export function registerDbTools(pi) {
1292
914
  registerAlias(pi, reassessRoadmapTool, "gsd_roadmap_reassess", "gsd_reassess_roadmap");
1293
915
  // ─── gsd_save_gate_result ──────────────────────────────────────────────
1294
916
  const saveGateResultExecute = async (_toolCallId, params, _signal, _onUpdate, _ctx) => {
1295
- const dbAvailable = await ensureDbOpen();
1296
- if (!dbAvailable) {
1297
- return {
1298
- content: [{ type: "text", text: "Error: GSD database is not available." }],
1299
- details: { operation: "save_gate_result", error: "db_unavailable" },
1300
- };
1301
- }
1302
- const validGates = ["Q3", "Q4", "Q5", "Q6", "Q7", "Q8"];
1303
- if (!validGates.includes(params.gateId)) {
1304
- return {
1305
- content: [{ type: "text", text: `Error: Invalid gateId "${params.gateId}". Must be one of: ${validGates.join(", ")}` }],
1306
- details: { operation: "save_gate_result", error: "invalid_gate_id" },
1307
- };
1308
- }
1309
- const validVerdicts = ["pass", "flag", "omitted"];
1310
- if (!validVerdicts.includes(params.verdict)) {
1311
- return {
1312
- content: [{ type: "text", text: `Error: Invalid verdict "${params.verdict}". Must be one of: ${validVerdicts.join(", ")}` }],
1313
- details: { operation: "save_gate_result", error: "invalid_verdict" },
1314
- };
1315
- }
1316
- try {
1317
- const { saveGateResult } = await import("../gsd-db.js");
1318
- const { invalidateStateCache } = await import("../state.js");
1319
- saveGateResult({
1320
- milestoneId: params.milestoneId,
1321
- sliceId: params.sliceId,
1322
- gateId: params.gateId,
1323
- taskId: params.taskId ?? "",
1324
- verdict: params.verdict,
1325
- rationale: params.rationale,
1326
- findings: params.findings ?? "",
1327
- });
1328
- invalidateStateCache();
1329
- return {
1330
- content: [{ type: "text", text: `Gate ${params.gateId} result saved: verdict=${params.verdict}` }],
1331
- details: { operation: "save_gate_result", gateId: params.gateId, verdict: params.verdict },
1332
- };
1333
- }
1334
- catch (err) {
1335
- const msg = err instanceof Error ? err.message : String(err);
1336
- logError("tool", `gsd_save_gate_result failed: ${msg}`, { tool: "gsd_save_gate_result", error: String(err) });
1337
- return {
1338
- content: [{ type: "text", text: `Error saving gate result: ${msg}` }],
1339
- details: { operation: "save_gate_result", error: msg },
1340
- };
1341
- }
917
+ return executeSaveGateResult(params, process.cwd());
1342
918
  };
1343
919
  const saveGateResultTool = {
1344
920
  name: "gsd_save_gate_result",
@@ -64,12 +64,9 @@ export function resolveProjectRootDbPath(basePath) {
64
64
  }
65
65
  return join(basePath, ".gsd", "gsd.db");
66
66
  }
67
- export async function ensureDbOpen() {
67
+ export async function ensureDbOpen(basePath = process.cwd()) {
68
68
  try {
69
69
  const db = await import("../gsd-db.js");
70
- if (db.isDbAvailable())
71
- return true;
72
- const basePath = process.cwd();
73
70
  const dbPath = resolveProjectRootDbPath(basePath);
74
71
  const gsdDir = join(basePath, ".gsd");
75
72
  // Derive the project root from the DB path (strip .gsd/gsd.db)
@@ -1,6 +1,7 @@
1
1
  // GSD2 — Read-only query tools exposing DB state to the LLM via the WAL connection
2
2
  import { Type } from "@sinclair/typebox";
3
- import { logWarning } from "../workflow-logger.js";
3
+ import { ensureDbOpen } from "./dynamic-tools.js";
4
+ import { executeMilestoneStatus } from "../tools/workflow-tool-executors.js";
4
5
  export function registerQueryTools(pi) {
5
6
  pi.registerTool({
6
7
  name: "gsd_milestone_status",
@@ -16,72 +17,14 @@ export function registerQueryTools(pi) {
16
17
  milestoneId: Type.String({ description: "Milestone ID to query (e.g. M001)" }),
17
18
  }),
18
19
  async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
19
- try {
20
- // Open the DB if not already open — safe for read-only use since
21
- // ensureDbOpen() only creates/migrates when .gsd/ has content (#3644).
22
- const { ensureDbOpen } = await import("./dynamic-tools.js");
23
- const dbAvailable = await ensureDbOpen();
24
- const { getMilestone, getSliceStatusSummary, getSliceTaskCounts, _getAdapter, } = await import("../gsd-db.js");
25
- if (!dbAvailable) {
26
- return {
27
- content: [{ type: "text", text: "Error: GSD database is not available." }],
28
- details: { operation: "milestone_status", error: "db_unavailable" },
29
- };
30
- }
31
- // Wrap all reads in a single transaction for snapshot consistency.
32
- // SQLite WAL mode guarantees reads within a transaction see a single
33
- // consistent snapshot, preventing torn reads from concurrent writes.
34
- const adapter = _getAdapter();
35
- adapter.exec("BEGIN"); // eslint-disable-line -- SQLite exec, not child_process
36
- try {
37
- const milestone = getMilestone(params.milestoneId);
38
- if (!milestone) {
39
- adapter.exec("COMMIT"); // eslint-disable-line
40
- return {
41
- content: [{ type: "text", text: `Milestone ${params.milestoneId} not found in database.` }],
42
- details: { operation: "milestone_status", milestoneId: params.milestoneId, found: false },
43
- };
44
- }
45
- const sliceStatuses = getSliceStatusSummary(params.milestoneId);
46
- const slices = sliceStatuses.map((s) => {
47
- const counts = getSliceTaskCounts(params.milestoneId, s.id);
48
- return {
49
- id: s.id,
50
- status: s.status,
51
- taskCounts: counts,
52
- };
53
- });
54
- adapter.exec("COMMIT"); // eslint-disable-line
55
- const result = {
56
- milestoneId: milestone.id,
57
- title: milestone.title,
58
- status: milestone.status,
59
- createdAt: milestone.created_at,
60
- completedAt: milestone.completed_at,
61
- sliceCount: slices.length,
62
- slices,
63
- };
64
- return {
65
- content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
66
- details: { operation: "milestone_status", milestoneId: milestone.id, sliceCount: slices.length },
67
- };
68
- }
69
- catch (txErr) {
70
- try {
71
- adapter.exec("ROLLBACK");
72
- }
73
- catch { /* swallow */ } // eslint-disable-line
74
- throw txErr;
75
- }
76
- }
77
- catch (err) {
78
- const msg = err instanceof Error ? err.message : String(err);
79
- logWarning("tool", `gsd_milestone_status tool failed: ${msg}`);
20
+ const dbAvailable = await ensureDbOpen();
21
+ if (!dbAvailable) {
80
22
  return {
81
- content: [{ type: "text", text: `Error querying milestone status: ${msg}` }],
82
- details: { operation: "milestone_status", error: msg },
23
+ content: [{ type: "text", text: "Error: GSD database is not available. Cannot read milestone status." }],
24
+ details: { operation: "milestone_status", error: "db_unavailable" },
83
25
  };
84
26
  }
27
+ return executeMilestoneStatus(params);
85
28
  },
86
29
  });
87
30
  }