gsd-pi 2.82.0-dev.c22380fc3 → 2.82.0-dev.e7a7f1ed5

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 (390) hide show
  1. package/README.md +5 -4
  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/claude-code-cli/stream-adapter.js +1 -1
  6. package/dist/resources/extensions/cmux/index.js +5 -0
  7. package/dist/resources/extensions/gsd/auto/infra-errors.js +9 -3
  8. package/dist/resources/extensions/gsd/auto/loop.js +5 -5
  9. package/dist/resources/extensions/gsd/auto/orchestrator.js +11 -0
  10. package/dist/resources/extensions/gsd/auto/phases.js +81 -31
  11. package/dist/resources/extensions/gsd/auto/workflow-memory-pressure.js +12 -0
  12. package/dist/resources/extensions/gsd/auto-dashboard.js +66 -1
  13. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +1 -0
  14. package/dist/resources/extensions/gsd/auto-dispatch.js +18 -17
  15. package/dist/resources/extensions/gsd/auto-model-selection.js +2 -0
  16. package/dist/resources/extensions/gsd/auto-post-unit.js +233 -127
  17. package/dist/resources/extensions/gsd/auto-prompts.js +2 -2
  18. package/dist/resources/extensions/gsd/auto-recovery.js +71 -14
  19. package/dist/resources/extensions/gsd/auto-start.js +87 -14
  20. package/dist/resources/extensions/gsd/auto-verification.js +45 -26
  21. package/dist/resources/extensions/gsd/auto-worktree.js +176 -10
  22. package/dist/resources/extensions/gsd/auto.js +37 -5
  23. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +31 -7
  24. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +9 -8
  25. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +4 -2
  26. package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +21 -9
  27. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +16 -2
  28. package/dist/resources/extensions/gsd/clean-root-preflight.js +170 -8
  29. package/dist/resources/extensions/gsd/commands/catalog.js +4 -1
  30. package/dist/resources/extensions/gsd/commands/handlers/core.js +37 -0
  31. package/dist/resources/extensions/gsd/commands-bootstrap.js +5 -0
  32. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +7 -2
  33. package/dist/resources/extensions/gsd/crash-recovery.js +43 -5
  34. package/dist/resources/extensions/gsd/db/milestone-leases.js +24 -0
  35. package/dist/resources/extensions/gsd/db/unit-dispatches.js +3 -2
  36. package/dist/resources/extensions/gsd/dispatch-guard.js +2 -2
  37. package/dist/resources/extensions/gsd/doctor-git-checks.js +46 -1
  38. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +28 -11
  39. package/dist/resources/extensions/gsd/doctor.js +2 -28
  40. package/dist/resources/extensions/gsd/export-html.js +27 -425
  41. package/dist/resources/extensions/gsd/git-service.js +45 -3
  42. package/dist/resources/extensions/gsd/gsd-db.js +21 -6
  43. package/dist/resources/extensions/gsd/guided-flow-queue.js +4 -3
  44. package/dist/resources/extensions/gsd/guided-flow.js +101 -116
  45. package/dist/resources/extensions/gsd/guided-unit-context.js +23 -0
  46. package/dist/resources/extensions/gsd/migrate/parsers.js +10 -0
  47. package/dist/resources/extensions/gsd/migration-auto-check.js +12 -17
  48. package/dist/resources/extensions/gsd/milestone-actions.js +11 -4
  49. package/dist/resources/extensions/gsd/native-git-bridge.js +48 -12
  50. package/dist/resources/extensions/gsd/pending-auto-start.js +52 -0
  51. package/dist/resources/extensions/gsd/post-execution-checks.js +73 -2
  52. package/dist/resources/extensions/gsd/pre-execution-checks.js +28 -1
  53. package/dist/resources/extensions/gsd/prompt-loader.js +1 -1
  54. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  55. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  56. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
  57. package/dist/resources/extensions/gsd/prompts/discuss.md +9 -9
  58. package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
  59. package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
  60. package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -4
  61. package/dist/resources/extensions/gsd/prompts/queue.md +4 -4
  62. package/dist/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  63. package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  64. package/dist/resources/extensions/gsd/queue-reorder-ui.js +30 -13
  65. package/dist/resources/extensions/gsd/smart-entry-routing.js +36 -0
  66. package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +6 -1
  67. package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +9 -14
  68. package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +19 -24
  69. package/dist/resources/extensions/gsd/status-guards.js +11 -0
  70. package/dist/resources/extensions/gsd/templates/plan.md +8 -5
  71. package/dist/resources/extensions/gsd/templates/task-plan.md +4 -2
  72. package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -8
  73. package/dist/resources/extensions/gsd/tools/complete-slice.js +6 -8
  74. package/dist/resources/extensions/gsd/tools/plan-milestone.js +7 -1
  75. package/dist/resources/extensions/gsd/tools/plan-slice.js +89 -14
  76. package/dist/resources/extensions/gsd/unit-context-manifest.js +32 -10
  77. package/dist/resources/extensions/gsd/validation.js +23 -1
  78. package/dist/resources/extensions/gsd/verification-gate.js +68 -7
  79. package/dist/resources/extensions/gsd/verification-verdict.js +26 -0
  80. package/dist/resources/extensions/gsd/workflow-mcp.js +17 -1
  81. package/dist/resources/extensions/gsd/workflow-projections.js +6 -8
  82. package/dist/resources/extensions/gsd/worktree-lifecycle.js +33 -8
  83. package/dist/resources/extensions/shared/html-shell.js +388 -0
  84. package/dist/resources/extensions/subagent/index.js +448 -78
  85. package/dist/resources/extensions/subagent/launch.js +77 -0
  86. package/dist/resources/extensions/subagent/run-store.js +148 -0
  87. package/dist/resources/extensions/visual-brief/artifact-policy.js +29 -0
  88. package/dist/resources/extensions/visual-brief/extension-manifest.json +8 -0
  89. package/dist/resources/extensions/visual-brief/index.js +5 -0
  90. package/dist/resources/extensions/visual-brief/page-contract.js +124 -0
  91. package/dist/resources/extensions/visual-brief/prompts.js +140 -0
  92. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  93. package/dist/web/standalone/.next/BUILD_ID +1 -1
  94. package/dist/web/standalone/.next/app-path-routes-manifest.json +13 -13
  95. package/dist/web/standalone/.next/build-manifest.json +3 -3
  96. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  97. package/dist/web/standalone/.next/react-loadable-manifest.json +3 -3
  98. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  99. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  100. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  105. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  108. package/dist/web/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  109. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  110. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  111. package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -7
  112. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -7
  113. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  114. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -5
  115. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  116. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  117. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -5
  118. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  120. package/dist/web/standalone/.next/server/app/index.html +1 -1
  121. package/dist/web/standalone/.next/server/app/index.rsc +4 -7
  122. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  123. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -7
  124. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  125. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -5
  126. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -5
  127. package/dist/web/standalone/.next/server/app/page.js +2 -2
  128. package/dist/web/standalone/.next/server/app/page.js.nft.json +1 -1
  129. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  130. package/dist/web/standalone/.next/server/app-paths-manifest.json +13 -13
  131. package/dist/web/standalone/.next/server/chunks/4266.js +2 -0
  132. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  133. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  134. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  136. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  137. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  138. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  139. package/dist/web/standalone/.next/static/chunks/2973.33f26573894b6153.js +2 -0
  140. package/dist/web/standalone/.next/static/chunks/{8359.e059d86b255fce1c.js → 8359.7eb3bb8f8ecf4c01.js} +2 -2
  141. package/dist/web/standalone/.next/static/chunks/app/layout-8c10ec293ae0f1d5.js +1 -0
  142. package/dist/web/standalone/.next/static/chunks/{webpack-de742b64187e13fe.js → webpack-9a4db269f9ed63ad.js} +1 -1
  143. package/dist/web/standalone/.next/static/css/746ee28c929d1880.css +1 -0
  144. package/package.json +4 -4
  145. package/packages/mcp-server/src/workflow-tools.test.ts +1 -1
  146. package/packages/native/tsconfig.json +2 -1
  147. package/packages/native/tsconfig.tsbuildinfo +1 -1
  148. package/packages/pi-ai/dist/providers/google-gemini-cli.d.ts.map +1 -1
  149. package/packages/pi-ai/dist/providers/google-gemini-cli.js +5 -0
  150. package/packages/pi-ai/dist/providers/google-gemini-cli.js.map +1 -1
  151. package/packages/pi-ai/dist/providers/google-gemini-cli.test.d.ts +2 -0
  152. package/packages/pi-ai/dist/providers/google-gemini-cli.test.d.ts.map +1 -0
  153. package/packages/pi-ai/dist/providers/google-gemini-cli.test.js +41 -0
  154. package/packages/pi-ai/dist/providers/google-gemini-cli.test.js.map +1 -0
  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/google-gemini-cli.test.ts +49 -0
  171. package/packages/pi-ai/src/providers/google-gemini-cli.ts +7 -0
  172. package/packages/pi-ai/src/providers/openai-codex-responses.test.ts +63 -0
  173. package/packages/pi-ai/src/providers/openai-codex-responses.ts +91 -1
  174. package/packages/pi-ai/src/providers/simple-options.test.ts +60 -0
  175. package/packages/pi-ai/src/providers/simple-options.ts +5 -6
  176. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  177. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts +2 -0
  178. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts.map +1 -0
  179. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js +66 -0
  180. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js.map +1 -0
  181. package/packages/pi-coding-agent/dist/core/agent-session.js +1 -1
  182. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  183. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  184. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +24 -6
  185. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  186. package/packages/pi-coding-agent/src/core/agent-session-thinking-level.test.ts +79 -0
  187. package/packages/pi-coding-agent/src/core/agent-session.ts +1 -1
  188. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +23 -7
  189. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  190. package/packages/pi-tui/dist/__tests__/terminal.test.d.ts +2 -0
  191. package/packages/pi-tui/dist/__tests__/terminal.test.d.ts.map +1 -0
  192. package/packages/pi-tui/dist/__tests__/terminal.test.js +103 -0
  193. package/packages/pi-tui/dist/__tests__/terminal.test.js.map +1 -0
  194. package/packages/pi-tui/dist/terminal.d.ts +2 -0
  195. package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
  196. package/packages/pi-tui/dist/terminal.js +12 -0
  197. package/packages/pi-tui/dist/terminal.js.map +1 -1
  198. package/packages/pi-tui/src/__tests__/terminal.test.ts +121 -0
  199. package/packages/pi-tui/src/terminal.ts +11 -0
  200. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  201. package/src/resources/GSD-WORKFLOW.md +10 -1
  202. package/src/resources/extensions/claude-code-cli/partial-builder.ts +2 -1
  203. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +1 -1
  204. package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +19 -2
  205. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +9 -0
  206. package/src/resources/extensions/cmux/index.ts +6 -0
  207. package/src/resources/extensions/gsd/auto/contracts.ts +14 -6
  208. package/src/resources/extensions/gsd/auto/infra-errors.ts +9 -3
  209. package/src/resources/extensions/gsd/auto/loop.ts +8 -5
  210. package/src/resources/extensions/gsd/auto/orchestrator.ts +11 -0
  211. package/src/resources/extensions/gsd/auto/phases.ts +90 -38
  212. package/src/resources/extensions/gsd/auto/workflow-memory-pressure.ts +13 -0
  213. package/src/resources/extensions/gsd/auto-dashboard.ts +72 -1
  214. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +1 -0
  215. package/src/resources/extensions/gsd/auto-dispatch.ts +19 -17
  216. package/src/resources/extensions/gsd/auto-model-selection.ts +2 -1
  217. package/src/resources/extensions/gsd/auto-post-unit.ts +266 -139
  218. package/src/resources/extensions/gsd/auto-prompts.ts +2 -2
  219. package/src/resources/extensions/gsd/auto-recovery.ts +74 -11
  220. package/src/resources/extensions/gsd/auto-start.ts +94 -12
  221. package/src/resources/extensions/gsd/auto-verification.ts +58 -36
  222. package/src/resources/extensions/gsd/auto-worktree.ts +193 -10
  223. package/src/resources/extensions/gsd/auto.ts +40 -5
  224. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +42 -7
  225. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +9 -8
  226. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +4 -2
  227. package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +19 -7
  228. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +19 -3
  229. package/src/resources/extensions/gsd/clean-root-preflight.ts +174 -8
  230. package/src/resources/extensions/gsd/commands/catalog.ts +4 -1
  231. package/src/resources/extensions/gsd/commands/handlers/core.ts +40 -0
  232. package/src/resources/extensions/gsd/commands-bootstrap.ts +10 -0
  233. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +8 -3
  234. package/src/resources/extensions/gsd/crash-recovery.ts +44 -4
  235. package/src/resources/extensions/gsd/db/milestone-leases.ts +26 -0
  236. package/src/resources/extensions/gsd/db/unit-dispatches.ts +4 -3
  237. package/src/resources/extensions/gsd/dispatch-guard.ts +2 -2
  238. package/src/resources/extensions/gsd/doctor-git-checks.ts +45 -1
  239. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +25 -13
  240. package/src/resources/extensions/gsd/doctor-types.ts +1 -0
  241. package/src/resources/extensions/gsd/doctor.ts +2 -27
  242. package/src/resources/extensions/gsd/export-html.ts +27 -427
  243. package/src/resources/extensions/gsd/git-service.ts +51 -4
  244. package/src/resources/extensions/gsd/gsd-db.ts +21 -6
  245. package/src/resources/extensions/gsd/guided-flow-queue.ts +4 -3
  246. package/src/resources/extensions/gsd/guided-flow.ts +134 -133
  247. package/src/resources/extensions/gsd/guided-unit-context.ts +30 -0
  248. package/src/resources/extensions/gsd/migrate/parsers.ts +11 -0
  249. package/src/resources/extensions/gsd/migration-auto-check.ts +15 -23
  250. package/src/resources/extensions/gsd/milestone-actions.ts +10 -4
  251. package/src/resources/extensions/gsd/native-git-bridge.ts +54 -12
  252. package/src/resources/extensions/gsd/pending-auto-start.ts +79 -0
  253. package/src/resources/extensions/gsd/post-execution-checks.ts +87 -2
  254. package/src/resources/extensions/gsd/pre-execution-checks.ts +32 -1
  255. package/src/resources/extensions/gsd/prompt-loader.ts +1 -1
  256. package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  257. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  258. package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
  259. package/src/resources/extensions/gsd/prompts/discuss.md +9 -9
  260. package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
  261. package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
  262. package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -4
  263. package/src/resources/extensions/gsd/prompts/queue.md +4 -4
  264. package/src/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  265. package/src/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  266. package/src/resources/extensions/gsd/queue-reorder-ui.ts +31 -13
  267. package/src/resources/extensions/gsd/smart-entry-routing.ts +77 -0
  268. package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +8 -1
  269. package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +12 -15
  270. package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +17 -25
  271. package/src/resources/extensions/gsd/status-guards.ts +13 -0
  272. package/src/resources/extensions/gsd/templates/plan.md +8 -5
  273. package/src/resources/extensions/gsd/templates/task-plan.md +4 -2
  274. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +71 -0
  275. package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +116 -0
  276. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +56 -0
  277. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +80 -1
  278. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +35 -7
  279. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +53 -2
  280. package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +12 -1
  281. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +91 -6
  282. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +1 -0
  283. package/src/resources/extensions/gsd/tests/auto-stop-notification.test.ts +20 -0
  284. package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +69 -1
  285. package/src/resources/extensions/gsd/tests/brief-command.test.ts +89 -0
  286. package/src/resources/extensions/gsd/tests/checkout-branch-stash-guard.test.ts +87 -0
  287. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +107 -2
  288. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +11 -2
  289. package/src/resources/extensions/gsd/tests/closeout-git-deferral.test.ts +16 -0
  290. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +4 -1
  291. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +5 -9
  292. package/src/resources/extensions/gsd/tests/complete-task.test.ts +3 -1
  293. package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +86 -2
  294. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +2 -0
  295. package/src/resources/extensions/gsd/tests/db-authority-regression.test.ts +208 -0
  296. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +59 -2
  297. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +66 -0
  298. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +27 -0
  299. package/src/resources/extensions/gsd/tests/doctor-empty-worktree.test.ts +65 -0
  300. package/src/resources/extensions/gsd/tests/evidence-cross-ref.test.ts +38 -0
  301. package/src/resources/extensions/gsd/tests/export-html-enhancements.test.ts +8 -0
  302. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +11 -0
  303. package/src/resources/extensions/gsd/tests/guided-discuss-project-prompt-rendering.test.ts +2 -0
  304. package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +106 -0
  305. package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +59 -11
  306. package/src/resources/extensions/gsd/tests/guided-flow.test.ts +21 -0
  307. package/src/resources/extensions/gsd/tests/guided-tool-contract.test.ts +65 -0
  308. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +7 -7
  309. package/src/resources/extensions/gsd/tests/hook-model-resolution.test.ts +5 -0
  310. package/src/resources/extensions/gsd/tests/infra-error.test.ts +2 -2
  311. package/src/resources/extensions/gsd/tests/infra-errors-cooldown.test.ts +9 -0
  312. package/src/resources/extensions/gsd/tests/integration/doctor-runtime.test.ts +20 -0
  313. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +112 -1
  314. package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +6 -1
  315. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +46 -0
  316. package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +179 -0
  317. package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +24 -1
  318. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +26 -18
  319. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +63 -2
  320. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +121 -1
  321. package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +55 -1
  322. package/src/resources/extensions/gsd/tests/pending-autostart-scope.test.ts +29 -5
  323. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +26 -0
  324. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
  325. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +225 -1
  326. package/src/resources/extensions/gsd/tests/plan-task.test.ts +17 -0
  327. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +79 -1
  328. package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +86 -0
  329. package/src/resources/extensions/gsd/tests/post-unit-git-failure.test.ts +1 -1
  330. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +53 -0
  331. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +59 -0
  332. package/src/resources/extensions/gsd/tests/prompt-loader.test.ts +23 -0
  333. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +37 -1
  334. package/src/resources/extensions/gsd/tests/queue-reorder-ui.test.ts +54 -0
  335. package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +89 -2
  336. package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +2 -3
  337. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +10 -0
  338. package/src/resources/extensions/gsd/tests/smart-entry-routing.test.ts +113 -0
  339. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +53 -2
  340. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +119 -23
  341. package/src/resources/extensions/gsd/tests/status-guards.test.ts +13 -1
  342. package/src/resources/extensions/gsd/tests/stuck-state-via-db.test.ts +64 -1
  343. package/src/resources/extensions/gsd/tests/summary-render-parity.test.ts +7 -3
  344. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +86 -7
  345. package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +29 -2
  346. package/src/resources/extensions/gsd/tests/verification-gate.test.ts +110 -1
  347. package/src/resources/extensions/gsd/tests/verification-verdict.test.ts +78 -0
  348. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +19 -1
  349. package/src/resources/extensions/gsd/tests/workflow-memory-pressure.test.ts +21 -1
  350. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +1 -1
  351. package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +39 -0
  352. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +64 -12
  353. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +54 -0
  354. package/src/resources/extensions/gsd/tools/complete-milestone.ts +8 -10
  355. package/src/resources/extensions/gsd/tools/complete-slice.ts +6 -8
  356. package/src/resources/extensions/gsd/tools/plan-milestone.ts +5 -1
  357. package/src/resources/extensions/gsd/tools/plan-slice.ts +98 -12
  358. package/src/resources/extensions/gsd/types.ts +1 -1
  359. package/src/resources/extensions/gsd/unit-context-manifest.ts +47 -11
  360. package/src/resources/extensions/gsd/validation.ts +23 -1
  361. package/src/resources/extensions/gsd/verification-gate.ts +78 -6
  362. package/src/resources/extensions/gsd/verification-verdict.ts +47 -0
  363. package/src/resources/extensions/gsd/workflow-mcp.ts +18 -1
  364. package/src/resources/extensions/gsd/workflow-projections.ts +6 -8
  365. package/src/resources/extensions/gsd/worktree-lifecycle.ts +41 -8
  366. package/src/resources/extensions/shared/html-shell.ts +412 -0
  367. package/src/resources/extensions/subagent/index.ts +567 -103
  368. package/src/resources/extensions/subagent/launch.ts +131 -0
  369. package/src/resources/extensions/subagent/run-store.ts +218 -0
  370. package/src/resources/extensions/subagent/tests/launch.test.ts +115 -0
  371. package/src/resources/extensions/subagent/tests/run-store.test.ts +111 -0
  372. package/src/resources/extensions/visual-brief/artifact-policy.ts +41 -0
  373. package/src/resources/extensions/visual-brief/extension-manifest.json +8 -0
  374. package/src/resources/extensions/visual-brief/index.ts +8 -0
  375. package/src/resources/extensions/visual-brief/page-contract.ts +136 -0
  376. package/src/resources/extensions/visual-brief/prompts.ts +183 -0
  377. package/src/resources/extensions/visual-brief/tests/visual-brief.test.ts +212 -0
  378. package/dist/web/standalone/.next/server/chunks/5822.js +0 -2
  379. package/dist/web/standalone/.next/static/chunks/2556.0527fea66e123b7f.js +0 -1
  380. package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +0 -1
  381. package/dist/web/standalone/.next/static/css/54ec2745c1da488b.css +0 -1
  382. package/dist/web/standalone/.next/static/css/de70bee13400563f.css +0 -1
  383. package/dist/web/standalone/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
  384. package/dist/web/standalone/.next/static/media/747892c23ea88013-s.woff2 +0 -0
  385. package/dist/web/standalone/.next/static/media/8d697b304b401681-s.woff2 +0 -0
  386. package/dist/web/standalone/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
  387. package/dist/web/standalone/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
  388. package/dist/web/standalone/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
  389. /package/dist/web/standalone/.next/static/{Wop3A7KRGyR06H3rla_1- → 4dSwdrs__8NwCZggxP9KF}/_buildManifest.js +0 -0
  390. /package/dist/web/standalone/.next/static/{Wop3A7KRGyR06H3rla_1- → 4dSwdrs__8NwCZggxP9KF}/_ssgManifest.js +0 -0
@@ -37,6 +37,7 @@ import {
37
37
  checkpointDatabase,
38
38
  refreshOpenDatabaseFromDisk,
39
39
  tryCreateMemoriesFts,
40
+ _isLikelyWslDrvFsPathForTest,
40
41
  } from '../gsd-db.ts';
41
42
  import { _resetLogs, peekLogs, setStderrLoggingEnabled } from '../workflow-logger.ts';
42
43
 
@@ -345,6 +346,16 @@ describe('gsd-db', () => {
345
346
  });
346
347
  });
347
348
 
349
+ test('gsd-db: detects WSL DrvFs mount paths for conservative pragmas', () => {
350
+ withPlatform('linux', () => {
351
+ assert.equal(_isLikelyWslDrvFsPathForTest('/mnt/d/code/project/.gsd/gsd.db'), true);
352
+ assert.equal(_isLikelyWslDrvFsPathForTest('/tmp/gsd.db'), false);
353
+ });
354
+ withPlatform('darwin', () => {
355
+ assert.equal(_isLikelyWslDrvFsPathForTest('/mnt/d/code/project/.gsd/gsd.db'), false);
356
+ });
357
+ });
358
+
348
359
  test('gsd-db: transaction rollback on error', () => {
349
360
  openDatabase(':memory:');
350
361
 
@@ -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
+ });
@@ -21,6 +21,15 @@ import {
21
21
  checkAutoStartAfterDiscuss,
22
22
  } from "../guided-flow.ts";
23
23
 
24
+ function pendingInput(basePath: string, milestoneId: string) {
25
+ return {
26
+ basePath,
27
+ milestoneId,
28
+ ctx: { ui: { notify: () => undefined } } as any,
29
+ pi: { setActiveTools: () => undefined, getActiveTools: () => [] } as any,
30
+ };
31
+ }
32
+
24
33
  // ─── Tests ─────────────────────────────────────────────────────────────────
25
34
 
26
35
  describe("#2985 Bug 3 — concurrent discuss sessions must be independent", () => {
@@ -34,13 +43,11 @@ describe("#2985 Bug 3 — concurrent discuss sessions must be independent", () =
34
43
  const projectB = "/projects/beta";
35
44
 
36
45
  setPendingAutoStart(projectA, {
37
- basePath: projectA,
38
- milestoneId: "M001-aaa111",
46
+ ...pendingInput(projectA, "M001-aaa111"),
39
47
  });
40
48
 
41
49
  setPendingAutoStart(projectB, {
42
- basePath: projectB,
43
- milestoneId: "M002-bbb222",
50
+ ...pendingInput(projectB, "M002-bbb222"),
44
51
  });
45
52
 
46
53
  // Both sessions should be retrievable
@@ -55,8 +62,8 @@ describe("#2985 Bug 3 — concurrent discuss sessions must be independent", () =
55
62
  const projectA = "/projects/alpha";
56
63
  const projectB = "/projects/beta";
57
64
 
58
- setPendingAutoStart(projectA, { basePath: projectA, milestoneId: "M001-aaa111" });
59
- setPendingAutoStart(projectB, { basePath: projectB, milestoneId: "M002-bbb222" });
65
+ setPendingAutoStart(projectA, pendingInput(projectA, "M001-aaa111"));
66
+ setPendingAutoStart(projectB, pendingInput(projectB, "M002-bbb222"));
60
67
 
61
68
  // Clear only projectA
62
69
  clearPendingAutoStart(projectA);
@@ -72,8 +79,8 @@ describe("#2985 Bug 4 — getDiscussionMilestoneId must be keyed by basePath", (
72
79
  });
73
80
 
74
81
  test("getDiscussionMilestoneId(basePath) returns correct milestone for each project", () => {
75
- setPendingAutoStart("/proj/a", { basePath: "/proj/a", milestoneId: "M001" });
76
- setPendingAutoStart("/proj/b", { basePath: "/proj/b", milestoneId: "M002" });
82
+ setPendingAutoStart("/proj/a", pendingInput("/proj/a", "M001"));
83
+ setPendingAutoStart("/proj/b", pendingInput("/proj/b", "M002"));
77
84
 
78
85
  assert.equal(getDiscussionMilestoneId("/proj/a"), "M001");
79
86
  assert.equal(getDiscussionMilestoneId("/proj/b"), "M002");
@@ -81,8 +88,8 @@ describe("#2985 Bug 4 — getDiscussionMilestoneId must be keyed by basePath", (
81
88
  });
82
89
 
83
90
  test("getDiscussionMilestoneId() without basePath returns null when multiple sessions exist", () => {
84
- setPendingAutoStart("/proj/a", { basePath: "/proj/a", milestoneId: "M001" });
85
- setPendingAutoStart("/proj/b", { basePath: "/proj/b", milestoneId: "M002" });
91
+ setPendingAutoStart("/proj/a", pendingInput("/proj/a", "M001"));
92
+ setPendingAutoStart("/proj/b", pendingInput("/proj/b", "M002"));
86
93
 
87
94
  // Without a key, the function should not blindly return the first entry
88
95
  const result = getDiscussionMilestoneId();
@@ -92,7 +99,7 @@ describe("#2985 Bug 4 — getDiscussionMilestoneId must be keyed by basePath", (
92
99
  });
93
100
 
94
101
  test("getDiscussionMilestoneId() without basePath returns the milestone when only one session", () => {
95
- setPendingAutoStart("/proj/a", { basePath: "/proj/a", milestoneId: "M001" });
102
+ setPendingAutoStart("/proj/a", pendingInput("/proj/a", "M001"));
96
103
 
97
104
  // With only one session, backward compat — return it
98
105
  const result = getDiscussionMilestoneId();
@@ -129,3 +136,44 @@ test("checkAutoStartAfterDiscuss ignores missing manifest for single-milestone d
129
136
  rmSync(base, { recursive: true, force: true });
130
137
  }
131
138
  });
139
+
140
+ test("checkAutoStartAfterDiscuss(basePath) selects the matching pending entry when multiple sessions exist", () => {
141
+ const projectA = mkdtempSync(join(tmpdir(), "gsd-auto-start-project-a-"));
142
+ const projectB = mkdtempSync(join(tmpdir(), "gsd-auto-start-project-b-"));
143
+
144
+ function writeReadyArtifacts(base: string, milestoneId: string): void {
145
+ const gsdDir = join(base, ".gsd");
146
+ const milestoneDir = join(gsdDir, "milestones", milestoneId);
147
+ mkdirSync(milestoneDir, { recursive: true });
148
+ writeFileSync(join(gsdDir, "PROJECT.md"), `# Project\n\n| ${milestoneId} | Milestone | active |\n`);
149
+ writeFileSync(join(gsdDir, "STATE.md"), "# State\n");
150
+ writeFileSync(join(milestoneDir, `${milestoneId}-CONTEXT.md`), "# Context\n");
151
+ }
152
+
153
+ try {
154
+ clearPendingAutoStart();
155
+ writeReadyArtifacts(projectA, "M001");
156
+ writeReadyArtifacts(projectB, "M002");
157
+ setPendingAutoStart(projectA, {
158
+ basePath: projectA,
159
+ milestoneId: "M001",
160
+ ctx: { ui: { notify: () => undefined } } as any,
161
+ pi: { setActiveTools: () => undefined, getActiveTools: () => [] } as any,
162
+ });
163
+ setPendingAutoStart(projectB, {
164
+ basePath: projectB,
165
+ milestoneId: "M002",
166
+ ctx: { ui: { notify: () => undefined } } as any,
167
+ pi: { setActiveTools: () => undefined, getActiveTools: () => [] } as any,
168
+ });
169
+
170
+ assert.equal(checkAutoStartAfterDiscuss(), false, "ambiguous pending sessions should not auto-start");
171
+ assert.equal(checkAutoStartAfterDiscuss(projectB), true, "explicit basePath should select projectB");
172
+ assert.equal(getDiscussionMilestoneId(projectA), "M001", "projectA should remain pending");
173
+ assert.equal(getDiscussionMilestoneId(projectB), null, "projectB should be cleared after start");
174
+ } finally {
175
+ clearPendingAutoStart();
176
+ rmSync(projectA, { recursive: true, force: true });
177
+ rmSync(projectB, { recursive: true, force: true });
178
+ }
179
+ });
@@ -0,0 +1,21 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { readFileSync } from "node:fs";
4
+ import { dirname, join } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+
7
+ const __dirname = dirname(fileURLToPath(import.meta.url));
8
+
9
+ test("guided milestone discussion callsites pass workingDirectory to loadPrompt", () => {
10
+ const source = readFileSync(join(__dirname, "..", "guided-flow.ts"), "utf-8");
11
+ const calls = [...source.matchAll(/loadPrompt\("guided-discuss-milestone",\s*\{([\s\S]*?)\}\)/g)];
12
+
13
+ assert.equal(calls.length, 6, "all guided-flow guided-discuss-milestone callsites should be covered");
14
+ for (const call of calls) {
15
+ assert.match(
16
+ call[1] ?? "",
17
+ /\bworkingDirectory:\s*basePath\b/,
18
+ "guided-discuss-milestone prompts need workingDirectory so template validation does not crash",
19
+ );
20
+ }
21
+ });
@@ -0,0 +1,65 @@
1
+ // GSD-2 — Guided Unit Tool Contract tests.
2
+ // Verifies guided workflow turns use manifest tool policy without auto-mode state.
3
+
4
+ import test from "node:test";
5
+ import assert from "node:assert/strict";
6
+ import { mkdtempSync, rmSync } from "node:fs";
7
+ import { tmpdir } from "node:os";
8
+ import { join } from "node:path";
9
+
10
+ import { registerHooks } from "../bootstrap/register-hooks.ts";
11
+ import {
12
+ clearGuidedUnitContext,
13
+ getGuidedUnitContext,
14
+ setGuidedUnitContext,
15
+ } from "../guided-unit-context.ts";
16
+
17
+ test("guided Unit context applies Tool Contract policy when auto-mode has no current Unit", async () => {
18
+ const basePath = mkdtempSync(join(tmpdir(), "gsd-guided-tool-contract-"));
19
+ const handlers = new Map<string, Array<(event: any, ctx?: any) => Promise<any> | any>>();
20
+ const pi = {
21
+ on(event: string, handler: (event: any, ctx?: any) => Promise<any> | any) {
22
+ const existing = handlers.get(event) ?? [];
23
+ existing.push(handler);
24
+ handlers.set(event, existing);
25
+ },
26
+ };
27
+
28
+ try {
29
+ clearGuidedUnitContext();
30
+ registerHooks(pi as any, []);
31
+ setGuidedUnitContext(basePath, "plan-slice");
32
+
33
+ let blockResult: { block?: boolean; reason?: string } | undefined;
34
+ for (const handler of handlers.get("tool_call") ?? []) {
35
+ const result = await handler({
36
+ toolName: "edit",
37
+ input: {
38
+ path: join(basePath, "src", "main.ts"),
39
+ },
40
+ }, { cwd: basePath });
41
+ if (result?.block) {
42
+ blockResult = result;
43
+ break;
44
+ }
45
+ }
46
+
47
+ assert.equal(blockResult?.block, true);
48
+ assert.match(blockResult?.reason ?? "", /plan-slice|ToolsPolicy|not allowed|blocked/i);
49
+ } finally {
50
+ clearGuidedUnitContext();
51
+ rmSync(basePath, { recursive: true, force: true });
52
+ }
53
+ });
54
+
55
+ test("guided Unit context can be cleared by project root", () => {
56
+ clearGuidedUnitContext();
57
+ setGuidedUnitContext("/project/a", "plan-slice");
58
+ setGuidedUnitContext("/project/b", "complete-slice");
59
+
60
+ clearGuidedUnitContext("/project/a");
61
+
62
+ assert.equal(getGuidedUnitContext("/project/a"), null);
63
+ assert.equal(getGuidedUnitContext("/project/b")?.unitType, "complete-slice");
64
+ clearGuidedUnitContext();
65
+ });
@@ -45,7 +45,7 @@ describe("headless milestone bootstrap — parity with interactive flow", () =>
45
45
 
46
46
  // Match only the actual dispatchWorkflow call — comments in the body
47
47
  // may mention "plan-milestone" as part of the fix rationale.
48
- const dispatchMatches = [...fnBody.matchAll(/dispatchWorkflow\([^)]*,\s*"([^"]+)"\s*\)/g)];
48
+ const dispatchMatches = [...fnBody.matchAll(/dispatchWorkflow\([\s\S]*?,\s*"([^"]+)"\s*,\s*\{\s*basePath\s*\}\s*\)/g)];
49
49
  assert.strictEqual(
50
50
  dispatchMatches.length,
51
51
  1,
@@ -65,15 +65,15 @@ describe("headless milestone bootstrap — parity with interactive flow", () =>
65
65
  /### Ready-phrase pre-condition \(NON-BYPASSABLE\)/.test(section),
66
66
  "single-milestone ready-phrase section must be present",
67
67
  );
68
- // All four required artifacts must appear as checkboxes, not a prose list.
68
+ // All four required outcomes must appear as checkboxes, not a prose list.
69
69
  for (const artifact of [
70
- "`.gsd/PROJECT.md`",
71
- "`.gsd/REQUIREMENTS.md`",
70
+ "PROJECT artifact",
71
+ "REQUIREMENTS artifact",
72
72
  "`{{contextPath}}`",
73
73
  "`gsd_plan_milestone`",
74
74
  ]) {
75
75
  assert.ok(
76
- new RegExp(`- \\[ \\] [A-Za-z]+ ${artifact.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`).test(section),
76
+ new RegExp(`- \\[ \\] [^\\n]*${artifact.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`).test(section),
77
77
  `single-milestone pre-condition must include a checkbox for ${artifact}`,
78
78
  );
79
79
  }
@@ -103,8 +103,8 @@ describe("headless milestone bootstrap — parity with interactive flow", () =>
103
103
  "multi-milestone ready-phrase section must be present",
104
104
  );
105
105
  for (const artifact of [
106
- "`.gsd/PROJECT.md`",
107
- "`.gsd/REQUIREMENTS.md`",
106
+ "PROJECT artifact",
107
+ "REQUIREMENTS artifact",
108
108
  "`gsd_plan_milestone`",
109
109
  "`.gsd/DISCUSSION-MANIFEST.json`",
110
110
  ]) {
@@ -92,6 +92,11 @@ test("resolveModelId: returns undefined for unknown model", () => {
92
92
  assert.equal(match, undefined);
93
93
  });
94
94
 
95
+ test("resolveModelId: returns undefined for missing model ID", () => {
96
+ const match = resolveModelId(undefined, AVAILABLE_MODELS, "anthropic");
97
+ assert.equal(match, undefined);
98
+ });
99
+
95
100
  test("resolveModelId: returns undefined for unknown provider/model combo", () => {
96
101
  const match = resolveModelId("fakeprovider/fake-model", AVAILABLE_MODELS, undefined);
97
102
  assert.equal(match, undefined);
@@ -9,11 +9,11 @@ import { isInfrastructureError, INFRA_ERROR_CODES } from "../auto/infra-errors.j
9
9
  test("INFRA_ERROR_CODES contains the expected codes", () => {
10
10
  for (const code of [
11
11
  "ENOSPC", "ENOMEM", "EROFS", "EDQUOT", "EMFILE", "ENFILE",
12
- "EAGAIN", "ECONNREFUSED", "ENOTFOUND", "ENETUNREACH",
12
+ "EAGAIN", "ENOBUFS", "ECONNREFUSED", "ENOTFOUND", "ENETUNREACH",
13
13
  ]) {
14
14
  assert.ok(INFRA_ERROR_CODES.has(code), `missing ${code}`);
15
15
  }
16
- assert.equal(INFRA_ERROR_CODES.size, 10, "unexpected extra codes");
16
+ assert.equal(INFRA_ERROR_CODES.size, 11, "unexpected extra codes");
17
17
  });
18
18
 
19
19
  // ── isInfrastructureError: code property detection ───────────────────────────
@@ -5,6 +5,8 @@ import test, { describe } from "node:test";
5
5
  import assert from "node:assert/strict";
6
6
 
7
7
  import {
8
+ INFRA_ERROR_CODES,
9
+ isInfrastructureError,
8
10
  isTransientCooldownError,
9
11
  getCooldownRetryAfterMs,
10
12
  MAX_COOLDOWN_RETRIES,
@@ -13,6 +15,13 @@ import {
13
15
 
14
16
  // ─── Constants ────────────────────────────────────────────────────────────────
15
17
 
18
+ describe("infra error classification", () => {
19
+ test("ENOBUFS is treated as infrastructure exhaustion", () => {
20
+ assert.equal(INFRA_ERROR_CODES.has("ENOBUFS"), true);
21
+ assert.equal(isInfrastructureError(Object.assign(new Error("spawnSync git ENOBUFS"), { code: "ENOBUFS" })), "ENOBUFS");
22
+ });
23
+ });
24
+
16
25
  describe("infra-errors cooldown constants", () => {
17
26
  test("COOLDOWN_FALLBACK_WAIT_MS is a positive number greater than the 30s rate-limit backoff", () => {
18
27
  assert.ok(typeof COOLDOWN_FALLBACK_WAIT_MS === "number");
@@ -446,6 +446,26 @@ node_modules/
446
446
  const strandedIssues = detect.issues.filter(i => i.code === "stranded_lock_directory");
447
447
  assert.deepStrictEqual(strandedIssues.length, 0, "live lock holder: stranded_lock_directory NOT detected");
448
448
  });
449
+
450
+ test('stranded_lock_directory still reports when worker lookup fails', async () => {
451
+ const dir = createMinimalProject();
452
+ cleanups.push(dir);
453
+
454
+ const lockDir = join(dir, ".gsd.lock");
455
+ mkdirSync(lockDir, { recursive: true });
456
+ const { openDatabase, _getAdapter, closeDatabase } = await import("../../gsd-db.ts");
457
+ openDatabase(join(dir, ".gsd", "gsd.db"));
458
+ const db = _getAdapter()!;
459
+ db.exec("DROP TABLE workers");
460
+
461
+ try {
462
+ const detect = await runGSDDoctor(dir);
463
+ const strandedIssues = detect.issues.filter(i => i.code === "stranded_lock_directory");
464
+ assert.ok(strandedIssues.length > 0, "reports stranded lock directory even when active worker lookup fails");
465
+ } finally {
466
+ closeDatabase();
467
+ }
468
+ });
449
469
  } else {
450
470
  }
451
471
 
@@ -5,7 +5,7 @@ import assert from 'node:assert/strict';
5
5
  import { mkdtempSync, mkdirSync, writeFileSync, rmSync, existsSync, symlinkSync, readFileSync } from "node:fs";
6
6
  import { join, dirname } from "node:path";
7
7
  import { tmpdir } from "node:os";
8
- import { execSync } from "node:child_process";
8
+ import { execFileSync, execSync } from "node:child_process";
9
9
 
10
10
  import {
11
11
  inferCommitType,
@@ -371,6 +371,18 @@ describe('git-service', async () => {
371
371
  return dir;
372
372
  }
373
373
 
374
+ function gitRun(args: string[], cwd: string): string {
375
+ return execFileSync("git", args, {
376
+ cwd,
377
+ stdio: ["ignore", "pipe", "pipe"],
378
+ encoding: "utf-8",
379
+ env: {
380
+ ...process.env,
381
+ GIT_ALLOW_PROTOCOL: "file",
382
+ },
383
+ }).trim();
384
+ }
385
+
374
386
  // ─── GitServiceImpl: smart staging ─────────────────────────────────────
375
387
 
376
388
  test('GitServiceImpl: smart staging', () => {
@@ -413,6 +425,96 @@ describe('git-service', async () => {
413
425
  rmSync(repo, { recursive: true, force: true });
414
426
  });
415
427
 
428
+ test('GitServiceImpl: task autoCommit skips keyFiles inside submodules', () => {
429
+ const repo = initTempRepo();
430
+ const subSrc = mkdtempSync(join(tmpdir(), "gsd-git-submodule-src-"));
431
+
432
+ try {
433
+ gitRun(["init", "-b", "main"], subSrc);
434
+ gitRun(["config", "user.name", "Pi Test"], subSrc);
435
+ gitRun(["config", "user.email", "pi@example.com"], subSrc);
436
+ createFile(subSrc, "tracked.txt", "initial\n");
437
+ gitRun(["add", "-A"], subSrc);
438
+ gitRun(["commit", "-m", "init submodule"], subSrc);
439
+
440
+ gitRun(["-c", "protocol.file.allow=always", "submodule", "add", `file://${subSrc}`, "sub"], repo);
441
+ gitRun(["commit", "-m", "add submodule"], repo);
442
+
443
+ createFile(repo, "sub/copied.txt", "copied from source\n");
444
+ createFile(repo, "src/feature.ts", "export const feature = true;\n");
445
+ createFile(repo, "src/unrelated.ts", "export const unrelated = true;\n");
446
+
447
+ const svc = new GitServiceImpl(repo);
448
+ const taskContext: TaskCommitContext = {
449
+ taskId: "S01/T01",
450
+ taskDisplayId: "T01",
451
+ taskTitle: "fix submodule staging",
452
+ milestoneId: "M001",
453
+ milestoneTitle: "Submodule auto commit",
454
+ sliceId: "S01",
455
+ sliceTitle: "Commit scoped files",
456
+ oneLiner: "Fixed auto commit when key files include submodule paths",
457
+ keyFiles: ["sub/copied.txt", "src/feature.ts"],
458
+ };
459
+
460
+ const result = svc.autoCommit("execute-task", "M001/S01/T01", [], taskContext);
461
+
462
+ assert.ok(result !== null, "autoCommit should commit non-submodule changes");
463
+ const committed = gitRun(["show", "--name-only", "--format=", "HEAD"], repo);
464
+ assert.ok(committed.includes("src/feature.ts"), "non-submodule keyFile is committed");
465
+ assert.ok(!committed.includes("sub/copied.txt"), "submodule inner keyFile is not pathspec-staged");
466
+ assert.ok(!committed.includes("src/unrelated.ts"), "scoped staging does not fall back to smartStage");
467
+ } finally {
468
+ rmSync(repo, { recursive: true, force: true });
469
+ rmSync(subSrc, { recursive: true, force: true });
470
+ }
471
+ });
472
+
473
+ test('GitServiceImpl: all keyFiles inside submodules falls back to smartStage', () => {
474
+ const repo = initTempRepo();
475
+ const subSrc = mkdtempSync(join(tmpdir(), "gsd-git-all-submodule-src-"));
476
+
477
+ try {
478
+ gitRun(["init", "-b", "main"], subSrc);
479
+ gitRun(["config", "user.name", "Pi Test"], subSrc);
480
+ gitRun(["config", "user.email", "pi@example.com"], subSrc);
481
+ createFile(subSrc, "tracked.txt", "initial\n");
482
+ gitRun(["add", "-A"], subSrc);
483
+ gitRun(["commit", "-m", "init submodule"], subSrc);
484
+
485
+ gitRun(["-c", "protocol.file.allow=always", "submodule", "add", `file://${subSrc}`, "sub"], repo);
486
+ gitRun(["commit", "-m", "add submodule"], repo);
487
+
488
+ createFile(repo, "sub/file1.txt", "inside submodule\n");
489
+ createFile(repo, "sub/file2.txt", "also inside\n");
490
+ createFile(repo, "src/real.ts", "export const real = true;\n");
491
+
492
+ const svc = new GitServiceImpl(repo);
493
+ const taskContext: TaskCommitContext = {
494
+ taskId: "S01/T02",
495
+ taskDisplayId: "T02",
496
+ taskTitle: "all keyFiles inside submodule",
497
+ milestoneId: "M001",
498
+ milestoneTitle: "Submodule auto commit",
499
+ sliceId: "S01",
500
+ sliceTitle: "Commit scoped files",
501
+ oneLiner: "Fell back when all key files are inside submodules",
502
+ keyFiles: ["sub", "sub/file1.txt", "sub/file2.txt"],
503
+ };
504
+
505
+ const result = svc.autoCommit("execute-task", "M001/S01/T02", [], taskContext);
506
+
507
+ assert.ok(result !== null, "autoCommit falls back to smartStage when all keyFiles are filtered");
508
+ const committed = gitRun(["show", "--name-only", "--format=", "HEAD"], repo);
509
+ assert.ok(!committed.includes("sub/file1.txt"), "submodule keyFile is not committed");
510
+ assert.ok(!committed.includes("sub/file2.txt"), "submodule keyFile is not committed");
511
+ assert.ok(committed.includes("src/real.ts"), "smartStage fallback commits other dirty files");
512
+ } finally {
513
+ rmSync(repo, { recursive: true, force: true });
514
+ rmSync(subSrc, { recursive: true, force: true });
515
+ }
516
+ });
517
+
416
518
  // ─── GitServiceImpl: smart staging excludes tracked runtime files ──────
417
519
 
418
520
  test('GitServiceImpl: smart staging excludes tracked runtime files', () => {
@@ -1066,6 +1168,15 @@ describe('git-service', async () => {
1066
1168
  rmSync(repo, { recursive: true, force: true });
1067
1169
  });
1068
1170
 
1171
+ test('Integration branch: rejects milestone branches', () => {
1172
+ const repo = initBranchTestRepo();
1173
+
1174
+ writeIntegrationBranch(repo, "M001", "milestone/M001");
1175
+ assert.deepStrictEqual(readIntegrationBranch(repo, "M001"), null, "milestone branches are not recorded as integration branch");
1176
+
1177
+ rmSync(repo, { recursive: true, force: true });
1178
+ });
1179
+
1069
1180
  // ─── writeIntegrationBranch: still records legitimate branches ────────
1070
1181
 
1071
1182
  test('Integration branch: records non-ephemeral gsd branches', () => {
@@ -195,6 +195,11 @@ describe("infrastructure error detection", () => {
195
195
  assert.equal(isInfrastructureError(err), "EAGAIN");
196
196
  });
197
197
 
198
+ test("ENOBUFS (no buffer space available) is detected", () => {
199
+ const err = Object.assign(new Error("spawnSync git ENOBUFS"), { code: "ENOBUFS" });
200
+ assert.equal(isInfrastructureError(err), "ENOBUFS");
201
+ });
202
+
198
203
  test("SQLite WAL corruption is detected via message scan", () => {
199
204
  const err = new Error("database disk image is malformed");
200
205
  assert.equal(isInfrastructureError(err), "SQLITE_CORRUPT");
@@ -223,7 +228,7 @@ describe("infrastructure error detection", () => {
223
228
  test("all INFRA_ERROR_CODES are covered", () => {
224
229
  const expectedCodes = [
225
230
  "ENOSPC", "ENOMEM", "EROFS", "EDQUOT", "EMFILE",
226
- "ENFILE", "EAGAIN", "ECONNREFUSED", "ENOTFOUND", "ENETUNREACH",
231
+ "ENFILE", "EAGAIN", "ENOBUFS", "ECONNREFUSED", "ENOTFOUND", "ENETUNREACH",
227
232
  ];
228
233
  for (const code of expectedCodes) {
229
234
  assert.ok(INFRA_ERROR_CODES.has(code), `${code} should be in INFRA_ERROR_CODES`);