@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
@@ -118,6 +118,37 @@ function makeRepoWithMultipleStrandedMilestones(): string {
118
118
  return base;
119
119
  }
120
120
 
121
+ function makeRepoWithActiveMismatchAndStrandedTarget(): string {
122
+ const base = mkdtempSync(join(tmpdir(), "gsd-targeted-stranded-bootstrap-"));
123
+ mkdirSync(join(base, ".gsd", "milestones", "M001"), { recursive: true });
124
+ mkdirSync(join(base, ".gsd", "milestones", "M002"), { recursive: true });
125
+ writeFileSync(
126
+ join(base, ".gsd", "PREFERENCES.md"),
127
+ "---\ngit:\n isolation: \"worktree\"\n---\n",
128
+ );
129
+ runGit(base, ["init"]);
130
+ runGit(base, ["config", "user.email", "test@test.com"]);
131
+ runGit(base, ["config", "user.name", "Test"]);
132
+ writeFileSync(join(base, "README.md"), "# test\n");
133
+ runGit(base, ["add", "-A"]);
134
+ runGit(base, ["commit", "-m", "init"]);
135
+ runGit(base, ["branch", "-M", "main"]);
136
+
137
+ runGit(base, ["checkout", "-b", "milestone/M002"]);
138
+ writeFileSync(join(base, "m002.txt"), "target stranded work\n");
139
+ runGit(base, ["add", "-A"]);
140
+ runGit(base, ["commit", "-m", "feat: M002 in progress"]);
141
+ runGit(base, ["checkout", "main"]);
142
+ runGit(base, ["worktree", "add", ".gsd/worktrees/M002", "milestone/M002"]);
143
+
144
+ openDatabase(join(base, ".gsd", "gsd.db"));
145
+ insertMilestone({ id: "M001", title: "Incorrect active milestone", status: "active" });
146
+ insertMilestone({ id: "M002", title: "Target stranded milestone", status: "active" });
147
+ closeDatabase();
148
+
149
+ return base;
150
+ }
151
+
121
152
  function makeRepoWithRecoveredCleanupAndStrandedMismatch(): string {
122
153
  const base = mkdtempSync(join(tmpdir(), "gsd-headless-stranded-bootstrap-"));
123
154
  mkdirSync(join(base, ".gsd", "milestones", "M001"), { recursive: true });
@@ -321,6 +352,9 @@ test("headless bootstrap checks stranded work before recovered-complete shortcut
321
352
  const messages = notifications.map((entry) => entry.message).join("\n");
322
353
  assert.equal(ready, false);
323
354
  assert.match(messages, /Stranded work for M002 blocks auto-mode/);
355
+ assert.match(messages, /\/gsd auto M002/);
356
+ assert.match(messages, /\/gsd park M002 "reason"/);
357
+ assert.match(messages, /\/gsd rethink/);
324
358
  assert.doesNotMatch(messages, /all milestones complete/);
325
359
  } finally {
326
360
  if (previousHeadless === undefined) {
@@ -409,6 +443,9 @@ test("bootstrap blocks active stranded recovery when another open milestone also
409
443
  assert.equal(ready, false);
410
444
  assert.deepEqual(adoptCalls, []);
411
445
  assert.match(messages, /Stranded work for M002 blocks auto-mode before M001/);
446
+ assert.match(messages, /\/gsd auto M002/);
447
+ assert.match(messages, /\/gsd park M002 "reason"/);
448
+ assert.match(messages, /explicitly discard M002/);
412
449
  } finally {
413
450
  try {
414
451
  closeDatabase();
@@ -418,6 +455,102 @@ test("bootstrap blocks active stranded recovery when another open milestone also
418
455
  }
419
456
  });
420
457
 
458
+ test("bootstrap honors explicit solo milestone lock when recovering stranded target worktree", async () => {
459
+ const base = makeRepoWithActiveMismatchAndStrandedTarget();
460
+ const previousCwd = process.cwd();
461
+ const previousLock = process.env.GSD_MILESTONE_LOCK;
462
+ const previousWorker = process.env.GSD_PARALLEL_WORKER;
463
+ const s = new AutoSession();
464
+ const adoptCalls: Array<{ milestoneId: string; mode: string }> = [];
465
+ const notifications: Array<{ message: string; level?: string }> = [];
466
+
467
+ try {
468
+ delete process.env.GSD_PARALLEL_WORKER;
469
+ process.env.GSD_MILESTONE_LOCK = "M002";
470
+
471
+ const ready = await bootstrapAutoSession(
472
+ s,
473
+ makeCtx(notifications) as any,
474
+ {
475
+ getThinkingLevel: () => "medium",
476
+ getActiveTools: () => [],
477
+ events: { emit: () => {} },
478
+ } as any,
479
+ base,
480
+ false,
481
+ false,
482
+ {
483
+ shouldUseWorktreeIsolation: () => false,
484
+ registerSigtermHandler: () => {},
485
+ registerAutoWorkerForSession: () => {},
486
+ lockBase: () => base,
487
+ buildLifecycle: () => ({
488
+ adoptSessionRoot: (sessionBase: string, originalBase?: string) => {
489
+ s.basePath = sessionBase;
490
+ if (originalBase !== undefined) {
491
+ s.originalBasePath = originalBase;
492
+ } else if (!s.originalBasePath) {
493
+ s.originalBasePath = sessionBase;
494
+ }
495
+ },
496
+ enterMilestone: () => ({ ok: true, mode: "worktree", path: base }),
497
+ adoptStrandedMilestone: (
498
+ milestoneId: string,
499
+ sessionBase: string,
500
+ _ctx: unknown,
501
+ opts: { mode: "worktree" | "branch" },
502
+ ) => {
503
+ adoptCalls.push({ milestoneId, mode: opts.mode });
504
+ s.basePath = sessionBase;
505
+ s.originalBasePath = sessionBase;
506
+ s.strandedRecoveryIsolationMode = opts.mode;
507
+ return { ok: true, mode: opts.mode, path: sessionBase };
508
+ },
509
+ adoptOrphanWorktree: <T extends { merged: boolean }>(
510
+ _mid: string,
511
+ _base: string,
512
+ run: () => T,
513
+ ): T => run(),
514
+ }) as any,
515
+ },
516
+ {
517
+ classification: "none",
518
+ lock: null,
519
+ pausedSession: null,
520
+ state: null,
521
+ recovery: null,
522
+ recoveryPrompt: null,
523
+ recoveryToolCallCount: 0,
524
+ artifactSatisfied: false,
525
+ hasResumableDiskState: false,
526
+ isBootstrapCrash: false,
527
+ },
528
+ );
529
+
530
+ const messages = notifications.map((entry) => entry.message).join("\n");
531
+ assert.equal(ready, true);
532
+ assert.deepEqual(adoptCalls, [{ milestoneId: "M002", mode: "worktree" }]);
533
+ assert.equal(s.currentMilestoneId, "M002");
534
+ assert.match(messages, /Resuming saved milestone work for M002/);
535
+ assert.doesNotMatch(messages, /blocks auto-mode before M001/);
536
+ assert.doesNotMatch(messages, /Stranded work for in-progress milestone M002/);
537
+ assert.ok(
538
+ notifications.some((entry) => entry.level === "info" && entry.message.includes("Resuming saved milestone work for M002")),
539
+ "active recovery should be presented as an info-level resume",
540
+ );
541
+ } finally {
542
+ if (previousLock === undefined) delete process.env.GSD_MILESTONE_LOCK;
543
+ else process.env.GSD_MILESTONE_LOCK = previousLock;
544
+ if (previousWorker === undefined) delete process.env.GSD_PARALLEL_WORKER;
545
+ else process.env.GSD_PARALLEL_WORKER = previousWorker;
546
+ try {
547
+ closeDatabase();
548
+ } catch {}
549
+ process.chdir(previousCwd);
550
+ rmSync(base, { recursive: true, force: true });
551
+ }
552
+ });
553
+
421
554
  test("bootstrap adopts stranded active branch even when isolation is none", async () => {
422
555
  const base = makeRepoWithStrandedActiveMilestone();
423
556
  const previousCwd = process.cwd();
@@ -496,7 +629,11 @@ test("bootstrap adopts stranded active branch even when isolation is none", asyn
496
629
  assert.equal(s.strandedRecoveryIsolationMode, "branch");
497
630
  assert.match(
498
631
  notifications.map((entry) => entry.message).join("\n"),
499
- /Recovering stranded work for M001/,
632
+ /Resuming saved milestone work for M001/,
633
+ );
634
+ assert.ok(
635
+ notifications.every((entry) => entry.level !== "warning" || !entry.message.includes("Stranded work for in-progress milestone M001")),
636
+ "adopting the active milestone should not emit a scary stranded-work warning",
500
637
  );
501
638
  } finally {
502
639
  try {
@@ -585,7 +722,11 @@ test("bootstrap adopts stranded active branch before deep project setup", async
585
722
  assert.equal(s.strandedRecoveryIsolationMode, "branch");
586
723
  assert.match(
587
724
  notifications.map((entry) => entry.message).join("\n"),
588
- /Recovering stranded work for M001/,
725
+ /Resuming saved milestone work for M001/,
726
+ );
727
+ assert.ok(
728
+ notifications.every((entry) => entry.level !== "warning" || !entry.message.includes("Stranded work for in-progress milestone M001")),
729
+ "adopting the active milestone should not emit a scary stranded-work warning",
589
730
  );
590
731
  } finally {
591
732
  try {
@@ -4,13 +4,35 @@ import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
4
4
  import { join } from "node:path";
5
5
  import { tmpdir } from "node:os";
6
6
 
7
- import { closeDatabase, getAllMilestones, insertMilestone, isDbAvailable, openDatabase } from "../gsd-db.ts";
8
- import { reconcileProjectMilestonesFromDisk } from "../auto-start.ts";
7
+ import { closeDatabase, getAllMilestones, getMilestone, insertMilestone, isDbAvailable, openDatabase } from "../gsd-db.ts";
8
+ import { reconcileMergedMilestonesFromJournal, reconcileProjectMilestonesFromDisk } from "../auto-start.ts";
9
+ import { emitWorktreeMerged } from "../worktree-telemetry.ts";
9
10
 
10
11
  test.afterEach(() => {
11
12
  if (isDbAvailable()) closeDatabase();
12
13
  });
13
14
 
15
+ test("bootstrap reconciliation treats a successful worktree merge as milestone closed", () => {
16
+ const base = mkdtempSync(join(tmpdir(), "gsd-merged-reconcile-"));
17
+ try {
18
+ mkdirSync(join(base, ".gsd"), { recursive: true });
19
+ openDatabase(join(base, ".gsd", "gsd.db"));
20
+ insertMilestone({ id: "M001", title: "Merged Milestone", status: "active" });
21
+
22
+ emitWorktreeMerged(base, "M001", { reason: "milestone-complete", conflict: false });
23
+
24
+ const closed = reconcileMergedMilestonesFromJournal(base);
25
+ const row = getMilestone("M001");
26
+
27
+ assert.equal(closed, 1);
28
+ assert.equal(row?.status, "complete");
29
+ assert.ok(row?.completed_at);
30
+ } finally {
31
+ if (isDbAvailable()) closeDatabase();
32
+ rmSync(base, { recursive: true, force: true });
33
+ }
34
+ });
35
+
14
36
  test("#5389: bootstrap reconciles PROJECT.md milestones that are missing from DB", () => {
15
37
  const base = mkdtempSync(join(tmpdir(), "gsd-project-reconcile-"));
16
38
  try {
@@ -0,0 +1,142 @@
1
+ // Project/App: gsd-pi
2
+ // File Purpose: Unit tests for hasBrowserRequiredText heading-depth section guard.
3
+
4
+ import { describe, test } from 'node:test';
5
+ import assert from 'node:assert/strict';
6
+
7
+ import { hasBrowserRequiredText } from '../browser-evidence.ts';
8
+
9
+ describe('hasBrowserRequiredText', () => {
10
+ test('detects browser requirement in a plain test-cases section', () => {
11
+ const text = [
12
+ '## Test Cases',
13
+ '',
14
+ '1. Open index.html in a browser and navigate to /dashboard.',
15
+ '',
16
+ ].join('\n');
17
+ assert.ok(hasBrowserRequiredText(text), 'plain browser step should be detected');
18
+ });
19
+
20
+ test('ignores browser mention under a top-level non-requirement heading', () => {
21
+ const text = [
22
+ '## Not Proven',
23
+ '',
24
+ '- Keyboard usability through a real browser.',
25
+ '- Browser console cleanliness.',
26
+ '',
27
+ ].join('\n');
28
+ assert.ok(!hasBrowserRequiredText(text), 'browser mention under "Not Proven" should be ignored');
29
+ });
30
+
31
+ test('sub-heading inside a non-requirement section does not re-enable detection', () => {
32
+ // BUG (pre-fix): ### sub-heading under ## Not Proven resets inNonRequirementSection
33
+ // to false, causing subsequent lines to be detected as browser requirements.
34
+ const text = [
35
+ '## Not Proven By This UAT',
36
+ '',
37
+ '- No live browser session was used.',
38
+ '',
39
+ '### Visual Checks',
40
+ '',
41
+ '- Browser visual polish deferred to next slice.',
42
+ '- Keyboard interaction in a real browser is not proven here.',
43
+ '',
44
+ ].join('\n');
45
+ assert.ok(
46
+ !hasBrowserRequiredText(text),
47
+ 'sub-heading under a non-requirement section must not re-enable browser detection',
48
+ );
49
+ });
50
+
51
+ test('requirement-level heading after non-requirement section re-enables detection', () => {
52
+ const text = [
53
+ '## Not Proven',
54
+ '',
55
+ '- Browser polish deferred.',
56
+ '',
57
+ '## Test Cases',
58
+ '',
59
+ '1. Launch browser and open localhost.',
60
+ '',
61
+ ].join('\n');
62
+ assert.ok(
63
+ hasBrowserRequiredText(text),
64
+ 'browser step under "Test Cases" (same depth as "Not Proven") must still be detected',
65
+ );
66
+ });
67
+
68
+ test('deferred sub-heading inside a requirement section scopes exclusion to its own block', () => {
69
+ const text = [
70
+ '## Test Cases',
71
+ '',
72
+ '1. Open browser at localhost.',
73
+ '',
74
+ '### Deferred: keyboard check',
75
+ '',
76
+ '- Keyboard UAT deferred to next slice.',
77
+ '',
78
+ '### Step 2: Verify DOM',
79
+ '',
80
+ '1. Navigate to /dashboard in the browser.',
81
+ '',
82
+ ].join('\n');
83
+ assert.ok(
84
+ hasBrowserRequiredText(text),
85
+ 'browser step under "Step 2" sub-heading must be detected after a sibling "Deferred" sub-heading',
86
+ );
87
+ });
88
+
89
+ test('deferred sub-heading at same depth as test cases does not escape to parent', () => {
90
+ const text = [
91
+ '## Test Cases',
92
+ '',
93
+ '### Deferred: responsive layout',
94
+ '',
95
+ '- Responsive layout check is deferred to S02.',
96
+ '',
97
+ ].join('\n');
98
+ assert.ok(
99
+ !hasBrowserRequiredText(text),
100
+ 'content under a "Deferred" sub-heading should be excluded from detection',
101
+ );
102
+ });
103
+
104
+ test('detects browser requirement written only in a heading', () => {
105
+ // Regression: the line-by-line scan previously skip-continued past headings,
106
+ // missing browser obligations expressed only in heading text.
107
+ const text = '## Open browser session at localhost\n';
108
+ assert.ok(hasBrowserRequiredText(text), 'browser requirement in heading text must be detected');
109
+ });
110
+
111
+ test('heading that opens a non-requirement section is not itself detected as a requirement', () => {
112
+ const text = '## Not Proven\n\n- Some note.\n';
113
+ assert.ok(
114
+ !hasBrowserRequiredText(text),
115
+ 'a non-requirement section heading should not trigger browser detection',
116
+ );
117
+ });
118
+
119
+ test('returns false for empty text', () => {
120
+ assert.ok(!hasBrowserRequiredText(''), 'empty string returns false');
121
+ });
122
+
123
+ test('notes-for-tester heading with sub-headings stays non-requirement', () => {
124
+ const text = [
125
+ '## Notes for Tester',
126
+ '',
127
+ '### Browser Setup',
128
+ '',
129
+ '- Run this spec without a browser; a DOM harness is sufficient.',
130
+ '- Browser-based visual checks are deferred.',
131
+ '',
132
+ '### Follow-up Items',
133
+ '',
134
+ '- Track browser session evidence in S02.',
135
+ '',
136
+ ].join('\n');
137
+ assert.ok(
138
+ !hasBrowserRequiredText(text),
139
+ 'sub-headings under "Notes for Tester" should not re-enable browser detection',
140
+ );
141
+ });
142
+ });
@@ -40,10 +40,12 @@ function makeMockCtx(base: string): {
40
40
  calls: NotifyCall[];
41
41
  widgets: Array<[string, unknown]>;
42
42
  statuses: Array<[string, string | undefined]>;
43
+ newSessions: Array<{ workspaceRoot?: string }>;
43
44
  } {
44
45
  const calls: NotifyCall[] = [];
45
46
  const widgets: Array<[string, unknown]> = [];
46
47
  const statuses: Array<[string, string | undefined]> = [];
48
+ const newSessions: Array<{ workspaceRoot?: string }> = [];
47
49
  return {
48
50
  ctx: {
49
51
  cwd: base,
@@ -58,10 +60,15 @@ function makeMockCtx(base: string): {
58
60
  statuses.push([key, value]);
59
61
  },
60
62
  },
63
+ newSession: async (options?: { workspaceRoot?: string }) => {
64
+ newSessions.push(options ?? {});
65
+ return { cancelled: false };
66
+ },
61
67
  },
62
68
  calls,
63
69
  widgets,
64
70
  statuses,
71
+ newSessions,
65
72
  };
66
73
  }
67
74
 
@@ -77,7 +84,10 @@ function makeMockPi(): { pi: any; messages: SentMessage[] } {
77
84
  };
78
85
  }
79
86
 
80
- function seedValidationBlockedMilestone(base: string): void {
87
+ function seedValidationBlockedMilestone(
88
+ base: string,
89
+ status: "needs-attention" | "needs-remediation" = "needs-attention",
90
+ ): void {
81
91
  openDatabase(join(base, ".gsd", "gsd.db"));
82
92
  insertMilestone({ id: "M006", title: "Mark All Complete", status: "active" });
83
93
  insertSlice({
@@ -91,9 +101,9 @@ function seedValidationBlockedMilestone(base: string): void {
91
101
  insertAssessment({
92
102
  path: "milestones/M006/M006-VALIDATION.md",
93
103
  milestoneId: "M006",
94
- status: "needs-attention",
104
+ status,
95
105
  scope: "milestone-validation",
96
- fullContent: "verdict: needs-attention",
106
+ fullContent: `verdict: ${status}`,
97
107
  });
98
108
  invalidateStateCache();
99
109
  }
@@ -155,6 +165,31 @@ test("dispatcher blocks workflow-advancing aliases while validation is blocked",
155
165
  }
156
166
  });
157
167
 
168
+ test("dispatcher allows reassess dispatch while validation needs remediation", async () => {
169
+ const base = makeBase();
170
+ try {
171
+ seedValidationBlockedMilestone(base, "needs-remediation");
172
+ const { ctx, calls, newSessions } = makeMockCtx(base);
173
+ const { pi, messages } = makeMockPi();
174
+
175
+ await handleGSDCommand("dispatch reassess", ctx, pi);
176
+
177
+ assert.equal(messages.length, 1);
178
+ assert.equal(messages[0].customType, "gsd-dispatch");
179
+ assert.equal(messages[0].display, false);
180
+ assert.match(messages[0].content, /UNIT: Reassess Roadmap/);
181
+ assert.ok(
182
+ calls.some((call) => call.kind === "info" && /Dispatching reassess-roadmap for M006\/S01/.test(call.message)),
183
+ `expected reassess dispatch notification, got: ${JSON.stringify(calls)}`,
184
+ );
185
+ assert.deepEqual(newSessions, [{ workspaceRoot: base }]);
186
+ } finally {
187
+ closeDatabase();
188
+ invalidateStateCache();
189
+ cleanup(base);
190
+ }
191
+ });
192
+
158
193
  test("dispatcher still allows recovery commands while validation is blocked", async () => {
159
194
  const base = makeBase();
160
195
  try {
@@ -399,8 +399,12 @@ test("handleVerdict needs-remediation override with --rationale rewrites verdict
399
399
  assert.match(rewritten, /found missing slice/);
400
400
 
401
401
  assert.ok(
402
- calls.some((c) => /gsd_reassess_roadmap/.test(c.message)),
403
- "needs-remediation override should suggest gsd_reassess_roadmap follow-up",
402
+ calls.some((c) => /\/gsd dispatch reassess/.test(c.message)),
403
+ "needs-remediation override should suggest the reassess dispatch follow-up",
404
+ );
405
+ assert.ok(
406
+ calls.every((c) => !/gsd_reassess_roadmap/.test(c.message)),
407
+ "needs-remediation override should not expose the internal tool name",
404
408
  );
405
409
  } finally {
406
410
  closeDatabase();
@@ -12,6 +12,7 @@ import { tmpdir } from "node:os";
12
12
 
13
13
  import { buildSliceSummaryExcerpt, buildCompleteMilestonePrompt, buildValidateMilestonePrompt } from "../auto-prompts.ts";
14
14
  import { invalidateAllCaches } from "../cache.ts";
15
+ import { closeDatabase, insertMilestone, openDatabase } from "../gsd-db.ts";
15
16
 
16
17
  // ─── Fixture helpers ──────────────────────────────────────────────────────
17
18
 
@@ -364,3 +365,32 @@ test("validate-milestone prompt uses slice excerpts and on-demand paths instead
364
365
  "validate prompt must not inline full assessment traces",
365
366
  );
366
367
  });
368
+
369
+ test("validate-milestone prompt inlines planned verification classes as canonical rows", async (t) => {
370
+ const base = createBase();
371
+ t.after(() => {
372
+ try { closeDatabase(); } catch { /* ignore */ }
373
+ cleanup(base);
374
+ });
375
+ invalidateAllCaches();
376
+
377
+ openDatabase(join(base, ".gsd", "gsd.db"));
378
+ insertMilestone({
379
+ id: "M001",
380
+ planning: {
381
+ verificationContract: "Local command exits 0.",
382
+ verificationOperational: "No long-running child process remains.",
383
+ },
384
+ });
385
+ writeRoadmap(base, makeRoadmap());
386
+ writeSummary(base, "S01", makeFatSummary("S01"));
387
+ writeSummary(base, "S02", makeFatSummary("S02"));
388
+
389
+ const prompt = await buildValidateMilestonePrompt("M001", "Test Milestone", base);
390
+
391
+ assert.match(prompt, /### Verification Classes \(from planning\)/);
392
+ assert.match(prompt, /Every row in this table must appear in `verificationClasses`/);
393
+ assert.match(prompt, /\| Class \| Planned Check \|/);
394
+ assert.match(prompt, /\| Contract \| Local command exits 0\. \|/);
395
+ assert.match(prompt, /\| Operational \| No long-running child process remains\. \|/);
396
+ });
@@ -20,6 +20,7 @@ import {
20
20
  insertMilestone,
21
21
  insertSlice,
22
22
  insertTask,
23
+ setSliceSummaryMd,
23
24
  } from '../gsd-db.ts';
24
25
  import { handleCompleteSlice } from '../tools/complete-slice.ts';
25
26
  import type { CompleteSliceParams } from '../types.ts';
@@ -153,4 +154,45 @@ describe('complete-slice verification gate (#3580)', () => {
153
154
  );
154
155
  }
155
156
  });
157
+
158
+ test('backfills prior verification narrative when verification is omitted on re-completion', async () => {
159
+ // Seed full_summary_md with a prior verification narrative (simulates a
160
+ // previous completion where the verification text was recorded).
161
+ const priorVerification = 'All 12 API integration tests pass — zero regressions detected.';
162
+ const priorSummary = [
163
+ '---',
164
+ 'verification_result: passed',
165
+ '---',
166
+ '',
167
+ '# S01: Test Slice',
168
+ '',
169
+ '## What Happened',
170
+ '',
171
+ 'narrative goes here',
172
+ '',
173
+ '## Verification',
174
+ '',
175
+ priorVerification,
176
+ '',
177
+ '## Requirements Advanced',
178
+ '',
179
+ ].join('\n');
180
+ setSliceSummaryMd('M001', 'S01', priorSummary, '');
181
+
182
+ // Complete slice without providing verification — handler must backfill
183
+ // from the existing summary rather than writing an empty section.
184
+ const result = await handleCompleteSlice(
185
+ makeParams({ verification: undefined }),
186
+ basePath,
187
+ );
188
+
189
+ assert.ok(!('error' in result), `expected success, got: ${'error' in result ? (result as { error: string }).error : ''}`);
190
+
191
+ const { summaryPath } = result as { summaryPath: string };
192
+ const written = fs.readFileSync(summaryPath, 'utf8');
193
+ assert.ok(
194
+ written.includes(priorVerification),
195
+ `prior verification narrative must be preserved when verification is omitted; got:\n${written}`,
196
+ );
197
+ });
156
198
  });
@@ -6,6 +6,7 @@ import test from "node:test";
6
6
  import assert from "node:assert/strict";
7
7
 
8
8
  import { GSDDashboardOverlay } from "../dashboard-overlay.ts";
9
+ import type { UnitMetrics } from "../metrics.ts";
9
10
  import { assertFullOuterBorder } from "./tui-border-assertions.ts";
10
11
 
11
12
  const fakeTheme = {
@@ -23,3 +24,47 @@ test("GSDDashboardOverlay renders inside the shared full border", (t) => {
23
24
  assert.ok(lines.some((line) => line.startsWith("│")), "body rows should have side borders");
24
25
  assert.match(lines.at(-1) ?? "", /^╰─+╯$/);
25
26
  });
27
+
28
+ test("GSDDashboardOverlay reuses metrics aggregations until the unit count changes", (t) => {
29
+ const overlay = new GSDDashboardOverlay({ requestRender() {} }, fakeTheme as any, () => {});
30
+ t.after(() => overlay.dispose());
31
+
32
+ const firstUnits = [makeUnit("M001/S001/T001", 0.25)];
33
+ const firstMetrics = (overlay as any).ensureMetricsCache(firstUnits);
34
+
35
+ overlay.invalidate();
36
+
37
+ const sameCountUnits = [makeUnit("M001/S001/T002", 0.5)];
38
+ const sameCountMetrics = (overlay as any).ensureMetricsCache(sameCountUnits);
39
+ assert.equal(sameCountMetrics, firstMetrics, "same unit count should reuse cached metrics");
40
+ assert.equal(sameCountMetrics.totals.cost, 0.25);
41
+
42
+ const increasedCountMetrics = (overlay as any).ensureMetricsCache([
43
+ ...sameCountUnits,
44
+ makeUnit("M001/S001/T003", 0.75),
45
+ ]);
46
+ assert.notEqual(increasedCountMetrics, firstMetrics, "changed unit count should recompute metrics");
47
+ assert.equal(increasedCountMetrics.totals.units, 2);
48
+ assert.equal(increasedCountMetrics.totals.cost, 1.25);
49
+ });
50
+
51
+ function makeUnit(id: string, cost: number): UnitMetrics {
52
+ return {
53
+ type: "execute-task",
54
+ id,
55
+ model: "claude-sonnet-4.5",
56
+ startedAt: 1000,
57
+ finishedAt: 2000,
58
+ tokens: {
59
+ input: 100,
60
+ output: 50,
61
+ cacheRead: 25,
62
+ cacheWrite: 10,
63
+ total: 185,
64
+ },
65
+ cost,
66
+ toolCalls: 1,
67
+ assistantMessages: 1,
68
+ userMessages: 1,
69
+ };
70
+ }