@opengsd/gsd-pi 1.1.1-dev.616a1a1 → 1.1.1-dev.75048e7

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 (452) 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 +55 -0
  14. package/dist/resources/extensions/gsd/auto-post-unit.js +134 -10
  15. package/dist/resources/extensions/gsd/auto-prompts.js +72 -22
  16. package/dist/resources/extensions/gsd/auto-recovery.js +7 -8
  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 +18 -65
  21. package/dist/resources/extensions/gsd/auto-worktree.js +18 -5
  22. package/dist/resources/extensions/gsd/auto.js +31 -6
  23. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +89 -4
  24. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +43 -0
  25. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +56 -20
  26. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +33 -38
  27. package/dist/resources/extensions/gsd/browser-evidence.js +29 -2
  28. package/dist/resources/extensions/gsd/closeout-consistency-gate.js +61 -0
  29. package/dist/resources/extensions/gsd/commands/catalog.js +6 -1
  30. package/dist/resources/extensions/gsd/commands/handlers/core.js +6 -2
  31. package/dist/resources/extensions/gsd/commands/handlers/ops.js +9 -5
  32. package/dist/resources/extensions/gsd/commands-handlers.js +76 -11
  33. package/dist/resources/extensions/gsd/commands-maintenance.js +172 -2
  34. package/dist/resources/extensions/gsd/commands-mcp-status.js +109 -60
  35. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +3 -1
  36. package/dist/resources/extensions/gsd/commands-verdict.js +1 -1
  37. package/dist/resources/extensions/gsd/config-overlay.js +2 -1
  38. package/dist/resources/extensions/gsd/dashboard-overlay.js +21 -7
  39. package/dist/resources/extensions/gsd/docs/preferences-reference.md +8 -0
  40. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +2 -2
  41. package/dist/resources/extensions/gsd/error-classifier.js +2 -1
  42. package/dist/resources/extensions/gsd/escalation.js +4 -4
  43. package/dist/resources/extensions/gsd/exec-sandbox.js +2 -0
  44. package/dist/resources/extensions/gsd/forensics.js +74 -2
  45. package/dist/resources/extensions/gsd/gsd-db.js +42 -6
  46. package/dist/resources/extensions/gsd/guided-flow.js +119 -176
  47. package/dist/resources/extensions/gsd/mcp-filter.js +3 -0
  48. package/dist/resources/extensions/gsd/mcp-project-config.js +76 -84
  49. package/dist/resources/extensions/gsd/memory-store.js +4 -1
  50. package/dist/resources/extensions/gsd/migration-auto-check.js +2 -2
  51. package/dist/resources/extensions/gsd/milestone-closeout.js +3 -1
  52. package/dist/resources/extensions/gsd/pending-auto-start.js +0 -1
  53. package/dist/resources/extensions/gsd/post-unit-hooks.js +9 -0
  54. package/dist/resources/extensions/gsd/preferences-validation.js +39 -0
  55. package/dist/resources/extensions/gsd/prompt-loader.js +7 -0
  56. package/dist/resources/extensions/gsd/prompts/forensics.md +61 -1
  57. package/dist/resources/extensions/gsd/prompts/gate-evaluate.md +3 -1
  58. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +3 -1
  59. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  60. package/dist/resources/extensions/gsd/prompts/reactive-execute.md +3 -1
  61. package/dist/resources/extensions/gsd/prompts/run-uat.md +33 -23
  62. package/dist/resources/extensions/gsd/prompts/system.md +3 -1
  63. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +3 -3
  64. package/dist/resources/extensions/gsd/recovery-classification.js +20 -0
  65. package/dist/resources/extensions/gsd/rule-registry.js +428 -52
  66. package/dist/resources/extensions/gsd/safety/destructive-guard.js +3 -0
  67. package/dist/resources/extensions/gsd/skill-activation.js +20 -3
  68. package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +4 -2
  69. package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +1 -1
  70. package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +18 -1
  71. package/dist/resources/extensions/gsd/state-reconciliation/index.js +6 -0
  72. package/dist/resources/extensions/gsd/state.js +17 -14
  73. package/dist/resources/extensions/gsd/templates/plan.md +3 -1
  74. package/dist/resources/extensions/gsd/tool-contract.js +5 -0
  75. package/dist/resources/extensions/gsd/tool-presentation-plan.js +143 -0
  76. package/dist/resources/extensions/gsd/tools/complete-slice.js +15 -1
  77. package/dist/resources/extensions/gsd/tools/complete-task.js +11 -1
  78. package/dist/resources/extensions/gsd/tools/exec-tool.js +109 -0
  79. package/dist/resources/extensions/gsd/tools/plan-slice.js +14 -9
  80. package/dist/resources/extensions/gsd/tools/reopen-milestone.js +2 -2
  81. package/dist/resources/extensions/gsd/tools/validate-milestone.js +46 -16
  82. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +483 -6
  83. package/dist/resources/extensions/gsd/unit-context-manifest.js +8 -3
  84. package/dist/resources/extensions/gsd/unit-tool-contracts.js +169 -0
  85. package/dist/resources/extensions/gsd/validation-block-guard.js +2 -0
  86. package/dist/resources/extensions/gsd/verdict-parser.js +59 -15
  87. package/dist/resources/extensions/gsd/verification-gate.js +72 -1
  88. package/dist/resources/extensions/gsd/workflow-mcp-auto-prep.js +3 -1
  89. package/dist/resources/extensions/gsd/workflow-mcp.js +5 -73
  90. package/dist/resources/extensions/gsd/worktree-lifecycle.js +24 -0
  91. package/dist/resources/extensions/mcp-client/manager.js +31 -1
  92. package/dist/resources/extensions/shared/gsd-browser-cli.js +145 -0
  93. package/dist/rtk.d.ts +7 -1
  94. package/dist/rtk.js +27 -11
  95. package/dist/update-check.d.ts +15 -1
  96. package/dist/update-check.js +87 -12
  97. package/dist/update-cmd.d.ts +1 -0
  98. package/dist/update-cmd.js +53 -2
  99. package/dist/web/standalone/.next/BUILD_ID +1 -1
  100. package/dist/web/standalone/.next/app-path-routes-manifest.json +5 -5
  101. package/dist/web/standalone/.next/build-manifest.json +2 -2
  102. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  103. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  104. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  105. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  108. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  110. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  112. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  114. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  115. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  116. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  117. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  118. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  119. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  120. package/dist/web/standalone/.next/server/app/index.html +1 -1
  121. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  122. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  123. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  124. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  125. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  126. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  127. package/dist/web/standalone/.next/server/app-paths-manifest.json +5 -5
  128. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  129. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  130. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  131. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  132. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  133. package/package.json +5 -3
  134. package/packages/cloud-mcp-gateway/package.json +2 -2
  135. package/packages/contracts/dist/workflow.d.ts +14 -0
  136. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  137. package/packages/contracts/dist/workflow.js +16 -0
  138. package/packages/contracts/dist/workflow.js.map +1 -1
  139. package/packages/contracts/package.json +1 -1
  140. package/packages/daemon/package.json +4 -4
  141. package/packages/gsd-agent-core/dist/agent-session.d.ts +9 -0
  142. package/packages/gsd-agent-core/dist/agent-session.d.ts.map +1 -1
  143. package/packages/gsd-agent-core/dist/agent-session.js +32 -0
  144. package/packages/gsd-agent-core/dist/agent-session.js.map +1 -1
  145. package/packages/gsd-agent-core/dist/index.d.ts +1 -0
  146. package/packages/gsd-agent-core/dist/index.d.ts.map +1 -1
  147. package/packages/gsd-agent-core/dist/index.js +1 -0
  148. package/packages/gsd-agent-core/dist/index.js.map +1 -1
  149. package/packages/gsd-agent-core/dist/session/agent-session-compaction.d.ts +2 -0
  150. package/packages/gsd-agent-core/dist/session/agent-session-compaction.d.ts.map +1 -1
  151. package/packages/gsd-agent-core/dist/session/agent-session-compaction.js +8 -2
  152. package/packages/gsd-agent-core/dist/session/agent-session-compaction.js.map +1 -1
  153. package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts +7 -0
  154. package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts.map +1 -1
  155. package/packages/gsd-agent-core/dist/session/agent-session-host.js.map +1 -1
  156. package/packages/gsd-agent-core/dist/session/agent-session-prompt.d.ts.map +1 -1
  157. package/packages/gsd-agent-core/dist/session/agent-session-prompt.js +69 -1
  158. package/packages/gsd-agent-core/dist/session/agent-session-prompt.js.map +1 -1
  159. package/packages/gsd-agent-core/dist/turn-latency.d.ts +47 -0
  160. package/packages/gsd-agent-core/dist/turn-latency.d.ts.map +1 -0
  161. package/packages/gsd-agent-core/dist/turn-latency.js +123 -0
  162. package/packages/gsd-agent-core/dist/turn-latency.js.map +1 -0
  163. package/packages/gsd-agent-core/package.json +6 -6
  164. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts +21 -0
  165. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts.map +1 -0
  166. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js +213 -0
  167. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js.map +1 -0
  168. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  169. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  170. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js +10 -0
  171. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js.map +1 -1
  172. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  173. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +5 -0
  174. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
  175. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts +1 -0
  176. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  177. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +92 -31
  178. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  179. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  180. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js +7 -1
  181. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  182. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.d.ts.map +1 -1
  183. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.js +6 -0
  184. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.js.map +1 -1
  185. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-dialogs.d.ts.map +1 -1
  186. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-dialogs.js +2 -0
  187. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-dialogs.js.map +1 -1
  188. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.d.ts +1 -1
  189. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.d.ts.map +1 -1
  190. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.js +1 -1
  191. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.js.map +1 -1
  192. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  193. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js +1 -0
  194. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js.map +1 -1
  195. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.d.ts.map +1 -1
  196. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js +5 -0
  197. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js.map +1 -1
  198. package/packages/gsd-agent-modes/package.json +7 -7
  199. package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -1
  200. package/packages/mcp-server/dist/remote-questions.js +23 -9
  201. package/packages/mcp-server/dist/remote-questions.js.map +1 -1
  202. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  203. package/packages/mcp-server/dist/workflow-tools.js +84 -2
  204. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  205. package/packages/mcp-server/package.json +3 -3
  206. package/packages/native/package.json +1 -1
  207. package/packages/pi-agent-core/dist/agent-loop.js +42 -3
  208. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  209. package/packages/pi-agent-core/dist/agent.d.ts +5 -1
  210. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  211. package/packages/pi-agent-core/dist/agent.js +2 -0
  212. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  213. package/packages/pi-agent-core/dist/harness/agent-harness.d.ts.map +1 -1
  214. package/packages/pi-agent-core/dist/harness/agent-harness.js +3 -1
  215. package/packages/pi-agent-core/dist/harness/agent-harness.js.map +1 -1
  216. package/packages/pi-agent-core/dist/harness/types.d.ts +1 -0
  217. package/packages/pi-agent-core/dist/harness/types.d.ts.map +1 -1
  218. package/packages/pi-agent-core/dist/harness/types.js.map +1 -1
  219. package/packages/pi-agent-core/dist/types.d.ts +6 -1
  220. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  221. package/packages/pi-agent-core/dist/types.js.map +1 -1
  222. package/packages/pi-agent-core/package.json +1 -1
  223. package/packages/pi-ai/dist/api-registry.d.ts +2 -0
  224. package/packages/pi-ai/dist/api-registry.d.ts.map +1 -1
  225. package/packages/pi-ai/dist/api-registry.js +23 -0
  226. package/packages/pi-ai/dist/api-registry.js.map +1 -1
  227. package/packages/pi-ai/dist/image-models.generated.d.ts +15 -0
  228. package/packages/pi-ai/dist/image-models.generated.d.ts.map +1 -1
  229. package/packages/pi-ai/dist/image-models.generated.js +15 -0
  230. package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
  231. package/packages/pi-ai/dist/models.generated.d.ts +411 -39
  232. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  233. package/packages/pi-ai/dist/models.generated.js +504 -153
  234. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  235. package/packages/pi-ai/dist/stream.js +6 -6
  236. package/packages/pi-ai/dist/stream.js.map +1 -1
  237. package/packages/pi-ai/package.json +1 -1
  238. package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts +3 -0
  239. package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts.map +1 -1
  240. package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.js.map +1 -1
  241. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  242. package/packages/pi-coding-agent/dist/core/model-registry.js +2 -2
  243. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  244. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
  245. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  246. package/packages/pi-coding-agent/dist/core/settings-manager.js +11 -0
  247. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  248. package/packages/pi-coding-agent/dist/core/tools/bash.js +2 -2
  249. package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
  250. package/packages/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
  251. package/packages/pi-coding-agent/dist/core/tools/edit.js +3 -2
  252. package/packages/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
  253. package/packages/pi-coding-agent/dist/core/tools/render-utils.d.ts +1 -0
  254. package/packages/pi-coding-agent/dist/core/tools/render-utils.d.ts.map +1 -1
  255. package/packages/pi-coding-agent/dist/core/tools/render-utils.js +6 -0
  256. package/packages/pi-coding-agent/dist/core/tools/render-utils.js.map +1 -1
  257. package/packages/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
  258. package/packages/pi-coding-agent/dist/core/tools/write.js +3 -2
  259. package/packages/pi-coding-agent/dist/core/tools/write.js.map +1 -1
  260. package/packages/pi-coding-agent/package.json +7 -7
  261. package/packages/pi-tui/dist/terminal.d.ts +1 -0
  262. package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
  263. package/packages/pi-tui/dist/terminal.js +8 -4
  264. package/packages/pi-tui/dist/terminal.js.map +1 -1
  265. package/packages/pi-tui/package.json +1 -1
  266. package/packages/rpc-client/package.json +2 -2
  267. package/pkg/package.json +1 -1
  268. package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +579 -0
  269. package/src/resources/extensions/browser-tools/engine/selection.ts +19 -0
  270. package/src/resources/extensions/browser-tools/extension-manifest.json +2 -2
  271. package/src/resources/extensions/browser-tools/index.ts +60 -9
  272. package/src/resources/extensions/browser-tools/package.json +5 -1
  273. package/src/resources/extensions/browser-tools/tests/browser-engine-selection.test.mjs +35 -0
  274. package/src/resources/extensions/browser-tools/tests/managed-gsd-browser-tools.test.mjs +33 -0
  275. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +196 -16
  276. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +239 -63
  277. package/src/resources/extensions/gsd/auto/orchestrator.ts +0 -1
  278. package/src/resources/extensions/gsd/auto/phases.ts +5 -3
  279. package/src/resources/extensions/gsd/auto-dashboard.ts +98 -18
  280. package/src/resources/extensions/gsd/auto-dispatch.ts +67 -0
  281. package/src/resources/extensions/gsd/auto-post-unit.ts +166 -9
  282. package/src/resources/extensions/gsd/auto-prompts.ts +106 -15
  283. package/src/resources/extensions/gsd/auto-recovery.ts +7 -7
  284. package/src/resources/extensions/gsd/auto-runtime-state.ts +4 -0
  285. package/src/resources/extensions/gsd/auto-start.ts +112 -17
  286. package/src/resources/extensions/gsd/auto-tool-tracking.ts +1 -1
  287. package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +43 -73
  288. package/src/resources/extensions/gsd/auto-worktree.ts +23 -5
  289. package/src/resources/extensions/gsd/auto.ts +47 -5
  290. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +96 -4
  291. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +51 -0
  292. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +81 -25
  293. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +70 -63
  294. package/src/resources/extensions/gsd/browser-evidence.ts +26 -2
  295. package/src/resources/extensions/gsd/closeout-consistency-gate.ts +137 -0
  296. package/src/resources/extensions/gsd/commands/catalog.ts +6 -1
  297. package/src/resources/extensions/gsd/commands/handlers/core.ts +6 -2
  298. package/src/resources/extensions/gsd/commands/handlers/ops.ts +9 -5
  299. package/src/resources/extensions/gsd/commands-handlers.ts +76 -11
  300. package/src/resources/extensions/gsd/commands-maintenance.ts +197 -2
  301. package/src/resources/extensions/gsd/commands-mcp-status.ts +136 -58
  302. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +4 -1
  303. package/src/resources/extensions/gsd/commands-verdict.ts +1 -1
  304. package/src/resources/extensions/gsd/config-overlay.ts +3 -1
  305. package/src/resources/extensions/gsd/dashboard-overlay.ts +28 -7
  306. package/src/resources/extensions/gsd/docs/preferences-reference.md +8 -0
  307. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +2 -2
  308. package/src/resources/extensions/gsd/error-classifier.ts +2 -1
  309. package/src/resources/extensions/gsd/escalation.ts +4 -4
  310. package/src/resources/extensions/gsd/exec-sandbox.ts +4 -0
  311. package/src/resources/extensions/gsd/forensics.ts +99 -5
  312. package/src/resources/extensions/gsd/gsd-db.ts +46 -8
  313. package/src/resources/extensions/gsd/guided-flow.ts +215 -217
  314. package/src/resources/extensions/gsd/mcp-filter.ts +3 -0
  315. package/src/resources/extensions/gsd/mcp-project-config.ts +105 -88
  316. package/src/resources/extensions/gsd/memory-store.ts +4 -1
  317. package/src/resources/extensions/gsd/migration-auto-check.ts +2 -2
  318. package/src/resources/extensions/gsd/milestone-closeout.ts +3 -1
  319. package/src/resources/extensions/gsd/pending-auto-start.ts +0 -2
  320. package/src/resources/extensions/gsd/post-unit-hooks.ts +14 -1
  321. package/src/resources/extensions/gsd/preferences-types.ts +1 -1
  322. package/src/resources/extensions/gsd/preferences-validation.ts +36 -0
  323. package/src/resources/extensions/gsd/prompt-loader.ts +8 -0
  324. package/src/resources/extensions/gsd/prompts/forensics.md +61 -1
  325. package/src/resources/extensions/gsd/prompts/gate-evaluate.md +3 -1
  326. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +3 -1
  327. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  328. package/src/resources/extensions/gsd/prompts/reactive-execute.md +3 -1
  329. package/src/resources/extensions/gsd/prompts/run-uat.md +33 -23
  330. package/src/resources/extensions/gsd/prompts/system.md +3 -1
  331. package/src/resources/extensions/gsd/prompts/validate-milestone.md +3 -3
  332. package/src/resources/extensions/gsd/recovery-classification.ts +20 -0
  333. package/src/resources/extensions/gsd/rule-registry.ts +558 -58
  334. package/src/resources/extensions/gsd/rule-types.ts +2 -0
  335. package/src/resources/extensions/gsd/safety/destructive-guard.ts +3 -0
  336. package/src/resources/extensions/gsd/skill-activation.ts +20 -2
  337. package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +4 -2
  338. package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +1 -1
  339. package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +20 -0
  340. package/src/resources/extensions/gsd/state-reconciliation/index.ts +6 -0
  341. package/src/resources/extensions/gsd/state-reconciliation/types.ts +1 -0
  342. package/src/resources/extensions/gsd/state.ts +18 -14
  343. package/src/resources/extensions/gsd/templates/plan.md +3 -1
  344. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +156 -4
  345. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +123 -0
  346. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +10 -2
  347. package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +4 -1
  348. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +143 -2
  349. package/src/resources/extensions/gsd/tests/auto-start-project-milestone-reconcile.test.ts +24 -2
  350. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +12 -2
  351. package/src/resources/extensions/gsd/tests/browser-evidence.test.ts +142 -0
  352. package/src/resources/extensions/gsd/tests/check-auto-start-pending-gate.test.ts +9 -15
  353. package/src/resources/extensions/gsd/tests/check-auto-start-ready-guard.test.ts +26 -16
  354. package/src/resources/extensions/gsd/tests/commands-dispatcher-unmerged-milestone.test.ts +21 -0
  355. package/src/resources/extensions/gsd/tests/commands-dispatcher-validation-block.test.ts +38 -3
  356. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +6 -2
  357. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +30 -0
  358. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +42 -0
  359. package/src/resources/extensions/gsd/tests/dashboard-overlay.test.ts +45 -0
  360. package/src/resources/extensions/gsd/tests/deep-planning-mode-dispatch.test.ts +53 -0
  361. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +8 -0
  362. package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +50 -13
  363. package/src/resources/extensions/gsd/tests/discuss-milestone-structured-questions.test.ts +31 -0
  364. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +40 -1
  365. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +60 -0
  366. package/src/resources/extensions/gsd/tests/doctor-runtime-checks.test.ts +27 -0
  367. package/src/resources/extensions/gsd/tests/escalation.test.ts +16 -27
  368. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +18 -0
  369. package/src/resources/extensions/gsd/tests/exec-tool.test.ts +69 -0
  370. package/src/resources/extensions/gsd/tests/forensics-issue-routing.test.ts +20 -0
  371. package/src/resources/extensions/gsd/tests/forensics-prompt-rendering.test.ts +3 -0
  372. package/src/resources/extensions/gsd/tests/forensics-tool-scope.test.ts +69 -0
  373. package/src/resources/extensions/gsd/tests/gate-1b-orphan-discrimination.test.ts +31 -79
  374. package/src/resources/extensions/gsd/tests/gsd-rebuild.test.ts +199 -0
  375. package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +75 -0
  376. package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +40 -1
  377. package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +86 -0
  378. package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +5 -3
  379. package/src/resources/extensions/gsd/tests/guided-flow-state-rebuild.test.ts +40 -4
  380. package/src/resources/extensions/gsd/tests/guided-flow.test.ts +12 -9
  381. package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +4 -4
  382. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +8 -0
  383. package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +16 -0
  384. package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +72 -10
  385. package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +13 -6
  386. package/src/resources/extensions/gsd/tests/mcp-filter.test.ts +15 -0
  387. package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +100 -0
  388. package/src/resources/extensions/gsd/tests/mcp-status.test.ts +179 -0
  389. package/src/resources/extensions/gsd/tests/memory-maintenance.test.ts +39 -8
  390. package/src/resources/extensions/gsd/tests/merge-closeout-consistency-gate.test.ts +63 -0
  391. package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +10 -1
  392. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +3 -3
  393. package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +9 -1
  394. package/src/resources/extensions/gsd/tests/new-milestone-discuss-routing.test.ts +3 -3
  395. package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +54 -7
  396. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +9 -0
  397. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +39 -1
  398. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +157 -0
  399. package/src/resources/extensions/gsd/tests/post-unit-retry-on-orchestrator-bridge.test.ts +179 -0
  400. package/src/resources/extensions/gsd/tests/preferences.test.ts +29 -0
  401. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +83 -1
  402. package/src/resources/extensions/gsd/tests/prompt-loader-extension-dir.test.ts +14 -0
  403. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +18 -1
  404. package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +7 -8
  405. package/src/resources/extensions/gsd/tests/reactive-executor.test.ts +36 -0
  406. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +79 -0
  407. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +1 -1
  408. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +75 -0
  409. package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +4 -0
  410. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +36 -0
  411. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +100 -0
  412. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +55 -0
  413. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +6 -2
  414. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +191 -0
  415. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +84 -10
  416. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +19 -0
  417. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +12 -2
  418. package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +7 -1
  419. package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +29 -6
  420. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +29 -6
  421. package/src/resources/extensions/gsd/tests/validate-milestone-prompt-verification-classes.test.ts +6 -3
  422. package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +133 -0
  423. package/src/resources/extensions/gsd/tests/validation-block-guard.test.ts +21 -0
  424. package/src/resources/extensions/gsd/tests/verification-gate.test.ts +51 -0
  425. package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +17 -2
  426. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +493 -0
  427. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +40 -0
  428. package/src/resources/extensions/gsd/tool-contract.ts +6 -0
  429. package/src/resources/extensions/gsd/tool-presentation-plan.ts +223 -0
  430. package/src/resources/extensions/gsd/tools/complete-slice.ts +14 -1
  431. package/src/resources/extensions/gsd/tools/complete-task.ts +20 -2
  432. package/src/resources/extensions/gsd/tools/exec-tool.ts +130 -0
  433. package/src/resources/extensions/gsd/tools/plan-slice.ts +14 -9
  434. package/src/resources/extensions/gsd/tools/reopen-milestone.ts +2 -2
  435. package/src/resources/extensions/gsd/tools/validate-milestone.ts +46 -15
  436. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +589 -8
  437. package/src/resources/extensions/gsd/types.ts +69 -5
  438. package/src/resources/extensions/gsd/unit-context-manifest.ts +14 -5
  439. package/src/resources/extensions/gsd/unit-tool-contracts.ts +186 -0
  440. package/src/resources/extensions/gsd/validation-block-guard.ts +2 -0
  441. package/src/resources/extensions/gsd/verdict-parser.ts +54 -13
  442. package/src/resources/extensions/gsd/verification-gate.ts +87 -1
  443. package/src/resources/extensions/gsd/workflow-mcp-auto-prep.ts +2 -1
  444. package/src/resources/extensions/gsd/workflow-mcp.ts +5 -73
  445. package/src/resources/extensions/gsd/worktree-lifecycle.ts +26 -0
  446. package/src/resources/extensions/mcp-client/manager.ts +33 -1
  447. package/src/resources/extensions/mcp-client/tests/manager.test.ts +35 -0
  448. package/src/resources/extensions/shared/gsd-browser-cli.ts +172 -0
  449. package/src/resources/extensions/gsd/tests/gate-1b-recovery-bound-corrections.test.ts +0 -246
  450. package/src/resources/extensions/gsd/tests/gate-1b-recovery-bound.test.ts +0 -218
  451. /package/dist/web/standalone/.next/static/{L9N5SPFi7f-Ne4u2uXzCe → h4TGni4xJzlZjGkxaT6uU}/_buildManifest.js +0 -0
  452. /package/dist/web/standalone/.next/static/{L9N5SPFi7f-Ne4u2uXzCe → h4TGni4xJzlZjGkxaT6uU}/_ssgManifest.js +0 -0
@@ -4,7 +4,7 @@ import { isAbsolute, join, relative, resolve, sep } from "node:path";
4
4
 
5
5
  import { minimatch } from "minimatch";
6
6
 
7
- import { shouldBlockAutoUnitToolCall } from "../auto-unit-tool-scope.js";
7
+ import { GSD_PHASE_SCOPE_DISPLAY_REASON, shouldBlockAutoUnitToolCall } from "../auto-unit-tool-scope.js";
8
8
  import { getIsolationMode } from "../preferences.js";
9
9
  import { compileSubagentPermissionContract, type ToolsPolicy } from "../unit-context-manifest.js";
10
10
  import { logWarning } from "../workflow-logger.js";
@@ -679,6 +679,7 @@ const PLANNING_SUBAGENT_TOOLS = new Set(["subagent", "task"]);
679
679
  * manifests still declare per-unit subsets via ToolsPolicy.allowedSubagents.
680
680
  */
681
681
  const PLANNING_DISPATCH_AGENT_REGISTRY = {
682
+ mnemo: { readOnlySpecialist: true },
682
683
  scout: { readOnlySpecialist: true },
683
684
  planner: { readOnlySpecialist: true },
684
685
  reviewer: { readOnlySpecialist: true },
@@ -692,7 +693,7 @@ export const ALLOWED_PLANNING_DISPATCH_AGENTS = new Set<string>(
692
693
  .map(([agentId]) => agentId),
693
694
  );
694
695
 
695
- let warnedMissingPlanningDispatchAgentClasses = false;
696
+ let warnedMissingControlledDispatchAgentClasses = false;
696
697
 
697
698
  function isReadOnlySpecialist(agentId: string): boolean {
698
699
  const metadata = PLANNING_DISPATCH_AGENT_REGISTRY[agentId as keyof typeof PLANNING_DISPATCH_AGENT_REGISTRY];
@@ -703,11 +704,20 @@ function allowedPlanningDispatchAgentsList(): string {
703
704
  return [...ALLOWED_PLANNING_DISPATCH_AGENTS].join(", ");
704
705
  }
705
706
 
706
- function warnMissingPlanningDispatchAgentClasses(unitType: string, mode: string, toolName: string): void {
707
- if (warnedMissingPlanningDispatchAgentClasses) return;
708
- warnedMissingPlanningDispatchAgentClasses = true;
707
+ function allowsControlledSubagentDispatch(
708
+ policy: ToolsPolicy,
709
+ ): policy is ToolsPolicy & { readonly allowedSubagents: readonly string[] } {
710
+ return (
711
+ (policy.mode === "planning-dispatch" || policy.mode === "verification") &&
712
+ Array.isArray((policy as { readonly allowedSubagents?: unknown }).allowedSubagents)
713
+ );
714
+ }
715
+
716
+ function warnMissingControlledDispatchAgentClasses(unitType: string, mode: string, toolName: string): void {
717
+ if (warnedMissingControlledDispatchAgentClasses) return;
718
+ warnedMissingControlledDispatchAgentClasses = true;
709
719
  // TODO(#5060): Remove this migration shim once all subagent/task callers are verified to forward agent identities.
710
- const message = `[write-gate] planning-dispatch: shouldBlockPlanningUnit called for tool "${toolName}" ` +
720
+ const message = `[write-gate] controlled-dispatch: shouldBlockPlanningUnit called for tool "${toolName}" ` +
711
721
  `on unit "${unitType}" without agentClasses - stale caller; blocking dispatch.`;
712
722
  console.warn(message);
713
723
  logWarning("intercept", message, {
@@ -762,6 +772,20 @@ function blockReason(unitType: string, mode: string, what: string): string {
762
772
  ].join(" ");
763
773
  }
764
774
 
775
+ function planningBlock(unitType: string, mode: string, what: string): PlanningUnitBlockResult {
776
+ return {
777
+ block: true,
778
+ reason: blockReason(unitType, mode, what),
779
+ displayReason: GSD_PHASE_SCOPE_DISPLAY_REASON,
780
+ };
781
+ }
782
+
783
+ type PlanningUnitBlockResult = {
784
+ block: boolean;
785
+ reason?: string;
786
+ displayReason?: string;
787
+ };
788
+
765
789
  /**
766
790
  * Planning-unit tool-policy enforcement. Returns { block } per the policy
767
791
  * resolved from the active unit's manifest:
@@ -777,8 +801,9 @@ function blockReason(unitType: string, mode: string, what: string): string {
777
801
  * - "docs" → like "planning" but also allows writes to paths
778
802
  * matching `allowedPathGlobs` relative to basePath.
779
803
  * - "verification"
780
- * → allows Bash for project verification commands, but keeps
781
- * writes restricted to .gsd/ and blocks subagent dispatch.
804
+ * → allows Bash for project verification commands, keeps
805
+ * writes restricted to .gsd/, and permits subagent dispatch
806
+ * only when the manifest declares allowedSubagents.
782
807
  *
783
808
  * `pathOrCommand` is the file path for write/edit-shaped tools and the
784
809
  * shell command for bash. Other tools ignore this argument.
@@ -801,7 +826,7 @@ export function shouldBlockPlanningUnit(
801
826
  agentClasses?: readonly string[],
802
827
  toolInput?: unknown,
803
828
  unitId?: string,
804
- ): { block: boolean; reason?: string } {
829
+ ): PlanningUnitBlockResult {
805
830
  const tool = canonicalToolName(toolName);
806
831
  const autoScopeGuard = shouldBlockAutoUnitToolCall(unitType, toolName, toolInput, unitId);
807
832
  if (autoScopeGuard.block) return autoScopeGuard;
@@ -814,10 +839,10 @@ export function shouldBlockPlanningUnit(
814
839
  if (PLANNING_SAFE_TOOLS.has(tool)) return { block: false };
815
840
  if (tool.startsWith("gsd_")) return { block: false };
816
841
  if (PLANNING_WRITE_TOOLS.has(tool) || tool === "bash" || PLANNING_SUBAGENT_TOOLS.has(tool)) {
817
- return { block: true, reason: blockReason(unitType, policy.mode, `${tool} is not permitted (read-only)`) };
842
+ return planningBlock(unitType, policy.mode, `${tool} is not permitted (read-only)`);
818
843
  }
819
844
  // Unknown tool in read-only mode — block by default.
820
- return { block: true, reason: blockReason(unitType, policy.mode, `tool "${tool}" is not on the read-only allowlist`) };
845
+ return planningBlock(unitType, policy.mode, `tool "${tool}" is not on the read-only allowlist`);
821
846
  }
822
847
 
823
848
  // planning / planning-dispatch / docs / verification modes share the same surface for safe tools, bash, and subagent.
@@ -825,7 +850,7 @@ export function shouldBlockPlanningUnit(
825
850
  if (tool.startsWith("gsd_")) return { block: false };
826
851
 
827
852
  if (PLANNING_SUBAGENT_TOOLS.has(tool)) {
828
- if (policy.mode === "planning-dispatch") {
853
+ if (allowsControlledSubagentDispatch(policy)) {
829
854
  const requested = (agentClasses ?? []).map(a => a.trim()).filter(Boolean);
830
855
  const dispatchContract = compileSubagentPermissionContract(policy);
831
856
  const allowedSubagents = dispatchContract.allowedSubagents;
@@ -834,15 +859,12 @@ export function shouldBlockPlanningUnit(
834
859
  // agent identities yet. Block and warn so stale callers surface in telemetry
835
860
  // instead of silently bypassing the gate.
836
861
  if (agentClasses === undefined) {
837
- warnMissingPlanningDispatchAgentClasses(unitType, policy.mode, tool);
838
- return {
839
- block: true,
840
- reason: blockReason(
841
- unitType,
842
- policy.mode,
843
- `subagent dispatch blocked: stale caller did not supply agent identities for "${tool}"; update extractSubagentAgentClasses to handle this input shape`,
844
- ),
845
- };
862
+ warnMissingControlledDispatchAgentClasses(unitType, policy.mode, tool);
863
+ return planningBlock(
864
+ unitType,
865
+ policy.mode,
866
+ `subagent dispatch blocked: stale caller did not supply agent identities for "${tool}"; update extractSubagentAgentClasses to handle this input shape`,
867
+ );
846
868
  }
847
869
  // agentClasses was explicitly provided but resolved to an empty list (for
848
870
  // example, a bare tool call with no agent field). Pass through; no agents
@@ -852,57 +874,45 @@ export function shouldBlockPlanningUnit(
852
874
  }
853
875
  const globallyDisallowed = requested.find(a => !isReadOnlySpecialist(a));
854
876
  if (globallyDisallowed) {
855
- return {
856
- block: true,
857
- reason: blockReason(
858
- unitType,
859
- policy.mode,
860
- `subagent dispatch of "${globallyDisallowed}" not permitted; only read-only specialists (${allowedPlanningDispatchAgentsList()}) may be dispatched from planning-dispatch units`,
861
- ),
862
- };
877
+ return planningBlock(
878
+ unitType,
879
+ policy.mode,
880
+ `subagent dispatch of "${globallyDisallowed}" not permitted; only read-only specialists (${allowedPlanningDispatchAgentsList()}) may be dispatched from ${policy.mode} units`,
881
+ );
863
882
  }
864
883
  const disallowedByPolicy = requested.find(a => !allowed.has(a));
865
884
  if (disallowedByPolicy) {
866
- return {
867
- block: true,
868
- reason: blockReason(
869
- unitType,
870
- policy.mode,
871
- `subagent dispatch of "${disallowedByPolicy}" not permitted by ToolsPolicy.allowedSubagents; permitted agents for this unit: ${allowedSubagents.join(", ")}`,
872
- ),
873
- };
885
+ return planningBlock(
886
+ unitType,
887
+ policy.mode,
888
+ `subagent dispatch of "${disallowedByPolicy}" not permitted by ToolsPolicy.allowedSubagents; permitted agents for this unit: ${allowedSubagents.join(", ")}`,
889
+ );
874
890
  }
875
891
  return { block: false };
876
892
  }
877
- return { block: true, reason: blockReason(unitType, policy.mode, `subagent dispatch is not permitted in planning units`) };
893
+ return planningBlock(unitType, policy.mode, "subagent dispatch is not permitted in planning units");
878
894
  }
879
895
 
880
896
  if (tool === "bash") {
881
897
  if (policy.mode === "verification") {
882
898
  if (BASH_VERIFICATION_RE.test(pathOrCommand) || BASH_READ_ONLY_RE.test(pathOrCommand)) return { block: false };
883
- return {
884
- block: true,
885
- reason: blockReason(
886
- unitType,
887
- policy.mode,
888
- `bash is restricted to build/test verification commands (npm run build, npm test, etc.); cannot run "${pathOrCommand.slice(0, 80)}${pathOrCommand.length > 80 ? "…" : ""}"`,
889
- ),
890
- };
891
- }
892
- if (BASH_READ_ONLY_RE.test(pathOrCommand)) return { block: false };
893
- return {
894
- block: true,
895
- reason: blockReason(
899
+ return planningBlock(
896
900
  unitType,
897
901
  policy.mode,
898
- `bash is restricted to read-only commands (cat/grep/git log/etc); cannot run "${pathOrCommand.slice(0, 80)}${pathOrCommand.length > 80 ? "…" : ""}"`,
899
- ),
900
- };
902
+ `bash is restricted to build/test verification commands (npm run build, npm test, etc.); cannot run "${pathOrCommand.slice(0, 80)}${pathOrCommand.length > 80 ? "…" : ""}"`,
903
+ );
904
+ }
905
+ if (BASH_READ_ONLY_RE.test(pathOrCommand)) return { block: false };
906
+ return planningBlock(
907
+ unitType,
908
+ policy.mode,
909
+ `bash is restricted to read-only commands (cat/grep/git log/etc); cannot run "${pathOrCommand.slice(0, 80)}${pathOrCommand.length > 80 ? "…" : ""}"`,
910
+ );
901
911
  }
902
912
 
903
913
  if (PLANNING_WRITE_TOOLS.has(tool)) {
904
914
  if (!pathOrCommand) {
905
- return { block: true, reason: blockReason(unitType, policy.mode, `${tool} called with empty path`) };
915
+ return planningBlock(unitType, policy.mode, `${tool} called with empty path`);
906
916
  }
907
917
  const absPath = isAbsolute(pathOrCommand) ? pathOrCommand : resolve(basePath, pathOrCommand);
908
918
 
@@ -914,14 +924,11 @@ export function shouldBlockPlanningUnit(
914
924
  return { block: false };
915
925
  }
916
926
 
917
- return {
918
- block: true,
919
- reason: blockReason(
920
- unitType,
921
- policy.mode,
922
- `cannot ${tool} "${pathOrCommand}" — writes are restricted to .gsd/${policy.mode === "docs" ? " and " + policy.allowedPathGlobs.join(", ") : ""}`,
923
- ),
924
- };
927
+ return planningBlock(
928
+ unitType,
929
+ policy.mode,
930
+ `cannot ${tool} "${pathOrCommand}" — writes are restricted to .gsd/${policy.mode === "docs" ? " and " + policy.allowedPathGlobs.join(", ") : ""}`,
931
+ );
925
932
  }
926
933
 
927
934
  // Unknown tool name — pass through. Other layers (queue, pending-gate,
@@ -1,11 +1,13 @@
1
1
  // Project/App: gsd-pi
2
2
  // File Purpose: Shared browser-observable UAT requirement and evidence detection.
3
3
 
4
- export const BROWSER_REQUIREMENT_RE = /\b(?:browser|file:\/\/|localhost|dom|localstorage|click(?:ing|ed)?|button|screenshot|snapshot|reload(?:ed)?|page refresh|user-visible|strikethrough|search box)\b/i;
4
+ export const BROWSER_REQUIREMENT_RE = /\b(?:file:\/\/|localhost|playwright|chrome|screenshot|snapshot|browser_(?:assert|batch|find|verify|snapshot_refs))\b|\b(?:open|launch|navigate|load|visit|serve|start)\b.{0,80}\b(?:browser|page|localhost|file:\/\/)\b|\bbrowser\s+(?:check|session|test|uat|tool|automation|interaction|flow)\b/i;
5
5
  export const NO_BROWSER_EVIDENCE_RE = /\b(?:no|without|not|wasn'?t|isn'?t)\s+(?:automated\s+)?(?:live\s+)?browser(?:\s+(?:session|test|uat))?|\bno\s+automated\s+browser\b|\bnot\s+conducted\b/i;
6
6
  export const BROWSER_RUNTIME_RE = /\b(?:browser|playwright|chrome|camoufox|browser_(?:assert|batch|find|verify|snapshot_refs)|screenshot|snapshot|file:\/\/|localhost)\b/i;
7
7
  export const BROWSER_ACTION_RE = /\b(?:open(?:ed)?|navigate(?:d)?|click(?:ed)?|type(?:d)?|reload(?:ed)?|capture(?:d)?|screenshot|snapshot)\b/i;
8
8
  export const BROWSER_ASSERTION_RE = /\b(?:assert(?:ed|ion)?|observed|confirmed|verified|expected|visible|text|count|label|strikethrough|localstorage|screenshot|snapshot|passed)\b/i;
9
+ const NON_REQUIREMENT_BROWSER_HEADING_RE = /^(?:not\s+proven|not\s+covered|out\s+of\s+scope|deferred|follow-?ups?|known\s+limitations|notes\s+for\s+tester)\b/i;
10
+ const NON_REQUIREMENT_BROWSER_LINE_RE = /\b(?:deferred|not\s+proven|not\s+covered|out\s+of\s+scope|future\s+slice|follow-?up|no\s+(?:live\s+)?browser|without\s+(?:a\s+)?browser|not\s+(?:a\s+)?browser)\b/i;
9
11
 
10
12
  export function compactTextParts(parts: Array<string | string[] | null | undefined>): string {
11
13
  return parts.flatMap((part) => Array.isArray(part) ? part : [part])
@@ -14,7 +16,29 @@ export function compactTextParts(parts: Array<string | string[] | null | undefin
14
16
  }
15
17
 
16
18
  export function hasBrowserRequiredText(text: string): boolean {
17
- return BROWSER_REQUIREMENT_RE.test(text);
19
+ let inNonRequirementSection = false;
20
+ let nonRequirementDepth = 0;
21
+ for (const line of text.split(/\r?\n/)) {
22
+ const headingMatch = line.match(/^(#{1,6})\s+(.+?)\s*$/);
23
+ if (headingMatch) {
24
+ const depth = headingMatch[1]!.length;
25
+ const title = headingMatch[2] ?? "";
26
+ // Only update section context when at the same or higher level than the
27
+ // heading that opened the non-requirement zone. A sub-heading deeper than
28
+ // the opening heading must not escape or re-enter the zone on its own.
29
+ if (!inNonRequirementSection || depth <= nonRequirementDepth) {
30
+ inNonRequirementSection = NON_REQUIREMENT_BROWSER_HEADING_RE.test(title);
31
+ nonRequirementDepth = inNonRequirementSection ? depth : 0;
32
+ }
33
+ // Check the heading title itself — section state is already updated, so
34
+ // we correctly skip headings that opened a non-requirement zone.
35
+ if (!inNonRequirementSection && BROWSER_REQUIREMENT_RE.test(title)) return true;
36
+ continue;
37
+ }
38
+ if (inNonRequirementSection || NON_REQUIREMENT_BROWSER_LINE_RE.test(line)) continue;
39
+ if (BROWSER_REQUIREMENT_RE.test(line)) return true;
40
+ }
41
+ return false;
18
42
  }
19
43
 
20
44
  export function hasBrowserEvidenceText(text: string): boolean {
@@ -0,0 +1,137 @@
1
+ // Project/App: gsd-pi
2
+ // File Purpose: Shared DB-backed guard for milestone closeout finalization.
3
+
4
+ import {
5
+ getDbPath,
6
+ getLatestAssessmentByScope,
7
+ getMilestone,
8
+ getMilestoneSlices,
9
+ getPendingGates,
10
+ getSliceTasks,
11
+ isDbAvailable,
12
+ refreshOpenDatabaseFromDisk,
13
+ } from "./gsd-db.js";
14
+ import { isClosedStatus } from "./status-guards.js";
15
+
16
+ export const CLOSEOUT_CONSISTENCY_BLOCKED_REASON = "closeout-consistency-blocked";
17
+
18
+ export type CloseoutConsistencyFailureReason =
19
+ | "db-unavailable"
20
+ | "db-refresh-failed"
21
+ | "milestone-missing"
22
+ | "milestone-open"
23
+ | "validation-not-pass"
24
+ | "slice-missing"
25
+ | "slice-open"
26
+ | "task-open"
27
+ | "quality-gate-pending";
28
+
29
+ export type CloseoutConsistencyResult =
30
+ | { ok: true }
31
+ | {
32
+ ok: false;
33
+ reason: CloseoutConsistencyFailureReason;
34
+ recoveryReason: typeof CLOSEOUT_CONSISTENCY_BLOCKED_REASON;
35
+ message: string;
36
+ };
37
+
38
+ export interface CloseoutConsistencyOptions {
39
+ refreshFromDisk?: boolean;
40
+ }
41
+
42
+ function blocked(reason: CloseoutConsistencyFailureReason, message: string): CloseoutConsistencyResult {
43
+ return {
44
+ ok: false,
45
+ reason,
46
+ recoveryReason: CLOSEOUT_CONSISTENCY_BLOCKED_REASON,
47
+ message,
48
+ };
49
+ }
50
+
51
+ function isFileBackedDbPath(path: string | null): boolean {
52
+ return Boolean(path && path !== ":memory:");
53
+ }
54
+
55
+ export function checkCloseoutConsistencyGate(
56
+ milestoneId: string,
57
+ options: CloseoutConsistencyOptions = {},
58
+ ): CloseoutConsistencyResult {
59
+ if (!isDbAvailable()) {
60
+ return blocked(
61
+ "db-unavailable",
62
+ `Closeout consistency blocked for ${milestoneId}: canonical DB is unavailable.`,
63
+ );
64
+ }
65
+
66
+ if (options.refreshFromDisk && isFileBackedDbPath(getDbPath()) && !refreshOpenDatabaseFromDisk()) {
67
+ return blocked(
68
+ "db-refresh-failed",
69
+ `Closeout consistency blocked for ${milestoneId}: canonical DB refresh failed.`,
70
+ );
71
+ }
72
+
73
+ const milestone = getMilestone(milestoneId);
74
+ if (!milestone) {
75
+ return blocked(
76
+ "milestone-missing",
77
+ `Closeout consistency blocked for ${milestoneId}: milestone is missing from canonical DB.`,
78
+ );
79
+ }
80
+ if (!isClosedStatus(milestone.status)) {
81
+ return blocked(
82
+ "milestone-open",
83
+ `Closeout consistency blocked for ${milestoneId}: canonical DB milestone status is "${milestone.status}".`,
84
+ );
85
+ }
86
+
87
+ if (milestone.status !== "skipped") {
88
+ const validation = getLatestAssessmentByScope(milestoneId, "milestone-validation");
89
+ if (validation?.status !== "pass") {
90
+ return blocked(
91
+ "validation-not-pass",
92
+ `Closeout consistency blocked for ${milestoneId}: latest milestone validation is "${validation?.status ?? "absent"}".`,
93
+ );
94
+ }
95
+ }
96
+
97
+ const slices = getMilestoneSlices(milestoneId);
98
+ if (slices.length === 0 && milestone.status !== "skipped") {
99
+ return blocked(
100
+ "slice-missing",
101
+ `Closeout consistency blocked for ${milestoneId}: no slices exist in canonical DB.`,
102
+ );
103
+ }
104
+
105
+ for (const slice of slices) {
106
+ if (!isClosedStatus(slice.status)) {
107
+ return blocked(
108
+ "slice-open",
109
+ `Closeout consistency blocked for ${milestoneId}: slice ${slice.id} status is "${slice.status}".`,
110
+ );
111
+ }
112
+
113
+ for (const task of getSliceTasks(milestoneId, slice.id)) {
114
+ if (!isClosedStatus(task.status)) {
115
+ return blocked(
116
+ "task-open",
117
+ `Closeout consistency blocked for ${milestoneId}: task ${slice.id}/${task.id} status is "${task.status}".`,
118
+ );
119
+ }
120
+ }
121
+
122
+ const pendingGate = getPendingGates(milestoneId, slice.id)[0];
123
+ if (pendingGate) {
124
+ return blocked(
125
+ "quality-gate-pending",
126
+ `Closeout consistency blocked for ${milestoneId}: quality gate ${pendingGate.gate_id} is still pending for ${slice.id}.`,
127
+ );
128
+ }
129
+ }
130
+
131
+ return { ok: true };
132
+ }
133
+
134
+ export function formatCloseoutConsistencyBlock(result: CloseoutConsistencyResult): string {
135
+ if (result.ok) return "";
136
+ return `${result.message} Recovery reason: ${result.recoveryReason}. Resolve the canonical DB state and run /gsd auto to retry.`;
137
+ }
@@ -14,7 +14,7 @@ export interface GsdCommandDefinition {
14
14
  type CompletionMap = Record<string, readonly GsdCommandDefinition[]>;
15
15
 
16
16
  export const GSD_COMMAND_DESCRIPTION =
17
- "GSD — Git Ship Done: /gsd help|start|templates|next|auto|stop|pause|status|widget|visualize|brief|report|queue|quick|discuss|capture|triage|dispatch|verdict|history|undo|undo-task|reset-slice|rate|skip|export|cleanup|closeout|model|mode|prefs|config|keys|hooks|run-hook|skill-health|doctor|debug|logs|forensics|changelog|migrate|remote|steer|knowledge|memory|new-milestone|new-project|parallel|cmux|park|unpark|init|setup|onboarding|inspect|extensions|update|upgrade|fast|mcp|rethink|workflow|codebase|notifications|ship|do|usage|context|session-report|backlog|pr-branch|add-tests|scan|language|worktree|eval-review";
17
+ "GSD — Git Ship Done: /gsd help|start|templates|next|auto|stop|pause|status|widget|visualize|brief|report|queue|quick|discuss|capture|triage|dispatch|verdict|history|undo|undo-task|reset-slice|rate|skip|export|cleanup|closeout|rebuild|model|mode|prefs|config|keys|hooks|run-hook|skill-health|doctor|debug|logs|forensics|changelog|migrate|remote|steer|knowledge|memory|new-milestone|new-project|parallel|cmux|park|unpark|init|setup|onboarding|inspect|extensions|update|upgrade|fast|mcp|rethink|workflow|codebase|notifications|ship|do|usage|context|session-report|backlog|pr-branch|add-tests|scan|language|worktree|eval-review";
18
18
 
19
19
  export const TOP_LEVEL_SUBCOMMANDS: readonly GsdCommandDefinition[] = [
20
20
  { cmd: "help", desc: "Categorized command reference with descriptions" },
@@ -44,6 +44,7 @@ export const TOP_LEVEL_SUBCOMMANDS: readonly GsdCommandDefinition[] = [
44
44
  { cmd: "export", desc: "Alias for /gsd report" },
45
45
  { cmd: "cleanup", desc: "Remove merged branches or snapshots" },
46
46
  { cmd: "closeout", desc: "Recover failed git closeout actions (status, retry, resolve)" },
47
+ { cmd: "rebuild", desc: "Rebuild markdown projections from the canonical DB" },
47
48
  { cmd: "model", desc: "Switch the active session model or open a picker" },
48
49
  { cmd: "mode", desc: "Switch workflow mode (solo/team)" },
49
50
  { cmd: "prefs", desc: "Manage preferences (model selection, timeouts, etc.)" },
@@ -214,6 +215,10 @@ const NESTED_COMPLETIONS: CompletionMap = {
214
215
  { cmd: "retry", desc: "Retry the latest failed closeout git action" },
215
216
  { cmd: "resolve", desc: "Mark closeout resolved after the worktree is clean" },
216
217
  ],
218
+ rebuild: [
219
+ { cmd: "markdown", desc: "Rebuild markdown projections from the canonical DB" },
220
+ { cmd: "database", desc: "Reserved for DB-native rebuilds; does not import markdown" },
221
+ ],
217
222
  knowledge: [
218
223
  { cmd: "rule", desc: "Add a project rule (always/never do X)" },
219
224
  { cmd: "pattern", desc: "Add a code pattern to follow" },
@@ -56,6 +56,7 @@ export function showHelp(ctx: ExtensionCommandContext, args = ""): void {
56
56
  " /gsd keys API key manager (LLM + tool keys)",
57
57
  " /gsd doctor Diagnose and repair .gsd/ state",
58
58
  " /gsd closeout Recover failed git closeout actions",
59
+ " /gsd rebuild Rebuild markdown projections from the DB [markdown]",
59
60
  "",
60
61
  "Use /gsd help full for the complete command reference.",
61
62
  ];
@@ -74,7 +75,7 @@ export function showHelp(ctx: ExtensionCommandContext, args = ""): void {
74
75
  " /gsd new-milestone Create milestone from headless context (used by gsd headless)",
75
76
  " /gsd new-project Bootstrap a new project (use --deep for staged project-level discovery)",
76
77
  " /gsd quick Execute a quick task without full planning overhead",
77
- " /gsd dispatch Dispatch a specific phase directly [research|plan|execute|complete|uat|replan]",
78
+ " /gsd dispatch Dispatch a specific phase directly [research|plan|execute|complete|validate|reassess|uat|replan]",
78
79
  " /gsd verdict <v> Override milestone validation verdict [pass|needs-attention|needs-remediation] [--milestone Mxxx] [--rationale \"...\"]",
79
80
  " /gsd parallel Parallel milestone orchestration [start|status|stop|pause|resume|merge|watch]",
80
81
  " /gsd workflow Custom workflow lifecycle [new|run|list|validate|pause|resume]",
@@ -138,7 +139,7 @@ export function showHelp(ctx: ExtensionCommandContext, args = ""): void {
138
139
  " /gsd skill-health Skill lifecycle dashboard",
139
140
  " /gsd extensions Manage extensions [list|enable|disable|info]",
140
141
  " /gsd fast Toggle OpenAI service tier [on|off|flex|status]",
141
- " /gsd mcp MCP server management [status|check|test|enable|disable|import|delete|init]",
142
+ " /gsd mcp MCP server management [status|check|discover|test|enable|disable|import|delete|init]",
142
143
  "",
143
144
  "MAINTENANCE",
144
145
  " /gsd doctor Diagnose and repair .gsd/ state [audit|fix|heal] [scope]",
@@ -147,6 +148,9 @@ export function showHelp(ctx: ExtensionCommandContext, args = ""): void {
147
148
  " /gsd export Alias for /gsd report",
148
149
  " /gsd cleanup Remove merged branches or snapshots [branches|snapshots]",
149
150
  " /gsd closeout Recover failed git closeout actions [status|retry|resolve] [unit-id]",
151
+ " /gsd rebuild markdown Rebuild markdown projections from the canonical DB",
152
+ " /gsd rebuild database Reserved for DB-native rebuilds; does not import markdown",
153
+ " /gsd recover --confirm Import markdown into the DB after DB loss/corruption",
150
154
  " /gsd worktree Manage worktrees from the TUI [list|merge|clean|remove]",
151
155
  " /gsd migrate Migrate .planning/ (v1) to DB-backed .gsd/ with backup + audit",
152
156
  " /gsd remote Control remote auto-mode [slack|discord|status|disconnect]",
@@ -9,7 +9,7 @@ import { handleDoctor, handleCapture, handleKnowledge, handleRunHook, handleSkil
9
9
  import { handleInspect } from "../../commands-inspect.js";
10
10
  import { handleLogs } from "../../commands-logs.js";
11
11
  import { handleDebug } from "../../commands-debug.js";
12
- import { handleCleanupBranches, handleCleanupSnapshots, handleSkip, handleCleanupProjects, handleCleanupWorktrees, handleRecover } from "../../commands-maintenance.js";
12
+ import { handleCleanupBranches, handleCleanupSnapshots, handleSkip, handleCleanupProjects, handleCleanupWorktrees, handleRecover, handleRebuild } from "../../commands-maintenance.js";
13
13
  import { handleExport } from "../../export.js";
14
14
  import { handleHistory } from "../../history.js";
15
15
  import { handleUndo } from "../../undo.js";
@@ -146,8 +146,12 @@ export async function handleOpsCommand(trimmed: string, ctx: ExtensionCommandCon
146
146
  await handleSkip(trimmed.replace(/^skip\s*/, "").trim(), ctx, projectRoot());
147
147
  return true;
148
148
  }
149
- if (trimmed === "recover") {
150
- await handleRecover(ctx, projectRoot());
149
+ if (trimmed === "recover" || trimmed.startsWith("recover ")) {
150
+ await handleRecover(ctx, projectRoot(), trimmed.replace(/^recover\s*/, "").trim());
151
+ return true;
152
+ }
153
+ if (trimmed === "rebuild" || trimmed.startsWith("rebuild ")) {
154
+ await handleRebuild(ctx, projectRoot(), trimmed.replace(/^rebuild\s*/, "").trim());
151
155
  return true;
152
156
  }
153
157
  if (trimmed === "closeout" || trimmed.startsWith("closeout ")) {
@@ -278,8 +282,8 @@ Examples:
278
282
  await handleInspect(ctx);
279
283
  return true;
280
284
  }
281
- if (trimmed === "update" || trimmed === "upgrade") {
282
- await handleUpdate(ctx);
285
+ if (trimmed === "update" || trimmed.startsWith("update ") || trimmed === "upgrade" || trimmed.startsWith("upgrade ")) {
286
+ await handleUpdate(ctx, trimmed.replace(/^(?:update|upgrade)\s*/, "").trim());
283
287
  return true;
284
288
  }
285
289
  if (trimmed === "fast" || trimmed.startsWith("fast ")) {
@@ -7,6 +7,8 @@
7
7
 
8
8
  import type { ExtensionAPI, ExtensionCommandContext } from "@gsd/pi-coding-agent";
9
9
  import { existsSync, readFileSync, mkdirSync } from "node:fs";
10
+ import { execFileSync } from "node:child_process";
11
+ import { createRequire } from "node:module";
10
12
  import { join, resolve as resolvePath, sep } from "node:path";
11
13
  import { homedir } from "node:os";
12
14
  import { deriveState } from "./state.js";
@@ -37,7 +39,10 @@ import {
37
39
  scopeGsdWorkflowToolsForDispatch,
38
40
  } from "./bootstrap/register-hooks.js";
39
41
 
42
+ const GSD_PI_PACKAGE = "@opengsd/gsd-pi";
43
+ const GSD_BROWSER_PACKAGE = "@opengsd/gsd-browser";
40
44
  const UPDATE_REGISTRY_URL = "https://registry.npmjs.org/@opengsd%2fgsd-pi/latest";
45
+ const BROWSER_UPDATE_REGISTRY_URL = "https://registry.npmjs.org/@opengsd%2fgsd-browser/latest";
41
46
  const UPDATE_FETCH_TIMEOUT_MS = 5000;
42
47
 
43
48
  // Detects a bun-installed gsd via `process.argv[1]`. Mirrors isBunInstall in
@@ -62,12 +67,12 @@ function resolveInstallCommand(pkg: string): string {
62
67
  return `npm install -g ${pkg}`;
63
68
  }
64
69
 
65
- async function fetchLatestVersionForCommand(): Promise<string | null> {
70
+ async function fetchLatestVersionForCommand(registryUrl: string = UPDATE_REGISTRY_URL): Promise<string | null> {
66
71
  const controller = new AbortController();
67
72
  const timeout = setTimeout(() => controller.abort(), UPDATE_FETCH_TIMEOUT_MS);
68
73
 
69
74
  try {
70
- const res = await fetch(UPDATE_REGISTRY_URL, { signal: controller.signal });
75
+ const res = await fetch(registryUrl, { signal: controller.signal });
71
76
  if (!res.ok) return null;
72
77
  const data = (await res.json()) as { version?: string };
73
78
  const latest = typeof data.version === "string" ? data.version.trim().replace(/^v/, "") : "";
@@ -79,6 +84,19 @@ async function fetchLatestVersionForCommand(): Promise<string | null> {
79
84
  }
80
85
  }
81
86
 
87
+ function resolveInstalledPackageVersionForCommand(packageName: string): string | null {
88
+ try {
89
+ const requireFromHere = createRequire(import.meta.url);
90
+ const packageJsonPath = requireFromHere.resolve(`${packageName}/package.json`);
91
+ const pkg = JSON.parse(readFileSync(packageJsonPath, "utf-8")) as { version?: unknown };
92
+ return typeof pkg.version === "string" && pkg.version.trim().length > 0
93
+ ? pkg.version.trim().replace(/^v/, "")
94
+ : null;
95
+ } catch {
96
+ return null;
97
+ }
98
+ }
99
+
82
100
  export function dispatchDoctorHeal(pi: ExtensionAPI, scope: string | undefined, reportText: string, structuredIssues: string): void {
83
101
  const workflowPath = process.env.GSD_WORKFLOW_PATH ?? join(gsdHome(), "agent", "GSD-WORKFLOW.md");
84
102
  const workflow = readFileSync(workflowPath, "utf-8");
@@ -473,34 +491,81 @@ function compareSemverLocal(a: string, b: string): number {
473
491
  return 0
474
492
  }
475
493
 
476
- export async function handleUpdate(ctx: ExtensionCommandContext): Promise<void> {
494
+ function formatCommandVersion(version: string | null): string {
495
+ return version ? `v${version}` : "unknown";
496
+ }
497
+
498
+ function pickHigherVersionForCommand(a: string | null, b: string | null): string | null {
499
+ if (!a) return b;
500
+ if (!b) return a;
501
+ return compareSemverLocal(a, b) >= 0 ? a : b;
502
+ }
503
+
504
+ // Mirrors resolveGsdBrowserPathVersion in src/update-check.ts — duplicated because
505
+ // tsconfig.resources.json rootDir prevents importing from src/.
506
+ function resolveGsdBrowserPathVersionForCommand(env: NodeJS.ProcessEnv = process.env): string | null {
507
+ const explicit = env.GSD_BROWSER_PATH_VERSION?.trim();
508
+ if (explicit) return explicit.match(/\b(\d+\.\d+\.\d+)\b/)?.[1] ?? null;
509
+ try {
510
+ const out = execFileSync("gsd-browser", ["--version"], {
511
+ encoding: "utf-8",
512
+ env,
513
+ stdio: ["ignore", "pipe", "ignore"],
514
+ timeout: 2000,
515
+ });
516
+ return out.match(/\b(\d+\.\d+\.\d+)\b/)?.[1] ?? null;
517
+ } catch {
518
+ return null;
519
+ }
520
+ }
521
+
522
+ export async function handleUpdate(ctx: ExtensionCommandContext, args = ""): Promise<void> {
477
523
  const { execSync } = await import("node:child_process");
478
524
 
479
- const NPM_PACKAGE = "@opengsd/gsd-pi";
480
- const current = process.env.GSD_VERSION || "0.0.0";
525
+ const target = args.trim();
526
+ const browserUpdate = target === "browser" || target === "gsd-browser";
527
+ if (target && !browserUpdate) {
528
+ ctx.ui.notify("Usage: /gsd update [browser]", "warning");
529
+ return;
530
+ }
531
+
532
+ const NPM_PACKAGE = browserUpdate ? GSD_BROWSER_PACKAGE : GSD_PI_PACKAGE;
533
+ const registryUrl = browserUpdate ? BROWSER_UPDATE_REGISTRY_URL : UPDATE_REGISTRY_URL;
534
+ const bundledVersion = browserUpdate
535
+ ? resolveInstalledPackageVersionForCommand(GSD_BROWSER_PACKAGE)
536
+ : null;
537
+ const current = browserUpdate
538
+ ? pickHigherVersionForCommand(bundledVersion, resolveGsdBrowserPathVersionForCommand())
539
+ : process.env.GSD_VERSION || "0.0.0";
540
+ const label = browserUpdate ? "gsd-browser version" : "version";
481
541
 
482
- ctx.ui.notify(`Current version: v${current}\nChecking npm registry...`, "info");
542
+ ctx.ui.notify(`Current ${label}: ${formatCommandVersion(current)}\nChecking npm registry...`, "info");
483
543
 
484
- const latest = await fetchLatestVersionForCommand();
544
+ const latest = await fetchLatestVersionForCommand(registryUrl);
485
545
  if (!latest) {
486
546
  ctx.ui.notify("Failed to reach npm registry. Check your network connection.", "error");
487
547
  return;
488
548
  }
489
549
 
490
- if (compareSemverLocal(latest, current) <= 0) {
491
- ctx.ui.notify(`Already up to date (v${current}).`, "info");
550
+ if (current && compareSemverLocal(latest, current) <= 0) {
551
+ ctx.ui.notify(`Already up to date (${formatCommandVersion(current)}).`, "info");
492
552
  return;
493
553
  }
494
554
 
495
- ctx.ui.notify(`Updating: v${current} → v${latest}...`, "info");
555
+ ctx.ui.notify(`Updating: ${formatCommandVersion(current)} → v${latest}...`, "info");
496
556
 
497
557
  const installCmd = resolveInstallCommand(`${NPM_PACKAGE}@latest`);
498
558
  try {
499
559
  execSync(installCmd, {
500
560
  stdio: ["ignore", "pipe", "ignore"],
501
561
  });
562
+ const newPathVersion = browserUpdate ? resolveGsdBrowserPathVersionForCommand() : null;
563
+ const pathReady = !browserUpdate || (!!newPathVersion && compareSemverLocal(newPathVersion, latest) >= 0);
502
564
  ctx.ui.notify(
503
- `Updated to v${latest}. Restart your GSD session to use the new version.`,
565
+ browserUpdate
566
+ ? `Updated gsd-browser to v${latest}. Restart your GSD session to use the new browser automation version.` +
567
+ (pathReady ? "" : "\nNote: Ensure the npm global bin directory is on your PATH so MCP automation uses the updated binary.")
568
+ : `Updated to v${latest}. Restart your GSD session to use the new version.`,
504
569
  "info",
505
570
  );
506
571
  } catch {