gsd-pi 2.65.0-dev.5c8557b → 2.65.0-dev.6cc5110

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 (305) hide show
  1. package/dist/mcp-server.js +6 -2
  2. package/dist/resources/extensions/browser-tools/capture.js +20 -1
  3. package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +93 -0
  4. package/dist/resources/extensions/gsd/auto/run-unit.js +13 -2
  5. package/dist/resources/extensions/gsd/auto/session.js +4 -0
  6. package/dist/resources/extensions/gsd/auto-dispatch.js +99 -9
  7. package/dist/resources/extensions/gsd/auto-model-selection.js +7 -5
  8. package/dist/resources/extensions/gsd/auto-post-unit.js +17 -6
  9. package/dist/resources/extensions/gsd/auto-prompts.js +24 -0
  10. package/dist/resources/extensions/gsd/auto-recovery.js +40 -22
  11. package/dist/resources/extensions/gsd/auto-start.js +42 -11
  12. package/dist/resources/extensions/gsd/auto-tool-tracking.js +10 -0
  13. package/dist/resources/extensions/gsd/auto-worktree.js +29 -7
  14. package/dist/resources/extensions/gsd/auto.js +21 -15
  15. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +17 -4
  16. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +10 -0
  17. package/dist/resources/extensions/gsd/bootstrap/query-tools.js +6 -4
  18. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +5 -1
  19. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +4 -1
  20. package/dist/resources/extensions/gsd/commands/context.js +8 -1
  21. package/dist/resources/extensions/gsd/commands/handlers/core.js +20 -0
  22. package/dist/resources/extensions/gsd/commands-extensions.js +1 -1
  23. package/dist/resources/extensions/gsd/config-overlay.js +312 -0
  24. package/dist/resources/extensions/gsd/db-writer.js +13 -3
  25. package/dist/resources/extensions/gsd/detection.js +1 -1
  26. package/dist/resources/extensions/gsd/dispatch-guard.js +2 -1
  27. package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -0
  28. package/dist/resources/extensions/gsd/doctor.js +2 -1
  29. package/dist/resources/extensions/gsd/gitignore.js +1 -0
  30. package/dist/resources/extensions/gsd/gsd-db.js +11 -2
  31. package/dist/resources/extensions/gsd/guided-flow.js +220 -29
  32. package/dist/resources/extensions/gsd/json-persistence.js +5 -2
  33. package/dist/resources/extensions/gsd/md-importer.js +14 -7
  34. package/dist/resources/extensions/gsd/parallel-orchestrator.js +17 -11
  35. package/dist/resources/extensions/gsd/pre-execution-checks.js +12 -5
  36. package/dist/resources/extensions/gsd/preferences-types.js +3 -0
  37. package/dist/resources/extensions/gsd/preferences-validation.js +45 -1
  38. package/dist/resources/extensions/gsd/preferences.js +9 -2
  39. package/dist/resources/extensions/gsd/preparation.js +1092 -0
  40. package/dist/resources/extensions/gsd/prompt-validation.js +67 -0
  41. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +3 -3
  42. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  43. package/dist/resources/extensions/gsd/prompts/discuss-prepared.md +424 -0
  44. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +4 -1
  45. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -4
  46. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +23 -0
  47. package/dist/resources/extensions/gsd/prompts/rethink.md +2 -1
  48. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +56 -23
  49. package/dist/resources/extensions/gsd/quick.js +19 -15
  50. package/dist/resources/extensions/gsd/reactive-graph.js +12 -0
  51. package/dist/resources/extensions/gsd/roadmap-slices.js +24 -5
  52. package/dist/resources/extensions/gsd/safety/content-validator.js +3 -3
  53. package/dist/resources/extensions/gsd/session-lock.js +23 -1
  54. package/dist/resources/extensions/gsd/state.js +112 -22
  55. package/dist/resources/extensions/gsd/templates/context-enhanced.md +138 -0
  56. package/dist/resources/extensions/gsd/tools/complete-milestone.js +15 -3
  57. package/dist/resources/extensions/gsd/tools/complete-slice.js +27 -6
  58. package/dist/resources/extensions/gsd/tools/complete-task.js +31 -7
  59. package/dist/resources/extensions/gsd/tools/plan-milestone.js +7 -5
  60. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +5 -2
  61. package/dist/resources/extensions/gsd/tools/reopen-milestone.js +119 -0
  62. package/dist/resources/extensions/gsd/tools/reopen-slice.js +30 -0
  63. package/dist/resources/extensions/gsd/tools/reopen-task.js +18 -0
  64. package/dist/resources/extensions/gsd/triage-resolution.js +33 -16
  65. package/dist/resources/extensions/gsd/undo.js +3 -2
  66. package/dist/resources/extensions/gsd/workflow-logger.js +1 -1
  67. package/dist/resources/extensions/gsd/workflow-projections.js +4 -7
  68. package/dist/resources/extensions/gsd/workflow-reconcile.js +100 -9
  69. package/dist/resources/extensions/gsd/workflow-templates.js +11 -2
  70. package/dist/resources/extensions/gsd/worktree-manager.js +5 -2
  71. package/dist/resources/extensions/gsd/worktree.js +9 -0
  72. package/dist/resources/extensions/shared/interview-ui.js +1 -1
  73. package/dist/web/standalone/.next/BUILD_ID +1 -1
  74. package/dist/web/standalone/.next/app-path-routes-manifest.json +18 -18
  75. package/dist/web/standalone/.next/build-manifest.json +3 -3
  76. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  77. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  78. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  79. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  87. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/index.html +1 -1
  95. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app-paths-manifest.json +18 -18
  102. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  103. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  104. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  105. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  106. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  107. package/dist/web/standalone/.next/static/chunks/6502.8874bcae249c02e1.js +9 -0
  108. package/dist/web/standalone/.next/static/chunks/{webpack-a1c1e452c6b32d04.js → webpack-9fed74684e1c5bb1.js} +1 -1
  109. package/package.json +1 -1
  110. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
  111. package/packages/pi-coding-agent/dist/core/retry-handler.js +30 -19
  112. package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
  113. package/packages/pi-coding-agent/dist/core/retry-handler.test.js +51 -0
  114. package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
  115. package/packages/pi-coding-agent/dist/core/sdk.js +9 -9
  116. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  117. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts +2 -1
  118. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
  119. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +10 -1
  120. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
  121. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +1 -0
  122. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  123. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +20 -5
  124. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  125. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +15 -1
  126. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  127. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +18 -0
  128. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
  129. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  130. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +4 -0
  131. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  132. package/packages/pi-coding-agent/src/core/retry-handler.test.ts +80 -0
  133. package/packages/pi-coding-agent/src/core/retry-handler.ts +37 -25
  134. package/packages/pi-coding-agent/src/core/sdk.ts +9 -9
  135. package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +10 -0
  136. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +20 -4
  137. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +27 -0
  138. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +16 -1
  139. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +5 -0
  140. package/packages/pi-tui/dist/components/image.d.ts +2 -0
  141. package/packages/pi-tui/dist/components/image.d.ts.map +1 -1
  142. package/packages/pi-tui/dist/components/image.js +4 -0
  143. package/packages/pi-tui/dist/components/image.js.map +1 -1
  144. package/packages/pi-tui/dist/components/image.test.d.ts +6 -0
  145. package/packages/pi-tui/dist/components/image.test.d.ts.map +1 -0
  146. package/packages/pi-tui/dist/components/image.test.js +32 -0
  147. package/packages/pi-tui/dist/components/image.test.js.map +1 -0
  148. package/packages/pi-tui/src/components/image.test.ts +36 -0
  149. package/packages/pi-tui/src/components/image.ts +5 -0
  150. package/src/resources/extensions/browser-tools/capture.ts +19 -1
  151. package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +93 -0
  152. package/src/resources/extensions/gsd/auto/run-unit.ts +12 -2
  153. package/src/resources/extensions/gsd/auto/session.ts +4 -0
  154. package/src/resources/extensions/gsd/auto-dispatch.ts +110 -9
  155. package/src/resources/extensions/gsd/auto-model-selection.ts +7 -5
  156. package/src/resources/extensions/gsd/auto-post-unit.ts +16 -6
  157. package/src/resources/extensions/gsd/auto-prompts.ts +31 -0
  158. package/src/resources/extensions/gsd/auto-recovery.ts +29 -23
  159. package/src/resources/extensions/gsd/auto-start.ts +45 -10
  160. package/src/resources/extensions/gsd/auto-tool-tracking.ts +10 -0
  161. package/src/resources/extensions/gsd/auto-worktree.ts +28 -7
  162. package/src/resources/extensions/gsd/auto.ts +19 -8
  163. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +16 -4
  164. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +10 -0
  165. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +5 -4
  166. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +4 -1
  167. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +4 -1
  168. package/src/resources/extensions/gsd/commands/context.ts +7 -1
  169. package/src/resources/extensions/gsd/commands/handlers/core.ts +23 -0
  170. package/src/resources/extensions/gsd/commands-extensions.ts +1 -1
  171. package/src/resources/extensions/gsd/config-overlay.ts +331 -0
  172. package/src/resources/extensions/gsd/db-writer.ts +11 -3
  173. package/src/resources/extensions/gsd/detection.ts +1 -1
  174. package/src/resources/extensions/gsd/dispatch-guard.ts +2 -1
  175. package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -0
  176. package/src/resources/extensions/gsd/doctor.ts +2 -1
  177. package/src/resources/extensions/gsd/gitignore.ts +1 -0
  178. package/src/resources/extensions/gsd/gsd-db.ts +13 -2
  179. package/src/resources/extensions/gsd/guided-flow.ts +254 -30
  180. package/src/resources/extensions/gsd/json-persistence.ts +6 -3
  181. package/src/resources/extensions/gsd/md-importer.ts +13 -6
  182. package/src/resources/extensions/gsd/parallel-orchestrator.ts +19 -11
  183. package/src/resources/extensions/gsd/pre-execution-checks.ts +15 -7
  184. package/src/resources/extensions/gsd/preferences-types.ts +25 -0
  185. package/src/resources/extensions/gsd/preferences-validation.ts +45 -1
  186. package/src/resources/extensions/gsd/preferences.ts +9 -2
  187. package/src/resources/extensions/gsd/preparation.ts +1419 -0
  188. package/src/resources/extensions/gsd/prompt-validation.ts +88 -0
  189. package/src/resources/extensions/gsd/prompts/complete-milestone.md +3 -3
  190. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  191. package/src/resources/extensions/gsd/prompts/discuss-prepared.md +424 -0
  192. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +4 -1
  193. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -4
  194. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +23 -0
  195. package/src/resources/extensions/gsd/prompts/rethink.md +2 -1
  196. package/src/resources/extensions/gsd/prompts/validate-milestone.md +56 -23
  197. package/src/resources/extensions/gsd/quick.ts +20 -15
  198. package/src/resources/extensions/gsd/reactive-graph.ts +18 -0
  199. package/src/resources/extensions/gsd/roadmap-slices.ts +21 -5
  200. package/src/resources/extensions/gsd/safety/content-validator.ts +3 -3
  201. package/src/resources/extensions/gsd/session-lock.ts +17 -1
  202. package/src/resources/extensions/gsd/state.ts +112 -20
  203. package/src/resources/extensions/gsd/templates/context-enhanced.md +138 -0
  204. package/src/resources/extensions/gsd/tests/adversarial-review-fixes.test.ts +223 -0
  205. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +33 -2
  206. package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +56 -0
  207. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +41 -0
  208. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +72 -0
  209. package/src/resources/extensions/gsd/tests/complete-task-normalize-lists.test.ts +54 -0
  210. package/src/resources/extensions/gsd/tests/defer-milestone-stamp.test.ts +30 -0
  211. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +4 -3
  212. package/src/resources/extensions/gsd/tests/discuss-incremental-persistence.test.ts +36 -0
  213. package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +46 -0
  214. package/src/resources/extensions/gsd/tests/dispatch-guard-closed-status.test.ts +33 -0
  215. package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +37 -0
  216. package/src/resources/extensions/gsd/tests/error-success-mask.test.ts +37 -0
  217. package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +48 -0
  218. package/src/resources/extensions/gsd/tests/frontmatter-parse-noise.test.ts +42 -0
  219. package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +38 -0
  220. package/src/resources/extensions/gsd/tests/guided-flow-state-rebuild.test.ts +103 -0
  221. package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +42 -0
  222. package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +11 -9
  223. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +4 -2
  224. package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +28 -30
  225. package/src/resources/extensions/gsd/tests/integration/test-isolation.ts +53 -0
  226. package/src/resources/extensions/gsd/tests/integration-prepared-discussion.test.ts +525 -0
  227. package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +62 -0
  228. package/src/resources/extensions/gsd/tests/needs-remediation-revalidation.test.ts +48 -0
  229. package/src/resources/extensions/gsd/tests/note-captures-executed.test.ts +46 -0
  230. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +77 -0
  231. package/src/resources/extensions/gsd/tests/phantom-ghost-detection.test.ts +55 -0
  232. package/src/resources/extensions/gsd/tests/phantom-milestone-default-queued.test.ts +39 -0
  233. package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +68 -0
  234. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +218 -20
  235. package/src/resources/extensions/gsd/tests/pre-execution-fail-closed.test.ts +2 -2
  236. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +2 -2
  237. package/src/resources/extensions/gsd/tests/preparation.test.ts +1211 -0
  238. package/src/resources/extensions/gsd/tests/project-root-cwd-crash.test.ts +53 -0
  239. package/src/resources/extensions/gsd/tests/projection-no-plan-overwrite.test.ts +83 -0
  240. package/src/resources/extensions/gsd/tests/prompt-builder.test.ts +669 -0
  241. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +7 -4
  242. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +85 -0
  243. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +2 -1
  244. package/src/resources/extensions/gsd/tests/query-tools-db-open.test.ts +47 -0
  245. package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +107 -0
  246. package/src/resources/extensions/gsd/tests/reactive-graph.test.ts +45 -0
  247. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +63 -0
  248. package/src/resources/extensions/gsd/tests/rogue-file-detection.test.ts +4 -5
  249. package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +51 -0
  250. package/src/resources/extensions/gsd/tests/show-config-command.test.ts +56 -0
  251. package/src/resources/extensions/gsd/tests/skip-slice-state-rebuild.test.ts +31 -0
  252. package/src/resources/extensions/gsd/tests/skipped-validation-completion.test.ts +39 -0
  253. package/src/resources/extensions/gsd/tests/slice-sequence-insert.test.ts +51 -0
  254. package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +1 -1
  255. package/src/resources/extensions/gsd/tests/stale-lockfile-recovery.test.ts +36 -0
  256. package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +147 -0
  257. package/src/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +13 -0
  258. package/src/resources/extensions/gsd/tests/stash-pop-gsd-conflict.test.ts +21 -0
  259. package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +21 -0
  260. package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +6 -7
  261. package/src/resources/extensions/gsd/tests/status-db-open.test.ts +47 -0
  262. package/src/resources/extensions/gsd/tests/stuck-detection-coverage.test.ts +1 -0
  263. package/src/resources/extensions/gsd/tests/symlink-extension-discovery.test.ts +125 -0
  264. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +65 -0
  265. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +29 -1
  266. package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +2 -1
  267. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +3 -4
  268. package/src/resources/extensions/gsd/tests/verification-operational-gate.test.ts +15 -0
  269. package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +89 -0
  270. package/src/resources/extensions/gsd/tests/wave1-critical-regressions.test.ts +49 -0
  271. package/src/resources/extensions/gsd/tests/wave2-events-regressions.test.ts +48 -0
  272. package/src/resources/extensions/gsd/tests/wave3-session-regressions.test.ts +47 -0
  273. package/src/resources/extensions/gsd/tests/wave4-write-safety-regressions.test.ts +70 -0
  274. package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +48 -0
  275. package/src/resources/extensions/gsd/tests/workflow-logger-audit.test.ts +6 -3
  276. package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +38 -0
  277. package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +16 -0
  278. package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +20 -0
  279. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +16 -17
  280. package/src/resources/extensions/gsd/tests/worktree-sync-tasks.test.ts +13 -9
  281. package/src/resources/extensions/gsd/tests/worktree.test.ts +26 -9
  282. package/src/resources/extensions/gsd/tests/zero-slice-roadmap-guided.test.ts +19 -0
  283. package/src/resources/extensions/gsd/tools/complete-milestone.ts +13 -3
  284. package/src/resources/extensions/gsd/tools/complete-slice.ts +26 -6
  285. package/src/resources/extensions/gsd/tools/complete-task.ts +29 -7
  286. package/src/resources/extensions/gsd/tools/plan-milestone.ts +11 -9
  287. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +5 -2
  288. package/src/resources/extensions/gsd/tools/reopen-milestone.ts +152 -0
  289. package/src/resources/extensions/gsd/tools/reopen-slice.ts +27 -0
  290. package/src/resources/extensions/gsd/tools/reopen-task.ts +17 -0
  291. package/src/resources/extensions/gsd/triage-resolution.ts +37 -17
  292. package/src/resources/extensions/gsd/types.ts +4 -0
  293. package/src/resources/extensions/gsd/undo.ts +3 -2
  294. package/src/resources/extensions/gsd/workflow-events.ts +1 -1
  295. package/src/resources/extensions/gsd/workflow-logger.ts +1 -1
  296. package/src/resources/extensions/gsd/workflow-projections.ts +4 -6
  297. package/src/resources/extensions/gsd/workflow-reconcile.ts +109 -8
  298. package/src/resources/extensions/gsd/workflow-templates.ts +11 -2
  299. package/src/resources/extensions/gsd/worktree-manager.ts +4 -2
  300. package/src/resources/extensions/gsd/worktree.ts +10 -0
  301. package/src/resources/extensions/shared/interview-ui.ts +1 -1
  302. package/src/resources/extensions/shared/tests/interview-notes-loop.test.ts +8 -10
  303. package/dist/web/standalone/.next/static/chunks/6502.7593d7797a4b3999.js +0 -9
  304. /package/dist/web/standalone/.next/static/{qq3YfHPfyqvh3DIMVmsRH → iueakR5x5bQbax2sGz8Yr}/_buildManifest.js +0 -0
  305. /package/dist/web/standalone/.next/static/{qq3YfHPfyqvh3DIMVmsRH → iueakR5x5bQbax2sGz8Yr}/_ssgManifest.js +0 -0
@@ -0,0 +1,312 @@
1
+ /**
2
+ * GSD Configuration Overlay
3
+ *
4
+ * Read-only TUI overlay showing the effective GSD configuration:
5
+ * token profile, model assignments, dynamic routing, git settings,
6
+ * budget, workflow toggles, and preference file sources.
7
+ * Opened via `/gsd show-config` or `/gsd config`.
8
+ */
9
+ import { matchesKey, Key, truncateToWidth } from "@gsd/pi-tui";
10
+ import { loadEffectiveGSDPreferences, loadGlobalGSDPreferences, loadProjectGSDPreferences, getGlobalGSDPreferencesPath, getProjectGSDPreferencesPath, resolveDynamicRoutingConfig, resolveEffectiveProfile, resolveModelWithFallbacksForUnit, resolveAutoSupervisorConfig, } from "./preferences.js";
11
+ function collectConfigSections() {
12
+ const sections = [];
13
+ const globalPrefs = loadGlobalGSDPreferences();
14
+ const projectPrefs = loadProjectGSDPreferences();
15
+ const effective = loadEffectiveGSDPreferences();
16
+ const prefs = effective?.preferences;
17
+ // ─── Sources ─────────────────────────────────────────────────────────
18
+ sections.push({
19
+ title: "Sources",
20
+ rows: [
21
+ { label: "Global", value: globalPrefs ? globalPrefs.path : `(none) ${getGlobalGSDPreferencesPath()}` },
22
+ { label: "Project", value: projectPrefs ? projectPrefs.path : `(none) ${getProjectGSDPreferencesPath()}` },
23
+ ],
24
+ });
25
+ // ─── Profile ─────────────────────────────────────────────────────────
26
+ const profile = resolveEffectiveProfile();
27
+ const profileRows = [
28
+ { label: "Token profile", value: `${profile}${!prefs?.token_profile ? " (default)" : ""}`, accent: true },
29
+ ];
30
+ if (prefs?.mode)
31
+ profileRows.push({ label: "Workflow mode", value: prefs.mode });
32
+ sections.push({ title: "Profile", rows: profileRows });
33
+ // ─── Models ──────────────────────────────────────────────────────────
34
+ const unitTypes = [
35
+ ["research", "research-milestone"],
36
+ ["planning", "plan-milestone"],
37
+ ["discuss", "discuss-milestone"],
38
+ ["execution", "execute-task"],
39
+ ["completion", "complete-slice"],
40
+ ["validation", "run-uat"],
41
+ ];
42
+ const modelRows = [];
43
+ for (const [label, unitType] of unitTypes) {
44
+ const resolved = resolveModelWithFallbacksForUnit(unitType);
45
+ if (resolved) {
46
+ let val = resolved.primary;
47
+ if (resolved.fallbacks.length > 0) {
48
+ val += ` \u2192 ${resolved.fallbacks.join(" \u2192 ")}`;
49
+ }
50
+ modelRows.push({ label, value: val });
51
+ }
52
+ else {
53
+ modelRows.push({ label, value: "(inherit)" });
54
+ }
55
+ }
56
+ // subagent is a direct config key
57
+ const models = prefs?.models;
58
+ const subVal = models?.subagent;
59
+ if (subVal) {
60
+ const model = typeof subVal === "string" ? subVal : subVal?.model ?? "?";
61
+ modelRows.push({ label: "subagent", value: model });
62
+ }
63
+ else {
64
+ modelRows.push({ label: "subagent", value: "(inherit)" });
65
+ }
66
+ sections.push({ title: "Models", rows: modelRows });
67
+ // ─── Dynamic Routing ─────────────────────────────────────────────────
68
+ const routing = resolveDynamicRoutingConfig();
69
+ const routingRows = [
70
+ { label: "Enabled", value: routing.enabled ? "yes" : "no", accent: routing.enabled },
71
+ ];
72
+ if (routing.enabled) {
73
+ routingRows.push({ label: "Escalate on fail", value: routing.escalate_on_failure !== false ? "yes" : "no" });
74
+ routingRows.push({ label: "Budget pressure", value: routing.budget_pressure !== false ? "yes" : "no" });
75
+ routingRows.push({ label: "Cross-provider", value: routing.cross_provider !== false ? "yes" : "no" });
76
+ if (routing.tier_models) {
77
+ const tm = routing.tier_models;
78
+ if (tm.light)
79
+ routingRows.push({ label: "[L] light", value: tm.light });
80
+ if (tm.standard)
81
+ routingRows.push({ label: "[S] standard", value: tm.standard });
82
+ if (tm.heavy)
83
+ routingRows.push({ label: "[H] heavy", value: tm.heavy });
84
+ }
85
+ }
86
+ sections.push({ title: "Dynamic Routing", rows: routingRows });
87
+ // ─── Git ─────────────────────────────────────────────────────────────
88
+ if (prefs?.git) {
89
+ const g = prefs.git;
90
+ const gitRows = [];
91
+ if (g.isolation !== undefined)
92
+ gitRows.push({ label: "Isolation", value: String(g.isolation) });
93
+ if (g.auto_push !== undefined)
94
+ gitRows.push({ label: "Auto push", value: String(g.auto_push) });
95
+ if (g.push_branches !== undefined)
96
+ gitRows.push({ label: "Push branches", value: String(g.push_branches) });
97
+ if (g.merge_strategy)
98
+ gitRows.push({ label: "Merge strategy", value: g.merge_strategy });
99
+ if (g.main_branch)
100
+ gitRows.push({ label: "Main branch", value: g.main_branch });
101
+ if (g.remote)
102
+ gitRows.push({ label: "Remote", value: g.remote });
103
+ if (gitRows.length > 0)
104
+ sections.push({ title: "Git", rows: gitRows });
105
+ }
106
+ // ─── Budget ──────────────────────────────────────────────────────────
107
+ if (prefs?.budget_ceiling !== undefined || prefs?.budget_enforcement) {
108
+ const budgetRows = [];
109
+ if (prefs.budget_ceiling !== undefined)
110
+ budgetRows.push({ label: "Ceiling", value: `$${prefs.budget_ceiling}` });
111
+ if (prefs.budget_enforcement)
112
+ budgetRows.push({ label: "Enforcement", value: String(prefs.budget_enforcement) });
113
+ sections.push({ title: "Budget", rows: budgetRows });
114
+ }
115
+ // ─── Auto Supervisor ─────────────────────────────────────────────────
116
+ if (prefs?.auto_supervisor) {
117
+ const sup = resolveAutoSupervisorConfig();
118
+ const supRows = [];
119
+ if (sup.model)
120
+ supRows.push({ label: "Model", value: sup.model });
121
+ supRows.push({ label: "Soft timeout", value: `${sup.soft_timeout_minutes}m` });
122
+ supRows.push({ label: "Idle timeout", value: `${sup.idle_timeout_minutes}m` });
123
+ supRows.push({ label: "Hard timeout", value: `${sup.hard_timeout_minutes}m` });
124
+ sections.push({ title: "Auto Supervisor", rows: supRows });
125
+ }
126
+ // ─── Toggles ─────────────────────────────────────────────────────────
127
+ const toggleRows = [];
128
+ if (prefs?.phases) {
129
+ const p = prefs.phases;
130
+ if (p.skip_research)
131
+ toggleRows.push({ label: "skip_research", value: "on" });
132
+ if (p.skip_reassess)
133
+ toggleRows.push({ label: "skip_reassess", value: "on" });
134
+ if (p.skip_slice_research)
135
+ toggleRows.push({ label: "skip_slice_research", value: "on" });
136
+ if (p.skip_milestone_validation)
137
+ toggleRows.push({ label: "skip_milestone_validation", value: "on" });
138
+ if (p.require_slice_discussion)
139
+ toggleRows.push({ label: "require_slice_discussion", value: "on" });
140
+ }
141
+ if (prefs?.uat_dispatch)
142
+ toggleRows.push({ label: "uat_dispatch", value: "on" });
143
+ if (prefs?.auto_visualize)
144
+ toggleRows.push({ label: "auto_visualize", value: "on" });
145
+ if (prefs?.auto_report === false)
146
+ toggleRows.push({ label: "auto_report", value: "off" });
147
+ if (prefs?.show_token_cost)
148
+ toggleRows.push({ label: "show_token_cost", value: "on" });
149
+ if (prefs?.forensics_dedup)
150
+ toggleRows.push({ label: "forensics_dedup", value: "on" });
151
+ if (prefs?.unique_milestone_ids)
152
+ toggleRows.push({ label: "unique_milestone_ids", value: "on" });
153
+ if (prefs?.service_tier)
154
+ toggleRows.push({ label: "service_tier", value: prefs.service_tier });
155
+ if (prefs?.search_provider && prefs.search_provider !== "auto")
156
+ toggleRows.push({ label: "search_provider", value: prefs.search_provider });
157
+ if (prefs?.context_selection)
158
+ toggleRows.push({ label: "context_selection", value: prefs.context_selection });
159
+ if (prefs?.widget_mode && prefs.widget_mode !== "full")
160
+ toggleRows.push({ label: "widget_mode", value: prefs.widget_mode });
161
+ if (prefs?.experimental?.rtk)
162
+ toggleRows.push({ label: "experimental.rtk", value: "on" });
163
+ if (toggleRows.length > 0)
164
+ sections.push({ title: "Toggles", rows: toggleRows });
165
+ // ─── Parallel ────────────────────────────────────────────────────────
166
+ if (prefs?.parallel) {
167
+ const pc = prefs.parallel;
168
+ const parallelRows = [];
169
+ if (pc.max_workers !== undefined)
170
+ parallelRows.push({ label: "Max workers", value: String(pc.max_workers) });
171
+ if (pc.merge_strategy)
172
+ parallelRows.push({ label: "Merge strategy", value: pc.merge_strategy });
173
+ if (pc.auto_merge)
174
+ parallelRows.push({ label: "Auto merge", value: pc.auto_merge });
175
+ if (parallelRows.length > 0)
176
+ sections.push({ title: "Parallel", rows: parallelRows });
177
+ }
178
+ // ─── Hooks ───────────────────────────────────────────────────────────
179
+ const postHooks = prefs?.post_unit_hooks?.filter(h => h.enabled !== false) ?? [];
180
+ const preHooks = prefs?.pre_dispatch_hooks?.filter(h => h.enabled !== false) ?? [];
181
+ if (postHooks.length > 0 || preHooks.length > 0) {
182
+ const hookRows = [];
183
+ if (preHooks.length > 0)
184
+ hookRows.push({ label: "Pre-dispatch", value: `${preHooks.length} active` });
185
+ if (postHooks.length > 0)
186
+ hookRows.push({ label: "Post-unit", value: `${postHooks.length} active` });
187
+ sections.push({ title: "Hooks", rows: hookRows });
188
+ }
189
+ // ─── Warnings ────────────────────────────────────────────────────────
190
+ const warnings = [
191
+ ...(globalPrefs?.warnings ?? []),
192
+ ...(projectPrefs?.warnings ?? []),
193
+ ];
194
+ if (warnings.length > 0) {
195
+ sections.push({
196
+ title: "Warnings",
197
+ rows: warnings.map(w => ({ label: "\u26a0", value: w })),
198
+ });
199
+ }
200
+ return sections;
201
+ }
202
+ // ─── Plain Text Formatter (headless/RPC fallback) ─────────────────────────
203
+ export function formatConfigText() {
204
+ const sections = collectConfigSections();
205
+ const lines = ["GSD Configuration\n"];
206
+ let maxLabel = 0;
207
+ for (const section of sections) {
208
+ for (const row of section.rows) {
209
+ if (row.label.length > maxLabel)
210
+ maxLabel = row.label.length;
211
+ }
212
+ }
213
+ const pad = Math.min(maxLabel + 2, 24);
214
+ for (const section of sections) {
215
+ lines.push("");
216
+ lines.push(section.title.toUpperCase());
217
+ for (const row of section.rows) {
218
+ lines.push(` ${row.label.padEnd(pad)}${row.value}`);
219
+ }
220
+ }
221
+ return lines.join("\n");
222
+ }
223
+ // ─── Overlay Class ────────────────────────────────────────────────────────
224
+ export class GSDConfigOverlay {
225
+ tui;
226
+ theme;
227
+ onClose;
228
+ sections;
229
+ cachedLines;
230
+ scrollOffset = 0;
231
+ disposed = false;
232
+ constructor(tui, theme, onClose) {
233
+ this.tui = tui;
234
+ this.theme = theme;
235
+ this.onClose = onClose;
236
+ this.sections = collectConfigSections();
237
+ }
238
+ invalidate() {
239
+ this.cachedLines = undefined;
240
+ }
241
+ dispose() {
242
+ this.disposed = true;
243
+ }
244
+ handleInput(data) {
245
+ if (matchesKey(data, Key.escape) || data === "q") {
246
+ this.dispose();
247
+ this.onClose();
248
+ return;
249
+ }
250
+ if (matchesKey(data, Key.down) || data === "j") {
251
+ this.scrollOffset++;
252
+ this.cachedLines = undefined;
253
+ this.tui.requestRender();
254
+ return;
255
+ }
256
+ if (matchesKey(data, Key.up) || data === "k") {
257
+ this.scrollOffset = Math.max(0, this.scrollOffset - 1);
258
+ this.cachedLines = undefined;
259
+ this.tui.requestRender();
260
+ return;
261
+ }
262
+ if (matchesKey(data, Key.pageDown)) {
263
+ this.scrollOffset += 10;
264
+ this.cachedLines = undefined;
265
+ this.tui.requestRender();
266
+ return;
267
+ }
268
+ if (matchesKey(data, Key.pageUp)) {
269
+ this.scrollOffset = Math.max(0, this.scrollOffset - 10);
270
+ this.cachedLines = undefined;
271
+ this.tui.requestRender();
272
+ return;
273
+ }
274
+ }
275
+ render(width) {
276
+ if (this.cachedLines)
277
+ return this.cachedLines;
278
+ const t = this.theme;
279
+ const w = Math.max(width, 50);
280
+ const allLines = [];
281
+ // Header
282
+ allLines.push(t.bold(t.fg("accent", " GSD Configuration ")));
283
+ allLines.push(t.fg("muted", "\u2500".repeat(w)));
284
+ // Find max label width for alignment
285
+ let maxLabel = 0;
286
+ for (const section of this.sections) {
287
+ for (const row of section.rows) {
288
+ if (row.label.length > maxLabel)
289
+ maxLabel = row.label.length;
290
+ }
291
+ }
292
+ const labelPad = Math.min(maxLabel + 2, 24);
293
+ for (const section of this.sections) {
294
+ allLines.push("");
295
+ allLines.push(t.bold(t.fg("accent", ` ${section.title}`)));
296
+ for (const row of section.rows) {
297
+ const label = t.fg("muted", ` ${row.label.padEnd(labelPad)}`);
298
+ const value = row.accent ? t.bold(row.value) : row.value;
299
+ allLines.push(truncateToWidth(`${label}${value}`, w));
300
+ }
301
+ }
302
+ allLines.push("");
303
+ allLines.push(t.fg("muted", ` ${"\u2500".repeat(w - 4)}`));
304
+ allLines.push(t.fg("muted", " esc/q close \u2502 \u2191\u2193/jk scroll \u2502 /gsd prefs to edit"));
305
+ // Apply scroll
306
+ const maxScroll = Math.max(0, allLines.length - 20);
307
+ this.scrollOffset = Math.min(this.scrollOffset, maxScroll);
308
+ const visible = allLines.slice(this.scrollOffset);
309
+ this.cachedLines = visible;
310
+ return visible;
311
+ }
312
+ }
@@ -300,8 +300,13 @@ export async function saveRequirementToDb(fields, basePath) {
300
300
  }
301
301
  catch (diskErr) {
302
302
  logError('manifest', 'disk write failed, rolling back DB row', { fn: 'saveRequirementToDb', error: String(diskErr.message) });
303
- const rollbackAdapter = db._getAdapter();
304
- rollbackAdapter?.prepare('DELETE FROM requirements WHERE id = :id').run({ ':id': id });
303
+ try {
304
+ const rollbackAdapter = db._getAdapter();
305
+ rollbackAdapter?.prepare('DELETE FROM requirements WHERE id = :id').run({ ':id': id });
306
+ }
307
+ catch (rollbackErr) {
308
+ logError('manifest', 'SPLIT BRAIN: disk write failed AND DB rollback failed — DB has orphaned row', { fn: 'saveRequirementToDb', id, error: String(rollbackErr.message) });
309
+ }
305
310
  throw diskErr;
306
311
  }
307
312
  invalidateStateCache();
@@ -399,7 +404,12 @@ export async function saveDecisionToDb(fields, basePath) {
399
404
  }
400
405
  catch (diskErr) {
401
406
  logError('manifest', 'disk write failed, rolling back DB row', { fn: 'saveDecisionToDb', error: String(diskErr.message) });
402
- adapter?.prepare('DELETE FROM decisions WHERE id = :id').run({ ':id': id });
407
+ try {
408
+ adapter?.prepare('DELETE FROM decisions WHERE id = :id').run({ ':id': id });
409
+ }
410
+ catch (rollbackErr) {
411
+ logError('manifest', 'SPLIT BRAIN: disk write failed AND DB rollback failed — DB has orphaned row', { fn: 'saveDecisionToDb', id, error: String(rollbackErr.message) });
412
+ }
403
413
  throw diskErr;
404
414
  }
405
415
  // #2661: When a decision defers a slice, update the slice status in the DB
@@ -945,7 +945,7 @@ function resolveVersionCatalogAccessors(basePath, versionCatalogFiles, settingsF
945
945
  }
946
946
  return accessors;
947
947
  }
948
- function scanProjectFiles(basePath) {
948
+ export function scanProjectFiles(basePath) {
949
949
  const files = [];
950
950
  const queue = [{ path: basePath, depth: 0 }];
951
951
  while (queue.length > 0 && files.length < MAX_RECURSIVE_SCAN_FILES) {
@@ -4,6 +4,7 @@ import { findMilestoneIds } from "./guided-flow.js";
4
4
  import { parseUnitId } from "./unit-id.js";
5
5
  import { isDbAvailable, getMilestoneSlices } from "./gsd-db.js";
6
6
  import { parseRoadmap } from "./parsers-legacy.js";
7
+ import { isClosedStatus } from "./status-guards.js";
7
8
  import { readFileSync } from "node:fs";
8
9
  const SLICE_DISPATCH_TYPES = new Set([
9
10
  "research-slice",
@@ -46,7 +47,7 @@ export function getPriorSliceCompletionBlocker(base, _mainBranch, unitType, unit
46
47
  if (rows.length > 0) {
47
48
  slices = rows.map((r) => ({
48
49
  id: r.id,
49
- done: r.status === "complete",
50
+ done: isClosedStatus(r.status),
50
51
  depends: r.depends ?? [],
51
52
  }));
52
53
  }
@@ -211,6 +211,7 @@ Setting `prefer_skills: []` does **not** disable skill discovery — it just mea
211
211
  - `budget_ceiling`: number — optional per-parallel-run budget ceiling.
212
212
  - `merge_strategy`: `"per-slice"` or `"per-milestone"` — when to merge worktree results back. Default: `"per-milestone"`.
213
213
  - `auto_merge`: `"auto"`, `"confirm"`, or `"manual"` — merge behavior after completion. `"auto"` merges immediately; `"confirm"` asks first; `"manual"` leaves branches for you. Default: `"confirm"`.
214
+ - `worker_model`: string — optional model override for parallel milestone workers. When set, workers use this model (e.g. `"claude-haiku-4-5"`) instead of inheriting the coordinator's model. Useful for cost savings on execution-heavy milestones.
214
215
 
215
216
  - `verification_commands`: string[] — shell commands to run as verification after task execution (e.g., `["npm test", "npm run lint"]`). Commands run in order; if any fails, the task is marked as needing fixes.
216
217
 
@@ -75,7 +75,8 @@ function validatePreferenceShape(preferences) {
75
75
  }
76
76
  return issues;
77
77
  }
78
- function buildStateMarkdown(state) {
78
+ /** Build STATE.md content from derived state. Exported for guided-flow pre-dispatch rebuild (#3475). */
79
+ export function buildStateMarkdown(state) {
79
80
  const lines = [];
80
81
  lines.push("# GSD State", "");
81
82
  const activeMilestone = state.activeMilestone
@@ -39,6 +39,7 @@ const BASELINE_PATTERNS = [
39
39
  // ── GSD state directory (symlink to external storage) ──
40
40
  ".gsd",
41
41
  ".gsd-id",
42
+ ".bg-shell/",
42
43
  // ── OS junk ──
43
44
  ".DS_Store",
44
45
  "Thumbs.db",
@@ -357,6 +357,7 @@ function initSchema(db, fileBacked) {
357
357
  db.exec("CREATE INDEX IF NOT EXISTS idx_milestones_status ON milestones(status)");
358
358
  db.exec("CREATE INDEX IF NOT EXISTS idx_quality_gates_pending ON quality_gates(milestone_id, slice_id, status)");
359
359
  db.exec("CREATE INDEX IF NOT EXISTS idx_verification_evidence_task ON verification_evidence(milestone_id, slice_id, task_id)");
360
+ db.exec("CREATE UNIQUE INDEX IF NOT EXISTS idx_verification_evidence_dedup ON verification_evidence(task_id, slice_id, milestone_id, command, verdict)");
360
361
  // v14 index — slice dependency lookups
361
362
  db.exec("CREATE INDEX IF NOT EXISTS idx_slice_deps_target ON slice_dependencies(milestone_id, depends_on_slice_id)");
362
363
  db.exec(`CREATE VIEW IF NOT EXISTS active_decisions AS SELECT * FROM decisions WHERE superseded_by IS NULL`);
@@ -644,6 +645,7 @@ function migrateSchema(db) {
644
645
  db.exec("CREATE INDEX IF NOT EXISTS idx_milestones_status ON milestones(status)");
645
646
  db.exec("CREATE INDEX IF NOT EXISTS idx_quality_gates_pending ON quality_gates(milestone_id, slice_id, status)");
646
647
  db.exec("CREATE INDEX IF NOT EXISTS idx_verification_evidence_task ON verification_evidence(milestone_id, slice_id, task_id)");
648
+ db.exec("CREATE UNIQUE INDEX IF NOT EXISTS idx_verification_evidence_dedup ON verification_evidence(task_id, slice_id, milestone_id, command, verdict)");
647
649
  db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
648
650
  ":version": 13,
649
651
  ":applied_at": new Date().toISOString(),
@@ -1007,7 +1009,9 @@ export function insertMilestone(m) {
1007
1009
  )`).run({
1008
1010
  ":id": m.id,
1009
1011
  ":title": m.title ?? "",
1010
- ":status": m.status ?? "active",
1012
+ // Default to "queued" never auto-create milestones as "active" (#3380).
1013
+ // Callers that need "active" must pass it explicitly.
1014
+ ":status": m.status ?? "queued",
1011
1015
  ":depends_on": JSON.stringify(m.depends_on ?? []),
1012
1016
  ":created_at": new Date().toISOString(),
1013
1017
  ":vision": m.planning?.vision ?? "",
@@ -1198,6 +1202,11 @@ export function updateTaskStatus(milestoneId, sliceId, taskId, status, completed
1198
1202
  ":id": taskId,
1199
1203
  });
1200
1204
  }
1205
+ export function setTaskBlockerDiscovered(milestoneId, sliceId, taskId, discovered) {
1206
+ if (!currentDb)
1207
+ return;
1208
+ currentDb.prepare(`UPDATE tasks SET blocker_discovered = :discovered WHERE milestone_id = :mid AND slice_id = :sid AND id = :tid`).run({ ":discovered": discovered ? 1 : 0, ":mid": milestoneId, ":sid": sliceId, ":tid": taskId });
1209
+ }
1201
1210
  export function upsertTaskPlanning(milestoneId, sliceId, taskId, planning) {
1202
1211
  if (!currentDb)
1203
1212
  throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
@@ -1323,7 +1332,7 @@ export function getSliceTasks(milestoneId, sliceId) {
1323
1332
  export function insertVerificationEvidence(e) {
1324
1333
  if (!currentDb)
1325
1334
  throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
1326
- currentDb.prepare(`INSERT INTO verification_evidence (task_id, slice_id, milestone_id, command, exit_code, verdict, duration_ms, created_at)
1335
+ currentDb.prepare(`INSERT OR IGNORE INTO verification_evidence (task_id, slice_id, milestone_id, command, exit_code, verdict, duration_ms, created_at)
1327
1336
  VALUES (:task_id, :slice_id, :milestone_id, :command, :exit_code, :verdict, :duration_ms, :created_at)`).run({
1328
1337
  ":task_id": e.taskId,
1329
1338
  ":slice_id": e.sliceId,