gsd-pi 2.82.0-dev.725028083 → 2.82.0-dev.98ea09b1e

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 (355) hide show
  1. package/README.md +4 -3
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/GSD-WORKFLOW.md +10 -1
  4. package/dist/resources/extensions/claude-code-cli/partial-builder.js +2 -1
  5. package/dist/resources/extensions/cmux/index.js +5 -0
  6. package/dist/resources/extensions/gsd/auto/infra-errors.js +9 -3
  7. package/dist/resources/extensions/gsd/auto/loop.js +5 -5
  8. package/dist/resources/extensions/gsd/auto/orchestrator.js +124 -6
  9. package/dist/resources/extensions/gsd/auto/phases.js +8 -1
  10. package/dist/resources/extensions/gsd/auto/workflow-memory-pressure.js +12 -0
  11. package/dist/resources/extensions/gsd/auto-dispatch.js +13 -6
  12. package/dist/resources/extensions/gsd/auto-model-selection.js +2 -0
  13. package/dist/resources/extensions/gsd/auto-post-unit.js +233 -127
  14. package/dist/resources/extensions/gsd/auto-prompts.js +2 -2
  15. package/dist/resources/extensions/gsd/auto-recovery.js +31 -1
  16. package/dist/resources/extensions/gsd/auto-start.js +85 -12
  17. package/dist/resources/extensions/gsd/auto-verification.js +28 -22
  18. package/dist/resources/extensions/gsd/auto-worktree.js +111 -1
  19. package/dist/resources/extensions/gsd/auto.js +158 -55
  20. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +4 -1
  21. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +9 -8
  22. package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +21 -9
  23. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +16 -2
  24. package/dist/resources/extensions/gsd/clean-root-preflight.js +170 -8
  25. package/dist/resources/extensions/gsd/commands/catalog.js +4 -1
  26. package/dist/resources/extensions/gsd/commands/handlers/core.js +37 -0
  27. package/dist/resources/extensions/gsd/commands-bootstrap.js +5 -0
  28. package/dist/resources/extensions/gsd/crash-recovery.js +31 -5
  29. package/dist/resources/extensions/gsd/db/unit-dispatches.js +3 -2
  30. package/dist/resources/extensions/gsd/dispatch-guard.js +2 -2
  31. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +28 -11
  32. package/dist/resources/extensions/gsd/doctor.js +2 -28
  33. package/dist/resources/extensions/gsd/export-html.js +27 -425
  34. package/dist/resources/extensions/gsd/git-service.js +39 -1
  35. package/dist/resources/extensions/gsd/gsd-db.js +1 -0
  36. package/dist/resources/extensions/gsd/guided-flow.js +13 -6
  37. package/dist/resources/extensions/gsd/md-importer.js +1 -1
  38. package/dist/resources/extensions/gsd/migrate/command.js +5 -0
  39. package/dist/resources/extensions/gsd/migrate/parsers.js +10 -0
  40. package/dist/resources/extensions/gsd/migrate/preview.js +9 -0
  41. package/dist/resources/extensions/gsd/migrate/transformer.js +51 -4
  42. package/dist/resources/extensions/gsd/migrate/writer.js +11 -1
  43. package/dist/resources/extensions/gsd/migration-auto-check.js +12 -17
  44. package/dist/resources/extensions/gsd/milestone-actions.js +11 -4
  45. package/dist/resources/extensions/gsd/native-git-bridge.js +48 -12
  46. package/dist/resources/extensions/gsd/post-execution-checks.js +73 -2
  47. package/dist/resources/extensions/gsd/pre-execution-checks.js +28 -1
  48. package/dist/resources/extensions/gsd/prompt-loader.js +1 -1
  49. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  50. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  51. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
  52. package/dist/resources/extensions/gsd/prompts/discuss.md +9 -9
  53. package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
  54. package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
  55. package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -4
  56. package/dist/resources/extensions/gsd/prompts/queue.md +4 -4
  57. package/dist/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  58. package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  59. package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +6 -1
  60. package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +9 -14
  61. package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +19 -24
  62. package/dist/resources/extensions/gsd/status-guards.js +4 -0
  63. package/dist/resources/extensions/gsd/templates/plan.md +8 -5
  64. package/dist/resources/extensions/gsd/templates/task-plan.md +4 -2
  65. package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -8
  66. package/dist/resources/extensions/gsd/tools/complete-slice.js +6 -8
  67. package/dist/resources/extensions/gsd/tools/plan-milestone.js +7 -1
  68. package/dist/resources/extensions/gsd/tools/plan-slice.js +89 -14
  69. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +119 -0
  70. package/dist/resources/extensions/gsd/unit-context-manifest.js +32 -10
  71. package/dist/resources/extensions/gsd/validation.js +23 -1
  72. package/dist/resources/extensions/gsd/verification-gate.js +68 -7
  73. package/dist/resources/extensions/gsd/verification-verdict.js +26 -0
  74. package/dist/resources/extensions/gsd/workflow-projections.js +6 -8
  75. package/dist/resources/extensions/gsd/worktree-lifecycle.js +54 -10
  76. package/dist/resources/extensions/shared/html-shell.js +388 -0
  77. package/dist/resources/extensions/subagent/index.js +448 -78
  78. package/dist/resources/extensions/subagent/launch.js +77 -0
  79. package/dist/resources/extensions/subagent/run-store.js +148 -0
  80. package/dist/resources/extensions/visual-brief/artifact-policy.js +29 -0
  81. package/dist/resources/extensions/visual-brief/extension-manifest.json +8 -0
  82. package/dist/resources/extensions/visual-brief/index.js +5 -0
  83. package/dist/resources/extensions/visual-brief/page-contract.js +124 -0
  84. package/dist/resources/extensions/visual-brief/prompts.js +140 -0
  85. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  86. package/dist/web/standalone/.next/BUILD_ID +1 -1
  87. package/dist/web/standalone/.next/app-path-routes-manifest.json +14 -14
  88. package/dist/web/standalone/.next/build-manifest.json +3 -3
  89. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  90. package/dist/web/standalone/.next/react-loadable-manifest.json +3 -3
  91. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  92. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  93. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  101. package/dist/web/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  102. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  103. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  104. package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -7
  105. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -7
  106. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -5
  108. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  110. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -5
  111. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  112. package/dist/web/standalone/.next/server/app/index.html +1 -1
  113. package/dist/web/standalone/.next/server/app/index.rsc +4 -7
  114. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  115. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -7
  116. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  117. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -5
  118. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -5
  119. package/dist/web/standalone/.next/server/app/page.js +2 -2
  120. package/dist/web/standalone/.next/server/app/page.js.nft.json +1 -1
  121. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  122. package/dist/web/standalone/.next/server/app-paths-manifest.json +14 -14
  123. package/dist/web/standalone/.next/server/chunks/4266.js +2 -0
  124. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  125. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  126. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  127. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  128. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  129. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  130. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  131. package/dist/web/standalone/.next/static/chunks/2973.33f26573894b6153.js +2 -0
  132. package/dist/web/standalone/.next/static/chunks/{8359.e059d86b255fce1c.js → 8359.7eb3bb8f8ecf4c01.js} +2 -2
  133. package/dist/web/standalone/.next/static/chunks/app/layout-8c10ec293ae0f1d5.js +1 -0
  134. package/dist/web/standalone/.next/static/chunks/{webpack-de742b64187e13fe.js → webpack-9a4db269f9ed63ad.js} +1 -1
  135. package/dist/web/standalone/.next/static/css/746ee28c929d1880.css +1 -0
  136. package/package.json +4 -4
  137. package/packages/contracts/dist/rpc.test.js +7 -0
  138. package/packages/contracts/dist/rpc.test.js.map +1 -1
  139. package/packages/contracts/dist/workflow.d.ts +21 -0
  140. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  141. package/packages/contracts/dist/workflow.js +24 -0
  142. package/packages/contracts/dist/workflow.js.map +1 -1
  143. package/packages/contracts/src/rpc.test.ts +8 -0
  144. package/packages/contracts/src/workflow.ts +24 -0
  145. package/packages/mcp-server/README.md +13 -4
  146. package/packages/mcp-server/dist/workflow-tools.d.ts +0 -3
  147. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  148. package/packages/mcp-server/dist/workflow-tools.js +80 -0
  149. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  150. package/packages/mcp-server/src/workflow-tools.test.ts +23 -1
  151. package/packages/mcp-server/src/workflow-tools.ts +168 -0
  152. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  153. package/packages/native/tsconfig.json +2 -1
  154. package/packages/native/tsconfig.tsbuildinfo +1 -1
  155. package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
  156. package/packages/pi-ai/dist/providers/openai-codex-responses.js +82 -1
  157. package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
  158. package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts +2 -0
  159. package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts.map +1 -0
  160. package/packages/pi-ai/dist/providers/openai-codex-responses.test.js +52 -0
  161. package/packages/pi-ai/dist/providers/openai-codex-responses.test.js.map +1 -0
  162. package/packages/pi-ai/dist/providers/simple-options.d.ts +2 -4
  163. package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  164. package/packages/pi-ai/dist/providers/simple-options.js +5 -6
  165. package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
  166. package/packages/pi-ai/dist/providers/simple-options.test.d.ts +2 -0
  167. package/packages/pi-ai/dist/providers/simple-options.test.d.ts.map +1 -0
  168. package/packages/pi-ai/dist/providers/simple-options.test.js +50 -0
  169. package/packages/pi-ai/dist/providers/simple-options.test.js.map +1 -0
  170. package/packages/pi-ai/src/providers/openai-codex-responses.test.ts +63 -0
  171. package/packages/pi-ai/src/providers/openai-codex-responses.ts +91 -1
  172. package/packages/pi-ai/src/providers/simple-options.test.ts +60 -0
  173. package/packages/pi-ai/src/providers/simple-options.ts +5 -6
  174. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  175. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts +2 -0
  176. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts.map +1 -0
  177. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js +66 -0
  178. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js.map +1 -0
  179. package/packages/pi-coding-agent/dist/core/agent-session.js +1 -1
  180. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  181. package/packages/pi-coding-agent/src/core/agent-session-thinking-level.test.ts +79 -0
  182. package/packages/pi-coding-agent/src/core/agent-session.ts +1 -1
  183. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  184. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  185. package/packages/pi-tui/dist/tui.js +5 -0
  186. package/packages/pi-tui/dist/tui.js.map +1 -1
  187. package/packages/pi-tui/src/tui.ts +6 -0
  188. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  189. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
  190. package/src/resources/GSD-WORKFLOW.md +10 -1
  191. package/src/resources/extensions/claude-code-cli/partial-builder.ts +2 -1
  192. package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +19 -2
  193. package/src/resources/extensions/cmux/index.ts +6 -0
  194. package/src/resources/extensions/gsd/auto/contracts.ts +59 -16
  195. package/src/resources/extensions/gsd/auto/infra-errors.ts +9 -3
  196. package/src/resources/extensions/gsd/auto/loop.ts +8 -5
  197. package/src/resources/extensions/gsd/auto/orchestrator.ts +129 -6
  198. package/src/resources/extensions/gsd/auto/phases.ts +7 -1
  199. package/src/resources/extensions/gsd/auto/workflow-memory-pressure.ts +13 -0
  200. package/src/resources/extensions/gsd/auto-dispatch.ts +14 -6
  201. package/src/resources/extensions/gsd/auto-model-selection.ts +2 -1
  202. package/src/resources/extensions/gsd/auto-post-unit.ts +266 -139
  203. package/src/resources/extensions/gsd/auto-prompts.ts +2 -2
  204. package/src/resources/extensions/gsd/auto-recovery.ts +29 -0
  205. package/src/resources/extensions/gsd/auto-start.ts +92 -9
  206. package/src/resources/extensions/gsd/auto-verification.ts +36 -34
  207. package/src/resources/extensions/gsd/auto-worktree.ts +119 -1
  208. package/src/resources/extensions/gsd/auto.ts +167 -53
  209. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +6 -1
  210. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +9 -8
  211. package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +19 -7
  212. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +19 -3
  213. package/src/resources/extensions/gsd/clean-root-preflight.ts +174 -8
  214. package/src/resources/extensions/gsd/commands/catalog.ts +4 -1
  215. package/src/resources/extensions/gsd/commands/handlers/core.ts +40 -0
  216. package/src/resources/extensions/gsd/commands-bootstrap.ts +10 -0
  217. package/src/resources/extensions/gsd/crash-recovery.ts +30 -4
  218. package/src/resources/extensions/gsd/db/unit-dispatches.ts +4 -3
  219. package/src/resources/extensions/gsd/dispatch-guard.ts +2 -2
  220. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +25 -13
  221. package/src/resources/extensions/gsd/doctor.ts +2 -27
  222. package/src/resources/extensions/gsd/export-html.ts +27 -427
  223. package/src/resources/extensions/gsd/git-service.ts +45 -1
  224. package/src/resources/extensions/gsd/gsd-db.ts +3 -0
  225. package/src/resources/extensions/gsd/guided-flow.ts +14 -7
  226. package/src/resources/extensions/gsd/md-importer.ts +1 -1
  227. package/src/resources/extensions/gsd/migrate/command.ts +5 -0
  228. package/src/resources/extensions/gsd/migrate/parsers.ts +11 -0
  229. package/src/resources/extensions/gsd/migrate/preview.ts +10 -0
  230. package/src/resources/extensions/gsd/migrate/transformer.ts +58 -4
  231. package/src/resources/extensions/gsd/migrate/writer.ts +14 -1
  232. package/src/resources/extensions/gsd/migration-auto-check.ts +15 -23
  233. package/src/resources/extensions/gsd/milestone-actions.ts +10 -4
  234. package/src/resources/extensions/gsd/native-git-bridge.ts +54 -12
  235. package/src/resources/extensions/gsd/post-execution-checks.ts +87 -2
  236. package/src/resources/extensions/gsd/pre-execution-checks.ts +32 -1
  237. package/src/resources/extensions/gsd/prompt-loader.ts +1 -1
  238. package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  239. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  240. package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
  241. package/src/resources/extensions/gsd/prompts/discuss.md +9 -9
  242. package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
  243. package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
  244. package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -4
  245. package/src/resources/extensions/gsd/prompts/queue.md +4 -4
  246. package/src/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  247. package/src/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  248. package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +8 -1
  249. package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +12 -15
  250. package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +17 -25
  251. package/src/resources/extensions/gsd/status-guards.ts +5 -0
  252. package/src/resources/extensions/gsd/templates/plan.md +8 -5
  253. package/src/resources/extensions/gsd/templates/task-plan.md +4 -2
  254. package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +116 -0
  255. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +54 -0
  256. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +487 -4
  257. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +12 -11
  258. package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +12 -1
  259. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +15 -1
  260. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +4 -4
  261. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +1 -0
  262. package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +69 -1
  263. package/src/resources/extensions/gsd/tests/brief-command.test.ts +89 -0
  264. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +107 -2
  265. package/src/resources/extensions/gsd/tests/closeout-git-deferral.test.ts +16 -0
  266. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +4 -1
  267. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +5 -9
  268. package/src/resources/extensions/gsd/tests/complete-task.test.ts +3 -1
  269. package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +43 -2
  270. package/src/resources/extensions/gsd/tests/db-authority-regression.test.ts +208 -0
  271. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +59 -2
  272. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +39 -0
  273. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +27 -0
  274. package/src/resources/extensions/gsd/tests/evidence-cross-ref.test.ts +38 -0
  275. package/src/resources/extensions/gsd/tests/export-html-enhancements.test.ts +8 -0
  276. package/src/resources/extensions/gsd/tests/guided-discuss-project-prompt-rendering.test.ts +2 -0
  277. package/src/resources/extensions/gsd/tests/guided-flow.test.ts +21 -0
  278. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +6 -6
  279. package/src/resources/extensions/gsd/tests/hook-model-resolution.test.ts +5 -0
  280. package/src/resources/extensions/gsd/tests/infra-error.test.ts +2 -2
  281. package/src/resources/extensions/gsd/tests/infra-errors-cooldown.test.ts +9 -0
  282. package/src/resources/extensions/gsd/tests/integration/doctor-runtime.test.ts +20 -0
  283. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +103 -1
  284. package/src/resources/extensions/gsd/tests/integration/migrate-command.test.ts +48 -3
  285. package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +6 -1
  286. package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +5 -1
  287. package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +24 -1
  288. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +6 -1
  289. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +26 -18
  290. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +63 -2
  291. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +121 -1
  292. package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +55 -1
  293. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +26 -0
  294. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
  295. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +225 -1
  296. package/src/resources/extensions/gsd/tests/plan-task.test.ts +17 -0
  297. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +79 -1
  298. package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +86 -0
  299. package/src/resources/extensions/gsd/tests/post-unit-git-failure.test.ts +1 -1
  300. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +53 -0
  301. package/src/resources/extensions/gsd/tests/prompt-loader.test.ts +23 -0
  302. package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +46 -2
  303. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +10 -0
  304. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +31 -1
  305. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +6 -0
  306. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +119 -23
  307. package/src/resources/extensions/gsd/tests/stuck-state-via-db.test.ts +64 -1
  308. package/src/resources/extensions/gsd/tests/summary-render-parity.test.ts +7 -3
  309. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +86 -7
  310. package/src/resources/extensions/gsd/tests/verification-gate.test.ts +110 -1
  311. package/src/resources/extensions/gsd/tests/verification-verdict.test.ts +78 -0
  312. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +1 -1
  313. package/src/resources/extensions/gsd/tests/workflow-memory-pressure.test.ts +21 -1
  314. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +1 -1
  315. package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +39 -0
  316. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +64 -12
  317. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +25 -0
  318. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +54 -0
  319. package/src/resources/extensions/gsd/tools/complete-milestone.ts +8 -10
  320. package/src/resources/extensions/gsd/tools/complete-slice.ts +6 -8
  321. package/src/resources/extensions/gsd/tools/plan-milestone.ts +5 -1
  322. package/src/resources/extensions/gsd/tools/plan-slice.ts +98 -12
  323. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +135 -0
  324. package/src/resources/extensions/gsd/types.ts +1 -1
  325. package/src/resources/extensions/gsd/unit-context-manifest.ts +47 -11
  326. package/src/resources/extensions/gsd/validation.ts +23 -1
  327. package/src/resources/extensions/gsd/verification-gate.ts +78 -6
  328. package/src/resources/extensions/gsd/verification-verdict.ts +47 -0
  329. package/src/resources/extensions/gsd/workflow-projections.ts +6 -8
  330. package/src/resources/extensions/gsd/worktree-lifecycle.ts +61 -10
  331. package/src/resources/extensions/shared/html-shell.ts +412 -0
  332. package/src/resources/extensions/subagent/index.ts +567 -103
  333. package/src/resources/extensions/subagent/launch.ts +131 -0
  334. package/src/resources/extensions/subagent/run-store.ts +218 -0
  335. package/src/resources/extensions/subagent/tests/launch.test.ts +115 -0
  336. package/src/resources/extensions/subagent/tests/run-store.test.ts +111 -0
  337. package/src/resources/extensions/visual-brief/artifact-policy.ts +41 -0
  338. package/src/resources/extensions/visual-brief/extension-manifest.json +8 -0
  339. package/src/resources/extensions/visual-brief/index.ts +8 -0
  340. package/src/resources/extensions/visual-brief/page-contract.ts +136 -0
  341. package/src/resources/extensions/visual-brief/prompts.ts +183 -0
  342. package/src/resources/extensions/visual-brief/tests/visual-brief.test.ts +212 -0
  343. package/dist/web/standalone/.next/server/chunks/5822.js +0 -2
  344. package/dist/web/standalone/.next/static/chunks/2556.0527fea66e123b7f.js +0 -1
  345. package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +0 -1
  346. package/dist/web/standalone/.next/static/css/54ec2745c1da488b.css +0 -1
  347. package/dist/web/standalone/.next/static/css/de70bee13400563f.css +0 -1
  348. package/dist/web/standalone/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
  349. package/dist/web/standalone/.next/static/media/747892c23ea88013-s.woff2 +0 -0
  350. package/dist/web/standalone/.next/static/media/8d697b304b401681-s.woff2 +0 -0
  351. package/dist/web/standalone/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
  352. package/dist/web/standalone/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
  353. package/dist/web/standalone/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
  354. /package/dist/web/standalone/.next/static/{KDRTXR-22LPCsa80X9dey → euQ0CLP_v8V4e76Tu3odJ}/_buildManifest.js +0 -0
  355. /package/dist/web/standalone/.next/static/{KDRTXR-22LPCsa80X9dey → euQ0CLP_v8V4e76Tu3odJ}/_ssgManifest.js +0 -0
@@ -34,6 +34,9 @@ export type MigrationImportCounts = ReturnType<typeof migrateFromMarkdown>;
34
34
 
35
35
  function assertMigrationImportMatchesPreview(imported: MigrationImportCounts, preview: MigrationPreview): void {
36
36
  const mismatches: string[] = [];
37
+ if (imported.decisions !== preview.decisions.total) {
38
+ mismatches.push(`decisions ${imported.decisions}/${preview.decisions.total}`);
39
+ }
37
40
  if (imported.hierarchy.milestones !== preview.milestoneCount) {
38
41
  mismatches.push(`milestones ${imported.hierarchy.milestones}/${preview.milestoneCount}`);
39
42
  }
@@ -73,6 +76,7 @@ export async function importWrittenMigrationToDb(
73
76
  /** Format preview stats for embedding in the review prompt. */
74
77
  function formatPreviewStats(preview: MigrationPreview): string {
75
78
  const lines = [
79
+ `- Decisions: ${preview.decisions.total}`,
76
80
  `- Milestones: ${preview.milestoneCount}`,
77
81
  `- Slices: ${preview.totalSlices} (${preview.doneSlices} done — ${preview.sliceCompletionPct}%)`,
78
82
  `- Tasks: ${preview.totalTasks} (${preview.doneTasks} done — ${preview.taskCompletionPct}%)`,
@@ -179,6 +183,7 @@ export async function handleMigrate(
179
183
 
180
184
  // ── Build preview text ─────────────────────────────────────────────────────
181
185
  const lines: string[] = [
186
+ `Decisions: ${preview.decisions.total}`,
182
187
  `Milestones: ${preview.milestoneCount}`,
183
188
  `Slices: ${preview.totalSlices} (${preview.doneSlices} done — ${preview.sliceCompletionPct}%)`,
184
189
  `Tasks: ${preview.totalTasks} (${preview.doneTasks} done — ${preview.taskCompletionPct}%)`,
@@ -95,6 +95,17 @@ function parsePhaseEntry(line: string): PlanningRoadmapEntry | null {
95
95
  };
96
96
  }
97
97
 
98
+ // Format 3: - ✅ v1.0 MVP — Phases 1-6
99
+ const fmtVersionPhases = stripped.match(/^-\s+([✅🚧])\s+v\d+(?:\.\d+)*\s+(.+?)\s*[—–]\s*Phases?\s+(\d+(?:\.\d+)?)(?:\s*-\s*\d+(?:\.\d+)?)?(?:\s+\(.*\))?\s*$/iu);
100
+ if (fmtVersionPhases) {
101
+ return {
102
+ number: parseFloat(fmtVersionPhases[3]),
103
+ title: fmtVersionPhases[2].trim(),
104
+ done: fmtVersionPhases[1] === '✅',
105
+ raw: line,
106
+ };
107
+ }
108
+
98
109
  return null;
99
110
  }
100
111
 
@@ -4,6 +4,13 @@
4
4
  import type { GSDProject } from './types.js';
5
5
  import type { MigrationPreview } from './writer.js';
6
6
 
7
+ function countCanonicalDecisionRows(content: string): number {
8
+ return content
9
+ .split('\n')
10
+ .filter((line) => /^\|\s*D\d+\s*\|/.test(line.trim()))
11
+ .length;
12
+ }
13
+
7
14
  /**
8
15
  * Compute pre-write statistics from a GSDProject without performing I/O.
9
16
  * Used to show the user what a migration will produce before writing anything.
@@ -36,6 +43,9 @@ export function generatePreview(project: GSDProject): MigrationPreview {
36
43
  }
37
44
 
38
45
  return {
46
+ decisions: {
47
+ total: countCanonicalDecisionRows(project.decisionsContent),
48
+ },
39
49
  milestoneCount: project.milestones.length,
40
50
  totalSlices,
41
51
  totalTasks,
@@ -238,16 +238,53 @@ function normalizeStatus(status: string): 'active' | 'validated' | 'deferred' {
238
238
  return 'active';
239
239
  }
240
240
 
241
+ function normalizeRequirementId(id: string): string | null {
242
+ const match = id.trim().match(/^R(\d+)$/i);
243
+ if (!match) return null;
244
+ return `R${match[1].padStart(3, '0')}`;
245
+ }
246
+
241
247
  function mapRequirements(reqs: PlanningRequirement[]): GSDRequirement[] {
242
248
  let autoId = 0;
249
+ const reservedIds = new Set(
250
+ reqs
251
+ .map((req) => normalizeRequirementId(req.id))
252
+ .filter((id): id is string => id !== null),
253
+ );
254
+ const usedIds = new Set<string>();
255
+
256
+ function nextRequirementId(): string {
257
+ let id = '';
258
+ do {
259
+ autoId++;
260
+ id = padId('R', autoId, 3);
261
+ } while (usedIds.has(id) || reservedIds.has(id));
262
+ usedIds.add(id);
263
+ return id;
264
+ }
265
+
243
266
  return reqs.map((req) => {
244
- autoId++;
267
+ const originalId = req.id.trim();
268
+ const canonicalId = normalizeRequirementId(originalId);
269
+ let id: string;
270
+ let description = req.description;
271
+
272
+ if (canonicalId && !usedIds.has(canonicalId)) {
273
+ id = canonicalId;
274
+ usedIds.add(id);
275
+ } else {
276
+ id = nextRequirementId();
277
+ if (originalId) {
278
+ description = `Legacy ID: ${originalId}\n\n${description}`;
279
+ }
280
+ }
281
+
245
282
  return {
246
- id: req.id && req.id.trim() !== '' ? req.id : padId('R', autoId, 3),
283
+ id,
247
284
  title: req.title,
248
285
  class: 'core-capability',
249
286
  status: normalizeStatus(req.status),
250
- description: req.description,
287
+ description,
251
288
  source: 'inferred',
252
289
  primarySlice: 'none yet',
253
290
  };
@@ -286,7 +323,24 @@ function deriveDecisions(parsed: PlanningProject): string {
286
323
  }
287
324
  }
288
325
  if (decisions.length === 0) return '';
289
- return decisions.map((d) => `- ${d}`).join('\n');
326
+ const lines = [
327
+ '# Decisions Register',
328
+ '',
329
+ '<!-- Append-only. Never edit or remove existing rows.',
330
+ ' To reverse a decision, add a new row that supersedes it.',
331
+ ' Read this file at the start of any planning or research phase. -->',
332
+ '',
333
+ '| # | When | Scope | Decision | Choice | Rationale | Revisable? | Made By |',
334
+ '|---|------|-------|----------|--------|-----------|------------|---------|',
335
+ ];
336
+
337
+ decisions.forEach((decision, index) => {
338
+ const id = padId('D', index + 1, 3);
339
+ const escaped = decision.replace(/\|/g, '\\|');
340
+ lines.push(`| ${id} | migration | migrated-summary | ${escaped} | ${escaped} | Migrated from legacy summary key-decisions | Yes | agent |`);
341
+ });
342
+
343
+ return lines.join('\n') + '\n';
290
344
  }
291
345
 
292
346
  // ─── Main Entry Point ──────────────────────────────────────────────────────
@@ -37,6 +37,9 @@ export interface WrittenFiles {
37
37
 
38
38
  /** Pre-write statistics computed from a GSDProject without I/O. */
39
39
  export interface MigrationPreview {
40
+ decisions: {
41
+ total: number;
42
+ };
40
43
  milestoneCount: number;
41
44
  totalSlices: number;
42
45
  totalTasks: number;
@@ -374,7 +377,17 @@ export function formatProject(content: string): string {
374
377
  */
375
378
  export function formatDecisions(content: string): string {
376
379
  if (!content || !content.trim()) {
377
- return '# Decisions\n\n<!-- Append-only register of architectural and pattern decisions -->\n\n| ID | Decision | Rationale | Date |\n|----|----------|-----------|------|\n';
380
+ return [
381
+ '# Decisions Register',
382
+ '',
383
+ '<!-- Append-only. Never edit or remove existing rows.',
384
+ ' To reverse a decision, add a new row that supersedes it.',
385
+ ' Read this file at the start of any planning or research phase. -->',
386
+ '',
387
+ '| # | When | Scope | Decision | Choice | Rationale | Revisable? | Made By |',
388
+ '|---|------|-------|----------|--------|-----------|------------|---------|',
389
+ '',
390
+ ].join('\n');
378
391
  }
379
392
  return content.endsWith('\n') ? content : content + '\n';
380
393
  }
@@ -2,21 +2,17 @@ import { existsSync, readdirSync, readFileSync } from "node:fs";
2
2
 
3
3
  import { ensureDbOpen } from "./bootstrap/dynamic-tools.js";
4
4
  import {
5
- clearEngineHierarchy,
6
5
  getAllMilestones,
7
6
  getMilestoneSlices,
8
7
  getSliceTasks,
9
8
  isDbAvailable,
10
- transaction,
11
9
  } from "./gsd-db.js";
12
- import { migrateHierarchyToDb } from "./md-importer.js";
13
10
  import { parsePlan, parseRoadmap } from "./parsers-legacy.js";
14
11
  import {
15
12
  milestonesDir,
16
13
  resolveMilestoneFile,
17
14
  resolveSliceFile,
18
15
  } from "./paths.js";
19
- import { invalidateStateCache } from "./state.js";
20
16
 
21
17
  export interface HierarchyCounts {
22
18
  milestones: number;
@@ -25,11 +21,13 @@ export interface HierarchyCounts {
25
21
  }
26
22
 
27
23
  export interface MigrationAutoCheckResult {
28
- action: "none" | "imported";
24
+ action: "none" | "recovery-required";
29
25
  reason: "no-markdown" | "in-sync" | "db-empty" | "count-mismatch";
30
26
  markdown: HierarchyCounts;
31
27
  beforeDb: HierarchyCounts;
32
28
  afterDb: HierarchyCounts;
29
+ recoveryCommand?: string;
30
+ message?: string;
33
31
  }
34
32
 
35
33
  function zeroCounts(): HierarchyCounts {
@@ -83,7 +81,7 @@ export function countDbHierarchy(): HierarchyCounts {
83
81
  return counts;
84
82
  }
85
83
 
86
- export async function autoImportMarkdownHierarchyIfDbMismatch(
84
+ export async function checkMarkdownHierarchyAgainstDb(
87
85
  basePath: string,
88
86
  ): Promise<MigrationAutoCheckResult> {
89
87
  const markdown = countMarkdownHierarchy(basePath);
@@ -108,22 +106,16 @@ export async function autoImportMarkdownHierarchyIfDbMismatch(
108
106
  }
109
107
 
110
108
  const reason = sameCounts(beforeDb, zeroCounts()) ? "db-empty" : "count-mismatch";
111
- const imported = transaction(() => {
112
- clearEngineHierarchy();
113
- return migrateHierarchyToDb(basePath);
114
- });
115
- invalidateStateCache();
116
-
117
- const afterDb = {
118
- milestones: imported.milestones,
119
- slices: imported.slices,
120
- tasks: imported.tasks,
109
+ return {
110
+ action: "recovery-required",
111
+ reason,
112
+ markdown,
113
+ beforeDb,
114
+ afterDb: beforeDb,
115
+ recoveryCommand: "gsd recover",
116
+ message:
117
+ `Markdown planning artifacts (${markdown.milestones}M/${markdown.slices}S/${markdown.tasks}T) ` +
118
+ `do not match the authoritative DB (${beforeDb.milestones}M/${beforeDb.slices}S/${beforeDb.tasks}T). ` +
119
+ "Runtime startup will not import markdown automatically; run explicit GSD recovery if markdown should repopulate the database.",
121
120
  };
122
- if (!sameCounts(markdown, afterDb)) {
123
- throw new Error(
124
- `migration auto-import verification failed: markdown ${markdown.milestones}M/${markdown.slices}S/${markdown.tasks}T, db ${afterDb.milestones}M/${afterDb.slices}S/${afterDb.tasks}T`,
125
- );
126
- }
127
-
128
- return { action: "imported", reason, markdown, beforeDb, afterDb };
129
121
  }
@@ -24,6 +24,7 @@ import { deleteMilestone, getMilestone, isDbAvailable, updateMilestoneStatus } f
24
24
  import { removeWorktree } from "./worktree-manager.js";
25
25
  import { logWarning } from "./workflow-logger.js";
26
26
  import { isAutoActive } from "./auto.js";
27
+ import { isClosedStatus } from "./status-guards.js";
27
28
 
28
29
  /**
29
30
  * Writer-side assert for mutations that race with auto-mode's squash merge (#4704).
@@ -44,7 +45,7 @@ function assertNotAutoActive(action: string): void {
44
45
  /**
45
46
  * Park a milestone — creates a PARKED.md marker file with reason and timestamp.
46
47
  * Parked milestones are skipped during active-milestone discovery but stay on disk.
47
- * Returns true if successfully parked, false if milestone not found or already parked.
48
+ * Returns true if successfully parked, false if milestone not found, already parked, or complete.
48
49
  */
49
50
  export function parkMilestone(basePath: string, milestoneId: string, reason: string): boolean {
50
51
  assertNotAutoActive("park milestone");
@@ -52,8 +53,13 @@ export function parkMilestone(basePath: string, milestoneId: string, reason: str
52
53
  if (!mDir || !existsSync(mDir)) return false;
53
54
 
54
55
  // Guard: do not park a completed milestone — it would corrupt depends_on satisfaction
55
- const summaryFile = resolveMilestoneFile(basePath, milestoneId, "SUMMARY");
56
- if (summaryFile) return false;
56
+ const dbAvailable = isDbAvailable();
57
+ const milestone = dbAvailable ? getMilestone(milestoneId) : null;
58
+ if (milestone && isClosedStatus(milestone.status)) return false;
59
+ if (!dbAvailable) {
60
+ const summaryFile = resolveMilestoneFile(basePath, milestoneId, "SUMMARY");
61
+ if (summaryFile) return false;
62
+ }
57
63
 
58
64
  const parkedPath = join(mDir, buildMilestoneFileName(milestoneId, "PARKED"));
59
65
  if (existsSync(parkedPath)) return false; // already parked
@@ -72,7 +78,7 @@ export function parkMilestone(basePath: string, milestoneId: string, reason: str
72
78
 
73
79
  writeFileSync(parkedPath, content, "utf-8");
74
80
  // Sync DB status so deriveStateFromDb also skips this milestone (#2694)
75
- if (isDbAvailable()) {
81
+ if (dbAvailable) {
76
82
  try {
77
83
  updateMilestoneStatus(milestoneId, "parked");
78
84
  } catch (err) {
@@ -6,6 +6,7 @@
6
6
  // execSync calls because git2 credential handling is too complex.
7
7
 
8
8
  import { execSync, execFileSync } from "node:child_process";
9
+ import type { ExecFileSyncOptionsWithStringEncoding } from "node:child_process";
9
10
  import { existsSync, readFileSync, unlinkSync, rmSync, writeFileSync } from "node:fs";
10
11
  import { join } from "node:path";
11
12
  import { GSDError, GSD_GIT_ERROR } from "./errors.js";
@@ -16,6 +17,8 @@ import { isInfrastructureError } from "./auto/infra-errors.js";
16
17
  // Issue #453: keep auto-mode bookkeeping on the stable git CLI path unless a
17
18
  // caller explicitly opts into the native helper.
18
19
  const NATIVE_GSD_GIT_ENABLED = process.env.GSD_ENABLE_NATIVE_GSD_GIT === "1";
20
+ const TRANSIENT_GIT_RETRY_CODES = new Set(["ENOBUFS", "EAGAIN"]);
21
+ const GIT_RETRY_DELAY_MS = 200;
19
22
 
20
23
  // ─── Native Module Types ──────────────────────────────────────────────────
21
24
 
@@ -144,9 +147,46 @@ function gitExec(basePath: string, args: string[], allowFailure = false): string
144
147
  encoding: "utf-8",
145
148
  env: GIT_NO_PROMPT_ENV,
146
149
  }).trim();
147
- } catch {
150
+ } catch (err) {
148
151
  if (allowFailure) return "";
149
- throw new GSDError(GSD_GIT_ERROR, `git ${args.join(" ")} failed in ${basePath}`);
152
+ throw new GSDError(GSD_GIT_ERROR, `git ${args.join(" ")} failed in ${basePath}: ${getErrorMessage(err)}`);
153
+ }
154
+ }
155
+
156
+ /** sleepSync uses Atomics.wait for a blocking pause without busy-waiting; it blocks the current thread and requires Atomics.wait support. */
157
+ function sleepSync(ms: number): void {
158
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
159
+ }
160
+
161
+ function isRetryableGitError(err: unknown): boolean {
162
+ const code = isInfrastructureError(err)
163
+ ?? isInfrastructureError((err as { stderr?: string })?.stderr ?? "");
164
+ return code !== null && TRANSIENT_GIT_RETRY_CODES.has(code);
165
+ }
166
+
167
+ function execGitFileSyncWithRetry(
168
+ basePath: string,
169
+ args: string[],
170
+ options: Partial<ExecFileSyncOptionsWithStringEncoding>,
171
+ ): string {
172
+ try {
173
+ return execFileSync("git", args, {
174
+ cwd: basePath,
175
+ stdio: ["ignore", "pipe", "pipe"],
176
+ encoding: "utf-8",
177
+ env: GIT_NO_PROMPT_ENV,
178
+ ...options,
179
+ }).trim();
180
+ } catch (err) {
181
+ if (!isRetryableGitError(err)) throw err;
182
+ sleepSync(GIT_RETRY_DELAY_MS);
183
+ return execFileSync("git", args, {
184
+ cwd: basePath,
185
+ stdio: ["ignore", "pipe", "pipe"],
186
+ encoding: "utf-8",
187
+ env: GIT_NO_PROMPT_ENV,
188
+ ...options,
189
+ }).trim();
150
190
  }
151
191
  }
152
192
 
@@ -159,9 +199,9 @@ function gitFileExec(basePath: string, args: string[], allowFailure = false): st
159
199
  encoding: "utf-8",
160
200
  env: GIT_NO_PROMPT_ENV,
161
201
  }).trim();
162
- } catch {
202
+ } catch (err) {
163
203
  if (allowFailure) return "";
164
- throw new GSDError(GSD_GIT_ERROR, `git ${args.join(" ")} failed in ${basePath}`);
204
+ throw new GSDError(GSD_GIT_ERROR, `git ${args.join(" ")} failed in ${basePath}: ${getErrorMessage(err)}`);
165
205
  }
166
206
  }
167
207
 
@@ -428,16 +468,21 @@ export function nativeDiffNameStatus(
428
468
 
429
469
  /**
430
470
  * Get numstat diff between two refs.
471
+ * useMergeBase: if true, uses three-dot semantics.
431
472
  * Native: libgit2 patch line stats.
432
473
  * Fallback: `git diff --numstat`.
433
474
  */
434
- export function nativeDiffNumstat(basePath: string, fromRef: string, toRef: string): GitNumstat[] {
475
+ export function nativeDiffNumstat(basePath: string, fromRef: string, toRef: string, useMergeBase?: boolean): GitNumstat[] {
435
476
  const native = loadNative();
436
- if (native) {
477
+ if (native && !useMergeBase) {
437
478
  return native.gitDiffNumstat(basePath, fromRef, toRef);
438
479
  }
439
480
 
440
- const result = gitExec(basePath, ["diff", "--numstat", fromRef, toRef], true);
481
+ const refspec = useMergeBase ? `${fromRef}...${toRef}` : undefined;
482
+ const args = refspec
483
+ ? ["diff", "--numstat", refspec]
484
+ : ["diff", "--numstat", fromRef, toRef];
485
+ const result = gitExec(basePath, args, true);
441
486
  if (!result) return [];
442
487
 
443
488
  return result.split("\n").filter(Boolean).map(line => {
@@ -935,13 +980,10 @@ export function nativeCommit(
935
980
  try {
936
981
  const args = ["commit", "-F", "-"];
937
982
  if (options?.allowEmpty) args.push("--allow-empty");
938
- const result = execFileSync("git", args, {
939
- cwd: basePath,
983
+ const result = execGitFileSyncWithRetry(basePath, args, {
940
984
  stdio: ["pipe", "pipe", "pipe"],
941
- encoding: "utf-8",
942
- env: GIT_NO_PROMPT_ENV,
943
985
  input: message,
944
- }).trim();
986
+ });
945
987
  return result;
946
988
  } catch (err: unknown) {
947
989
  const errObj = err as { stdout?: string; stderr?: string; message?: string };
@@ -46,6 +46,46 @@ export interface PostExecutionResult {
46
46
 
47
47
  // ─── Import Resolution Check ─────────────────────────────────────────────────
48
48
 
49
+ /**
50
+ * Replace the contents of single- and double-quoted string literals on a single
51
+ * source line with spaces so import patterns do not match text inside strings.
52
+ * Template-literal spans are handled separately via the inTemplateLiteral flag.
53
+ */
54
+ function stripStringLiterals(line: string): string {
55
+ let result = "";
56
+ let i = 0;
57
+
58
+ while (i < line.length) {
59
+ const ch = line[i];
60
+
61
+ if (ch === '"' || ch === "'") {
62
+ result += ch;
63
+ i++;
64
+
65
+ while (i < line.length) {
66
+ const c = line[i];
67
+
68
+ if (c === "\\" && i + 1 < line.length) {
69
+ result += " ";
70
+ i += 2;
71
+ } else if (c === ch) {
72
+ result += ch;
73
+ i++;
74
+ break;
75
+ } else {
76
+ result += " ";
77
+ i++;
78
+ }
79
+ }
80
+ } else {
81
+ result += ch;
82
+ i++;
83
+ }
84
+ }
85
+
86
+ return result;
87
+ }
88
+
49
89
  /**
50
90
  * Extract relative import paths from TypeScript/JavaScript source code.
51
91
  * Returns array of { importPath, lineNum } for relative imports.
@@ -62,14 +102,23 @@ export function extractRelativeImports(
62
102
  // import './path'
63
103
  // require('./path')
64
104
  // require("../path")
65
- const importPattern = /(?:import\s+(?:.*?\s+from\s+)?|require\s*\(\s*)(['"])(\.\.?\/[^'"]+)\1/g;
105
+ const importPattern = /(?:^|[;{}]\s*)import\s+(?:.*?\s+from\s+)?(['"])(\.\.?\/[^'"]+)\1/g;
106
+ const requirePattern = /require\s*\(\s*(['"])(\.\.?\/[^'"]+)\1/g;
66
107
 
67
108
  // Track if we're inside a block comment
68
109
  let inBlockComment = false;
110
+ let inTemplateLiteral = false;
69
111
 
70
112
  for (let i = 0; i < lines.length; i++) {
71
113
  const line = lines[i];
72
114
 
115
+ if (inTemplateLiteral) {
116
+ if ((line.match(/(?<!\\)`/g) ?? []).length % 2 === 1) {
117
+ inTemplateLiteral = false;
118
+ }
119
+ continue;
120
+ }
121
+
73
122
  // Handle block comment boundaries
74
123
  if (inBlockComment) {
75
124
  if (line.includes("*/")) {
@@ -101,10 +150,22 @@ export function extractRelativeImports(
101
150
 
102
151
  // Reset lastIndex for each line
103
152
  importPattern.lastIndex = 0;
153
+ requirePattern.lastIndex = 0;
154
+
155
+ const strippedLine = stripStringLiterals(line);
104
156
 
105
157
  while ((match = importPattern.exec(line)) !== null) {
158
+ const importOffset = match[0].indexOf("import");
159
+ const importStart = match.index + importOffset;
160
+ if (
161
+ strippedLine.slice(importStart, importStart + "import".length) !==
162
+ "import"
163
+ ) {
164
+ continue;
165
+ }
166
+
106
167
  // Check if this match is after a // comment marker on the same line
107
- const beforeMatch = line.substring(0, match.index);
168
+ const beforeMatch = strippedLine.substring(0, match.index);
108
169
  if (beforeMatch.includes("//")) {
109
170
  continue;
110
171
  }
@@ -114,6 +175,30 @@ export function extractRelativeImports(
114
175
  lineNum: i + 1,
115
176
  });
116
177
  }
178
+
179
+ while ((match = requirePattern.exec(line)) !== null) {
180
+ if (
181
+ strippedLine.slice(match.index, match.index + "require".length) !==
182
+ "require"
183
+ ) {
184
+ continue;
185
+ }
186
+
187
+ // Check if this match is after a // comment marker on the same line
188
+ const beforeMatch = strippedLine.substring(0, match.index);
189
+ if (beforeMatch.includes("//")) {
190
+ continue;
191
+ }
192
+
193
+ imports.push({
194
+ importPath: match[2],
195
+ lineNum: i + 1,
196
+ });
197
+ }
198
+
199
+ if ((strippedLine.match(/(?<!\\)`/g) ?? []).length % 2 === 1) {
200
+ inTemplateLiteral = true;
201
+ }
117
202
  }
118
203
 
119
204
  return imports;
@@ -23,6 +23,7 @@ import { homedir } from "node:os";
23
23
  import { resolve } from "node:path";
24
24
  import type { TaskRow } from "./db-task-slice-rows.js";
25
25
  import type { PreExecutionCheckJSON } from "./verification-evidence.ts";
26
+ import { validateVerificationCommand } from "./verification-gate.js";
26
27
 
27
28
  const NPM_COMMAND = process.platform === "win32" ? "npm.cmd" : "npm";
28
29
 
@@ -37,6 +38,35 @@ export interface PreExecutionResult {
37
38
  durationMs: number;
38
39
  }
39
40
 
41
+ export function checkVerificationCommands(tasks: TaskRow[]): PreExecutionCheckJSON[] {
42
+ const results: PreExecutionCheckJSON[] = [];
43
+
44
+ for (const task of tasks) {
45
+ const verify = task.verify.trim();
46
+ if (!verify) continue;
47
+
48
+ const commands = verify
49
+ .split("&&")
50
+ .map((command) => command.trim())
51
+ .filter(Boolean);
52
+
53
+ for (const command of commands) {
54
+ const validation = validateVerificationCommand(command);
55
+ if (!validation.ok) {
56
+ results.push({
57
+ category: "tool",
58
+ target: `${task.id} Verify`,
59
+ passed: false,
60
+ message: `Unsafe or non-runnable Verify command: ${command} (${validation.reason})`,
61
+ blocking: true,
62
+ });
63
+ }
64
+ }
65
+ }
66
+
67
+ return results;
68
+ }
69
+
40
70
  // ─── Package Existence Check ─────────────────────────────────────────────────
41
71
 
42
72
  /**
@@ -757,8 +787,9 @@ export async function runPreExecutionChecks(
757
787
  const fileChecks = checkFilePathConsistency(tasks, basePath);
758
788
  const orderingChecks = checkTaskOrdering(tasks, basePath);
759
789
  const contractChecks = checkInterfaceContracts(tasks, basePath);
790
+ const verificationChecks = checkVerificationCommands(tasks);
760
791
 
761
- allChecks.push(...fileChecks, ...orderingChecks, ...contractChecks);
792
+ allChecks.push(...fileChecks, ...orderingChecks, ...contractChecks, ...verificationChecks);
762
793
 
763
794
  // Run async package checks
764
795
  const packageChecks = await checkPackageExistence(tasks, basePath);
@@ -200,7 +200,7 @@ export function loadPrompt(name: string, vars: Record<string, string> = {}): str
200
200
  if (missing.length > 0) {
201
201
  throw new GSDError(
202
202
  GSD_PARSE_ERROR,
203
- `loadPrompt("${name}"): template declares {{${missing.join("}}, {{")}}}} but no value was provided. ` +
203
+ `loadPrompt("${name}"): template declares {{${missing.join("}}, {{")}}} but no value was provided. ` +
204
204
  `This usually means the extension code in memory is older than the template on disk. ` +
205
205
  `Restart pi to reload the extension.`,
206
206
  );
@@ -57,7 +57,7 @@ Subagents report only; they do not write user source. Fold any findings into Dec
57
57
  **Success path** (all verifications passed):
58
58
 
59
59
  10. For each requirement whose status changed in step 9, call `gsd_requirement_update` with the requirement ID and updated `status` and `validation` fields — the tool regenerates `.gsd/REQUIREMENTS.md` automatically. Do this BEFORE completing the milestone so requirement updates are persisted.
60
- 11. Update `.gsd/PROJECT.md`: use the `write` tool with `path: ".gsd/PROJECT.md"` and `content` containing the full updated document reflecting milestone completion and current project state. Do NOT use the `edit` tool for this PROJECT.md is a full-document refresh.
60
+ 11. Refresh the project state through `gsd_summary_save` with `artifact_type: "PROJECT"` and the full updated project markdown as `content`; omit `milestone_id`. The tool persists the DB-backed PROJECT artifact and renders `.gsd/PROJECT.md`. Do not write or edit `.gsd/PROJECT.md` directly.
61
61
  12. Extract structured learnings from this milestone and persist them to the GSD memory store. Follow the procedure block immediately below — it writes `{{milestoneId}}-LEARNINGS.md` as the audit trail and persists Patterns, Lessons, and Decisions via `capture_thought` (categories: pattern, gotcha/convention, architecture). The memory store is the single source of truth for cross-session durable knowledge (ADR-013).
62
62
 
63
63
  {{extractLearningsSteps}}
@@ -34,7 +34,7 @@ Use `subagent` only for fresh-context review when useful: reviewer for cross-cut
34
34
  12. Review the inlined task-summary excerpts for DECISIONS.md and KNOWLEDGE.md-worthy decisions, patterns, and gotchas. Read full `*-SUMMARY.md` files only when an excerpt is absent, truncated, or lacks the specific evidence needed for the slice narrative. Capture significant items with `capture_thought`; do not append knowledge files directly.
35
35
  13. When verification passes, call `gsd_slice_complete`. The DB-backed tool is the canonical write path. Do **not** manually write `{{sliceSummaryPath}}`. Do **not** manually write `{{sliceUatPath}}`. Do not edit roadmap checkboxes; the tool renders files and updates projections.
36
36
  14. Do not run git commands.
37
- 15. Update `.gsd/PROJECT.md` with a full `write` only if the current project state needs refresh.
37
+ 15. If the current project state needs refresh, call `gsd_summary_save` with `artifact_type: "PROJECT"` and the full updated project markdown as `content`; omit `milestone_id`. Do not write or edit `.gsd/PROJECT.md` directly.
38
38
 
39
39
  **Autonomous execution:** no human is available. Do not call `ask_user_questions` or `secure_env_collect`; make reasonable assumptions and document them.
40
40