gsd-pi 2.82.0-dev.2841a1e44 → 2.82.0-dev.3709f22a5

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/README.md +2 -2
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/GSD-WORKFLOW.md +7 -0
  4. package/dist/resources/extensions/claude-code-cli/partial-builder.js +2 -1
  5. package/dist/resources/extensions/gsd/auto/infra-errors.js +9 -3
  6. package/dist/resources/extensions/gsd/auto/loop.js +5 -5
  7. package/dist/resources/extensions/gsd/auto/orchestrator.js +11 -0
  8. package/dist/resources/extensions/gsd/auto/phases.js +28 -2
  9. package/dist/resources/extensions/gsd/auto/workflow-memory-pressure.js +12 -0
  10. package/dist/resources/extensions/gsd/auto-dashboard.js +66 -1
  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 +70 -9
  14. package/dist/resources/extensions/gsd/auto-recovery.js +31 -1
  15. package/dist/resources/extensions/gsd/auto-start.js +85 -12
  16. package/dist/resources/extensions/gsd/auto-worktree.js +111 -1
  17. package/dist/resources/extensions/gsd/auto.js +37 -4
  18. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +25 -6
  19. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +9 -8
  20. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +4 -2
  21. package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +5 -2
  22. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +13 -1
  23. package/dist/resources/extensions/gsd/commands/handlers/core.js +17 -1
  24. package/dist/resources/extensions/gsd/crash-recovery.js +31 -5
  25. package/dist/resources/extensions/gsd/db/unit-dispatches.js +3 -2
  26. package/dist/resources/extensions/gsd/dispatch-guard.js +2 -2
  27. package/dist/resources/extensions/gsd/doctor-git-checks.js +46 -1
  28. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +28 -11
  29. package/dist/resources/extensions/gsd/doctor.js +2 -28
  30. package/dist/resources/extensions/gsd/export-html.js +27 -425
  31. package/dist/resources/extensions/gsd/git-service.js +39 -1
  32. package/dist/resources/extensions/gsd/gsd-db.js +1 -0
  33. package/dist/resources/extensions/gsd/guided-flow.js +93 -111
  34. package/dist/resources/extensions/gsd/guided-unit-context.js +23 -0
  35. package/dist/resources/extensions/gsd/migrate/parsers.js +10 -0
  36. package/dist/resources/extensions/gsd/migration-auto-check.js +12 -17
  37. package/dist/resources/extensions/gsd/milestone-actions.js +11 -4
  38. package/dist/resources/extensions/gsd/native-git-bridge.js +48 -12
  39. package/dist/resources/extensions/gsd/pending-auto-start.js +52 -0
  40. package/dist/resources/extensions/gsd/post-execution-checks.js +73 -2
  41. package/dist/resources/extensions/gsd/pre-execution-checks.js +28 -1
  42. package/dist/resources/extensions/gsd/prompt-loader.js +1 -1
  43. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  44. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  45. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
  46. package/dist/resources/extensions/gsd/prompts/discuss.md +9 -9
  47. package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
  48. package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
  49. package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -4
  50. package/dist/resources/extensions/gsd/prompts/queue.md +4 -4
  51. package/dist/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  52. package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  53. package/dist/resources/extensions/gsd/smart-entry-routing.js +36 -0
  54. package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +6 -1
  55. package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +9 -14
  56. package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +19 -24
  57. package/dist/resources/extensions/gsd/status-guards.js +4 -0
  58. package/dist/resources/extensions/gsd/templates/plan.md +8 -5
  59. package/dist/resources/extensions/gsd/templates/task-plan.md +4 -2
  60. package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -8
  61. package/dist/resources/extensions/gsd/tools/complete-slice.js +6 -8
  62. package/dist/resources/extensions/gsd/tools/plan-milestone.js +7 -1
  63. package/dist/resources/extensions/gsd/tools/plan-slice.js +89 -14
  64. package/dist/resources/extensions/gsd/unit-context-manifest.js +7 -8
  65. package/dist/resources/extensions/gsd/validation.js +23 -1
  66. package/dist/resources/extensions/gsd/verification-gate.js +68 -7
  67. package/dist/resources/extensions/gsd/workflow-projections.js +6 -8
  68. package/dist/resources/extensions/gsd/worktree-lifecycle.js +33 -8
  69. package/dist/resources/extensions/shared/html-shell.js +388 -0
  70. package/dist/resources/extensions/visual-brief/page-contract.js +2 -0
  71. package/dist/resources/extensions/visual-brief/prompts.js +29 -0
  72. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  73. package/dist/web/standalone/.next/BUILD_ID +1 -1
  74. package/dist/web/standalone/.next/app-path-routes-manifest.json +15 -15
  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/server/app/_global-error/page_client-reference-manifest.js +1 -1
  78. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  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/page.js +2 -2
  87. package/dist/web/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  88. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  89. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  90. package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -7
  91. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -7
  92. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -5
  94. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -5
  97. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  98. package/dist/web/standalone/.next/server/app/index.html +1 -1
  99. package/dist/web/standalone/.next/server/app/index.rsc +4 -7
  100. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -7
  102. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -5
  104. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -5
  105. package/dist/web/standalone/.next/server/app/page.js +2 -2
  106. package/dist/web/standalone/.next/server/app/page.js.nft.json +1 -1
  107. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  108. package/dist/web/standalone/.next/server/app-paths-manifest.json +15 -15
  109. package/dist/web/standalone/.next/server/chunks/4266.js +2 -0
  110. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  111. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  112. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  113. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  114. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  115. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  116. package/dist/web/standalone/.next/static/chunks/app/layout-8c10ec293ae0f1d5.js +1 -0
  117. package/dist/web/standalone/.next/static/chunks/{webpack-6a95bc41e0f7ec89.js → webpack-9a4db269f9ed63ad.js} +1 -1
  118. package/dist/web/standalone/.next/static/css/746ee28c929d1880.css +1 -0
  119. package/package.json +2 -2
  120. package/packages/mcp-server/src/workflow-tools.test.ts +1 -1
  121. package/packages/native/tsconfig.json +2 -1
  122. package/packages/native/tsconfig.tsbuildinfo +1 -1
  123. package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
  124. package/packages/pi-ai/dist/providers/openai-codex-responses.js +82 -1
  125. package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
  126. package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts +2 -0
  127. package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts.map +1 -0
  128. package/packages/pi-ai/dist/providers/openai-codex-responses.test.js +52 -0
  129. package/packages/pi-ai/dist/providers/openai-codex-responses.test.js.map +1 -0
  130. package/packages/pi-ai/dist/providers/simple-options.d.ts +2 -4
  131. package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  132. package/packages/pi-ai/dist/providers/simple-options.js +5 -6
  133. package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
  134. package/packages/pi-ai/dist/providers/simple-options.test.d.ts +2 -0
  135. package/packages/pi-ai/dist/providers/simple-options.test.d.ts.map +1 -0
  136. package/packages/pi-ai/dist/providers/simple-options.test.js +50 -0
  137. package/packages/pi-ai/dist/providers/simple-options.test.js.map +1 -0
  138. package/packages/pi-ai/src/providers/openai-codex-responses.test.ts +63 -0
  139. package/packages/pi-ai/src/providers/openai-codex-responses.ts +91 -1
  140. package/packages/pi-ai/src/providers/simple-options.test.ts +60 -0
  141. package/packages/pi-ai/src/providers/simple-options.ts +5 -6
  142. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  143. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts +2 -0
  144. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts.map +1 -0
  145. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js +66 -0
  146. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js.map +1 -0
  147. package/packages/pi-coding-agent/dist/core/agent-session.js +1 -1
  148. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  149. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  150. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +24 -6
  151. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  152. package/packages/pi-coding-agent/src/core/agent-session-thinking-level.test.ts +79 -0
  153. package/packages/pi-coding-agent/src/core/agent-session.ts +1 -1
  154. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +23 -7
  155. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  156. package/src/resources/GSD-WORKFLOW.md +7 -0
  157. package/src/resources/extensions/claude-code-cli/partial-builder.ts +2 -1
  158. package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +19 -2
  159. package/src/resources/extensions/gsd/auto/contracts.ts +14 -6
  160. package/src/resources/extensions/gsd/auto/infra-errors.ts +9 -3
  161. package/src/resources/extensions/gsd/auto/loop.ts +8 -5
  162. package/src/resources/extensions/gsd/auto/orchestrator.ts +11 -0
  163. package/src/resources/extensions/gsd/auto/phases.ts +30 -2
  164. package/src/resources/extensions/gsd/auto/workflow-memory-pressure.ts +13 -0
  165. package/src/resources/extensions/gsd/auto-dashboard.ts +72 -1
  166. package/src/resources/extensions/gsd/auto-dispatch.ts +14 -6
  167. package/src/resources/extensions/gsd/auto-model-selection.ts +2 -1
  168. package/src/resources/extensions/gsd/auto-post-unit.ts +77 -7
  169. package/src/resources/extensions/gsd/auto-recovery.ts +29 -0
  170. package/src/resources/extensions/gsd/auto-start.ts +92 -9
  171. package/src/resources/extensions/gsd/auto-worktree.ts +119 -1
  172. package/src/resources/extensions/gsd/auto.ts +40 -4
  173. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +33 -6
  174. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +9 -8
  175. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +4 -2
  176. package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +3 -1
  177. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +16 -1
  178. package/src/resources/extensions/gsd/commands/handlers/core.ts +17 -1
  179. package/src/resources/extensions/gsd/crash-recovery.ts +30 -4
  180. package/src/resources/extensions/gsd/db/unit-dispatches.ts +4 -3
  181. package/src/resources/extensions/gsd/dispatch-guard.ts +2 -2
  182. package/src/resources/extensions/gsd/doctor-git-checks.ts +45 -1
  183. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +25 -13
  184. package/src/resources/extensions/gsd/doctor-types.ts +1 -0
  185. package/src/resources/extensions/gsd/doctor.ts +2 -27
  186. package/src/resources/extensions/gsd/export-html.ts +27 -427
  187. package/src/resources/extensions/gsd/git-service.ts +45 -1
  188. package/src/resources/extensions/gsd/gsd-db.ts +3 -0
  189. package/src/resources/extensions/gsd/guided-flow.ts +126 -128
  190. package/src/resources/extensions/gsd/guided-unit-context.ts +30 -0
  191. package/src/resources/extensions/gsd/migrate/parsers.ts +11 -0
  192. package/src/resources/extensions/gsd/migration-auto-check.ts +15 -23
  193. package/src/resources/extensions/gsd/milestone-actions.ts +10 -4
  194. package/src/resources/extensions/gsd/native-git-bridge.ts +54 -12
  195. package/src/resources/extensions/gsd/pending-auto-start.ts +79 -0
  196. package/src/resources/extensions/gsd/post-execution-checks.ts +87 -2
  197. package/src/resources/extensions/gsd/pre-execution-checks.ts +32 -1
  198. package/src/resources/extensions/gsd/prompt-loader.ts +1 -1
  199. package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  200. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  201. package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
  202. package/src/resources/extensions/gsd/prompts/discuss.md +9 -9
  203. package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
  204. package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
  205. package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -4
  206. package/src/resources/extensions/gsd/prompts/queue.md +4 -4
  207. package/src/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  208. package/src/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  209. package/src/resources/extensions/gsd/smart-entry-routing.ts +77 -0
  210. package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +8 -1
  211. package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +12 -15
  212. package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +17 -25
  213. package/src/resources/extensions/gsd/status-guards.ts +5 -0
  214. package/src/resources/extensions/gsd/templates/plan.md +8 -5
  215. package/src/resources/extensions/gsd/templates/task-plan.md +4 -2
  216. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +71 -0
  217. package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +116 -0
  218. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +54 -0
  219. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +80 -1
  220. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +6 -6
  221. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +53 -2
  222. package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +12 -1
  223. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +15 -1
  224. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +1 -0
  225. package/src/resources/extensions/gsd/tests/auto-stop-notification.test.ts +20 -0
  226. package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +69 -1
  227. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +11 -2
  228. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +4 -1
  229. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +5 -9
  230. package/src/resources/extensions/gsd/tests/complete-task.test.ts +3 -1
  231. package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +43 -2
  232. package/src/resources/extensions/gsd/tests/db-authority-regression.test.ts +208 -0
  233. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +59 -2
  234. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +39 -0
  235. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +27 -0
  236. package/src/resources/extensions/gsd/tests/doctor-empty-worktree.test.ts +65 -0
  237. package/src/resources/extensions/gsd/tests/export-html-enhancements.test.ts +8 -0
  238. package/src/resources/extensions/gsd/tests/guided-discuss-project-prompt-rendering.test.ts +2 -0
  239. package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +106 -0
  240. package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +59 -11
  241. package/src/resources/extensions/gsd/tests/guided-flow.test.ts +21 -0
  242. package/src/resources/extensions/gsd/tests/guided-tool-contract.test.ts +65 -0
  243. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +7 -7
  244. package/src/resources/extensions/gsd/tests/hook-model-resolution.test.ts +5 -0
  245. package/src/resources/extensions/gsd/tests/infra-error.test.ts +2 -2
  246. package/src/resources/extensions/gsd/tests/infra-errors-cooldown.test.ts +9 -0
  247. package/src/resources/extensions/gsd/tests/integration/doctor-runtime.test.ts +20 -0
  248. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +103 -1
  249. package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +6 -1
  250. package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +24 -1
  251. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +26 -18
  252. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +63 -2
  253. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +121 -1
  254. package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +55 -1
  255. package/src/resources/extensions/gsd/tests/pending-autostart-scope.test.ts +29 -5
  256. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +26 -0
  257. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
  258. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +225 -1
  259. package/src/resources/extensions/gsd/tests/plan-task.test.ts +17 -0
  260. package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +86 -0
  261. package/src/resources/extensions/gsd/tests/post-unit-git-failure.test.ts +1 -1
  262. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +53 -0
  263. package/src/resources/extensions/gsd/tests/prompt-loader.test.ts +23 -0
  264. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +20 -1
  265. package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +46 -2
  266. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +10 -0
  267. package/src/resources/extensions/gsd/tests/smart-entry-routing.test.ts +113 -0
  268. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +53 -2
  269. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +119 -23
  270. package/src/resources/extensions/gsd/tests/stuck-state-via-db.test.ts +64 -1
  271. package/src/resources/extensions/gsd/tests/summary-render-parity.test.ts +7 -3
  272. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +65 -7
  273. package/src/resources/extensions/gsd/tests/verification-gate.test.ts +110 -1
  274. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +1 -1
  275. package/src/resources/extensions/gsd/tests/workflow-memory-pressure.test.ts +21 -1
  276. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +1 -1
  277. package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +39 -0
  278. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +64 -12
  279. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +38 -0
  280. package/src/resources/extensions/gsd/tools/complete-milestone.ts +8 -10
  281. package/src/resources/extensions/gsd/tools/complete-slice.ts +6 -8
  282. package/src/resources/extensions/gsd/tools/plan-milestone.ts +5 -1
  283. package/src/resources/extensions/gsd/tools/plan-slice.ts +98 -12
  284. package/src/resources/extensions/gsd/types.ts +1 -1
  285. package/src/resources/extensions/gsd/unit-context-manifest.ts +12 -9
  286. package/src/resources/extensions/gsd/validation.ts +23 -1
  287. package/src/resources/extensions/gsd/verification-gate.ts +78 -6
  288. package/src/resources/extensions/gsd/workflow-projections.ts +6 -8
  289. package/src/resources/extensions/gsd/worktree-lifecycle.ts +41 -8
  290. package/src/resources/extensions/shared/html-shell.ts +412 -0
  291. package/src/resources/extensions/visual-brief/page-contract.ts +2 -0
  292. package/src/resources/extensions/visual-brief/prompts.ts +37 -1
  293. package/src/resources/extensions/visual-brief/tests/visual-brief.test.ts +40 -0
  294. package/dist/web/standalone/.next/server/chunks/5822.js +0 -2
  295. package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +0 -1
  296. package/dist/web/standalone/.next/static/css/0262768ec1b89d34.css +0 -1
  297. package/dist/web/standalone/.next/static/css/de70bee13400563f.css +0 -1
  298. package/dist/web/standalone/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
  299. package/dist/web/standalone/.next/static/media/747892c23ea88013-s.woff2 +0 -0
  300. package/dist/web/standalone/.next/static/media/8d697b304b401681-s.woff2 +0 -0
  301. package/dist/web/standalone/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
  302. package/dist/web/standalone/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
  303. package/dist/web/standalone/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
  304. /package/dist/web/standalone/.next/static/{Qgr2B_MRhPxC0z8fwv4vT → kkGf3_VaPFkiDNV_D7Dtl}/_buildManifest.js +0 -0
  305. /package/dist/web/standalone/.next/static/{Qgr2B_MRhPxC0z8fwv4vT → kkGf3_VaPFkiDNV_D7Dtl}/_ssgManifest.js +0 -0
@@ -0,0 +1,208 @@
1
+ // Project/App: GSD-2
2
+ // File Purpose: Regression tests for DB authority over markdown projections.
3
+
4
+ import test from "node:test";
5
+ import assert from "node:assert/strict";
6
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
7
+ import { join } from "node:path";
8
+ import { tmpdir } from "node:os";
9
+
10
+ import {
11
+ closeDatabase,
12
+ getAllMilestones,
13
+ getSliceTasks,
14
+ insertMilestone,
15
+ insertRequirement,
16
+ insertSlice,
17
+ openDatabase,
18
+ } from "../gsd-db.ts";
19
+ import { migrateHierarchyToDb } from "../md-importer.ts";
20
+ import { checkMarkdownHierarchyAgainstDb } from "../migration-auto-check.ts";
21
+ import { queryDecisions } from "../context-store.ts";
22
+ import { deriveStateFromDb, invalidateStateCache } from "../state.ts";
23
+ import type { Requirement } from "../types.ts";
24
+
25
+ function makeBase(prefix = "gsd-db-authority-"): string {
26
+ const base = mkdtempSync(join(tmpdir(), prefix));
27
+ mkdirSync(join(base, ".gsd"), { recursive: true });
28
+ return base;
29
+ }
30
+
31
+ function cleanup(base: string): void {
32
+ try {
33
+ closeDatabase();
34
+ } catch {
35
+ /* noop */
36
+ }
37
+ rmSync(base, { recursive: true, force: true });
38
+ }
39
+
40
+ function openProjectDb(base: string): void {
41
+ openDatabase(join(base, ".gsd", "gsd.db"));
42
+ }
43
+
44
+ function activeRequirement(id: string): Requirement {
45
+ return {
46
+ id,
47
+ class: "functional",
48
+ status: "active",
49
+ description: `${id} from DB`,
50
+ why: "DB authority regression fixture",
51
+ source: "test",
52
+ primary_owner: "M999/S01",
53
+ supporting_slices: "",
54
+ validation: "derive state",
55
+ notes: "",
56
+ full_content: `${id} from DB`,
57
+ superseded_by: null,
58
+ };
59
+ }
60
+
61
+ test("DB authority: PROJECT.md and QUEUE-ORDER projections do not choose runtime milestone", async (t) => {
62
+ const base = makeBase();
63
+ t.after(() => cleanup(base));
64
+
65
+ mkdirSync(join(base, ".gsd", "milestones", "M001"), { recursive: true });
66
+ writeFileSync(
67
+ join(base, ".gsd", "PROJECT.md"),
68
+ [
69
+ "# Projection Project",
70
+ "",
71
+ "## Milestone Sequence",
72
+ "- [ ] M001: Projection Only -- should not become active",
73
+ "",
74
+ ].join("\n"),
75
+ );
76
+ writeFileSync(
77
+ join(base, ".gsd", "QUEUE-ORDER.json"),
78
+ JSON.stringify({ order: ["M001", "M999"], updatedAt: new Date().toISOString() }),
79
+ );
80
+
81
+ openProjectDb(base);
82
+ insertMilestone({ id: "M999", title: "DB Milestone", status: "active" });
83
+ insertSlice({ id: "S01", milestoneId: "M999", title: "DB Slice", status: "pending", risk: "low", depends: [], demo: "DB demo", sequence: 1 });
84
+
85
+ invalidateStateCache();
86
+ const state = await deriveStateFromDb(base);
87
+
88
+ assert.equal(state.activeMilestone?.id, "M999");
89
+ assert.equal(state.registry.some((entry) => entry.id === "M001"), false);
90
+ });
91
+
92
+ test("DB authority: REQUIREMENTS.md and DECISIONS.md projections do not populate DB reads", async (t) => {
93
+ const base = makeBase();
94
+ t.after(() => cleanup(base));
95
+
96
+ writeFileSync(
97
+ join(base, ".gsd", "REQUIREMENTS.md"),
98
+ [
99
+ "# Requirements",
100
+ "",
101
+ "## Active",
102
+ "### R001 - Projection-only requirement",
103
+ "- Class: functional",
104
+ "- Status: active",
105
+ "",
106
+ ].join("\n"),
107
+ );
108
+ writeFileSync(
109
+ join(base, ".gsd", "DECISIONS.md"),
110
+ [
111
+ "# Decisions",
112
+ "",
113
+ "| # | When / Context | Scope | Decision | Choice | Rationale | Revisable | Made By |",
114
+ "|---|----------------|-------|----------|--------|-----------|----------|---------|",
115
+ "| D001 | Now | global | Projection-only decision | Ignore | DB is authority | Yes | human |",
116
+ "",
117
+ ].join("\n"),
118
+ );
119
+
120
+ openProjectDb(base);
121
+ insertMilestone({ id: "M999", title: "DB Milestone", status: "active" });
122
+
123
+ invalidateStateCache();
124
+ const state = await deriveStateFromDb(base);
125
+
126
+ assert.deepEqual(state.requirements, {
127
+ active: 0,
128
+ validated: 0,
129
+ deferred: 0,
130
+ outOfScope: 0,
131
+ blocked: 0,
132
+ total: 0,
133
+ });
134
+ assert.deepEqual(queryDecisions(), []);
135
+ });
136
+
137
+ test("DB authority: DB requirements remain canonical when REQUIREMENTS.md disagrees", async (t) => {
138
+ const base = makeBase();
139
+ t.after(() => cleanup(base));
140
+
141
+ writeFileSync(
142
+ join(base, ".gsd", "REQUIREMENTS.md"),
143
+ [
144
+ "# Requirements",
145
+ "",
146
+ "## Active",
147
+ "### R999 - Projection-only requirement",
148
+ "- Class: functional",
149
+ "- Status: active",
150
+ "",
151
+ ].join("\n"),
152
+ );
153
+
154
+ openProjectDb(base);
155
+ insertMilestone({ id: "M999", title: "DB Milestone", status: "active" });
156
+ insertRequirement(activeRequirement("R001"));
157
+
158
+ invalidateStateCache();
159
+ const state = await deriveStateFromDb(base);
160
+
161
+ assert.ok(state.requirements);
162
+ assert.equal(state.requirements.active, 1);
163
+ assert.equal(state.requirements.total, 1);
164
+ });
165
+
166
+ test("explicit markdown import remains opt-in and is not run by startup mismatch check", async (t) => {
167
+ const base = makeBase();
168
+ t.after(() => cleanup(base));
169
+
170
+ const milestoneDir = join(base, ".gsd", "milestones", "M001");
171
+ const sliceDir = join(milestoneDir, "slices", "S01");
172
+ const tasksDir = join(sliceDir, "tasks");
173
+ mkdirSync(tasksDir, { recursive: true });
174
+ writeFileSync(
175
+ join(milestoneDir, "M001-ROADMAP.md"),
176
+ [
177
+ "# M001: Imported Explicitly",
178
+ "",
179
+ "**Vision:** Explicit recovery import only",
180
+ "",
181
+ "## Slices",
182
+ "- [ ] **S01: Slice** `risk:low` `depends:[]`",
183
+ "",
184
+ ].join("\n"),
185
+ );
186
+ writeFileSync(
187
+ join(sliceDir, "S01-PLAN.md"),
188
+ [
189
+ "# S01: Slice",
190
+ "",
191
+ "**Goal:** prove explicit import",
192
+ "",
193
+ "## Tasks",
194
+ "- [ ] **T01: Task** `est:5m`",
195
+ "",
196
+ ].join("\n"),
197
+ );
198
+
199
+ openProjectDb(base);
200
+ const check = await checkMarkdownHierarchyAgainstDb(base);
201
+ assert.equal(check.action, "recovery-required");
202
+ assert.equal(getAllMilestones().length, 0, "startup mismatch check must not import markdown");
203
+
204
+ const imported = migrateHierarchyToDb(base);
205
+ assert.deepEqual(imported, { milestones: 1, slices: 1, tasks: 1 });
206
+ assert.equal(getAllMilestones().length, 1);
207
+ assert.equal(getSliceTasks("M001", "S01").length, 1);
208
+ });
@@ -1,6 +1,6 @@
1
1
  import test from "node:test";
2
2
  import assert from "node:assert/strict";
3
- import { existsSync, mkdirSync, readFileSync, realpathSync, rmSync, writeFileSync } from "node:fs";
3
+ import { chmodSync, existsSync, mkdirSync, readFileSync, realpathSync, rmSync, writeFileSync } from "node:fs";
4
4
  import { execFileSync } from "node:child_process";
5
5
  import { tmpdir } from "node:os";
6
6
  import { join } from "node:path";
@@ -10,7 +10,7 @@ import { runDispatch, runPreDispatch } from "../auto/phases.ts";
10
10
  import { AutoSession } from "../auto/session.ts";
11
11
  import { resolveUnitSupervisionTimeouts } from "../auto-timers.ts";
12
12
  import { bootstrapAutoSession } from "../auto-start.ts";
13
- import { postUnitPreVerification } from "../auto-post-unit.ts";
13
+ import { postUnitPostVerification, postUnitPreVerification } from "../auto-post-unit.ts";
14
14
  import { resolveDispatch, setResearchProjectPromptBuilderForTest } from "../auto-dispatch.ts";
15
15
  import { resolveExpectedArtifactPath, verifyExpectedArtifact, writeBlockerPlaceholder } from "../auto-recovery.ts";
16
16
  import { finalizeProjectResearchTimeout } from "../project-research-policy.ts";
@@ -272,6 +272,7 @@ test("deep project setup: bootstrap can start auto-mode without an active milest
272
272
  {
273
273
  shouldUseWorktreeIsolation: () => false,
274
274
  registerSigtermHandler: () => {},
275
+ registerAutoWorkerForSession: () => {},
275
276
  lockBase: () => base,
276
277
  buildLifecycle: () => ({
277
278
  adoptSessionRoot: (sessionBase: string, originalBase?: string) => {
@@ -386,6 +387,7 @@ test("deep project setup: bootstrap continues queued M002 without milestone cont
386
387
  {
387
388
  shouldUseWorktreeIsolation: () => false,
388
389
  registerSigtermHandler: () => {},
390
+ registerAutoWorkerForSession: () => {},
389
391
  lockBase: () => base,
390
392
  buildLifecycle: () => ({
391
393
  adoptSessionRoot: (sessionBase: string, originalBase?: string) => {
@@ -1587,6 +1589,61 @@ test("deep project setup: discuss-milestone question failure pauses instead of a
1587
1589
  }
1588
1590
  });
1589
1591
 
1592
+ test("verified task git closeout failure retries and continues auto-mode", async () => {
1593
+ const base = makeBase();
1594
+ try {
1595
+ execFileSync("git", ["init"], { cwd: base, stdio: "ignore" });
1596
+ execFileSync("git", ["config", "user.email", "test@example.com"], { cwd: base, stdio: "ignore" });
1597
+ execFileSync("git", ["config", "user.name", "Test User"], { cwd: base, stdio: "ignore" });
1598
+ const hookPath = join(base, ".git", "hooks", "pre-commit");
1599
+ writeFileSync(
1600
+ hookPath,
1601
+ [
1602
+ "#!/bin/sh",
1603
+ "count_file=.git/pre-commit-count",
1604
+ "count=0",
1605
+ "if [ -f \"$count_file\" ]; then count=$(cat \"$count_file\"); fi",
1606
+ "count=$((count + 1))",
1607
+ "printf \"%s\" \"$count\" > \"$count_file\"",
1608
+ "echo blocked by test hook >&2",
1609
+ "exit 1",
1610
+ ].join("\n"),
1611
+ );
1612
+ chmodSync(hookPath, 0o755);
1613
+ writeFileSync(join(base, "work.txt"), "changed\n");
1614
+
1615
+ const s = new AutoSession();
1616
+ s.active = true;
1617
+ s.basePath = base;
1618
+ s.originalBasePath = base;
1619
+ s.currentUnit = { type: "execute-task", id: "M001/S01/T01", startedAt: Date.now() };
1620
+
1621
+ let pauseCalled = false;
1622
+ const notifications: Array<{ message: string; severity?: string }> = [];
1623
+ const result = await postUnitPostVerification({
1624
+ s,
1625
+ ctx: { ui: { notify: (message: string, severity?: string) => notifications.push({ message, severity }) } } as any,
1626
+ pi: {} as any,
1627
+ buildSnapshotOpts: () => ({}) as any,
1628
+ lockBase: () => base,
1629
+ stopAuto: async () => {},
1630
+ pauseAuto: async () => { pauseCalled = true; },
1631
+ updateProgressWidget: () => {},
1632
+ });
1633
+
1634
+ assert.equal(result, "continue");
1635
+ assert.equal(pauseCalled, false);
1636
+ assert.equal(s.lastGitActionStatus, "failed");
1637
+ assert.equal(readFileSync(join(base, ".git", "pre-commit-count"), "utf-8"), "3");
1638
+ assert.ok(
1639
+ notifications.some((entry) => entry.severity === "warning" && entry.message.includes("Git commit failed")),
1640
+ "verified task git closeout failure should warn instead of stopping auto-mode",
1641
+ );
1642
+ } finally {
1643
+ rmSync(base, { recursive: true, force: true });
1644
+ }
1645
+ });
1646
+
1590
1647
  test("deep project setup: approval wait wins over deterministic write-gate placeholder", async () => {
1591
1648
  const base = makeBase();
1592
1649
  try {
@@ -118,3 +118,42 @@ describe("complete phase dispatch guard (#5683)", () => {
118
118
  assert.equal(result?.reason, "All milestones complete.");
119
119
  });
120
120
  });
121
+
122
+ describe("complete milestone context recovery guard (#5831)", () => {
123
+ let base = "";
124
+ const executionEntryRule = DISPATCH_RULES.find(
125
+ (candidate) => candidate.name === "execution-entry phase (no context) → discuss-milestone",
126
+ );
127
+ const prePlanningRule = DISPATCH_RULES.find(
128
+ (candidate) => candidate.name === "pre-planning (no context) → discuss-milestone",
129
+ );
130
+ assert.ok(executionEntryRule, "execution-entry missing-context rule should exist");
131
+ assert.ok(prePlanningRule, "pre-planning missing-context rule should exist");
132
+
133
+ afterEach(() => {
134
+ if (base) rmSync(base, { recursive: true, force: true });
135
+ base = "";
136
+ });
137
+
138
+ test("does not discuss a complete execution-entry milestone with no CONTEXT file", async () => {
139
+ base = makeBase();
140
+ const ctx = buildDispatchCtx(base);
141
+ ctx.state.registry = [{ id: "M001", title: "Milestone One", status: "complete" }];
142
+ ctx.state.phase = "completing-milestone";
143
+
144
+ const result = await executionEntryRule.match(ctx);
145
+
146
+ assert.equal(result, null);
147
+ });
148
+
149
+ test("does not discuss a complete pre-planning milestone with no CONTEXT file", async () => {
150
+ base = makeBase();
151
+ const ctx = buildDispatchCtx(base);
152
+ ctx.state.registry = [{ id: "M001", title: "Milestone One", status: "complete" }];
153
+ ctx.state.phase = "pre-planning";
154
+
155
+ const result = await prePlanningRule.match(ctx);
156
+
157
+ assert.equal(result, null);
158
+ });
159
+ });
@@ -47,6 +47,33 @@ test("dispatch guard blocks when prior milestone has incomplete slices", (t) =>
47
47
  );
48
48
  });
49
49
 
50
+ test("dispatch guard skips prior DB parked or deferred milestones without marker files", (t) => {
51
+ const repo = setupRepo();
52
+ t.after(() => teardownRepo(repo));
53
+
54
+ mkdirSync(join(repo, ".gsd", "milestones", "M001"), { recursive: true });
55
+ mkdirSync(join(repo, ".gsd", "milestones", "M002"), { recursive: true });
56
+ mkdirSync(join(repo, ".gsd", "milestones", "M003"), { recursive: true });
57
+
58
+ insertMilestone({ id: "M001", title: "Parked", status: "parked" });
59
+ insertSlice({ id: "S01", milestoneId: "M001", title: "Incomplete", status: "pending", depends: [], sequence: 1 });
60
+
61
+ insertMilestone({ id: "M002", title: "Deferred", status: "deferred" });
62
+ insertSlice({ id: "S01", milestoneId: "M002", title: "Incomplete", status: "pending", depends: [], sequence: 1 });
63
+
64
+ insertMilestone({ id: "M003", title: "Current", status: "active" });
65
+ insertSlice({ id: "S01", milestoneId: "M003", title: "First", status: "pending", depends: [], sequence: 1 });
66
+
67
+ writeFileSync(join(repo, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), "# M001\n");
68
+ writeFileSync(join(repo, ".gsd", "milestones", "M002", "M002-ROADMAP.md"), "# M002\n");
69
+ writeFileSync(join(repo, ".gsd", "milestones", "M003", "M003-ROADMAP.md"), "# M003\n");
70
+
71
+ assert.equal(
72
+ getPriorSliceCompletionBlocker(repo, "main", "plan-slice", "M003/S01"),
73
+ null,
74
+ );
75
+ });
76
+
50
77
  test("dispatch guard blocks later slice in same milestone when earlier incomplete", (t) => {
51
78
  const repo = setupRepo();
52
79
  t.after(() => teardownRepo(repo));
@@ -0,0 +1,65 @@
1
+ // Project/App: GSD-2
2
+ // File Purpose: Regression tests for doctor repair of empty milestone worktrees.
3
+
4
+ import test from "node:test";
5
+ import assert from "node:assert/strict";
6
+ import { execFileSync } from "node:child_process";
7
+ import { existsSync, mkdtempSync, readdirSync, rmSync, writeFileSync } from "node:fs";
8
+ import { tmpdir } from "node:os";
9
+ import { join } from "node:path";
10
+
11
+ import { runGSDDoctor } from "../doctor.ts";
12
+ import { createWorktree, worktreePath } from "../worktree-manager.ts";
13
+
14
+ function runGit(args: string[], cwd: string): string {
15
+ return execFileSync("git", args, {
16
+ cwd,
17
+ stdio: ["ignore", "pipe", "pipe"],
18
+ encoding: "utf-8",
19
+ }).trim();
20
+ }
21
+
22
+ function makeRepo(): string {
23
+ const base = mkdtempSync(join(tmpdir(), "gsd-doctor-empty-worktree-"));
24
+ runGit(["init", "-b", "main"], base);
25
+ runGit(["config", "user.name", "Test User"], base);
26
+ runGit(["config", "user.email", "test@example.com"], base);
27
+ writeFileSync(join(base, "package.json"), "{\"scripts\":{}}\n", "utf-8");
28
+ runGit(["add", "."], base);
29
+ runGit(["commit", "-m", "chore: init"], base);
30
+ return base;
31
+ }
32
+
33
+ test("doctor fix recreates an empty registered milestone worktree", async (t) => {
34
+ const base = makeRepo();
35
+ t.after(() => rmSync(base, { recursive: true, force: true }));
36
+
37
+ createWorktree(base, "M001", { branch: "milestone/M001" });
38
+ const wtPath = worktreePath(base, "M001");
39
+ writeFileSync(join(wtPath, "milestone-note.txt"), "worktree branch content\n", "utf-8");
40
+ runGit(["add", "milestone-note.txt"], wtPath);
41
+ runGit(["commit", "-m", "test: add milestone content"], wtPath);
42
+ for (const entry of readdirSync(wtPath)) {
43
+ if (entry === ".git") continue;
44
+ rmSync(join(wtPath, entry), { recursive: true, force: true });
45
+ }
46
+ assert.ok(existsSync(join(wtPath, ".git")), "test setup keeps registered worktree marker");
47
+ assert.equal(existsSync(join(wtPath, "package.json")), false, "test setup removes project content");
48
+
49
+ const report = await runGSDDoctor(base, {
50
+ fix: true,
51
+ fixLevel: "all",
52
+ isolationMode: "worktree",
53
+ });
54
+
55
+ assert.ok(
56
+ report.issues.some((issue) => issue.code === "worktree_empty_with_project_content"),
57
+ "doctor reports the empty worktree",
58
+ );
59
+ assert.ok(
60
+ report.fixesApplied.some((fix) => fix.includes("recreated empty worktree")),
61
+ "doctor applies the repair",
62
+ );
63
+ assert.ok(existsSync(join(wtPath, "package.json")), "worktree content is restored");
64
+ assert.ok(existsSync(join(wtPath, "milestone-note.txt")), "branch content is restored");
65
+ });
@@ -141,6 +141,14 @@ test("Feature 1: executive summary paragraph is rendered", () => {
141
141
  assert.ok(html.includes("$2.50 spent"), "should contain cost");
142
142
  });
143
143
 
144
+ test("report uses the shared GSD HTML shell", () => {
145
+ const html = generateHtmlReport(mockData(), mockOpts());
146
+ assert.ok(html.includes('<span class="logo">GSD</span>'), "should render shared shell logo");
147
+ assert.ok(html.includes('<span class="kind-chip">Report</span>'), "should render report kind chip");
148
+ assert.ok(html.includes('<nav class="toc" aria-label="Report sections">'), "should render shared shell TOC");
149
+ assert.ok(html.includes('<main>'), "should render content inside shared shell main");
150
+ });
151
+
144
152
  test("Feature 1: executive summary includes budget context when set", () => {
145
153
  const data = mockData({ health: { ...mockData().health, budgetCeiling: 10.00 } });
146
154
  const html = generateHtmlReport(data, mockOpts());
@@ -34,6 +34,8 @@ test("guided project prompt renders compact interview and artifact guidance", as
34
34
  assert.match(prompt, /depth_verification_project_confirm/);
35
35
  assert.match(prompt, /artifact_type: "PROJECT"/);
36
36
  assert.match(prompt, /omit `milestone_id`/);
37
+ assert.match(prompt, /do not write the projection directly/i);
38
+ assert.doesNotMatch(prompt, /then write `.gsd\/PROJECT\.md`/);
37
39
  assert.match(prompt, /Do NOT use `artifact_type: "CONTEXT"` and do NOT pass `milestone_id: "PROJECT"`/);
38
40
  assert.match(prompt, /\*\*Complexity:\*\* simple/);
39
41
  assert.match(prompt, /\*\*Complexity:\*\* complex/);
@@ -0,0 +1,106 @@
1
+ // GSD-2 — Guided workflow dispatch project-root tests.
2
+ // Verifies smart entry dispatch uses the explicit project root instead of cwd.
3
+
4
+ import test from "node:test";
5
+ import assert from "node:assert/strict";
6
+ import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
7
+ import { tmpdir } from "node:os";
8
+ import { join } from "node:path";
9
+
10
+ import {
11
+ _dispatchWorkflowForTest,
12
+ resolveGuidedDispatchProjectRoot,
13
+ } from "../guided-flow.ts";
14
+
15
+ test("guided dispatch falls back to cwd only when no project root is supplied", () => {
16
+ const cwd = process.cwd();
17
+ assert.equal(resolveGuidedDispatchProjectRoot(), cwd);
18
+ assert.equal(resolveGuidedDispatchProjectRoot("/tmp/explicit-root"), "/tmp/explicit-root");
19
+ });
20
+
21
+ test("guided dispatch passes the explicit project root through model and compatibility checks", async () => {
22
+ const explicitRoot = mkdtempSync(join(tmpdir(), "gsd-guided-root-explicit-"));
23
+ const otherRoot = mkdtempSync(join(tmpdir(), "gsd-guided-root-cwd-"));
24
+ const workflowPath = join(explicitRoot, "GSD-WORKFLOW.md");
25
+ const originalWorkflowPath = process.env.GSD_WORKFLOW_PATH;
26
+ const originalCwd = process.cwd();
27
+ const seen = {
28
+ prefsRoot: "",
29
+ modelRoot: "",
30
+ compatibilityRoot: "",
31
+ sent: false,
32
+ };
33
+
34
+ const ctx = {
35
+ model: { provider: "local-provider" },
36
+ modelRegistry: {
37
+ getProviderAuthMode: () => "apiKey",
38
+ },
39
+ ui: {
40
+ notify: () => {},
41
+ },
42
+ };
43
+
44
+ const pi = {
45
+ getActiveTools: () => ["gsd_plan_slice"],
46
+ setActiveTools: () => {},
47
+ sendMessage: () => {
48
+ seen.sent = true;
49
+ },
50
+ };
51
+
52
+ try {
53
+ writeFileSync(workflowPath, "# Workflow\n", "utf-8");
54
+ process.env.GSD_WORKFLOW_PATH = workflowPath;
55
+ process.chdir(otherRoot);
56
+
57
+ await _dispatchWorkflowForTest(
58
+ pi as any,
59
+ "Plan the slice.",
60
+ "gsd-run",
61
+ ctx as any,
62
+ "plan-slice",
63
+ {
64
+ basePath: explicitRoot,
65
+ deps: {
66
+ loadPreferences: (projectRoot?: string) => {
67
+ seen.prefsRoot = projectRoot ?? "";
68
+ return { preferences: {} } as any;
69
+ },
70
+ selectModel: async (
71
+ _ctx: unknown,
72
+ _pi: unknown,
73
+ _unitType: string,
74
+ _unitId: string,
75
+ projectRoot: string,
76
+ ) => {
77
+ seen.modelRoot = projectRoot;
78
+ return { routing: null, appliedModel: null };
79
+ },
80
+ getTransportSupportError: (
81
+ _provider: string | undefined,
82
+ _requiredTools: string[],
83
+ options?: { projectRoot?: string },
84
+ ) => {
85
+ seen.compatibilityRoot = options?.projectRoot ?? "";
86
+ return null;
87
+ },
88
+ },
89
+ },
90
+ );
91
+
92
+ assert.equal(seen.prefsRoot, explicitRoot);
93
+ assert.equal(seen.modelRoot, explicitRoot);
94
+ assert.equal(seen.compatibilityRoot, explicitRoot);
95
+ assert.equal(seen.sent, true);
96
+ } finally {
97
+ process.chdir(originalCwd);
98
+ if (originalWorkflowPath === undefined) {
99
+ delete process.env.GSD_WORKFLOW_PATH;
100
+ } else {
101
+ process.env.GSD_WORKFLOW_PATH = originalWorkflowPath;
102
+ }
103
+ rmSync(explicitRoot, { recursive: true, force: true });
104
+ rmSync(otherRoot, { recursive: true, force: true });
105
+ }
106
+ });