gsd-pi 2.82.0-dev.2841a1e44 → 2.82.0-dev.3a3c6509d

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 (377) hide show
  1. package/README.md +3 -3
  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/claude-code-cli/stream-adapter.js +1 -1
  6. package/dist/resources/extensions/gsd/auto/infra-errors.js +9 -3
  7. package/dist/resources/extensions/gsd/auto/loop.js +5 -5
  8. package/dist/resources/extensions/gsd/auto/orchestrator.js +11 -0
  9. package/dist/resources/extensions/gsd/auto/phases.js +81 -31
  10. package/dist/resources/extensions/gsd/auto/workflow-memory-pressure.js +12 -0
  11. package/dist/resources/extensions/gsd/auto-dashboard.js +66 -1
  12. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +1 -0
  13. package/dist/resources/extensions/gsd/auto-dispatch.js +20 -19
  14. package/dist/resources/extensions/gsd/auto-model-selection.js +2 -0
  15. package/dist/resources/extensions/gsd/auto-post-unit.js +71 -10
  16. package/dist/resources/extensions/gsd/auto-recovery.js +71 -14
  17. package/dist/resources/extensions/gsd/auto-start.js +87 -14
  18. package/dist/resources/extensions/gsd/auto-verification.js +17 -4
  19. package/dist/resources/extensions/gsd/auto-worktree.js +176 -10
  20. package/dist/resources/extensions/gsd/auto.js +37 -5
  21. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +31 -7
  22. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +10 -9
  23. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +4 -2
  24. package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +5 -2
  25. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +14 -2
  26. package/dist/resources/extensions/gsd/commands/handlers/core.js +17 -1
  27. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +7 -2
  28. package/dist/resources/extensions/gsd/crash-recovery.js +43 -5
  29. package/dist/resources/extensions/gsd/db/milestone-leases.js +24 -0
  30. package/dist/resources/extensions/gsd/db/unit-dispatches.js +3 -2
  31. package/dist/resources/extensions/gsd/dispatch-guard.js +2 -2
  32. package/dist/resources/extensions/gsd/doctor-git-checks.js +46 -1
  33. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +28 -11
  34. package/dist/resources/extensions/gsd/doctor.js +2 -28
  35. package/dist/resources/extensions/gsd/export-html.js +27 -425
  36. package/dist/resources/extensions/gsd/forensics.js +3 -3
  37. package/dist/resources/extensions/gsd/git-service.js +45 -3
  38. package/dist/resources/extensions/gsd/gsd-db.js +21 -6
  39. package/dist/resources/extensions/gsd/guided-flow-queue.js +4 -3
  40. package/dist/resources/extensions/gsd/guided-flow.js +101 -116
  41. package/dist/resources/extensions/gsd/guided-unit-context.js +23 -0
  42. package/dist/resources/extensions/gsd/migrate/parsers.js +10 -0
  43. package/dist/resources/extensions/gsd/migration-auto-check.js +12 -17
  44. package/dist/resources/extensions/gsd/milestone-actions.js +11 -4
  45. package/dist/resources/extensions/gsd/native-git-bridge.js +48 -12
  46. package/dist/resources/extensions/gsd/pending-auto-start.js +52 -0
  47. package/dist/resources/extensions/gsd/post-execution-checks.js +73 -2
  48. package/dist/resources/extensions/gsd/pre-execution-checks.js +28 -1
  49. package/dist/resources/extensions/gsd/prompt-loader.js +1 -1
  50. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  51. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  52. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
  53. package/dist/resources/extensions/gsd/prompts/discuss.md +9 -9
  54. package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
  55. package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
  56. package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -4
  57. package/dist/resources/extensions/gsd/prompts/queue.md +4 -4
  58. package/dist/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  59. package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  60. package/dist/resources/extensions/gsd/queue-reorder-ui.js +30 -13
  61. package/dist/resources/extensions/gsd/smart-entry-routing.js +36 -0
  62. package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +6 -1
  63. package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +9 -14
  64. package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +19 -24
  65. package/dist/resources/extensions/gsd/state.js +1 -1
  66. package/dist/resources/extensions/gsd/status-guards.js +11 -0
  67. package/dist/resources/extensions/gsd/templates/plan.md +8 -5
  68. package/dist/resources/extensions/gsd/templates/task-plan.md +4 -2
  69. package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -8
  70. package/dist/resources/extensions/gsd/tools/complete-slice.js +6 -8
  71. package/dist/resources/extensions/gsd/tools/plan-milestone.js +7 -1
  72. package/dist/resources/extensions/gsd/tools/plan-slice.js +89 -14
  73. package/dist/resources/extensions/gsd/unit-context-manifest.js +7 -8
  74. package/dist/resources/extensions/gsd/validation.js +23 -1
  75. package/dist/resources/extensions/gsd/verification-gate.js +68 -7
  76. package/dist/resources/extensions/gsd/workflow-mcp.js +17 -1
  77. package/dist/resources/extensions/gsd/workflow-projections.js +6 -8
  78. package/dist/resources/extensions/gsd/worktree-lifecycle.js +33 -8
  79. package/dist/resources/extensions/gsd/worktree-manager.js +1 -1
  80. package/dist/resources/extensions/shared/html-shell.js +388 -0
  81. package/dist/resources/extensions/visual-brief/page-contract.js +2 -0
  82. package/dist/resources/extensions/visual-brief/prompts.js +29 -0
  83. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  84. package/dist/web/standalone/.next/BUILD_ID +1 -1
  85. package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
  86. package/dist/web/standalone/.next/build-manifest.json +3 -3
  87. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  88. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  89. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  90. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  98. package/dist/web/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  99. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  100. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  101. package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -7
  102. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -7
  103. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -5
  105. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -5
  108. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  110. package/dist/web/standalone/.next/server/app/index.html +1 -1
  111. package/dist/web/standalone/.next/server/app/index.rsc +4 -7
  112. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -7
  114. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  115. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -5
  116. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -5
  117. package/dist/web/standalone/.next/server/app/page.js +2 -2
  118. package/dist/web/standalone/.next/server/app/page.js.nft.json +1 -1
  119. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  120. package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
  121. package/dist/web/standalone/.next/server/chunks/4266.js +2 -0
  122. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  124. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  125. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  126. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  127. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  128. package/dist/web/standalone/.next/static/chunks/app/layout-8c10ec293ae0f1d5.js +1 -0
  129. package/dist/web/standalone/.next/static/chunks/{webpack-6a95bc41e0f7ec89.js → webpack-9a4db269f9ed63ad.js} +1 -1
  130. package/dist/web/standalone/.next/static/css/746ee28c929d1880.css +1 -0
  131. package/package.json +2 -2
  132. package/packages/mcp-server/src/workflow-tools.test.ts +1 -1
  133. package/packages/native/tsconfig.json +2 -1
  134. package/packages/native/tsconfig.tsbuildinfo +1 -1
  135. package/packages/pi-ai/dist/providers/google-gemini-cli.d.ts.map +1 -1
  136. package/packages/pi-ai/dist/providers/google-gemini-cli.js +5 -0
  137. package/packages/pi-ai/dist/providers/google-gemini-cli.js.map +1 -1
  138. package/packages/pi-ai/dist/providers/google-gemini-cli.test.d.ts +2 -0
  139. package/packages/pi-ai/dist/providers/google-gemini-cli.test.d.ts.map +1 -0
  140. package/packages/pi-ai/dist/providers/google-gemini-cli.test.js +41 -0
  141. package/packages/pi-ai/dist/providers/google-gemini-cli.test.js.map +1 -0
  142. package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
  143. package/packages/pi-ai/dist/providers/openai-codex-responses.js +82 -1
  144. package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
  145. package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts +2 -0
  146. package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts.map +1 -0
  147. package/packages/pi-ai/dist/providers/openai-codex-responses.test.js +52 -0
  148. package/packages/pi-ai/dist/providers/openai-codex-responses.test.js.map +1 -0
  149. package/packages/pi-ai/dist/providers/simple-options.d.ts +2 -4
  150. package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  151. package/packages/pi-ai/dist/providers/simple-options.js +5 -6
  152. package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
  153. package/packages/pi-ai/dist/providers/simple-options.test.d.ts +2 -0
  154. package/packages/pi-ai/dist/providers/simple-options.test.d.ts.map +1 -0
  155. package/packages/pi-ai/dist/providers/simple-options.test.js +50 -0
  156. package/packages/pi-ai/dist/providers/simple-options.test.js.map +1 -0
  157. package/packages/pi-ai/src/providers/google-gemini-cli.test.ts +49 -0
  158. package/packages/pi-ai/src/providers/google-gemini-cli.ts +7 -0
  159. package/packages/pi-ai/src/providers/openai-codex-responses.test.ts +63 -0
  160. package/packages/pi-ai/src/providers/openai-codex-responses.ts +91 -1
  161. package/packages/pi-ai/src/providers/simple-options.test.ts +60 -0
  162. package/packages/pi-ai/src/providers/simple-options.ts +5 -6
  163. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  164. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts +2 -0
  165. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts.map +1 -0
  166. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js +66 -0
  167. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js.map +1 -0
  168. package/packages/pi-coding-agent/dist/core/agent-session.js +1 -1
  169. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  170. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +44 -3
  171. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  172. package/packages/pi-coding-agent/dist/core/sdk.js +1 -1
  173. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  174. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  175. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +24 -6
  176. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  177. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  178. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +71 -97
  179. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  180. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js +12 -0
  181. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js.map +1 -1
  182. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  183. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +19 -8
  184. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  185. package/packages/pi-coding-agent/src/core/agent-session-thinking-level.test.ts +79 -0
  186. package/packages/pi-coding-agent/src/core/agent-session.ts +1 -1
  187. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +53 -3
  188. package/packages/pi-coding-agent/src/core/sdk.ts +1 -1
  189. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +23 -7
  190. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +75 -102
  191. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-ordering.test.ts +14 -0
  192. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +23 -8
  193. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  194. package/packages/pi-tui/dist/__tests__/terminal.test.d.ts +2 -0
  195. package/packages/pi-tui/dist/__tests__/terminal.test.d.ts.map +1 -0
  196. package/packages/pi-tui/dist/__tests__/terminal.test.js +103 -0
  197. package/packages/pi-tui/dist/__tests__/terminal.test.js.map +1 -0
  198. package/packages/pi-tui/dist/terminal.d.ts +2 -0
  199. package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
  200. package/packages/pi-tui/dist/terminal.js +12 -0
  201. package/packages/pi-tui/dist/terminal.js.map +1 -1
  202. package/packages/pi-tui/src/__tests__/terminal.test.ts +121 -0
  203. package/packages/pi-tui/src/terminal.ts +11 -0
  204. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  205. package/src/resources/GSD-WORKFLOW.md +7 -0
  206. package/src/resources/extensions/claude-code-cli/partial-builder.ts +2 -1
  207. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +1 -1
  208. package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +19 -2
  209. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +9 -0
  210. package/src/resources/extensions/gsd/auto/contracts.ts +14 -6
  211. package/src/resources/extensions/gsd/auto/infra-errors.ts +9 -3
  212. package/src/resources/extensions/gsd/auto/loop.ts +8 -5
  213. package/src/resources/extensions/gsd/auto/orchestrator.ts +11 -0
  214. package/src/resources/extensions/gsd/auto/phases.ts +90 -38
  215. package/src/resources/extensions/gsd/auto/workflow-memory-pressure.ts +13 -0
  216. package/src/resources/extensions/gsd/auto-dashboard.ts +72 -1
  217. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +1 -0
  218. package/src/resources/extensions/gsd/auto-dispatch.ts +21 -19
  219. package/src/resources/extensions/gsd/auto-model-selection.ts +2 -1
  220. package/src/resources/extensions/gsd/auto-post-unit.ts +78 -8
  221. package/src/resources/extensions/gsd/auto-recovery.ts +74 -11
  222. package/src/resources/extensions/gsd/auto-start.ts +94 -12
  223. package/src/resources/extensions/gsd/auto-verification.ts +22 -2
  224. package/src/resources/extensions/gsd/auto-worktree.ts +193 -10
  225. package/src/resources/extensions/gsd/auto.ts +40 -5
  226. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +42 -7
  227. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +10 -9
  228. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +4 -2
  229. package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +3 -1
  230. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +17 -2
  231. package/src/resources/extensions/gsd/commands/handlers/core.ts +17 -1
  232. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +8 -3
  233. package/src/resources/extensions/gsd/crash-recovery.ts +44 -4
  234. package/src/resources/extensions/gsd/db/milestone-leases.ts +26 -0
  235. package/src/resources/extensions/gsd/db/unit-dispatches.ts +4 -3
  236. package/src/resources/extensions/gsd/dispatch-guard.ts +2 -2
  237. package/src/resources/extensions/gsd/doctor-git-checks.ts +45 -1
  238. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +25 -13
  239. package/src/resources/extensions/gsd/doctor-types.ts +1 -0
  240. package/src/resources/extensions/gsd/doctor.ts +2 -27
  241. package/src/resources/extensions/gsd/export-html.ts +27 -427
  242. package/src/resources/extensions/gsd/forensics.ts +3 -3
  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/state.ts +1 -1
  272. package/src/resources/extensions/gsd/status-guards.ts +13 -0
  273. package/src/resources/extensions/gsd/templates/plan.md +8 -5
  274. package/src/resources/extensions/gsd/templates/task-plan.md +4 -2
  275. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +71 -0
  276. package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +116 -0
  277. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +56 -0
  278. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +80 -1
  279. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +35 -7
  280. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +53 -2
  281. package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +12 -1
  282. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +91 -6
  283. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +1 -0
  284. package/src/resources/extensions/gsd/tests/auto-stop-notification.test.ts +20 -0
  285. package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +69 -1
  286. package/src/resources/extensions/gsd/tests/checkout-branch-stash-guard.test.ts +87 -0
  287. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +11 -2
  288. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +4 -1
  289. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +5 -9
  290. package/src/resources/extensions/gsd/tests/complete-task.test.ts +3 -1
  291. package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +86 -2
  292. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +2 -0
  293. package/src/resources/extensions/gsd/tests/db-authority-regression.test.ts +208 -0
  294. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +59 -2
  295. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +66 -0
  296. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +27 -0
  297. package/src/resources/extensions/gsd/tests/doctor-empty-worktree.test.ts +65 -0
  298. package/src/resources/extensions/gsd/tests/export-html-enhancements.test.ts +8 -0
  299. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +11 -0
  300. package/src/resources/extensions/gsd/tests/guided-discuss-project-prompt-rendering.test.ts +2 -0
  301. package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +106 -0
  302. package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +59 -11
  303. package/src/resources/extensions/gsd/tests/guided-flow.test.ts +21 -0
  304. package/src/resources/extensions/gsd/tests/guided-tool-contract.test.ts +65 -0
  305. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +7 -7
  306. package/src/resources/extensions/gsd/tests/hook-model-resolution.test.ts +5 -0
  307. package/src/resources/extensions/gsd/tests/infra-error.test.ts +2 -2
  308. package/src/resources/extensions/gsd/tests/infra-errors-cooldown.test.ts +9 -0
  309. package/src/resources/extensions/gsd/tests/integration/doctor-runtime.test.ts +20 -0
  310. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +112 -1
  311. package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +6 -1
  312. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +46 -0
  313. package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +179 -0
  314. package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +24 -1
  315. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +26 -18
  316. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +63 -2
  317. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +121 -1
  318. package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +55 -1
  319. package/src/resources/extensions/gsd/tests/pending-autostart-scope.test.ts +29 -5
  320. package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +2 -1
  321. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +26 -0
  322. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
  323. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +225 -1
  324. package/src/resources/extensions/gsd/tests/plan-task.test.ts +17 -0
  325. package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +86 -0
  326. package/src/resources/extensions/gsd/tests/post-unit-git-failure.test.ts +1 -1
  327. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +53 -0
  328. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +59 -0
  329. package/src/resources/extensions/gsd/tests/prompt-loader.test.ts +23 -0
  330. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +37 -1
  331. package/src/resources/extensions/gsd/tests/queue-reorder-ui.test.ts +54 -0
  332. package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +89 -2
  333. package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +2 -3
  334. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +10 -0
  335. package/src/resources/extensions/gsd/tests/smart-entry-routing.test.ts +113 -0
  336. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +53 -2
  337. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +119 -23
  338. package/src/resources/extensions/gsd/tests/status-guards.test.ts +13 -1
  339. package/src/resources/extensions/gsd/tests/stuck-state-via-db.test.ts +64 -1
  340. package/src/resources/extensions/gsd/tests/summary-render-parity.test.ts +7 -3
  341. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +82 -7
  342. package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +29 -2
  343. package/src/resources/extensions/gsd/tests/verification-gate.test.ts +110 -1
  344. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +19 -1
  345. package/src/resources/extensions/gsd/tests/workflow-memory-pressure.test.ts +21 -1
  346. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +1 -1
  347. package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +39 -0
  348. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +64 -12
  349. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +38 -0
  350. package/src/resources/extensions/gsd/tools/complete-milestone.ts +8 -10
  351. package/src/resources/extensions/gsd/tools/complete-slice.ts +6 -8
  352. package/src/resources/extensions/gsd/tools/plan-milestone.ts +5 -1
  353. package/src/resources/extensions/gsd/tools/plan-slice.ts +98 -12
  354. package/src/resources/extensions/gsd/types.ts +1 -1
  355. package/src/resources/extensions/gsd/unit-context-manifest.ts +12 -9
  356. package/src/resources/extensions/gsd/validation.ts +23 -1
  357. package/src/resources/extensions/gsd/verification-gate.ts +78 -6
  358. package/src/resources/extensions/gsd/workflow-mcp.ts +18 -1
  359. package/src/resources/extensions/gsd/workflow-projections.ts +6 -8
  360. package/src/resources/extensions/gsd/worktree-lifecycle.ts +41 -8
  361. package/src/resources/extensions/gsd/worktree-manager.ts +1 -1
  362. package/src/resources/extensions/shared/html-shell.ts +412 -0
  363. package/src/resources/extensions/visual-brief/page-contract.ts +2 -0
  364. package/src/resources/extensions/visual-brief/prompts.ts +37 -1
  365. package/src/resources/extensions/visual-brief/tests/visual-brief.test.ts +40 -0
  366. package/dist/web/standalone/.next/server/chunks/5822.js +0 -2
  367. package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +0 -1
  368. package/dist/web/standalone/.next/static/css/0262768ec1b89d34.css +0 -1
  369. package/dist/web/standalone/.next/static/css/de70bee13400563f.css +0 -1
  370. package/dist/web/standalone/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
  371. package/dist/web/standalone/.next/static/media/747892c23ea88013-s.woff2 +0 -0
  372. package/dist/web/standalone/.next/static/media/8d697b304b401681-s.woff2 +0 -0
  373. package/dist/web/standalone/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
  374. package/dist/web/standalone/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
  375. package/dist/web/standalone/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
  376. /package/dist/web/standalone/.next/static/{Qgr2B_MRhPxC0z8fwv4vT → O6femb9LLl3nlgsDaYwS-}/_buildManifest.js +0 -0
  377. /package/dist/web/standalone/.next/static/{Qgr2B_MRhPxC0z8fwv4vT → O6femb9LLl3nlgsDaYwS-}/_ssgManifest.js +0 -0
@@ -5,7 +5,7 @@ import { join } from "node:path";
5
5
  import { tmpdir } from "node:os";
6
6
  import { randomUUID } from "node:crypto";
7
7
 
8
- import { verifyExpectedArtifact, hasImplementationArtifacts, resolveExpectedArtifactPath, diagnoseExpectedArtifact, buildLoopRemediationSteps, writeBlockerPlaceholder, refreshRecoveryDbForArtifact } from "../auto-recovery.ts";
8
+ import { verifyExpectedArtifact, hasImplementationArtifacts, resolveExpectedArtifactPath, diagnoseExpectedArtifact, diagnoseWorktreeIntegrityFailure, buildLoopRemediationSteps, writeBlockerPlaceholder, refreshRecoveryDbForArtifact } from "../auto-recovery.ts";
9
9
  import { resolveMilestoneFile } from "../paths.ts";
10
10
  import { openDatabase, closeDatabase, insertMilestone, insertSlice, insertGateRow, insertTask, getMilestoneCommitAttributionShas } from "../gsd-db.ts";
11
11
  import { clearParseCache } from "../files.ts";
@@ -141,6 +141,20 @@ test("resolveExpectedArtifactPath returns null for unknown type", () => {
141
141
  }
142
142
  });
143
143
 
144
+ test("diagnoseWorktreeIntegrityFailure reports missing GSD worktree paths only", () => {
145
+ const missingWorktreePath = join(tmpdir(), `gsd-test-${randomUUID()}`, ".gsd", "worktrees", "M001-S01");
146
+ assert.equal(
147
+ diagnoseWorktreeIntegrityFailure(join(tmpdir(), `gsd-test-${randomUUID()}`)),
148
+ null,
149
+ "non-GSD paths should keep falling through to artifact recovery",
150
+ );
151
+ assert.equal(
152
+ diagnoseWorktreeIntegrityFailure(missingWorktreePath),
153
+ `Worktree integrity failure: ${missingWorktreePath} does not exist. Repair or recreate the worktree before retrying.`,
154
+ "missing GSD worktree paths should fail terminally before artifact retry",
155
+ );
156
+ });
157
+
144
158
  test("resolveExpectedArtifactPath returns correct path for all milestone-level types", () => {
145
159
  const base = makeTmpBase();
146
160
  try {
@@ -793,6 +807,51 @@ test("hasImplementationArtifacts finds integration implementation-only commits w
793
807
  }
794
808
  });
795
809
 
810
+ test("hasImplementationArtifacts ignores corrupted milestone/* integration metadata", () => {
811
+ const base = makeGitBase();
812
+ try {
813
+ mkdirSync(join(base, "src"), { recursive: true });
814
+ writeFileSync(join(base, "src", "feature.ts"), "export function feature() {}\n");
815
+ execFileSync("git", ["add", "src/feature.ts"], { cwd: base, stdio: "ignore" });
816
+ execFileSync("git", ["commit", "-m", "feat: add milestone feature\n\nGSD-Task: S01/T01"], { cwd: base, stdio: "ignore" });
817
+
818
+ mkdirSync(join(base, ".gsd"), { recursive: true });
819
+ openDatabase(join(base, ".gsd", "gsd.db"));
820
+ insertMilestone({ id: "M001", title: "Milestone One", status: "active" });
821
+ insertSlice({
822
+ id: "S01",
823
+ milestoneId: "M001",
824
+ title: "Slice One",
825
+ status: "complete",
826
+ risk: "low",
827
+ depends: [],
828
+ });
829
+ insertTask({
830
+ id: "T01",
831
+ sliceId: "S01",
832
+ milestoneId: "M001",
833
+ title: "Task One",
834
+ status: "complete",
835
+ });
836
+
837
+ execFileSync("git", ["checkout", "-b", "milestone/M001"], { cwd: base, stdio: "ignore" });
838
+ mkdirSync(join(base, ".gsd", "milestones", "M001"), { recursive: true });
839
+ writeFileSync(join(base, ".gsd", "milestones", "M001", "M001-SUMMARY.md"), "# Milestone Summary\nDone.");
840
+ execFileSync("git", ["add", "."], { cwd: base, stdio: "ignore" });
841
+ execFileSync("git", ["commit", "-m", "chore: auto-commit after complete-milestone\n\nGSD-Unit: M001"], { cwd: base, stdio: "ignore" });
842
+
843
+ writeFileSync(
844
+ join(base, ".gsd", "milestones", "M001", "M001-META.json"),
845
+ JSON.stringify({ integrationBranch: "milestone/M001" }, null, 2) + "\n",
846
+ );
847
+
848
+ const result = hasImplementationArtifacts(base, "M001");
849
+ assert.equal(result, "present", "corrupted milestone integration metadata should fall back to main branch for artifact detection");
850
+ } finally {
851
+ cleanup(base);
852
+ }
853
+ });
854
+
796
855
  test("hasImplementationArtifacts backfills untagged main implementation commits from completed task file hints", () => {
797
856
  const base = makeGitBase();
798
857
  try {
@@ -1029,24 +1088,50 @@ test("hasImplementationArtifacts binds GSD-Task trailer to milestone via DB stat
1029
1088
  }
1030
1089
  });
1031
1090
 
1032
- test("hasImplementationArtifacts does not bind GSD-Task trailer without milestone ownership evidence", () => {
1091
+ test("hasImplementationArtifacts does not claim Sxx/Tyy commit trailers across milestones when ownership points elsewhere", () => {
1033
1092
  const base = makeGitBase();
1034
1093
  try {
1035
1094
  writeFileSync(join(base, ".git", "info", "exclude"), ".gsd/\n");
1095
+ mkdirSync(join(base, ".gsd"), { recursive: true });
1096
+ openDatabase(join(base, ".gsd", "gsd.db"));
1097
+ insertMilestone({ id: "M001", title: "Milestone One", status: "active" });
1098
+ insertMilestone({ id: "M002", title: "Milestone Two", status: "active" });
1099
+ insertSlice({
1100
+ id: "S01",
1101
+ milestoneId: "M002",
1102
+ title: "Slice One",
1103
+ status: "complete",
1104
+ risk: "low",
1105
+ depends: [],
1106
+ });
1107
+ insertTask({
1108
+ id: "T01",
1109
+ sliceId: "S01",
1110
+ milestoneId: "M002",
1111
+ title: "Task One",
1112
+ status: "complete",
1113
+ });
1114
+
1036
1115
  mkdirSync(join(base, "src"), { recursive: true });
1037
1116
  writeFileSync(join(base, "src", "feature.ts"), "export function feature() {}\n");
1038
1117
  execFileSync("git", ["add", "."], { cwd: base, stdio: "ignore" });
1039
1118
  execFileSync(
1040
1119
  "git",
1041
- ["commit", "-m", "feat: add feature\n\nGSD-Task: S01/T01"],
1120
+ ["commit", "-m", "feat: add sibling feature\n\nGSD-Task: S01/T01"],
1042
1121
  { cwd: base, stdio: "ignore" },
1043
1122
  );
1044
1123
 
1045
- const result = hasImplementationArtifacts(base, "M001");
1124
+ const m001Result = hasImplementationArtifacts(base, "M001");
1125
+ const m002Result = hasImplementationArtifacts(base, "M002");
1046
1126
  assert.equal(
1047
- result,
1127
+ m001Result,
1048
1128
  "absent",
1049
- "S01/T01 shape alone must not bind an implementation commit to M001",
1129
+ "Sxx/Tyy commit trailers owned by M002 must not be attributed to M001",
1130
+ );
1131
+ assert.equal(
1132
+ m002Result,
1133
+ "present",
1134
+ "the owning milestone should still claim the implementation-bearing commit",
1050
1135
  );
1051
1136
  } finally {
1052
1137
  cleanup(base);
@@ -98,6 +98,7 @@ test("bootstrap aborts before starting next milestone when completed orphan merg
98
98
  {
99
99
  shouldUseWorktreeIsolation: () => true,
100
100
  registerSigtermHandler: () => {},
101
+ registerAutoWorkerForSession: () => {},
101
102
  lockBase: () => base,
102
103
  buildLifecycle: () => ({
103
104
  adoptSessionRoot: (sessionBase: string, originalBase?: string) => {
@@ -0,0 +1,20 @@
1
+ // Project/App: GSD-2
2
+ // File Purpose: Regression tests for auto-mode stop notification formatting.
3
+
4
+ import test from "node:test";
5
+ import assert from "node:assert/strict";
6
+
7
+ import { formatAutoStopNotification } from "../auto.ts";
8
+
9
+ test("auto stop notification keeps session totals on a separate line", () => {
10
+ const message = formatAutoStopNotification(
11
+ "Auto-mode stopped",
12
+ { cost: 0.652, tokens: { total: 87000 } },
13
+ 2,
14
+ );
15
+
16
+ assert.equal(
17
+ message,
18
+ "Auto-mode stopped.\nSession: $0.652 · 87.0k tokens · 2 units",
19
+ );
20
+ });
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { describe, test, beforeEach } from "node:test";
4
4
  import assert from "node:assert/strict";
5
- import { mkdtempSync, mkdirSync, writeFileSync, rmSync, realpathSync } from "node:fs";
5
+ import { existsSync, mkdtempSync, mkdirSync, writeFileSync, rmSync, realpathSync } from "node:fs";
6
6
  import { join } from "node:path";
7
7
  import { tmpdir } from "node:os";
8
8
  import { execFileSync } from "node:child_process";
@@ -13,6 +13,7 @@ import {
13
13
  _resetAutoWorktreeOriginalBaseForTests,
14
14
  createAutoWorktree,
15
15
  enterAutoWorktree,
16
+ mergeMilestoneToMain,
16
17
  teardownAutoWorktree,
17
18
  } from "../auto-worktree.ts";
18
19
 
@@ -173,4 +174,71 @@ describe("auto-worktree workspace registry", () => {
173
174
  teardownAutoWorktree(dir2, "M020");
174
175
  try { process.chdir(savedCwd); } catch { /* ignore */ }
175
176
  });
177
+
178
+ test("mergeMilestoneToMain cleans up when milestone branch was already regular-merged", (t) => {
179
+ const tempDir = createTempRepo(t);
180
+ const msDir = join(tempDir, ".gsd", "milestones", "M003");
181
+ mkdirSync(msDir, { recursive: true });
182
+ writeFileSync(join(msDir, "CONTEXT.md"), "# M003 Context\n");
183
+ git(["add", "."], tempDir);
184
+ git(["commit", "-m", "add milestone"], tempDir);
185
+
186
+ createAutoWorktree(tempDir, "M003");
187
+ const wtDir = join(tempDir, ".gsd", "worktrees", "M003");
188
+ writeFileSync(join(wtDir, "feature.txt"), "implemented\n");
189
+ git(["add", "feature.txt"], wtDir);
190
+ git(["commit", "-m", "feat: implement M003"], wtDir);
191
+
192
+ process.chdir(tempDir);
193
+ git(["merge", "--no-ff", "milestone/M003", "-m", "merge M003"], tempDir);
194
+
195
+ process.chdir(wtDir);
196
+ const result = mergeMilestoneToMain(tempDir, "M003", "# M003\n- [x] **S01: Done**\n");
197
+
198
+ assert.equal(result.codeFilesChanged, true);
199
+ assert.equal(result.pushed, false);
200
+ assert.equal(result.prCreated, false);
201
+ assert.equal(existsSync(wtDir), false, "worktree directory is removed");
202
+ assert.throws(
203
+ () => git(["rev-parse", "--verify", "milestone/M003"], tempDir),
204
+ /Command failed/,
205
+ "already-merged milestone branch is deleted",
206
+ );
207
+ try { process.chdir(savedCwd); } catch { /* ignore */ }
208
+ });
209
+
210
+ test("mergeMilestoneToMain cleans up already-merged milestone after main advances", (t) => {
211
+ const tempDir = createTempRepo(t);
212
+ const msDir = join(tempDir, ".gsd", "milestones", "M004");
213
+ mkdirSync(msDir, { recursive: true });
214
+ writeFileSync(join(msDir, "CONTEXT.md"), "# M004 Context\n");
215
+ git(["add", "."], tempDir);
216
+ git(["commit", "-m", "add milestone"], tempDir);
217
+
218
+ createAutoWorktree(tempDir, "M004");
219
+ const wtDir = join(tempDir, ".gsd", "worktrees", "M004");
220
+ writeFileSync(join(wtDir, "feature.txt"), "implemented\n");
221
+ git(["add", "feature.txt"], wtDir);
222
+ git(["commit", "-m", "feat: implement M004"], wtDir);
223
+
224
+ process.chdir(tempDir);
225
+ git(["merge", "--no-ff", "milestone/M004", "-m", "merge M004"], tempDir);
226
+ writeFileSync(join(tempDir, "hotfix.txt"), "later main work\n");
227
+ git(["add", "hotfix.txt"], tempDir);
228
+ git(["commit", "-m", "fix: advance main"], tempDir);
229
+
230
+ process.chdir(wtDir);
231
+ const result = mergeMilestoneToMain(tempDir, "M004", "# M004\n- [x] **S01: Done**\n");
232
+
233
+ assert.equal(result.codeFilesChanged, true);
234
+ assert.equal(result.pushed, false);
235
+ assert.equal(result.prCreated, false);
236
+ assert.equal(existsSync(wtDir), false, "worktree directory is removed");
237
+ assert.throws(
238
+ () => git(["rev-parse", "--verify", "milestone/M004"], tempDir),
239
+ /Command failed/,
240
+ "already-merged milestone branch is deleted",
241
+ );
242
+ try { process.chdir(savedCwd); } catch { /* ignore */ }
243
+ });
176
244
  });
@@ -0,0 +1,87 @@
1
+ import { describe, test } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { execFileSync } from "node:child_process";
4
+ import { mkdtempSync, readFileSync, realpathSync, rmSync, writeFileSync } from "node:fs";
5
+ import { join } from "node:path";
6
+ import { tmpdir } from "node:os";
7
+
8
+ import { checkoutBranchWithStashGuard } from "../auto-worktree.ts";
9
+
10
+ function git(args: string[], cwd: string): string {
11
+ return execFileSync("git", args, {
12
+ cwd,
13
+ stdio: ["ignore", "pipe", "pipe"],
14
+ encoding: "utf-8",
15
+ });
16
+ }
17
+
18
+ function createRepo(t: { after: (fn: () => void) => void }): string {
19
+ const dir = realpathSync(mkdtempSync(join(tmpdir(), "checkout-stash-guard-")));
20
+ t.after(() => rmSync(dir, { recursive: true, force: true }));
21
+ git(["init"], dir);
22
+ git(["config", "user.email", "test@example.com"], dir);
23
+ git(["config", "user.name", "Test User"], dir);
24
+ writeFileSync(join(dir, "note.txt"), "base\n");
25
+ git(["add", "note.txt"], dir);
26
+ git(["commit", "-m", "init"], dir);
27
+ git(["branch", "-M", "main"], dir);
28
+ return dir;
29
+ }
30
+
31
+ describe("checkoutBranchWithStashGuard", () => {
32
+ test("restores dirty working tree after successful checkout", (t) => {
33
+ const repo = createRepo(t);
34
+ git(["checkout", "-b", "milestone/M001"], repo);
35
+ git(["checkout", "main"], repo);
36
+
37
+ writeFileSync(join(repo, "note.txt"), "dirty\n");
38
+
39
+ checkoutBranchWithStashGuard(repo, "milestone/M001", "test-success");
40
+
41
+ const branch = git(["branch", "--show-current"], repo).trim();
42
+ assert.equal(branch, "milestone/M001");
43
+ const content = git(["show", "HEAD:note.txt"], repo).trim();
44
+ assert.equal(content, "base");
45
+ const wtContent = readFileSync(join(repo, "note.txt"), "utf8");
46
+ assert.equal(wtContent, "dirty\n");
47
+ const status = git(["status", "--porcelain"], repo);
48
+ assert.match(status, /note\.txt/);
49
+ });
50
+
51
+ test("restores dirty working tree when checkout throws", (t) => {
52
+ const repo = createRepo(t);
53
+ writeFileSync(join(repo, "note.txt"), "dirty\n");
54
+
55
+ assert.throws(
56
+ () => checkoutBranchWithStashGuard(repo, "milestone/DOES-NOT-EXIST", "test-failure"),
57
+ );
58
+
59
+ const status = git(["status", "--porcelain"], repo);
60
+ assert.match(status, /note\.txt/);
61
+ const stashList = git(["stash", "list"], repo).trim();
62
+ assert.equal(stashList, "");
63
+ });
64
+
65
+ test("surfaces distinct error when checkout succeeds but stash pop conflicts", (t) => {
66
+ const repo = createRepo(t);
67
+ // Branch B has a divergent version of note.txt so popping a stash made
68
+ // against main will conflict after the checkout to B.
69
+ git(["checkout", "-b", "milestone/B"], repo);
70
+ writeFileSync(join(repo, "note.txt"), "B-version\n");
71
+ git(["add", "note.txt"], repo);
72
+ git(["commit", "-m", "B"], repo);
73
+ git(["checkout", "main"], repo);
74
+
75
+ writeFileSync(join(repo, "note.txt"), "local\n");
76
+
77
+ assert.throws(
78
+ () => checkoutBranchWithStashGuard(repo, "milestone/B", "test-pop-failure"),
79
+ /checkout to 'milestone\/B' succeeded but stash restore failed/,
80
+ );
81
+
82
+ const branch = git(["branch", "--show-current"], repo).trim();
83
+ assert.equal(branch, "milestone/B");
84
+ const stashList = git(["stash", "list"], repo).trim();
85
+ assert.match(stashList, /gsd: checkout stash/);
86
+ });
87
+ });
@@ -17,6 +17,15 @@ import {
17
17
  setPendingAutoStart,
18
18
  } from "../guided-flow.ts";
19
19
 
20
+ function pendingInput(basePath: string, milestoneId: string) {
21
+ return {
22
+ basePath,
23
+ milestoneId,
24
+ ctx: { ui: { notify: () => undefined } } as any,
25
+ pi: { sendMessage: () => undefined } as any,
26
+ };
27
+ }
28
+
20
29
  afterEach(() => {
21
30
  clearPendingAutoStart();
22
31
  });
@@ -28,7 +37,7 @@ describe("clear stale pending auto-start (#3667)", () => {
28
37
  mkdirSync(join(base, ".gsd"), { recursive: true });
29
38
  const before = Date.now();
30
39
 
31
- setPendingAutoStart(base, { basePath: base, milestoneId: "M001" });
40
+ setPendingAutoStart(base, pendingInput(base, "M001"));
32
41
 
33
42
  const entry = _getPendingAutoStart(base);
34
43
  assert.ok(entry);
@@ -41,7 +50,7 @@ describe("clear stale pending auto-start (#3667)", () => {
41
50
  t.after(() => rmSync(base, { recursive: true, force: true }));
42
51
  mkdirSync(join(base, ".gsd"), { recursive: true });
43
52
 
44
- setPendingAutoStart(base, { basePath: base, milestoneId: "M001", createdAt: 123 });
53
+ setPendingAutoStart(base, { ...pendingInput(base, "M001"), createdAt: 123 });
45
54
 
46
55
  assert.equal(_getPendingAutoStart(base)?.createdAt, 123);
47
56
  });
@@ -645,7 +645,7 @@ describe("complete-milestone", () => {
645
645
  assert.strictEqual(sanitized.triggerReason, undefined);
646
646
  });
647
647
 
648
- test("rendered SUMMARY.md uses placeholder text for empty enrichment fields", async () => {
648
+ test("rendered SUMMARY.md uses empty frontmatter lists for empty key fields", async () => {
649
649
  const { handleCompleteMilestone } = await import("../tools/complete-milestone.ts");
650
650
  const base = createFixtureBase();
651
651
  const mid = "M001";
@@ -678,6 +678,9 @@ describe("complete-milestone", () => {
678
678
  assert.match(summary, /## Success Criteria Results\n\nNot provided\./);
679
679
  assert.match(summary, /## Definition of Done Results\n\nNot provided\./);
680
680
  assert.match(summary, /## Requirement Outcomes\n\nNot provided\./);
681
+ assert.match(summary, /key_decisions:\s*\[\]/);
682
+ assert.match(summary, /key_files:\s*\[\]/);
683
+ assert.doesNotMatch(summary, /key_(?:decisions|files):\n - \(none\)/);
681
684
  assert.match(summary, /## Deviations\n\nNone\./);
682
685
  assert.match(summary, /## Follow-ups\n\nNone\./);
683
686
  } finally {
@@ -408,10 +408,10 @@ console.log('\n=== complete-slice: handler with missing roadmap ===');
408
408
  }
409
409
 
410
410
  // ═══════════════════════════════════════════════════════════════════════════
411
- // complete-slice: step 13 specifies write tool for PROJECT.md (#2946)
411
+ // complete-slice: PROJECT refresh uses DB-backed artifact tool.
412
412
  // ═══════════════════════════════════════════════════════════════════════════
413
413
 
414
- console.log('\n=== complete-slice: step 13 specifies write tool for PROJECT.md (#2946) ===');
414
+ console.log('\n=== complete-slice: PROJECT refresh uses gsd_summary_save ===');
415
415
  {
416
416
  const promptPath = path.join(
417
417
  path.dirname(new URL(import.meta.url).pathname),
@@ -419,13 +419,9 @@ console.log('\n=== complete-slice: step 13 specifies write tool for PROJECT.md (
419
419
  );
420
420
  const prompt = fs.readFileSync(promptPath, 'utf-8');
421
421
 
422
- // Step 13 must explicitly name the `write` tool so the LLM doesn't
423
- // confuse it with `edit` (which requires path + oldText + newText).
424
- // See: https://github.com/gsd-build/gsd-2/issues/2946
425
- const mentionsWriteTool =
426
- /PROJECT\.md.*\bwrite\b/i.test(prompt) ||
427
- /\bwrite\b.*PROJECT\.md/i.test(prompt);
428
- assertTrue(mentionsWriteTool, 'step 13 must name the `write` tool when updating PROJECT.md');
422
+ assertTrue(prompt.includes('gsd_summary_save'), 'PROJECT refresh must use gsd_summary_save');
423
+ assertTrue(prompt.includes('artifact_type: "PROJECT"'), 'PROJECT refresh must use artifact_type PROJECT');
424
+ assertTrue(!/with a full `write`/i.test(prompt), 'prompt must not instruct direct PROJECT.md writes');
429
425
  }
430
426
 
431
427
  // ═══════════════════════════════════════════════════════════════════════════
@@ -491,7 +491,9 @@ console.log('\n=== complete-task: minimal params (no keyFiles, keyDecisions, ver
491
491
  assertTrue(fs.existsSync(result.summaryPath), 'summary file should be written with minimal params');
492
492
  const summaryContent = fs.readFileSync(result.summaryPath, 'utf-8');
493
493
  assertMatch(summaryContent, /blocker_discovered:\s*false/, 'blocker_discovered should default to false');
494
- assertMatch(summaryContent, /\(none\)/, 'key_files/key_decisions should show (none) placeholder');
494
+ assertMatch(summaryContent, /key_files:\s*\[\]/, 'key_files should render as an empty frontmatter list');
495
+ assertMatch(summaryContent, /key_decisions:\s*\[\]/, 'key_decisions should render as an empty frontmatter list');
496
+ assertTrue(!summaryContent.includes(' - (none)'), 'empty frontmatter lists should not render (none) as a list item');
495
497
  }
496
498
 
497
499
  cleanupDir(basePath);
@@ -19,14 +19,15 @@ import {
19
19
  insertMilestone,
20
20
  _getAdapter,
21
21
  } from "../gsd-db.ts";
22
- import { registerAutoWorker } from "../db/auto-workers.ts";
22
+ import { getAutoWorker, registerAutoWorker } from "../db/auto-workers.ts";
23
23
  import { claimMilestoneLease } from "../db/milestone-leases.ts";
24
- import { recordDispatchClaim } from "../db/unit-dispatches.ts";
24
+ import { getLatestForUnit, markRunning, recordDispatchClaim } from "../db/unit-dispatches.ts";
25
25
  import { setRuntimeKv, getRuntimeKv } from "../db/runtime-kv.ts";
26
26
  import {
27
27
  writeLock,
28
28
  readCrashLock,
29
29
  clearLock,
30
+ clearStaleWorkerLock,
30
31
  isLockProcessAlive,
31
32
  } from "../crash-recovery.ts";
32
33
  import { normalizeRealPath } from "../paths.ts";
@@ -223,3 +224,86 @@ test("clearLock removes the session_file row for the active worker", (t) => {
223
224
  assert.equal(getRuntimeKv("worker", workerId, "session_file"), null,
224
225
  "session_file row deleted by clearLock");
225
226
  });
227
+
228
+ test("clearLock marks stale worker crashed when no current-process worker matches", (t) => {
229
+ const base = makeBase();
230
+ t.after(() => cleanup(base));
231
+ openDatabase(join(base, ".gsd", "gsd.db"));
232
+ const projectRoot = normalizeRealPath(base);
233
+ const workerId = registerAutoWorker({ projectRootRealpath: projectRoot });
234
+
235
+ setRuntimeKv("worker", workerId, "session_file", "/tmp/stale-session.jsonl");
236
+ setWorkerPid(workerId, 99999);
237
+ expireWorker(workerId);
238
+ assert.ok(readCrashLock(base), "stale worker is detected before clearLock");
239
+
240
+ clearLock(base);
241
+
242
+ assert.equal(getAutoWorker(workerId)?.status, "crashed");
243
+ assert.equal(getRuntimeKv("worker", workerId, "session_file"), null);
244
+ assert.equal(readCrashLock(base), null);
245
+ });
246
+
247
+ test("clearStaleWorkerLock crashes stale worker and cancels latest active dispatch", (t) => {
248
+ const base = makeBase();
249
+ t.after(() => cleanup(base));
250
+ openDatabase(join(base, ".gsd", "gsd.db"));
251
+ insertMilestone({ id: "M001", title: "T", status: "active" });
252
+ const projectRoot = normalizeRealPath(base);
253
+ const workerId = registerAutoWorker({ projectRootRealpath: projectRoot });
254
+ const lease = claimMilestoneLease(workerId, "M001");
255
+ assert.equal(lease.ok, true);
256
+ if (!lease.ok) return;
257
+ const claim = recordDispatchClaim({
258
+ traceId: "t1",
259
+ workerId,
260
+ milestoneLeaseToken: lease.token,
261
+ milestoneId: "M001",
262
+ sliceId: "S01",
263
+ taskId: "T02",
264
+ unitType: "hook/codex-review",
265
+ unitId: "M001/S01/T02",
266
+ });
267
+ assert.equal(claim.ok, true);
268
+ if (!claim.ok) return;
269
+ markRunning(claim.dispatchId);
270
+ setRuntimeKv("worker", workerId, "session_file", "/tmp/pi-session-hook.jsonl");
271
+ setWorkerPid(workerId, 99999);
272
+ expireWorker(workerId);
273
+
274
+ assert.ok(readCrashLock(base), "stale worker is detected before cleanup");
275
+
276
+ clearStaleWorkerLock(base);
277
+
278
+ assert.equal(getAutoWorker(workerId)?.status, "crashed");
279
+ const dispatch = getLatestForUnit("M001/S01/T02");
280
+ assert.ok(dispatch);
281
+ assert.equal(dispatch!.status, "canceled");
282
+ assert.equal(dispatch!.exit_reason, "crash-recovered");
283
+ assert.equal(getRuntimeKv("worker", workerId, "session_file"), null);
284
+ assert.equal(readCrashLock(base), null);
285
+ });
286
+
287
+ test("clearLock marks stale worker crashed and releases held milestone lease", (t) => {
288
+ const base = makeBase();
289
+ t.after(() => cleanup(base));
290
+ openDatabase(join(base, ".gsd", "gsd.db"));
291
+ insertMilestone({ id: "M001", title: "T", status: "active" });
292
+ const projectRoot = normalizeRealPath(base);
293
+ const workerId = registerAutoWorker({ projectRootRealpath: projectRoot });
294
+ const lease = claimMilestoneLease(workerId, "M001");
295
+ assert.equal(lease.ok, true);
296
+ if (!lease.ok) return;
297
+
298
+ setWorkerPid(workerId, 99999);
299
+ expireWorker(workerId);
300
+ assert.ok(readCrashLock(base), "stale worker is detected before clearLock");
301
+
302
+ clearLock(base);
303
+
304
+ assert.equal(getAutoWorker(workerId)?.status, "crashed");
305
+ const leaseRow = _getAdapter()!.prepare(
306
+ `SELECT status FROM milestone_leases WHERE milestone_id = :m`,
307
+ ).get({ ":m": "M001" }) as { status: string } | undefined;
308
+ assert.equal(leaseRow?.status, "released");
309
+ });
@@ -98,6 +98,8 @@ function makeMockPi() {
98
98
  sendMessage: (...args: unknown[]) => {
99
99
  calls.push(args);
100
100
  },
101
+ getThinkingLevel: () => "off",
102
+ setThinkingLevel: () => {},
101
103
  calls,
102
104
  } as any;
103
105
  }