@opengsd/gsd-pi 1.1.1-dev.616a1a1 → 1.1.1-dev.9bb7453

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 (395) hide show
  1. package/dist/cli.js +3 -2
  2. package/dist/help-text.js +10 -6
  3. package/dist/resources/.managed-resources-content-hash +1 -1
  4. package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +495 -0
  5. package/dist/resources/extensions/browser-tools/engine/selection.js +16 -0
  6. package/dist/resources/extensions/browser-tools/extension-manifest.json +2 -2
  7. package/dist/resources/extensions/browser-tools/index.js +57 -9
  8. package/dist/resources/extensions/browser-tools/package.json +5 -1
  9. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +167 -16
  10. package/dist/resources/extensions/gsd/auto/orchestrator.js +0 -1
  11. package/dist/resources/extensions/gsd/auto/phases.js +4 -3
  12. package/dist/resources/extensions/gsd/auto-dashboard.js +92 -17
  13. package/dist/resources/extensions/gsd/auto-dispatch.js +44 -0
  14. package/dist/resources/extensions/gsd/auto-post-unit.js +134 -10
  15. package/dist/resources/extensions/gsd/auto-prompts.js +68 -22
  16. package/dist/resources/extensions/gsd/auto-recovery.js +4 -4
  17. package/dist/resources/extensions/gsd/auto-runtime-state.js +3 -0
  18. package/dist/resources/extensions/gsd/auto-start.js +94 -15
  19. package/dist/resources/extensions/gsd/auto-tool-tracking.js +1 -1
  20. package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +2 -1
  21. package/dist/resources/extensions/gsd/auto.js +31 -6
  22. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +83 -4
  23. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +43 -0
  24. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +39 -14
  25. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +16 -10
  26. package/dist/resources/extensions/gsd/browser-evidence.js +29 -2
  27. package/dist/resources/extensions/gsd/commands/catalog.js +6 -1
  28. package/dist/resources/extensions/gsd/commands/handlers/core.js +6 -2
  29. package/dist/resources/extensions/gsd/commands/handlers/ops.js +9 -5
  30. package/dist/resources/extensions/gsd/commands-handlers.js +76 -11
  31. package/dist/resources/extensions/gsd/commands-maintenance.js +172 -2
  32. package/dist/resources/extensions/gsd/commands-mcp-status.js +109 -60
  33. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +3 -1
  34. package/dist/resources/extensions/gsd/commands-verdict.js +1 -1
  35. package/dist/resources/extensions/gsd/config-overlay.js +2 -1
  36. package/dist/resources/extensions/gsd/dashboard-overlay.js +21 -7
  37. package/dist/resources/extensions/gsd/docs/preferences-reference.md +8 -0
  38. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +2 -2
  39. package/dist/resources/extensions/gsd/error-classifier.js +2 -1
  40. package/dist/resources/extensions/gsd/escalation.js +4 -4
  41. package/dist/resources/extensions/gsd/exec-sandbox.js +2 -0
  42. package/dist/resources/extensions/gsd/forensics.js +74 -2
  43. package/dist/resources/extensions/gsd/gsd-db.js +42 -6
  44. package/dist/resources/extensions/gsd/guided-flow.js +30 -69
  45. package/dist/resources/extensions/gsd/mcp-filter.js +3 -0
  46. package/dist/resources/extensions/gsd/mcp-project-config.js +76 -84
  47. package/dist/resources/extensions/gsd/memory-store.js +4 -1
  48. package/dist/resources/extensions/gsd/migration-auto-check.js +2 -2
  49. package/dist/resources/extensions/gsd/post-unit-hooks.js +9 -0
  50. package/dist/resources/extensions/gsd/preferences-validation.js +39 -0
  51. package/dist/resources/extensions/gsd/prompt-loader.js +7 -0
  52. package/dist/resources/extensions/gsd/prompts/forensics.md +61 -1
  53. package/dist/resources/extensions/gsd/prompts/gate-evaluate.md +3 -1
  54. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +3 -1
  55. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  56. package/dist/resources/extensions/gsd/prompts/reactive-execute.md +3 -1
  57. package/dist/resources/extensions/gsd/prompts/run-uat.md +48 -24
  58. package/dist/resources/extensions/gsd/prompts/system.md +3 -1
  59. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +3 -3
  60. package/dist/resources/extensions/gsd/rule-registry.js +428 -52
  61. package/dist/resources/extensions/gsd/safety/destructive-guard.js +3 -0
  62. package/dist/resources/extensions/gsd/skill-activation.js +20 -3
  63. package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +4 -2
  64. package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +1 -1
  65. package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +18 -1
  66. package/dist/resources/extensions/gsd/state-reconciliation/index.js +6 -0
  67. package/dist/resources/extensions/gsd/state.js +17 -14
  68. package/dist/resources/extensions/gsd/templates/plan.md +3 -1
  69. package/dist/resources/extensions/gsd/tool-presentation-plan.js +120 -0
  70. package/dist/resources/extensions/gsd/tools/complete-slice.js +15 -1
  71. package/dist/resources/extensions/gsd/tools/complete-task.js +11 -1
  72. package/dist/resources/extensions/gsd/tools/exec-tool.js +109 -0
  73. package/dist/resources/extensions/gsd/tools/plan-slice.js +14 -9
  74. package/dist/resources/extensions/gsd/tools/reopen-milestone.js +2 -2
  75. package/dist/resources/extensions/gsd/tools/validate-milestone.js +46 -16
  76. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +403 -3
  77. package/dist/resources/extensions/gsd/unit-context-manifest.js +8 -3
  78. package/dist/resources/extensions/gsd/validation-block-guard.js +2 -0
  79. package/dist/resources/extensions/gsd/verdict-parser.js +59 -15
  80. package/dist/resources/extensions/gsd/verification-gate.js +72 -1
  81. package/dist/resources/extensions/gsd/workflow-mcp-auto-prep.js +3 -1
  82. package/dist/resources/extensions/gsd/workflow-mcp.js +5 -1
  83. package/dist/resources/extensions/gsd/worktree-lifecycle.js +24 -0
  84. package/dist/resources/extensions/mcp-client/manager.js +31 -1
  85. package/dist/resources/extensions/shared/gsd-browser-cli.js +145 -0
  86. package/dist/rtk.d.ts +7 -1
  87. package/dist/rtk.js +27 -11
  88. package/dist/update-check.d.ts +15 -1
  89. package/dist/update-check.js +87 -12
  90. package/dist/update-cmd.d.ts +1 -0
  91. package/dist/update-cmd.js +53 -2
  92. package/dist/web/standalone/.next/BUILD_ID +1 -1
  93. package/dist/web/standalone/.next/app-path-routes-manifest.json +6 -6
  94. package/dist/web/standalone/.next/build-manifest.json +2 -2
  95. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  96. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  97. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  105. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  108. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  110. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  112. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  113. package/dist/web/standalone/.next/server/app/index.html +1 -1
  114. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  115. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  116. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  117. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  118. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  119. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  120. package/dist/web/standalone/.next/server/app-paths-manifest.json +6 -6
  121. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  122. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  124. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  125. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  126. package/package.json +5 -3
  127. package/packages/cloud-mcp-gateway/package.json +2 -2
  128. package/packages/contracts/dist/workflow.d.ts +14 -0
  129. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  130. package/packages/contracts/dist/workflow.js +16 -0
  131. package/packages/contracts/dist/workflow.js.map +1 -1
  132. package/packages/contracts/package.json +1 -1
  133. package/packages/daemon/package.json +4 -4
  134. package/packages/gsd-agent-core/dist/agent-session.d.ts +9 -0
  135. package/packages/gsd-agent-core/dist/agent-session.d.ts.map +1 -1
  136. package/packages/gsd-agent-core/dist/agent-session.js +32 -0
  137. package/packages/gsd-agent-core/dist/agent-session.js.map +1 -1
  138. package/packages/gsd-agent-core/dist/index.d.ts +1 -0
  139. package/packages/gsd-agent-core/dist/index.d.ts.map +1 -1
  140. package/packages/gsd-agent-core/dist/index.js +1 -0
  141. package/packages/gsd-agent-core/dist/index.js.map +1 -1
  142. package/packages/gsd-agent-core/dist/session/agent-session-compaction.d.ts +2 -0
  143. package/packages/gsd-agent-core/dist/session/agent-session-compaction.d.ts.map +1 -1
  144. package/packages/gsd-agent-core/dist/session/agent-session-compaction.js +8 -2
  145. package/packages/gsd-agent-core/dist/session/agent-session-compaction.js.map +1 -1
  146. package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts +7 -0
  147. package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts.map +1 -1
  148. package/packages/gsd-agent-core/dist/session/agent-session-host.js.map +1 -1
  149. package/packages/gsd-agent-core/dist/session/agent-session-prompt.d.ts.map +1 -1
  150. package/packages/gsd-agent-core/dist/session/agent-session-prompt.js +69 -1
  151. package/packages/gsd-agent-core/dist/session/agent-session-prompt.js.map +1 -1
  152. package/packages/gsd-agent-core/dist/turn-latency.d.ts +47 -0
  153. package/packages/gsd-agent-core/dist/turn-latency.d.ts.map +1 -0
  154. package/packages/gsd-agent-core/dist/turn-latency.js +123 -0
  155. package/packages/gsd-agent-core/dist/turn-latency.js.map +1 -0
  156. package/packages/gsd-agent-core/package.json +6 -6
  157. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts +21 -0
  158. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts.map +1 -0
  159. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js +213 -0
  160. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js.map +1 -0
  161. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  162. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  163. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js +10 -0
  164. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js.map +1 -1
  165. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts +1 -0
  166. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  167. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +92 -31
  168. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  169. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  170. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js +7 -1
  171. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  172. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.d.ts.map +1 -1
  173. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.js +6 -0
  174. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.js.map +1 -1
  175. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-dialogs.d.ts.map +1 -1
  176. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-dialogs.js +2 -0
  177. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-dialogs.js.map +1 -1
  178. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.d.ts +1 -1
  179. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.d.ts.map +1 -1
  180. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.js +1 -1
  181. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.js.map +1 -1
  182. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  183. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js +1 -0
  184. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js.map +1 -1
  185. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.d.ts.map +1 -1
  186. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js +5 -0
  187. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js.map +1 -1
  188. package/packages/gsd-agent-modes/package.json +7 -7
  189. package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -1
  190. package/packages/mcp-server/dist/remote-questions.js +23 -9
  191. package/packages/mcp-server/dist/remote-questions.js.map +1 -1
  192. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  193. package/packages/mcp-server/dist/workflow-tools.js +84 -2
  194. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  195. package/packages/mcp-server/package.json +3 -3
  196. package/packages/native/package.json +1 -1
  197. package/packages/pi-agent-core/dist/agent-loop.js +38 -0
  198. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  199. package/packages/pi-agent-core/dist/agent.d.ts +5 -1
  200. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  201. package/packages/pi-agent-core/dist/agent.js +2 -0
  202. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  203. package/packages/pi-agent-core/dist/types.d.ts +3 -0
  204. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  205. package/packages/pi-agent-core/dist/types.js.map +1 -1
  206. package/packages/pi-agent-core/package.json +1 -1
  207. package/packages/pi-ai/dist/api-registry.d.ts +2 -0
  208. package/packages/pi-ai/dist/api-registry.d.ts.map +1 -1
  209. package/packages/pi-ai/dist/api-registry.js +23 -0
  210. package/packages/pi-ai/dist/api-registry.js.map +1 -1
  211. package/packages/pi-ai/dist/image-models.generated.d.ts +15 -0
  212. package/packages/pi-ai/dist/image-models.generated.d.ts.map +1 -1
  213. package/packages/pi-ai/dist/image-models.generated.js +15 -0
  214. package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
  215. package/packages/pi-ai/dist/models.generated.d.ts +406 -17
  216. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  217. package/packages/pi-ai/dist/models.generated.js +484 -116
  218. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  219. package/packages/pi-ai/dist/stream.js +6 -6
  220. package/packages/pi-ai/dist/stream.js.map +1 -1
  221. package/packages/pi-ai/package.json +1 -1
  222. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  223. package/packages/pi-coding-agent/dist/core/model-registry.js +2 -2
  224. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  225. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
  226. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  227. package/packages/pi-coding-agent/dist/core/settings-manager.js +11 -0
  228. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  229. package/packages/pi-coding-agent/package.json +7 -7
  230. package/packages/pi-tui/dist/terminal.d.ts +1 -0
  231. package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
  232. package/packages/pi-tui/dist/terminal.js +8 -4
  233. package/packages/pi-tui/dist/terminal.js.map +1 -1
  234. package/packages/pi-tui/package.json +1 -1
  235. package/packages/rpc-client/package.json +2 -2
  236. package/pkg/package.json +1 -1
  237. package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +579 -0
  238. package/src/resources/extensions/browser-tools/engine/selection.ts +19 -0
  239. package/src/resources/extensions/browser-tools/extension-manifest.json +2 -2
  240. package/src/resources/extensions/browser-tools/index.ts +60 -9
  241. package/src/resources/extensions/browser-tools/package.json +5 -1
  242. package/src/resources/extensions/browser-tools/tests/browser-engine-selection.test.mjs +35 -0
  243. package/src/resources/extensions/browser-tools/tests/managed-gsd-browser-tools.test.mjs +33 -0
  244. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +196 -16
  245. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +239 -63
  246. package/src/resources/extensions/gsd/auto/orchestrator.ts +0 -1
  247. package/src/resources/extensions/gsd/auto/phases.ts +5 -3
  248. package/src/resources/extensions/gsd/auto-dashboard.ts +98 -18
  249. package/src/resources/extensions/gsd/auto-dispatch.ts +53 -0
  250. package/src/resources/extensions/gsd/auto-post-unit.ts +166 -9
  251. package/src/resources/extensions/gsd/auto-prompts.ts +102 -15
  252. package/src/resources/extensions/gsd/auto-recovery.ts +4 -4
  253. package/src/resources/extensions/gsd/auto-runtime-state.ts +4 -0
  254. package/src/resources/extensions/gsd/auto-start.ts +112 -17
  255. package/src/resources/extensions/gsd/auto-tool-tracking.ts +1 -1
  256. package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +2 -1
  257. package/src/resources/extensions/gsd/auto.ts +47 -5
  258. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +90 -4
  259. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +51 -0
  260. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +60 -19
  261. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +21 -10
  262. package/src/resources/extensions/gsd/browser-evidence.ts +26 -2
  263. package/src/resources/extensions/gsd/commands/catalog.ts +6 -1
  264. package/src/resources/extensions/gsd/commands/handlers/core.ts +6 -2
  265. package/src/resources/extensions/gsd/commands/handlers/ops.ts +9 -5
  266. package/src/resources/extensions/gsd/commands-handlers.ts +76 -11
  267. package/src/resources/extensions/gsd/commands-maintenance.ts +197 -2
  268. package/src/resources/extensions/gsd/commands-mcp-status.ts +136 -58
  269. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +4 -1
  270. package/src/resources/extensions/gsd/commands-verdict.ts +1 -1
  271. package/src/resources/extensions/gsd/config-overlay.ts +3 -1
  272. package/src/resources/extensions/gsd/dashboard-overlay.ts +28 -7
  273. package/src/resources/extensions/gsd/docs/preferences-reference.md +8 -0
  274. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +2 -2
  275. package/src/resources/extensions/gsd/error-classifier.ts +2 -1
  276. package/src/resources/extensions/gsd/escalation.ts +4 -4
  277. package/src/resources/extensions/gsd/exec-sandbox.ts +4 -0
  278. package/src/resources/extensions/gsd/forensics.ts +99 -5
  279. package/src/resources/extensions/gsd/gsd-db.ts +46 -8
  280. package/src/resources/extensions/gsd/guided-flow.ts +91 -83
  281. package/src/resources/extensions/gsd/mcp-filter.ts +3 -0
  282. package/src/resources/extensions/gsd/mcp-project-config.ts +105 -88
  283. package/src/resources/extensions/gsd/memory-store.ts +4 -1
  284. package/src/resources/extensions/gsd/migration-auto-check.ts +2 -2
  285. package/src/resources/extensions/gsd/post-unit-hooks.ts +14 -1
  286. package/src/resources/extensions/gsd/preferences-types.ts +1 -1
  287. package/src/resources/extensions/gsd/preferences-validation.ts +36 -0
  288. package/src/resources/extensions/gsd/prompt-loader.ts +8 -0
  289. package/src/resources/extensions/gsd/prompts/forensics.md +61 -1
  290. package/src/resources/extensions/gsd/prompts/gate-evaluate.md +3 -1
  291. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +3 -1
  292. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  293. package/src/resources/extensions/gsd/prompts/reactive-execute.md +3 -1
  294. package/src/resources/extensions/gsd/prompts/run-uat.md +48 -24
  295. package/src/resources/extensions/gsd/prompts/system.md +3 -1
  296. package/src/resources/extensions/gsd/prompts/validate-milestone.md +3 -3
  297. package/src/resources/extensions/gsd/rule-registry.ts +558 -58
  298. package/src/resources/extensions/gsd/rule-types.ts +2 -0
  299. package/src/resources/extensions/gsd/safety/destructive-guard.ts +3 -0
  300. package/src/resources/extensions/gsd/skill-activation.ts +20 -2
  301. package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +4 -2
  302. package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +1 -1
  303. package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +20 -0
  304. package/src/resources/extensions/gsd/state-reconciliation/index.ts +6 -0
  305. package/src/resources/extensions/gsd/state-reconciliation/types.ts +1 -0
  306. package/src/resources/extensions/gsd/state.ts +18 -14
  307. package/src/resources/extensions/gsd/templates/plan.md +3 -1
  308. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +156 -4
  309. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +123 -0
  310. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +143 -2
  311. package/src/resources/extensions/gsd/tests/auto-start-project-milestone-reconcile.test.ts +24 -2
  312. package/src/resources/extensions/gsd/tests/browser-evidence.test.ts +142 -0
  313. package/src/resources/extensions/gsd/tests/commands-dispatcher-validation-block.test.ts +38 -3
  314. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +6 -2
  315. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +30 -0
  316. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +42 -0
  317. package/src/resources/extensions/gsd/tests/dashboard-overlay.test.ts +45 -0
  318. package/src/resources/extensions/gsd/tests/deep-planning-mode-dispatch.test.ts +53 -0
  319. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +8 -0
  320. package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +50 -13
  321. package/src/resources/extensions/gsd/tests/discuss-milestone-structured-questions.test.ts +31 -0
  322. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +60 -0
  323. package/src/resources/extensions/gsd/tests/doctor-runtime-checks.test.ts +27 -0
  324. package/src/resources/extensions/gsd/tests/escalation.test.ts +16 -27
  325. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +18 -0
  326. package/src/resources/extensions/gsd/tests/exec-tool.test.ts +69 -0
  327. package/src/resources/extensions/gsd/tests/forensics-issue-routing.test.ts +20 -0
  328. package/src/resources/extensions/gsd/tests/forensics-prompt-rendering.test.ts +3 -0
  329. package/src/resources/extensions/gsd/tests/forensics-tool-scope.test.ts +69 -0
  330. package/src/resources/extensions/gsd/tests/gsd-rebuild.test.ts +199 -0
  331. package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +75 -0
  332. package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +40 -1
  333. package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +86 -0
  334. package/src/resources/extensions/gsd/tests/guided-flow.test.ts +12 -9
  335. package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +4 -4
  336. package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +66 -10
  337. package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +13 -6
  338. package/src/resources/extensions/gsd/tests/mcp-filter.test.ts +15 -0
  339. package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +100 -0
  340. package/src/resources/extensions/gsd/tests/mcp-status.test.ts +179 -0
  341. package/src/resources/extensions/gsd/tests/memory-maintenance.test.ts +39 -8
  342. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +3 -3
  343. package/src/resources/extensions/gsd/tests/new-milestone-discuss-routing.test.ts +3 -3
  344. package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +54 -7
  345. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +9 -0
  346. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +39 -1
  347. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +157 -0
  348. package/src/resources/extensions/gsd/tests/post-unit-retry-on-orchestrator-bridge.test.ts +179 -0
  349. package/src/resources/extensions/gsd/tests/preferences.test.ts +29 -0
  350. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +53 -1
  351. package/src/resources/extensions/gsd/tests/prompt-loader-extension-dir.test.ts +14 -0
  352. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +18 -1
  353. package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +7 -8
  354. package/src/resources/extensions/gsd/tests/reactive-executor.test.ts +36 -0
  355. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +35 -0
  356. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +1 -1
  357. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +75 -0
  358. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +100 -0
  359. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +55 -0
  360. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +6 -2
  361. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +191 -0
  362. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +84 -10
  363. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +19 -0
  364. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +12 -2
  365. package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +7 -1
  366. package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +29 -6
  367. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +29 -6
  368. package/src/resources/extensions/gsd/tests/validate-milestone-prompt-verification-classes.test.ts +6 -3
  369. package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +133 -0
  370. package/src/resources/extensions/gsd/tests/validation-block-guard.test.ts +21 -0
  371. package/src/resources/extensions/gsd/tests/verification-gate.test.ts +51 -0
  372. package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +17 -2
  373. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +213 -0
  374. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +25 -0
  375. package/src/resources/extensions/gsd/tool-presentation-plan.ts +167 -0
  376. package/src/resources/extensions/gsd/tools/complete-slice.ts +14 -1
  377. package/src/resources/extensions/gsd/tools/complete-task.ts +20 -2
  378. package/src/resources/extensions/gsd/tools/exec-tool.ts +130 -0
  379. package/src/resources/extensions/gsd/tools/plan-slice.ts +14 -9
  380. package/src/resources/extensions/gsd/tools/reopen-milestone.ts +2 -2
  381. package/src/resources/extensions/gsd/tools/validate-milestone.ts +46 -15
  382. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +489 -3
  383. package/src/resources/extensions/gsd/types.ts +69 -5
  384. package/src/resources/extensions/gsd/unit-context-manifest.ts +14 -5
  385. package/src/resources/extensions/gsd/validation-block-guard.ts +2 -0
  386. package/src/resources/extensions/gsd/verdict-parser.ts +54 -13
  387. package/src/resources/extensions/gsd/verification-gate.ts +87 -1
  388. package/src/resources/extensions/gsd/workflow-mcp-auto-prep.ts +2 -1
  389. package/src/resources/extensions/gsd/workflow-mcp.ts +5 -1
  390. package/src/resources/extensions/gsd/worktree-lifecycle.ts +26 -0
  391. package/src/resources/extensions/mcp-client/manager.ts +33 -1
  392. package/src/resources/extensions/mcp-client/tests/manager.test.ts +35 -0
  393. package/src/resources/extensions/shared/gsd-browser-cli.ts +172 -0
  394. /package/dist/web/standalone/.next/static/{L9N5SPFi7f-Ne4u2uXzCe → jBtwT9v1u2lUA3UEOy_ZH}/_buildManifest.js +0 -0
  395. /package/dist/web/standalone/.next/static/{L9N5SPFi7f-Ne4u2uXzCe → jBtwT9v1u2lUA3UEOy_ZH}/_ssgManifest.js +0 -0
@@ -72,6 +72,38 @@ function makeBrowserObservableUatContent(mode = 'artifact-driven'): string {
72
72
  ].join('\n');
73
73
  }
74
74
 
75
+ function makeDeferredBrowserUatContent(): string {
76
+ return [
77
+ '# UAT File',
78
+ '',
79
+ '## UAT Type',
80
+ '',
81
+ '- UAT mode: artifact-driven',
82
+ '- Why this mode is sufficient: Node interaction tests exercise the real app.js render/event/localStorage loop through a DOM harness. Live browser, keyboard, responsive, and visual-polish UAT remain intentionally deferred to S02.',
83
+ '',
84
+ '## Smoke Test',
85
+ '',
86
+ 'Run `node --test tests/s01-static-interactions.test.js` and confirm all tests pass.',
87
+ '',
88
+ '## Test Cases',
89
+ '',
90
+ '1. Click the todo row edit control in the DOM harness.',
91
+ '2. Save changed text and reload/recreate the app from persisted localStorage.',
92
+ '3. Expected: the stored record shape remains unchanged.',
93
+ '',
94
+ '## Not Proven By This UAT',
95
+ '',
96
+ '- Final visual polish of edit controls.',
97
+ '- Keyboard usability through a real browser.',
98
+ '- Browser console and local network cleanliness.',
99
+ '',
100
+ '## Notes for Tester',
101
+ '',
102
+ 'S02 should capture browser evidence for the full loop rather than changing this persisted model.',
103
+ '',
104
+ ].join('\n');
105
+ }
106
+
75
107
  describe('run-uat', () => {
76
108
  test('(a) artifact-driven', () => {
77
109
  assert.deepStrictEqual(
@@ -232,8 +264,8 @@ test('(k) run-uat prompt template', () => {
232
264
  `prompt contains detected dynamic uatType value "${uatType}" after substitution`,
233
265
  );
234
266
  assert.ok(
235
- promptResult?.includes(`uatType: ${uatType}`) ?? false,
236
- `prompt contains dynamic uatType frontmatter value "${uatType}" after substitution`,
267
+ promptResult?.includes(`uatType: "${uatType}"`) ?? false,
268
+ `prompt contains dynamic uatType field "${uatType}" after substitution`,
237
269
  );
238
270
  assert.ok(
239
271
  !/\{\{[^}]+\}\}/.test(promptResult ?? ''),
@@ -249,7 +281,7 @@ test('(k) run-uat prompt template', () => {
249
281
  );
250
282
  });
251
283
 
252
- test('(k2) run-uat prompt references gsd_summary_save, not direct write', () => {
284
+ test('(k2) run-uat prompt references gsd_uat_result_save, not direct write', () => {
253
285
  const promptResult = loadPromptFromWorktree('run-uat', {
254
286
  workingDirectory: '/tmp/test-project',
255
287
  milestoneId: 'M001',
@@ -261,17 +293,25 @@ test('(k2) run-uat prompt references gsd_summary_save, not direct write', () =>
261
293
  });
262
294
 
263
295
  assert.ok(
264
- promptResult.includes('gsd_summary_save'),
265
- 'run-uat prompt should reference gsd_summary_save tool',
296
+ promptResult.includes('gsd_uat_result_save'),
297
+ 'run-uat prompt should reference gsd_uat_result_save tool',
298
+ );
299
+ assert.ok(
300
+ promptResult.includes('presentedTools') && promptResult.includes('blockedTools'),
301
+ 'run-uat prompt should specify the tool presentation contract',
266
302
  );
267
303
  assert.ok(
268
- promptResult.includes('artifact_type: "ASSESSMENT"'),
269
- 'run-uat prompt should specify ASSESSMENT artifact type',
304
+ !promptResult.includes('Call `gsd_summary_save`'),
305
+ 'run-uat prompt should not instruct direct summary-save UAT persistence',
270
306
  );
271
307
  assert.ok(
272
308
  !promptResult.includes('MUST write'),
273
309
  'run-uat prompt should not instruct direct file write in footer',
274
310
  );
311
+ assert.ok(
312
+ !promptResult.includes('Call `gsd_summary_save` with `artifact_type: "ASSESSMENT"`'),
313
+ 'run-uat prompt should not instruct the legacy summary-save UAT path',
314
+ );
275
315
  });
276
316
 
277
317
  test('(l) dispatch preconditions via resolveSliceFile', () => {
@@ -482,8 +522,8 @@ test('(n) stale replay guard', async () => {
482
522
  });
483
523
 
484
524
  test('(q) verdict in ASSESSMENT file skips UAT dispatch (file-based path)', async () => {
485
- // Regression test for #2644: run-uat prompt writes the verdict to
486
- // S{sid}-ASSESSMENT.md (via gsd_summary_save artifact_type:"ASSESSMENT"),
525
+ // Regression test for #2644: run-uat writes the verdict to
526
+ // S{sid}-ASSESSMENT.md through the structured UAT save path,
487
527
  // but checkNeedsRunUat only checked S{sid}-UAT.md — causing a stuck loop.
488
528
  const base = createFixtureBase();
489
529
  try {
@@ -679,11 +719,27 @@ test('(u) run-uat prompt promotes artifact-driven browser specs to browser-execu
679
719
  const prompt = await buildRunUatPrompt('M001', 'S01', uatRel, uatContent, base);
680
720
 
681
721
  assert.match(prompt, /\*\*Detected UAT mode:\*\*\s*`browser-executable`/);
682
- assert.match(prompt, /uatType: browser-executable/);
722
+ assert.match(prompt, /uatType: "browser-executable"/);
683
723
  assert.match(prompt, /use gsd-browser tools/i);
684
724
  } finally {
685
725
  cleanup(base);
686
726
  }
687
727
  });
688
728
 
729
+ test('(v) run-uat prompt keeps deferred browser work artifact-driven', async () => {
730
+ const base = createFixtureBase();
731
+ try {
732
+ const uatRel = '.gsd/milestones/M001/slices/S01/S01-UAT.md';
733
+ const uatContent = makeDeferredBrowserUatContent();
734
+ writeSliceFile(base, 'M001', 'S01', 'UAT', uatContent);
735
+
736
+ const prompt = await buildRunUatPrompt('M001', 'S01', uatRel, uatContent, base);
737
+
738
+ assert.match(prompt, /\*\*Detected UAT mode:\*\*\s*`artifact-driven`/);
739
+ assert.match(prompt, /uatType: "artifact-driven"/);
740
+ assert.doesNotMatch(prompt, /uatType: "browser-executable"/);
741
+ } finally {
742
+ cleanup(base);
743
+ }
744
+ });
689
745
  });
@@ -50,6 +50,7 @@ import { handleCompleteSlice } from "../../tools/complete-slice.ts";
50
50
  import { handleCompleteMilestone } from "../../tools/complete-milestone.ts";
51
51
  import { handleReopenTask } from "../../tools/reopen-task.ts";
52
52
  import { handleReopenSlice } from "../../tools/reopen-slice.ts";
53
+ import { handleReopenMilestone } from "../../tools/reopen-milestone.ts";
53
54
 
54
55
  // ── State derivation ──────────────────────────────────────────────────────
55
56
  import {
@@ -700,9 +701,7 @@ describe("state-machine-live-validation", () => {
700
701
  assert.match((result as any).error, /closed milestone/);
701
702
  });
702
703
 
703
- test("no reopen-milestone tool exists milestone completion is irrevocable (H5)", async () => {
704
- // This test documents the H5 finding: there is no handleReopenMilestone function.
705
- // A completed milestone can only be undone via direct DB manipulation.
704
+ test("closed milestone cannot be reopened by generic DB update", async () => {
706
705
  base = createFullFixture();
707
706
  openDatabase(join(base, ".gsd", "gsd.db"));
708
707
  insertMilestone({ id: "M001", title: "Done", status: "complete" });
@@ -710,10 +709,18 @@ describe("state-machine-live-validation", () => {
710
709
  const milestone = getMilestone("M001");
711
710
  assert.ok(isClosedStatus(milestone!.status), "milestone is closed");
712
711
 
713
- // The only escape is direct DB manipulation — no handler exists
714
- updateMilestoneStatus("M001", "active", null);
712
+ assert.throws(
713
+ () => updateMilestoneStatus("M001", "active", null),
714
+ /use gsd_milestone_reopen for an explicit reopen/,
715
+ );
716
+
717
+ const result = await handleReopenMilestone(
718
+ { milestoneId: "M001", reason: "regression surfaced after closure" },
719
+ base,
720
+ );
721
+ assert.ok(!("error" in result), `unexpected reopen error: ${"error" in result ? result.error : ""}`);
715
722
  const reopened = getMilestone("M001");
716
- assert.equal(reopened!.status, "active", "direct DB manipulation can reopen, but no tool exposes this");
723
+ assert.equal(reopened!.status, "active", "explicit reopen handler reopens the milestone");
717
724
  });
718
725
  });
719
726
 
@@ -48,6 +48,21 @@ describe("discoverMcpServerNames", () => {
48
48
  assert.deepEqual(result.sort(), ["server-a", "server-b", "shared"]);
49
49
  });
50
50
 
51
+ it("reads from .claude/settings.local.json for Claude Code project-local servers", () => {
52
+ const dir = mkdtempSync(join(tmpdir(), "mcp-filter-test-"));
53
+ mkdirSync(join(dir, ".claude"), { recursive: true });
54
+ writeFileSync(
55
+ join(dir, ".claude", "settings.local.json"),
56
+ JSON.stringify({ mcpServers: { "local-server": {}, "shared": {} } }),
57
+ );
58
+ writeFileSync(
59
+ join(dir, ".claude", "settings.json"),
60
+ JSON.stringify({ mcpServers: { "project-server": {}, "shared": {} } }),
61
+ );
62
+ const result = discoverMcpServerNames(dir);
63
+ assert.deepEqual(result.sort(), ["local-server", "project-server", "shared"]);
64
+ });
65
+
51
66
  it("handles .claude/settings.json missing gracefully", () => {
52
67
  const dir = mkdtempSync(join(tmpdir(), "mcp-filter-test-"));
53
68
  writeFileSync(
@@ -5,6 +5,8 @@ import { join } from "node:path";
5
5
  import { tmpdir } from "node:os";
6
6
 
7
7
  import {
8
+ buildProjectBrowserMcpServerConfig,
9
+ ensureClaudeCodeMcpJsonServerEnabled,
8
10
  ensureProjectWorkflowMcpConfig,
9
11
  GSD_BROWSER_MCP_SERVER_NAME,
10
12
  GSD_WORKFLOW_MCP_SERVER_NAME,
@@ -54,6 +56,14 @@ test("ensureProjectWorkflowMcpConfig creates .mcp.json with workflow and browser
54
56
  ]);
55
57
  assert.equal(browserArgs[mcpArgIndex + 6], projectRoot);
56
58
  assert.equal((browserServer as { cwd?: string })?.cwd, projectRoot);
59
+
60
+ const settings = JSON.parse(readFileSync(join(projectRoot, ".claude", "settings.local.json"), "utf-8")) as {
61
+ enabledMcpjsonServers?: string[];
62
+ };
63
+ assert.deepEqual(settings.enabledMcpjsonServers, [
64
+ GSD_WORKFLOW_MCP_SERVER_NAME,
65
+ GSD_BROWSER_MCP_SERVER_NAME,
66
+ ]);
57
67
  } finally {
58
68
  rmSync(projectRoot, { recursive: true, force: true });
59
69
  }
@@ -115,6 +125,11 @@ test("ensureProjectWorkflowMcpConfig uses custom workflow server name from env",
115
125
  assert.ok(parsed.mcpServers?.["custom-workflow"]);
116
126
  assert.ok(parsed.mcpServers?.[GSD_BROWSER_MCP_SERVER_NAME]);
117
127
  assert.equal(parsed.mcpServers?.[GSD_WORKFLOW_MCP_SERVER_NAME], undefined);
128
+
129
+ const settings = JSON.parse(readFileSync(join(projectRoot, ".claude", "settings.local.json"), "utf-8")) as {
130
+ enabledMcpjsonServers?: string[];
131
+ };
132
+ assert.deepEqual(settings.enabledMcpjsonServers, ["custom-workflow", GSD_BROWSER_MCP_SERVER_NAME]);
118
133
  } finally {
119
134
  rmSync(projectRoot, { recursive: true, force: true });
120
135
  }
@@ -136,6 +151,42 @@ test("ensureProjectWorkflowMcpConfig can disable the default browser MCP server"
136
151
  };
137
152
  assert.ok(parsed.mcpServers?.[GSD_WORKFLOW_MCP_SERVER_NAME]);
138
153
  assert.equal(parsed.mcpServers?.[GSD_BROWSER_MCP_SERVER_NAME], undefined);
154
+
155
+ const settings = JSON.parse(readFileSync(join(projectRoot, ".claude", "settings.local.json"), "utf-8")) as {
156
+ enabledMcpjsonServers?: string[];
157
+ };
158
+ assert.deepEqual(settings.enabledMcpjsonServers, [GSD_WORKFLOW_MCP_SERVER_NAME]);
159
+ } finally {
160
+ rmSync(projectRoot, { recursive: true, force: true });
161
+ }
162
+ });
163
+
164
+ test("buildProjectBrowserMcpServerConfig prefers newer gsd-browser on PATH", () => {
165
+ const projectRoot = mkdtempSync(join(tmpdir(), "gsd-mcp-browser-"));
166
+
167
+ try {
168
+ const config = buildProjectBrowserMcpServerConfig(projectRoot, {
169
+ GSD_BROWSER_PATH_VERSION: "99.0.0",
170
+ });
171
+
172
+ assert.equal(config?.command, "gsd-browser");
173
+ assert.equal(config?.args?.[0], "mcp");
174
+ } finally {
175
+ rmSync(projectRoot, { recursive: true, force: true });
176
+ }
177
+ });
178
+
179
+ test("buildProjectBrowserMcpServerConfig keeps bundled browser when PATH version is older", () => {
180
+ const projectRoot = mkdtempSync(join(tmpdir(), "gsd-mcp-browser-"));
181
+
182
+ try {
183
+ const config = buildProjectBrowserMcpServerConfig(projectRoot, {
184
+ GSD_BROWSER_PATH_VERSION: "0.0.1",
185
+ });
186
+
187
+ assert.equal(config?.command, process.execPath);
188
+ assert.match(config?.args?.[0] ?? "", /@opengsd[\/\\]gsd-browser[\/\\]bin[\/\\]gsd-browser/);
189
+ assert.equal(config?.args?.[1], "mcp");
139
190
  } finally {
140
191
  rmSync(projectRoot, { recursive: true, force: true });
141
192
  }
@@ -156,3 +207,52 @@ test("ensureProjectWorkflowMcpConfig is idempotent when config is already curren
156
207
  rmSync(projectRoot, { recursive: true, force: true });
157
208
  }
158
209
  });
210
+
211
+ test("ensureProjectWorkflowMcpConfig updates stale Claude Code MCP approval state", () => {
212
+ const projectRoot = mkdtempSync(join(tmpdir(), "gsd-mcp-init-"));
213
+ mkdirSync(join(projectRoot, ".gsd"), { recursive: true });
214
+ const settingsPath = join(projectRoot, ".claude", "settings.local.json");
215
+
216
+ try {
217
+ const first = ensureProjectWorkflowMcpConfig(projectRoot);
218
+ assert.equal(first.status, "created");
219
+
220
+ writeFileSync(
221
+ settingsPath,
222
+ `${JSON.stringify({
223
+ permissions: { allow: ["Bash(gh issue *)"] },
224
+ enabledMcpjsonServers: [],
225
+ disabledMcpjsonServers: [GSD_WORKFLOW_MCP_SERVER_NAME, GSD_BROWSER_MCP_SERVER_NAME],
226
+ }, null, 2)}\n`,
227
+ "utf-8",
228
+ );
229
+
230
+ const second = ensureProjectWorkflowMcpConfig(projectRoot);
231
+ assert.equal(second.status, "updated");
232
+
233
+ const settings = JSON.parse(readFileSync(settingsPath, "utf-8")) as {
234
+ permissions?: { allow?: string[] };
235
+ enabledMcpjsonServers?: string[];
236
+ disabledMcpjsonServers?: string[];
237
+ };
238
+ assert.deepEqual(settings.permissions?.allow, ["Bash(gh issue *)"]);
239
+ assert.deepEqual(settings.enabledMcpjsonServers, [
240
+ GSD_WORKFLOW_MCP_SERVER_NAME,
241
+ GSD_BROWSER_MCP_SERVER_NAME,
242
+ ]);
243
+ assert.deepEqual(settings.disabledMcpjsonServers, []);
244
+ } finally {
245
+ rmSync(projectRoot, { recursive: true, force: true });
246
+ }
247
+ });
248
+
249
+ test("ensureClaudeCodeMcpJsonServerEnabled is idempotent", () => {
250
+ const projectRoot = mkdtempSync(join(tmpdir(), "gsd-mcp-init-"));
251
+
252
+ try {
253
+ assert.equal(ensureClaudeCodeMcpJsonServerEnabled(projectRoot, "gsd-workflow"), true);
254
+ assert.equal(ensureClaudeCodeMcpJsonServerEnabled(projectRoot, "gsd-workflow"), false);
255
+ } finally {
256
+ rmSync(projectRoot, { recursive: true, force: true });
257
+ }
258
+ });
@@ -1,14 +1,23 @@
1
1
  import test, { describe } from "node:test";
2
2
  import assert from "node:assert/strict";
3
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
4
+ import { createRequire } from "node:module";
5
+ import { tmpdir } from "node:os";
6
+ import { join } from "node:path";
7
+ import { pathToFileURL } from "node:url";
8
+ import type { ExtensionCommandContext } from "@gsd/pi-coding-agent";
3
9
 
4
10
  import {
11
+ formatMcpDiscoveryResult,
5
12
  formatMcpInitResult,
6
13
  formatMcpConnectionTestResult,
7
14
  formatMcpStatusReport,
8
15
  formatMcpServerDetail,
9
16
  hasHostMcpTool,
17
+ handleMcpStatus,
10
18
  type McpServerStatus,
11
19
  } from "../commands-mcp-status.ts";
20
+ import { clearMcpConfigCache } from "../../mcp-client/manager.ts";
12
21
 
13
22
  // ─── formatMcpStatusReport ──────────────────────────────────────────────────
14
23
 
@@ -49,6 +58,16 @@ describe("formatMcpStatusReport", () => {
49
58
  assert.match(result, /disabled/i);
50
59
  });
51
60
 
61
+ test("shows available state for servers that pass a status probe", () => {
62
+ const servers: McpServerStatus[] = [
63
+ { name: "gsd-workflow", transport: "stdio", connected: false, available: true, toolCount: 62, error: undefined },
64
+ ];
65
+ const result = formatMcpStatusReport(servers);
66
+ assert.match(result, /gsd-workflow/);
67
+ assert.match(result, /available — 62 tools/);
68
+ assert.doesNotMatch(result, /disconnected/);
69
+ });
70
+
52
71
  test("includes server count in header", () => {
53
72
  const servers: McpServerStatus[] = [
54
73
  { name: "a", transport: "stdio", connected: true, toolCount: 3, error: undefined },
@@ -113,6 +132,20 @@ describe("formatMcpServerDetail", () => {
113
132
  assert.match(result, /disconnected/i);
114
133
  });
115
134
 
135
+ test("shows available status with tool names", () => {
136
+ const result = formatMcpServerDetail({
137
+ name: "gsd-workflow",
138
+ transport: "stdio",
139
+ connected: false,
140
+ available: true,
141
+ toolCount: 1,
142
+ tools: ["gsd_milestone_status"],
143
+ error: undefined,
144
+ });
145
+ assert.match(result, /available/i);
146
+ assert.match(result, /gsd_milestone_status/);
147
+ });
148
+
116
149
  test("shows env warnings for server detail", () => {
117
150
  const result = formatMcpServerDetail({
118
151
  name: "warned",
@@ -128,6 +161,150 @@ describe("formatMcpServerDetail", () => {
128
161
  });
129
162
  });
130
163
 
164
+ describe("handleMcpStatus", () => {
165
+ test("probes configured stdio servers before reporting disconnected", async () => {
166
+ const previousGsdHome = process.env.GSD_HOME;
167
+ const originalCwd = process.cwd();
168
+ const projectDir = mkdtempSync(join(tmpdir(), "gsd-mcp-status-project-"));
169
+ const gsdHomeDir = mkdtempSync(join(tmpdir(), "gsd-mcp-status-home-"));
170
+ try {
171
+ process.env.GSD_HOME = gsdHomeDir;
172
+ process.chdir(projectDir);
173
+ mkdirSync(join(projectDir, ".gsd"), { recursive: true });
174
+
175
+ const require = createRequire(import.meta.url);
176
+ const mcpModuleUrl = pathToFileURL(require.resolve("@modelcontextprotocol/sdk/server/mcp.js")).href;
177
+ const stdioModuleUrl = pathToFileURL(require.resolve("@modelcontextprotocol/sdk/server/stdio.js")).href;
178
+ const serverPath = join(projectDir, "fake-mcp-server.mjs");
179
+ writeFileSync(
180
+ serverPath,
181
+ [
182
+ `const { McpServer } = await import(${JSON.stringify(mcpModuleUrl)});`,
183
+ `const { StdioServerTransport } = await import(${JSON.stringify(stdioModuleUrl)});`,
184
+ 'const server = new McpServer({ name: "fake", version: "1.0.0" }, { capabilities: { tools: {} } });',
185
+ 'server.tool("fake_tool", "Probe-visible tool", {}, async () => ({ content: [{ type: "text", text: "ok" }] }));',
186
+ 'await server.connect(new StdioServerTransport());',
187
+ ].join("\n"),
188
+ "utf-8",
189
+ );
190
+ writeFileSync(
191
+ join(projectDir, ".mcp.json"),
192
+ JSON.stringify({ mcpServers: { "gsd-workflow": { command: process.execPath, args: [serverPath] } } }),
193
+ "utf-8",
194
+ );
195
+
196
+ let message = "";
197
+ const ctx = {
198
+ getSystemPrompt: () => "",
199
+ ui: {
200
+ notify: (text: string) => {
201
+ message = text;
202
+ },
203
+ },
204
+ };
205
+
206
+ await handleMcpStatus("status", ctx as unknown as ExtensionCommandContext);
207
+
208
+ assert.match(message, /gsd-workflow/);
209
+ assert.match(message, /available — 1 tools/);
210
+ assert.doesNotMatch(message, /disconnected/);
211
+ } finally {
212
+ process.chdir(originalCwd);
213
+ if (previousGsdHome === undefined) delete process.env.GSD_HOME;
214
+ else process.env.GSD_HOME = previousGsdHome;
215
+ rmSync(projectDir, { recursive: true, force: true });
216
+ rmSync(gsdHomeDir, { recursive: true, force: true });
217
+ clearMcpConfigCache();
218
+ }
219
+ });
220
+
221
+ test("discovers the only configured server when no server name is provided", async () => {
222
+ const previousGsdHome = process.env.GSD_HOME;
223
+ const originalCwd = process.cwd();
224
+ const projectDir = mkdtempSync(join(tmpdir(), "gsd-mcp-discover-project-"));
225
+ const gsdHomeDir = mkdtempSync(join(tmpdir(), "gsd-mcp-discover-home-"));
226
+ try {
227
+ process.env.GSD_HOME = gsdHomeDir;
228
+ process.chdir(projectDir);
229
+
230
+ const require = createRequire(import.meta.url);
231
+ const mcpModuleUrl = pathToFileURL(require.resolve("@modelcontextprotocol/sdk/server/mcp.js")).href;
232
+ const stdioModuleUrl = pathToFileURL(require.resolve("@modelcontextprotocol/sdk/server/stdio.js")).href;
233
+ const serverPath = join(projectDir, "discover-mcp-server.mjs");
234
+ writeFileSync(
235
+ serverPath,
236
+ [
237
+ `const { McpServer } = await import(${JSON.stringify(mcpModuleUrl)});`,
238
+ `const { StdioServerTransport } = await import(${JSON.stringify(stdioModuleUrl)});`,
239
+ 'const server = new McpServer({ name: "fake", version: "1.0.0" }, { capabilities: { tools: {} } });',
240
+ 'server.tool("discover_tool", "Discover-visible tool", {}, async () => ({ content: [{ type: "text", text: "ok" }] }));',
241
+ 'await server.connect(new StdioServerTransport());',
242
+ ].join("\n"),
243
+ "utf-8",
244
+ );
245
+ writeFileSync(
246
+ join(projectDir, ".mcp.json"),
247
+ JSON.stringify({ mcpServers: { "gsd-workflow": { command: process.execPath, args: [serverPath] } } }),
248
+ "utf-8",
249
+ );
250
+
251
+ let message = "";
252
+ const ctx = {
253
+ getSystemPrompt: () => "",
254
+ ui: {
255
+ notify: (text: string) => {
256
+ message = text;
257
+ },
258
+ },
259
+ };
260
+
261
+ await handleMcpStatus("discover", ctx as unknown as ExtensionCommandContext);
262
+
263
+ assert.match(message, /MCP discovery completed for gsd-workflow/);
264
+ assert.match(message, /discover_tool/);
265
+ assert.doesNotMatch(message, /Usage: \/gsd mcp/);
266
+ } finally {
267
+ process.chdir(originalCwd);
268
+ if (previousGsdHome === undefined) delete process.env.GSD_HOME;
269
+ else process.env.GSD_HOME = previousGsdHome;
270
+ rmSync(projectDir, { recursive: true, force: true });
271
+ rmSync(gsdHomeDir, { recursive: true, force: true });
272
+ clearMcpConfigCache();
273
+ }
274
+ });
275
+ });
276
+
277
+ describe("formatMcpDiscoveryResult", () => {
278
+ test("summarizes discovered tools", () => {
279
+ const result = formatMcpDiscoveryResult({
280
+ ok: true,
281
+ server: "demo",
282
+ transport: "stdio",
283
+ toolCount: 1,
284
+ tools: ["ping"],
285
+ warnings: [],
286
+ });
287
+ assert.match(result, /discovery completed/i);
288
+ assert.match(result, /ping/);
289
+ assert.match(result, /mcp_call/);
290
+ });
291
+
292
+ test("summarizes discovery failures", () => {
293
+ const result = formatMcpDiscoveryResult({
294
+ ok: false,
295
+ server: "demo",
296
+ transport: "http",
297
+ toolCount: 0,
298
+ tools: [],
299
+ warnings: ["url references unset environment variable TOKEN."],
300
+ error: "bad config",
301
+ });
302
+ assert.match(result, /discovery failed/i);
303
+ assert.match(result, /bad config/);
304
+ assert.match(result, /TOKEN/);
305
+ });
306
+ });
307
+
131
308
  describe("formatMcpConnectionTestResult", () => {
132
309
  test("summarizes successful tools/list", () => {
133
310
  const result = formatMcpConnectionTestResult({
@@ -164,6 +341,8 @@ describe("formatMcpInitResult", () => {
164
341
  assert.match(result, /created project mcp config/i);
165
342
  assert.match(result, /\/tmp\/project\/\.mcp\.json/);
166
343
  assert.match(result, /mcp-capable clients/i);
344
+ assert.match(result, /workflow and gsd-browser MCP servers/i);
345
+ assert.match(result, /Pi Providers use the managed gsd-browser engine/i);
167
346
  assert.doesNotMatch(result, /claude code/i);
168
347
  });
169
348
 
@@ -11,6 +11,16 @@ import {
11
11
  import { createMemoryRelation, listRelationsFor } from '../memory-relations.ts';
12
12
  import { saveEmbedding, getEmbeddingForMemory } from '../memory-embeddings.ts';
13
13
 
14
+ function markProcessedUnits(count = 21): void {
15
+ const now = Date.now();
16
+ for (let i = 0; i < count; i++) {
17
+ markUnitProcessed(`unit/${i}`, `file-${i}`);
18
+ _getAdapter()!
19
+ .prepare('UPDATE memory_processed_units SET processed_at = :ts WHERE unit_key = :key')
20
+ .run({ ':ts': new Date(now + i * 1000).toISOString(), ':key': `unit/${i}` });
21
+ }
22
+ }
23
+
14
24
  // ═══════════════════════════════════════════════════════════════════════════
15
25
  // enforceMemoryCap — cascade cleanup of embeddings and relations
16
26
  // ═══════════════════════════════════════════════════════════════════════════
@@ -71,14 +81,7 @@ test('memory-decay: returns decayed memory IDs', () => {
71
81
  openDatabase(':memory:');
72
82
 
73
83
  // Insert processed units — decayStaleMemories needs at least N rows.
74
- const now = Date.now();
75
- for (let i = 0; i < 21; i++) {
76
- markUnitProcessed(`unit/${i}`, `file-${i}`);
77
- // small spacing to create deterministic ordering
78
- const row = _getAdapter()!
79
- .prepare('UPDATE memory_processed_units SET processed_at = :ts WHERE unit_key = :key');
80
- row.run({ ':ts': new Date(now + i * 1000).toISOString(), ':key': `unit/${i}` });
81
- }
84
+ markProcessedUnits();
82
85
 
83
86
  // Create memory with updated_at in the distant past
84
87
  createMemory({ category: 'pattern', content: 'stale entry', confidence: 0.9 });
@@ -98,6 +101,34 @@ test('memory-decay: returns decayed memory IDs', () => {
98
101
  closeDatabase();
99
102
  });
100
103
 
104
+ test('memory-decay: skips stale decision-sourced memories', () => {
105
+ openDatabase(':memory:');
106
+ markProcessedUnits();
107
+
108
+ createMemory({ category: 'pattern', content: 'stale working note', confidence: 0.9 });
109
+ createMemory({
110
+ category: 'architecture',
111
+ content: 'decision-backed architecture memory',
112
+ confidence: 0.85,
113
+ structuredFields: { sourceDecisionId: 'D001' },
114
+ });
115
+ _getAdapter()!
116
+ .prepare("UPDATE memories SET updated_at = '2000-01-01T00:00:00Z' WHERE id IN ('MEM001', 'MEM002')")
117
+ .run({});
118
+
119
+ const decayed = decayStaleMemories(20);
120
+ assert.ok(decayed.includes('MEM001'));
121
+ assert.ok(!decayed.includes('MEM002'));
122
+
123
+ const rows = _getAdapter()!
124
+ .prepare("SELECT id, confidence FROM memories WHERE id IN ('MEM001', 'MEM002') ORDER BY id")
125
+ .all() as Array<{ id: string; confidence: number }>;
126
+ assert.ok(rows.find((row) => row.id === 'MEM001')!.confidence < 0.9);
127
+ assert.equal(rows.find((row) => row.id === 'MEM002')!.confidence, 0.85);
128
+
129
+ closeDatabase();
130
+ });
131
+
101
132
  test('memory-decay: returns empty when there are fewer processed units than the threshold', () => {
102
133
  openDatabase(':memory:');
103
134
  createMemory({ category: 'pattern', content: 'fresh' });
@@ -102,8 +102,8 @@ test("migration auto-check preserves empty DB and reports explicit recovery", as
102
102
  assert.equal(result.action, "recovery-required");
103
103
  assert.equal(result.reason, "db-empty");
104
104
  assert.deepEqual(result.afterDb, { milestones: 0, slices: 0, tasks: 0 });
105
- assert.equal(result.recoveryCommand, "/gsd recover");
106
- assert.match(result.message ?? "", /run `\/gsd recover`/);
105
+ assert.equal(result.recoveryCommand, "/gsd recover --confirm");
106
+ assert.match(result.message ?? "", /run `\/gsd recover --confirm`/);
107
107
  assert.equal(getAllMilestones().length, 0);
108
108
  assert.equal(getSliceTasks("M001", "S01").length, 0);
109
109
  } finally {
@@ -125,7 +125,7 @@ test("migration auto-check preserves DB on hierarchy count mismatch", async () =
125
125
  assert.equal(result.reason, "count-mismatch");
126
126
  assert.deepEqual(result.beforeDb, { milestones: 1, slices: 1, tasks: 0 });
127
127
  assert.deepEqual(result.afterDb, { milestones: 1, slices: 1, tasks: 0 });
128
- assert.equal(result.recoveryCommand, "/gsd recover");
128
+ assert.equal(result.recoveryCommand, "/gsd recover --confirm");
129
129
  assert.equal(getSliceTasks("M001", "S01").length, 0);
130
130
  } finally {
131
131
  cleanup(base);
@@ -13,10 +13,10 @@ test("dispatchNewMilestoneDiscuss uses discuss.md only on greenfield projects",
13
13
 
14
14
  assert.match(fnBody, /findMilestoneIds\(basePath\)\.length === 0/);
15
15
  assert.match(fnBody, /prepareAndBuildDiscussPrompt/);
16
- assert.match(fnBody, /loadPrompt\("guided-discuss-milestone"/);
16
+ assert.match(fnBody, /buildDiscussMilestonePrompt/);
17
17
  assert.match(
18
18
  fnBody,
19
- /if \(isGreenfield\)[\s\S]*prepareAndBuildDiscussPrompt[\s\S]*loadPrompt\("guided-discuss-milestone"/,
19
+ /if \(isGreenfield\)[\s\S]*prepareAndBuildDiscussPrompt[\s\S]*buildDiscussMilestonePrompt/,
20
20
  "greenfield branch must precede guided-discuss-milestone branch",
21
21
  );
22
22
  });
@@ -24,7 +24,7 @@ test("dispatchNewMilestoneDiscuss uses discuss.md only on greenfield projects",
24
24
  test("dispatchNewMilestoneDiscuss uses milestone-specific preparation guidance", () => {
25
25
  const source = readFileSync(join(__dirname, "..", "guided-flow.ts"), "utf-8");
26
26
  const fnBody = extractSourceRegion(source, "async function dispatchNewMilestoneDiscuss(");
27
- assert.match(fnBody, /buildDiscussPreparationContext\(ctx, basePath, "milestone"\)/);
27
+ assert.match(fnBody, /buildDiscussPreparationContext\(ctx, basePath, "milestone", true\)/);
28
28
  });
29
29
 
30
30
  test("launchNextMilestoneDiscuss routes through dispatchNewMilestoneDiscuss for normal path", () => {