gsd-pi 2.44.0-dev.d25d507 → 2.45.0-dev.1afbdaa

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 (407) hide show
  1. package/dist/help-text.js +1 -1
  2. package/dist/loader.js +34 -0
  3. package/dist/resources/extensions/gsd/activity-log.js +7 -0
  4. package/dist/resources/extensions/gsd/auto/infra-errors.js +3 -0
  5. package/dist/resources/extensions/gsd/auto/phases.js +63 -77
  6. package/dist/resources/extensions/gsd/auto/run-unit.js +6 -3
  7. package/dist/resources/extensions/gsd/auto/session.js +0 -11
  8. package/dist/resources/extensions/gsd/auto-artifact-paths.js +112 -0
  9. package/dist/resources/extensions/gsd/auto-post-unit.js +25 -96
  10. package/dist/resources/extensions/gsd/auto-prompts.js +24 -1
  11. package/dist/resources/extensions/gsd/auto-start.js +23 -5
  12. package/dist/resources/extensions/gsd/auto-timers.js +57 -3
  13. package/dist/resources/extensions/gsd/auto-worktree-sync.js +4 -0
  14. package/dist/resources/extensions/gsd/auto-worktree.js +14 -10
  15. package/dist/resources/extensions/gsd/auto.js +42 -60
  16. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +170 -11
  17. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +18 -0
  18. package/dist/resources/extensions/gsd/commands/catalog.js +7 -1
  19. package/dist/resources/extensions/gsd/commands/context.js +0 -4
  20. package/dist/resources/extensions/gsd/commands/handlers/core.js +2 -0
  21. package/dist/resources/extensions/gsd/commands/handlers/ops.js +10 -0
  22. package/dist/resources/extensions/gsd/commands/handlers/parallel.js +1 -1
  23. package/dist/resources/extensions/gsd/commands-mcp-status.js +187 -0
  24. package/dist/resources/extensions/gsd/crash-recovery.js +2 -4
  25. package/dist/resources/extensions/gsd/dashboard-overlay.js +0 -44
  26. package/dist/resources/extensions/gsd/db-writer.js +40 -22
  27. package/dist/resources/extensions/gsd/doctor-checks.js +167 -2
  28. package/dist/resources/extensions/gsd/doctor.js +13 -3
  29. package/dist/resources/extensions/gsd/git-service.js +8 -3
  30. package/dist/resources/extensions/gsd/gsd-db.js +28 -4
  31. package/dist/resources/extensions/gsd/guided-flow.js +1 -2
  32. package/dist/resources/extensions/gsd/markdown-renderer.js +1 -1
  33. package/dist/resources/extensions/gsd/parallel-merge.js +1 -1
  34. package/dist/resources/extensions/gsd/parallel-orchestrator.js +5 -18
  35. package/dist/resources/extensions/gsd/preferences-types.js +2 -2
  36. package/dist/resources/extensions/gsd/preferences.js +8 -4
  37. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +21 -10
  38. package/dist/resources/extensions/gsd/prompts/complete-slice.md +10 -23
  39. package/dist/resources/extensions/gsd/prompts/discuss.md +2 -2
  40. package/dist/resources/extensions/gsd/prompts/execute-task.md +5 -15
  41. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
  42. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
  43. package/dist/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
  44. package/dist/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
  45. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  46. package/dist/resources/extensions/gsd/prompts/plan-slice.md +5 -3
  47. package/dist/resources/extensions/gsd/prompts/queue.md +2 -2
  48. package/dist/resources/extensions/gsd/prompts/quick-task.md +2 -0
  49. package/dist/resources/extensions/gsd/prompts/reactive-execute.md +1 -1
  50. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
  51. package/dist/resources/extensions/gsd/prompts/replan-slice.md +3 -14
  52. package/dist/resources/extensions/gsd/prompts/research-slice.md +3 -3
  53. package/dist/resources/extensions/gsd/prompts/rethink.md +83 -0
  54. package/dist/resources/extensions/gsd/prompts/system.md +1 -1
  55. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +7 -37
  56. package/dist/resources/extensions/gsd/provider-error-pause.js +7 -0
  57. package/dist/resources/extensions/gsd/repo-identity.js +45 -7
  58. package/dist/resources/extensions/gsd/rethink.js +115 -0
  59. package/dist/resources/extensions/gsd/session-lock.js +1 -3
  60. package/dist/resources/extensions/gsd/state.js +48 -3
  61. package/dist/resources/extensions/gsd/sync-lock.js +89 -0
  62. package/dist/resources/extensions/gsd/tools/complete-milestone.js +61 -11
  63. package/dist/resources/extensions/gsd/tools/complete-slice.js +56 -11
  64. package/dist/resources/extensions/gsd/tools/complete-task.js +50 -2
  65. package/dist/resources/extensions/gsd/tools/plan-milestone.js +37 -1
  66. package/dist/resources/extensions/gsd/tools/plan-slice.js +31 -1
  67. package/dist/resources/extensions/gsd/tools/plan-task.js +28 -1
  68. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +32 -2
  69. package/dist/resources/extensions/gsd/tools/reopen-slice.js +86 -0
  70. package/dist/resources/extensions/gsd/tools/reopen-task.js +90 -0
  71. package/dist/resources/extensions/gsd/tools/replan-slice.js +34 -2
  72. package/dist/resources/extensions/gsd/tools/validate-milestone.js +88 -0
  73. package/dist/resources/extensions/gsd/unit-ownership.js +85 -0
  74. package/dist/resources/extensions/gsd/workflow-events.js +102 -0
  75. package/dist/resources/extensions/gsd/workflow-logger.js +193 -0
  76. package/dist/resources/extensions/gsd/workflow-manifest.js +244 -0
  77. package/dist/resources/extensions/gsd/workflow-migration.js +280 -0
  78. package/dist/resources/extensions/gsd/workflow-projections.js +373 -0
  79. package/dist/resources/extensions/gsd/workflow-reconcile.js +411 -0
  80. package/dist/resources/extensions/gsd/worktree-manager.js +34 -3
  81. package/dist/resources/extensions/gsd/worktree-resolver.js +43 -0
  82. package/dist/resources/extensions/gsd/write-intercept.js +84 -0
  83. package/dist/resources/extensions/mcp-client/index.js +14 -0
  84. package/dist/resources/extensions/voice/index.js +11 -16
  85. package/dist/resources/extensions/voice/linux-ready.js +67 -0
  86. package/dist/web/standalone/.next/BUILD_ID +1 -1
  87. package/dist/web/standalone/.next/app-path-routes-manifest.json +14 -14
  88. package/dist/web/standalone/.next/build-manifest.json +3 -3
  89. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  90. package/dist/web/standalone/.next/react-loadable-manifest.json +2 -2
  91. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  92. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  93. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/_not-found/page.js +1 -1
  101. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  102. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  103. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  104. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  105. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  107. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  108. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  110. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  150. package/dist/web/standalone/.next/server/app/index.html +1 -1
  151. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  152. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  153. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  154. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  155. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +2 -2
  156. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  157. package/dist/web/standalone/.next/server/app/page.js +1 -1
  158. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  159. package/dist/web/standalone/.next/server/app-paths-manifest.json +14 -14
  160. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  161. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  162. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  163. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  164. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  165. package/dist/web/standalone/.next/static/chunks/4024.11ca5c01938e5948.js +9 -0
  166. package/dist/web/standalone/.next/static/chunks/{3721.bf31263de6d5fa46.js → 485.243af25f0cdf50d6.js} +2 -2
  167. package/dist/web/standalone/.next/static/chunks/app/{page-b9367c5ae13b99c6.js → page-6654a8cca61a3d1c.js} +1 -1
  168. package/dist/web/standalone/.next/static/chunks/webpack-0a4cd455ec4197d2.js +1 -0
  169. package/dist/web/standalone/.next/static/css/dd4ae3f58ac9b600.css +1 -0
  170. package/package.json +2 -1
  171. package/packages/native/dist/stream-process/index.js +2 -2
  172. package/packages/native/src/__tests__/stream-process.test.mjs +34 -0
  173. package/packages/native/src/stream-process/index.ts +2 -2
  174. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +3 -1
  175. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  176. package/packages/pi-coding-agent/dist/core/auth-storage.js +15 -1
  177. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  178. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts.map +1 -1
  179. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +2 -0
  180. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -1
  181. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +2 -1
  182. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  183. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  184. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts +4 -0
  185. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts.map +1 -1
  186. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js +10 -5
  187. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js.map +1 -1
  188. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.d.ts +2 -0
  189. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.d.ts.map +1 -0
  190. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.js +185 -0
  191. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.js.map +1 -0
  192. package/packages/pi-coding-agent/dist/core/local-model-check.d.ts +15 -0
  193. package/packages/pi-coding-agent/dist/core/local-model-check.d.ts.map +1 -0
  194. package/packages/pi-coding-agent/dist/core/local-model-check.js +41 -0
  195. package/packages/pi-coding-agent/dist/core/local-model-check.js.map +1 -0
  196. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +239 -10
  197. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
  198. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +13 -1
  199. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  200. package/packages/pi-coding-agent/dist/core/model-registry.js +40 -3
  201. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  202. package/packages/pi-coding-agent/dist/core/package-commands.test.js +206 -195
  203. package/packages/pi-coding-agent/dist/core/package-commands.test.js.map +1 -1
  204. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
  205. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  206. package/packages/pi-coding-agent/dist/core/settings-manager.js +6 -0
  207. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  208. package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
  209. package/packages/pi-coding-agent/dist/main.js +17 -0
  210. package/packages/pi-coding-agent/dist/main.js.map +1 -1
  211. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts +2 -0
  212. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts.map +1 -0
  213. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js +32 -0
  214. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js.map +1 -0
  215. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +3 -1
  216. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  217. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +8 -1
  218. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  219. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  220. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  221. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +12 -0
  222. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
  223. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts +15 -0
  224. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts.map +1 -0
  225. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js +40 -0
  226. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js.map +1 -0
  227. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  228. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +4 -1
  229. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  230. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +5 -2
  231. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  232. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +13 -2
  233. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
  234. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  235. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +17 -8
  236. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  237. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  238. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +7 -3
  239. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  240. package/packages/pi-coding-agent/package.json +1 -1
  241. package/packages/pi-coding-agent/src/core/auth-storage.ts +15 -1
  242. package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +2 -0
  243. package/packages/pi-coding-agent/src/core/extensions/types.ts +2 -1
  244. package/packages/pi-coding-agent/src/core/lifecycle-hooks.test.ts +227 -0
  245. package/packages/pi-coding-agent/src/core/lifecycle-hooks.ts +11 -5
  246. package/packages/pi-coding-agent/src/core/local-model-check.ts +45 -0
  247. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +297 -11
  248. package/packages/pi-coding-agent/src/core/model-registry.ts +51 -4
  249. package/packages/pi-coding-agent/src/core/package-commands.test.ts +227 -205
  250. package/packages/pi-coding-agent/src/core/settings-manager.ts +9 -0
  251. package/packages/pi-coding-agent/src/main.ts +19 -0
  252. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/timestamp.test.ts +38 -0
  253. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +10 -0
  254. package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +15 -0
  255. package/packages/pi-coding-agent/src/modes/interactive/components/timestamp.ts +48 -0
  256. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +3 -1
  257. package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +18 -3
  258. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +16 -7
  259. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +8 -1
  260. package/pkg/package.json +1 -1
  261. package/src/resources/extensions/gsd/activity-log.ts +1 -0
  262. package/src/resources/extensions/gsd/auto/infra-errors.ts +3 -0
  263. package/src/resources/extensions/gsd/auto/loop-deps.ts +0 -19
  264. package/src/resources/extensions/gsd/auto/phases.ts +69 -91
  265. package/src/resources/extensions/gsd/auto/run-unit.ts +6 -3
  266. package/src/resources/extensions/gsd/auto/session.ts +0 -18
  267. package/src/resources/extensions/gsd/auto-artifact-paths.ts +131 -0
  268. package/src/resources/extensions/gsd/auto-dashboard.ts +0 -1
  269. package/src/resources/extensions/gsd/auto-post-unit.ts +25 -106
  270. package/src/resources/extensions/gsd/auto-prompts.ts +24 -1
  271. package/src/resources/extensions/gsd/auto-start.ts +26 -5
  272. package/src/resources/extensions/gsd/auto-timers.ts +64 -3
  273. package/src/resources/extensions/gsd/auto-worktree-sync.ts +5 -0
  274. package/src/resources/extensions/gsd/auto-worktree.ts +17 -11
  275. package/src/resources/extensions/gsd/auto.ts +44 -86
  276. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +162 -11
  277. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +22 -0
  278. package/src/resources/extensions/gsd/commands/catalog.ts +7 -1
  279. package/src/resources/extensions/gsd/commands/context.ts +0 -5
  280. package/src/resources/extensions/gsd/commands/handlers/core.ts +2 -0
  281. package/src/resources/extensions/gsd/commands/handlers/ops.ts +10 -0
  282. package/src/resources/extensions/gsd/commands/handlers/parallel.ts +1 -1
  283. package/src/resources/extensions/gsd/commands-mcp-status.ts +247 -0
  284. package/src/resources/extensions/gsd/crash-recovery.ts +1 -5
  285. package/src/resources/extensions/gsd/dashboard-overlay.ts +0 -50
  286. package/src/resources/extensions/gsd/db-writer.ts +41 -27
  287. package/src/resources/extensions/gsd/doctor-checks.ts +180 -2
  288. package/src/resources/extensions/gsd/doctor-types.ts +7 -1
  289. package/src/resources/extensions/gsd/doctor.ts +13 -4
  290. package/src/resources/extensions/gsd/git-service.ts +6 -2
  291. package/src/resources/extensions/gsd/gsd-db.ts +32 -4
  292. package/src/resources/extensions/gsd/guided-flow.ts +1 -2
  293. package/src/resources/extensions/gsd/journal.ts +6 -1
  294. package/src/resources/extensions/gsd/markdown-renderer.ts +1 -1
  295. package/src/resources/extensions/gsd/parallel-merge.ts +1 -1
  296. package/src/resources/extensions/gsd/parallel-orchestrator.ts +5 -21
  297. package/src/resources/extensions/gsd/preferences-types.ts +2 -2
  298. package/src/resources/extensions/gsd/preferences.ts +7 -3
  299. package/src/resources/extensions/gsd/prompts/complete-milestone.md +21 -10
  300. package/src/resources/extensions/gsd/prompts/complete-slice.md +10 -23
  301. package/src/resources/extensions/gsd/prompts/discuss.md +2 -2
  302. package/src/resources/extensions/gsd/prompts/execute-task.md +5 -15
  303. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
  304. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
  305. package/src/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
  306. package/src/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
  307. package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  308. package/src/resources/extensions/gsd/prompts/plan-slice.md +5 -3
  309. package/src/resources/extensions/gsd/prompts/queue.md +2 -2
  310. package/src/resources/extensions/gsd/prompts/quick-task.md +2 -0
  311. package/src/resources/extensions/gsd/prompts/reactive-execute.md +1 -1
  312. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
  313. package/src/resources/extensions/gsd/prompts/replan-slice.md +3 -14
  314. package/src/resources/extensions/gsd/prompts/research-slice.md +3 -3
  315. package/src/resources/extensions/gsd/prompts/rethink.md +83 -0
  316. package/src/resources/extensions/gsd/prompts/system.md +1 -1
  317. package/src/resources/extensions/gsd/prompts/validate-milestone.md +7 -37
  318. package/src/resources/extensions/gsd/provider-error-pause.ts +9 -0
  319. package/src/resources/extensions/gsd/repo-identity.ts +46 -7
  320. package/src/resources/extensions/gsd/rethink.ts +154 -0
  321. package/src/resources/extensions/gsd/session-lock.ts +0 -4
  322. package/src/resources/extensions/gsd/state.ts +49 -1
  323. package/src/resources/extensions/gsd/sync-lock.ts +94 -0
  324. package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +5 -13
  325. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +6 -10
  326. package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +88 -0
  327. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +96 -0
  328. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +264 -228
  329. package/src/resources/extensions/gsd/tests/complete-task.test.ts +317 -250
  330. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +114 -0
  331. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +2 -8
  332. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +0 -3
  333. package/src/resources/extensions/gsd/tests/db-writer.test.ts +79 -0
  334. package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +121 -0
  335. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +60 -0
  336. package/src/resources/extensions/gsd/tests/est-annotation-timeout.test.ts +120 -0
  337. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1 -1
  338. package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +1 -1
  339. package/src/resources/extensions/gsd/tests/infra-error.test.ts +20 -2
  340. package/src/resources/extensions/gsd/tests/inherited-repo-home-dir.test.ts +121 -0
  341. package/src/resources/extensions/gsd/tests/integration-proof.test.ts +15 -24
  342. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +0 -3
  343. package/src/resources/extensions/gsd/tests/mcp-status.test.ts +103 -0
  344. package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
  345. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
  346. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +66 -0
  347. package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +8 -9
  348. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +42 -3
  349. package/src/resources/extensions/gsd/tests/parallel-budget-atomicity.test.ts +0 -1
  350. package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +0 -7
  351. package/src/resources/extensions/gsd/tests/parallel-merge.test.ts +7 -8
  352. package/src/resources/extensions/gsd/tests/parallel-orchestration.test.ts +20 -24
  353. package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +0 -2
  354. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +9 -6
  355. package/src/resources/extensions/gsd/tests/post-mutation-hook.test.ts +171 -0
  356. package/src/resources/extensions/gsd/tests/preferences.test.ts +7 -9
  357. package/src/resources/extensions/gsd/tests/projection-regression.test.ts +174 -0
  358. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +26 -21
  359. package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +176 -0
  360. package/src/resources/extensions/gsd/tests/reopen-slice.test.ts +155 -0
  361. package/src/resources/extensions/gsd/tests/reopen-task.test.ts +165 -0
  362. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +1 -4
  363. package/src/resources/extensions/gsd/tests/stop-auto-merge-back.test.ts +67 -0
  364. package/src/resources/extensions/gsd/tests/stop-auto-remote.test.ts +2 -3
  365. package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +108 -0
  366. package/src/resources/extensions/gsd/tests/sync-lock.test.ts +122 -0
  367. package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +49 -0
  368. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +2 -1
  369. package/src/resources/extensions/gsd/tests/unit-ownership.test.ts +175 -0
  370. package/src/resources/extensions/gsd/tests/workflow-events.test.ts +205 -0
  371. package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +275 -0
  372. package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +186 -0
  373. package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +171 -0
  374. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +220 -0
  375. package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +65 -0
  376. package/src/resources/extensions/gsd/tests/write-intercept.test.ts +76 -0
  377. package/src/resources/extensions/gsd/tools/complete-milestone.ts +74 -11
  378. package/src/resources/extensions/gsd/tools/complete-slice.ts +68 -11
  379. package/src/resources/extensions/gsd/tools/complete-task.ts +63 -1
  380. package/src/resources/extensions/gsd/tools/plan-milestone.ts +45 -0
  381. package/src/resources/extensions/gsd/tools/plan-slice.ts +40 -0
  382. package/src/resources/extensions/gsd/tools/plan-task.ts +37 -1
  383. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +39 -1
  384. package/src/resources/extensions/gsd/tools/reopen-slice.ts +125 -0
  385. package/src/resources/extensions/gsd/tools/reopen-task.ts +129 -0
  386. package/src/resources/extensions/gsd/tools/replan-slice.ts +41 -1
  387. package/src/resources/extensions/gsd/tools/validate-milestone.ts +127 -0
  388. package/src/resources/extensions/gsd/types.ts +8 -0
  389. package/src/resources/extensions/gsd/unit-ownership.ts +104 -0
  390. package/src/resources/extensions/gsd/workflow-events.ts +154 -0
  391. package/src/resources/extensions/gsd/workflow-logger.ts +243 -0
  392. package/src/resources/extensions/gsd/workflow-manifest.ts +334 -0
  393. package/src/resources/extensions/gsd/workflow-migration.ts +345 -0
  394. package/src/resources/extensions/gsd/workflow-projections.ts +425 -0
  395. package/src/resources/extensions/gsd/workflow-reconcile.ts +503 -0
  396. package/src/resources/extensions/gsd/worktree-manager.ts +41 -5
  397. package/src/resources/extensions/gsd/worktree-resolver.ts +44 -0
  398. package/src/resources/extensions/gsd/write-intercept.ts +90 -0
  399. package/src/resources/extensions/mcp-client/index.ts +20 -0
  400. package/src/resources/extensions/voice/index.ts +11 -21
  401. package/src/resources/extensions/voice/linux-ready.ts +87 -0
  402. package/src/resources/extensions/voice/tests/linux-ready.test.ts +124 -0
  403. package/dist/web/standalone/.next/static/chunks/4024.0de81b543b28b9fe.js +0 -9
  404. package/dist/web/standalone/.next/static/chunks/webpack-9014b5adb127a98a.js +0 -1
  405. package/dist/web/standalone/.next/static/css/8a727f372cf53002.css +0 -1
  406. /package/dist/web/standalone/.next/static/{tokoGmfkYfWf1_Yl_Gz7i → j-BskPs0nxxPeYY-bSrab}/_buildManifest.js +0 -0
  407. /package/dist/web/standalone/.next/static/{tokoGmfkYfWf1_Yl_Gz7i → j-BskPs0nxxPeYY-bSrab}/_ssgManifest.js +0 -0
@@ -297,7 +297,6 @@ describe("parallel-orchestrator: lifecycle", () => {
297
297
  worktreePath: "/tmp/wt-M001",
298
298
  startedAt: Date.now(),
299
299
  state: "running",
300
- completedUnits: 2,
301
300
  cost: 0.25,
302
301
  },
303
302
  ],
@@ -309,7 +308,6 @@ describe("parallel-orchestrator: lifecycle", () => {
309
308
  const workers = getWorkerStatuses(base);
310
309
  assert.equal(workers.length, 1);
311
310
  assert.equal(workers[0].milestoneId, "M001");
312
- assert.equal(workers[0].completedUnits, 2);
313
311
  assert.equal(isParallelActive(), true);
314
312
  } finally {
315
313
  resetOrchestrator();
@@ -416,7 +414,6 @@ describe("parallel-orchestrator: lifecycle", () => {
416
414
  const workers = getWorkerStatuses();
417
415
  assert.equal(workers.length, 1);
418
416
  assert.equal(workers[0].state, "running");
419
- assert.equal(workers[0].completedUnits, 4);
420
417
  } finally {
421
418
  resetOrchestrator();
422
419
  rmSync(base, { recursive: true, force: true });
@@ -552,7 +549,6 @@ function makeWorker(overrides: Partial<WorkerInfo> = {}): WorkerInfo {
552
549
  worktreePath: "/tmp/test-worktree",
553
550
  startedAt: Date.now() - 60_000,
554
551
  state: "stopped",
555
- completedUnits: 5,
556
552
  cost: 2.50,
557
553
  ...overrides,
558
554
  };
@@ -563,9 +559,9 @@ function makeWorker(overrides: Partial<WorkerInfo> = {}): WorkerInfo {
563
559
  describe("parallel-merge: determineMergeOrder sequential", () => {
564
560
  it("returns milestone IDs sorted alphabetically by default", () => {
565
561
  const workers = [
566
- makeWorker({ milestoneId: "M003", state: "stopped", completedUnits: 1 }),
567
- makeWorker({ milestoneId: "M001", state: "stopped", completedUnits: 2 }),
568
- makeWorker({ milestoneId: "M002", state: "stopped", completedUnits: 3 }),
562
+ makeWorker({ milestoneId: "M003", state: "stopped" }),
563
+ makeWorker({ milestoneId: "M001", state: "stopped" }),
564
+ makeWorker({ milestoneId: "M002", state: "stopped" }),
569
565
  ];
570
566
  const order = determineMergeOrder(workers, "sequential");
571
567
  assert.deepEqual(order, ["M001", "M002", "M003"]);
@@ -573,27 +569,27 @@ describe("parallel-merge: determineMergeOrder sequential", () => {
573
569
 
574
570
  it("excludes workers that are still running", () => {
575
571
  const workers = [
576
- makeWorker({ milestoneId: "M001", state: "stopped", completedUnits: 5 }),
577
- makeWorker({ milestoneId: "M002", state: "running", completedUnits: 0 }),
578
- makeWorker({ milestoneId: "M003", state: "stopped", completedUnits: 2 }),
572
+ makeWorker({ milestoneId: "M001", state: "stopped" }),
573
+ makeWorker({ milestoneId: "M002", state: "running" }),
574
+ makeWorker({ milestoneId: "M003", state: "stopped" }),
579
575
  ];
580
576
  const order = determineMergeOrder(workers, "sequential");
581
577
  assert.deepEqual(order, ["M001", "M003"]);
582
578
  });
583
579
 
584
- it("excludes workers with zero completedUnits even if stopped", () => {
580
+ it("includes all stopped workers", () => {
585
581
  const workers = [
586
- makeWorker({ milestoneId: "M001", state: "stopped", completedUnits: 0 }),
587
- makeWorker({ milestoneId: "M002", state: "stopped", completedUnits: 3 }),
582
+ makeWorker({ milestoneId: "M001", state: "stopped" }),
583
+ makeWorker({ milestoneId: "M002", state: "stopped" }),
588
584
  ];
589
585
  const order = determineMergeOrder(workers, "sequential");
590
- assert.deepEqual(order, ["M002"]);
586
+ assert.deepEqual(order, ["M001", "M002"]);
591
587
  });
592
588
 
593
589
  it("returns empty array when no workers are completed", () => {
594
590
  const workers = [
595
- makeWorker({ milestoneId: "M001", state: "running", completedUnits: 0 }),
596
- makeWorker({ milestoneId: "M002", state: "paused", completedUnits: 0 }),
591
+ makeWorker({ milestoneId: "M001", state: "running" }),
592
+ makeWorker({ milestoneId: "M002", state: "paused" }),
597
593
  ];
598
594
  const order = determineMergeOrder(workers);
599
595
  assert.deepEqual(order, []);
@@ -601,8 +597,8 @@ describe("parallel-merge: determineMergeOrder sequential", () => {
601
597
 
602
598
  it("uses sequential order as the default when no order arg provided", () => {
603
599
  const workers = [
604
- makeWorker({ milestoneId: "M002", state: "stopped", completedUnits: 1 }),
605
- makeWorker({ milestoneId: "M001", state: "stopped", completedUnits: 1 }),
600
+ makeWorker({ milestoneId: "M002", state: "stopped" }),
601
+ makeWorker({ milestoneId: "M001", state: "stopped" }),
606
602
  ];
607
603
  // Call with no second argument — should default to "sequential"
608
604
  const order = determineMergeOrder(workers);
@@ -614,9 +610,9 @@ describe("parallel-merge: determineMergeOrder by-completion", () => {
614
610
  it("returns milestones sorted by startedAt (earliest first)", () => {
615
611
  const now = Date.now();
616
612
  const workers = [
617
- makeWorker({ milestoneId: "M003", state: "stopped", completedUnits: 1, startedAt: now - 30_000 }),
618
- makeWorker({ milestoneId: "M001", state: "stopped", completedUnits: 1, startedAt: now - 90_000 }),
619
- makeWorker({ milestoneId: "M002", state: "stopped", completedUnits: 1, startedAt: now - 60_000 }),
613
+ makeWorker({ milestoneId: "M003", state: "stopped", startedAt: now - 30_000 }),
614
+ makeWorker({ milestoneId: "M001", state: "stopped", startedAt: now - 90_000 }),
615
+ makeWorker({ milestoneId: "M002", state: "stopped", startedAt: now - 60_000 }),
620
616
  ];
621
617
  const order = determineMergeOrder(workers, "by-completion");
622
618
  assert.deepEqual(order, ["M001", "M002", "M003"]);
@@ -625,9 +621,9 @@ describe("parallel-merge: determineMergeOrder by-completion", () => {
625
621
  it("excludes paused workers from by-completion order", () => {
626
622
  const now = Date.now();
627
623
  const workers = [
628
- makeWorker({ milestoneId: "M001", state: "stopped", completedUnits: 2, startedAt: now - 90_000 }),
629
- makeWorker({ milestoneId: "M002", state: "paused", completedUnits: 1, startedAt: now - 60_000 }),
630
- makeWorker({ milestoneId: "M003", state: "stopped", completedUnits: 3, startedAt: now - 30_000 }),
624
+ makeWorker({ milestoneId: "M001", state: "stopped", startedAt: now - 90_000 }),
625
+ makeWorker({ milestoneId: "M002", state: "paused", startedAt: now - 60_000 }),
626
+ makeWorker({ milestoneId: "M003", state: "stopped", startedAt: now - 30_000 }),
631
627
  ];
632
628
  const order = determineMergeOrder(workers, "by-completion");
633
629
  assert.deepEqual(order, ["M001", "M003"]);
@@ -155,7 +155,6 @@ describe("parallel-worker-monitoring", () => {
155
155
  worktreePath: "/tmp/wt-M001",
156
156
  startedAt: Date.now(),
157
157
  state: "running",
158
- completedUnits: 1,
159
158
  cost: 0.1,
160
159
  },
161
160
  ],
@@ -191,7 +190,6 @@ describe("parallel-worker-monitoring", () => {
191
190
  refreshWorkerStatuses(base, { restoreIfNeeded: true });
192
191
  const workers = getWorkerStatuses();
193
192
  assert.deepStrictEqual(workers[0].state, "running", "live session status restored");
194
- assert.deepStrictEqual(workers[0].completedUnits, 3, "completed units restored from status file");
195
193
  } finally {
196
194
  resetOrchestrator();
197
195
  rmSync(base, { recursive: true, force: true });
@@ -92,9 +92,11 @@ test('handlePlanMilestone writes milestone and slice planning state and renders
92
92
  assert.ok(existsSync(roadmapPath), 'roadmap should be rendered to disk');
93
93
  const roadmap = readFileSync(roadmapPath, 'utf-8');
94
94
  assert.match(roadmap, /# M001: DB-backed planning/);
95
- assert.match(roadmap, /\*\*Vision:\*\* Make planning write through the database\./);
96
- assert.match(roadmap, /- \[ \] \*\*S01: Tool wiring\*\* `risk:medium` `depends:\[\]`/);
97
- assert.match(roadmap, /- \[ \] \*\*S02: Prompt migration\*\* `risk:low` `depends:\[S01\]`/);
95
+ assert.match(roadmap, /## Vision/);
96
+ assert.match(roadmap, /Make planning write through the database\./);
97
+ assert.match(roadmap, /## Slice Overview/);
98
+ assert.match(roadmap, /\| S01 \| Tool wiring \| medium \|/);
99
+ assert.match(roadmap, /\| S02 \| Prompt migration \| low \| S01 \|/);
98
100
  } finally {
99
101
  cleanup(base);
100
102
  }
@@ -152,9 +154,10 @@ test('handlePlanMilestone clears parse-visible roadmap state after successful re
152
154
  const result = await handlePlanMilestone(validParams(), base);
153
155
  assert.ok(!('error' in result));
154
156
 
155
- const parsedAfter = parseRoadmap(readFileSync(roadmapPath, 'utf-8'));
156
- assert.equal(parsedAfter.vision, 'Make planning write through the database.');
157
- assert.equal(parsedAfter.slices.length, 2);
157
+ const contentAfter = readFileSync(roadmapPath, 'utf-8');
158
+ assert.match(contentAfter, /Make planning write through the database\./);
159
+ assert.match(contentAfter, /S01/);
160
+ assert.match(contentAfter, /S02/);
158
161
  } finally {
159
162
  cleanup(base);
160
163
  }
@@ -0,0 +1,171 @@
1
+ // GSD Extension — post-mutation hook regression tests
2
+ // Verifies that after a successful handleCompleteTask call, the post-mutation
3
+ // hook fires: event-log.jsonl and state-manifest.json are both written.
4
+
5
+ import test from 'node:test';
6
+ import assert from 'node:assert/strict';
7
+ import * as fs from 'node:fs';
8
+ import * as path from 'node:path';
9
+ import * as os from 'node:os';
10
+ import { openDatabase, closeDatabase } from '../gsd-db.ts';
11
+ import { handleCompleteTask } from '../tools/complete-task.ts';
12
+ import { readEvents } from '../workflow-events.ts';
13
+ import { readManifest } from '../workflow-manifest.ts';
14
+
15
+ function tempDir(): string {
16
+ return fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-post-hook-'));
17
+ }
18
+
19
+ function cleanupDir(dirPath: string): void {
20
+ try { fs.rmSync(dirPath, { recursive: true, force: true }); } catch { /* best effort */ }
21
+ }
22
+
23
+ /** Create a minimal project directory with a PLAN.md for complete-task to find. */
24
+ function createProject(basePath: string): void {
25
+ const sliceDir = path.join(basePath, '.gsd', 'milestones', 'M001', 'slices', 'S01');
26
+ const tasksDir = path.join(sliceDir, 'tasks');
27
+ fs.mkdirSync(tasksDir, { recursive: true });
28
+ fs.writeFileSync(path.join(sliceDir, 'S01-PLAN.md'), `# S01: Test Slice
29
+
30
+ ## Tasks
31
+
32
+ - [ ] **T01: Test task** \`est:30m\`
33
+ - Do: Implement the thing
34
+ - Verify: Run tests
35
+
36
+ - [ ] **T02: Second task** \`est:1h\`
37
+ - Do: Implement more
38
+ - Verify: Run more tests
39
+ `);
40
+ }
41
+
42
+ function makeCompleteTaskParams() {
43
+ return {
44
+ taskId: 'T01',
45
+ sliceId: 'S01',
46
+ milestoneId: 'M001',
47
+ oneLiner: 'Implemented auth middleware',
48
+ narrative: 'Added JWT validation middleware with proper error handling.',
49
+ verification: 'Ran npm test — all tests pass.',
50
+ deviations: 'None.',
51
+ knownIssues: 'None.',
52
+ keyFiles: ['src/middleware/auth.ts'],
53
+ keyDecisions: [],
54
+ blockerDiscovered: false,
55
+ verificationEvidence: [
56
+ { command: 'npm test', exitCode: 0, verdict: '✅ pass', durationMs: 2500 },
57
+ ],
58
+ };
59
+ }
60
+
61
+ // ─── Post-mutation hook: event log ───────────────────────────────────────
62
+
63
+ test('post-mutation-hook: event-log.jsonl exists after handleCompleteTask', async () => {
64
+ const base = tempDir();
65
+ const dbPath = path.join(base, 'test.db');
66
+ openDatabase(dbPath);
67
+ createProject(base);
68
+
69
+ try {
70
+ const result = await handleCompleteTask(makeCompleteTaskParams(), base);
71
+ assert.ok(!('error' in result), `handler should succeed, got: ${JSON.stringify(result)}`);
72
+
73
+ const logPath = path.join(base, '.gsd', 'event-log.jsonl');
74
+ assert.ok(fs.existsSync(logPath), 'event-log.jsonl should exist after handler completes');
75
+ } finally {
76
+ closeDatabase();
77
+ cleanupDir(base);
78
+ }
79
+ });
80
+
81
+ test('post-mutation-hook: event log contains complete-task event with correct params', async () => {
82
+ const base = tempDir();
83
+ const dbPath = path.join(base, 'test.db');
84
+ openDatabase(dbPath);
85
+ createProject(base);
86
+
87
+ try {
88
+ await handleCompleteTask(makeCompleteTaskParams(), base);
89
+
90
+ const logPath = path.join(base, '.gsd', 'event-log.jsonl');
91
+ const events = readEvents(logPath);
92
+ assert.ok(events.length > 0, 'event log should have at least one event');
93
+
94
+ const ev = events.find((e) => e.cmd === 'complete-task');
95
+ assert.ok(ev !== undefined, 'should have a complete-task event');
96
+ assert.strictEqual((ev!.params as { milestoneId?: string }).milestoneId, 'M001');
97
+ assert.strictEqual((ev!.params as { sliceId?: string }).sliceId, 'S01');
98
+ assert.strictEqual((ev!.params as { taskId?: string }).taskId, 'T01');
99
+ assert.strictEqual(ev!.actor, 'agent');
100
+ } finally {
101
+ closeDatabase();
102
+ cleanupDir(base);
103
+ }
104
+ });
105
+
106
+ // ─── Post-mutation hook: manifest ────────────────────────────────────────
107
+
108
+ test('post-mutation-hook: state-manifest.json exists after handleCompleteTask', async () => {
109
+ const base = tempDir();
110
+ const dbPath = path.join(base, 'test.db');
111
+ openDatabase(dbPath);
112
+ createProject(base);
113
+
114
+ try {
115
+ const result = await handleCompleteTask(makeCompleteTaskParams(), base);
116
+ assert.ok(!('error' in result), `handler should succeed, got: ${JSON.stringify(result)}`);
117
+
118
+ const manifestPath = path.join(base, '.gsd', 'state-manifest.json');
119
+ assert.ok(fs.existsSync(manifestPath), 'state-manifest.json should exist after handler completes');
120
+ } finally {
121
+ closeDatabase();
122
+ cleanupDir(base);
123
+ }
124
+ });
125
+
126
+ test('post-mutation-hook: manifest has version 1 and includes completed task', async () => {
127
+ const base = tempDir();
128
+ const dbPath = path.join(base, 'test.db');
129
+ openDatabase(dbPath);
130
+ createProject(base);
131
+
132
+ try {
133
+ await handleCompleteTask(makeCompleteTaskParams(), base);
134
+
135
+ const manifest = readManifest(base);
136
+ assert.ok(manifest !== null, 'manifest should be readable');
137
+ assert.strictEqual(manifest!.version, 1);
138
+
139
+ const task = manifest!.tasks.find((t) => t.id === 'T01');
140
+ assert.ok(task !== undefined, 'T01 should appear in manifest');
141
+ assert.strictEqual(task!.status, 'complete');
142
+ assert.strictEqual(task!.milestone_id, 'M001');
143
+ assert.strictEqual(task!.slice_id, 'S01');
144
+ } finally {
145
+ closeDatabase();
146
+ cleanupDir(base);
147
+ }
148
+ });
149
+
150
+ // ─── Post-mutation hook: non-fatal on hook failure ───────────────────────
151
+
152
+ test('post-mutation-hook: handler still returns success even if projections dir is missing', async () => {
153
+ // basePath with NO .gsd directory — projections will fail to find milestones
154
+ // but handler should still return a result (not throw)
155
+ const base = tempDir();
156
+ const dbPath = path.join(base, 'test.db');
157
+ openDatabase(dbPath);
158
+
159
+ // Create tasks dir but NO plan file (projections will soft-fail)
160
+ const tasksDir = path.join(base, '.gsd', 'milestones', 'M001', 'slices', 'S01', 'tasks');
161
+ fs.mkdirSync(tasksDir, { recursive: true });
162
+
163
+ try {
164
+ const result = await handleCompleteTask(makeCompleteTaskParams(), base);
165
+ // Handler should succeed (post-hook failures are non-fatal)
166
+ assert.ok(!('error' in result), `handler should not propagate hook errors, got: ${JSON.stringify(result)}`);
167
+ } finally {
168
+ closeDatabase();
169
+ cleanupDir(base);
170
+ }
171
+ });
@@ -41,18 +41,16 @@ test("git.merge_to_main produces deprecation warning", () => {
41
41
  });
42
42
 
43
43
 
44
- test("getIsolationMode defaults to worktree when preferences have no isolation setting", () => {
44
+ test("getIsolationMode defaults to none when preferences have no isolation setting", () => {
45
45
  // Validate the default via validatePreferences: when no isolation is set,
46
- // preferences.git.isolation is undefined, and getIsolationMode returns "worktree".
47
- // We test the function's logic by verifying its documented default.
46
+ // preferences.git.isolation is undefined, and getIsolationMode returns "none".
47
+ // Default changed from "worktree" to "none" so GSD works out of the box
48
+ // without preferences.md (#2480).
48
49
  const { preferences } = validatePreferences({});
49
50
  assert.equal(preferences.git?.isolation, undefined, "no isolation in empty prefs");
50
- // The function returns "worktree" when prefs?.git?.isolation is not "none" or "branch"
51
- // This is a compile-time-verifiable truth from the function body — test it directly
52
- // by constructing the same conditions getIsolationMode checks.
53
51
  const isolation = preferences.git?.isolation;
54
- const expected = isolation === "none" ? "none" : isolation === "branch" ? "branch" : "worktree";
55
- assert.equal(expected, "worktree", "default isolation mode is worktree");
52
+ const expected = isolation === "worktree" ? "worktree" : isolation === "branch" ? "branch" : "none";
53
+ assert.equal(expected, "none", "default isolation mode is none");
56
54
  });
57
55
 
58
56
  // ── Mode defaults ────────────────────────────────────────────────────────────
@@ -63,7 +61,7 @@ test("solo mode applies correct defaults", () => {
63
61
  assert.equal(result.git?.push_branches, false);
64
62
  assert.equal(result.git?.pre_merge_check, false);
65
63
  assert.equal(result.git?.merge_strategy, "squash");
66
- assert.equal(result.git?.isolation, "worktree");
64
+ assert.equal(result.git?.isolation, "none");
67
65
  assert.equal(result.unique_milestone_ids, false);
68
66
  });
69
67
 
@@ -0,0 +1,174 @@
1
+ // GSD — projection renderer regression tests
2
+ // Verifies that "done" vs "complete" status mismatch doesn't recur.
3
+ // Copyright (c) 2026 Jeremy McSpadden <jeremy@fluxlabs.net>
4
+
5
+ import test from 'node:test';
6
+ import assert from 'node:assert/strict';
7
+
8
+ import { renderPlanContent, renderRoadmapContent } from '../workflow-projections.ts';
9
+ import type { SliceRow, TaskRow } from '../gsd-db.ts';
10
+
11
+ // ─── Helpers ─────────────────────────────────────────────────────────────
12
+
13
+ function makeSliceRow(overrides?: Partial<SliceRow>): SliceRow {
14
+ return {
15
+ milestone_id: 'M001',
16
+ id: 'S01',
17
+ title: 'Test Slice',
18
+ status: 'pending',
19
+ risk: 'medium',
20
+ depends: [],
21
+ demo: 'Demo.',
22
+ created_at: '2026-01-01T00:00:00Z',
23
+ completed_at: null,
24
+ full_summary_md: '',
25
+ full_uat_md: '',
26
+ goal: 'Test goal',
27
+ success_criteria: '',
28
+ proof_level: '',
29
+ integration_closure: '',
30
+ observability_impact: '',
31
+ sequence: 0,
32
+ replan_triggered_at: null,
33
+ ...overrides,
34
+ };
35
+ }
36
+
37
+ function makeTaskRow(overrides?: Partial<TaskRow>): TaskRow {
38
+ return {
39
+ milestone_id: 'M001',
40
+ slice_id: 'S01',
41
+ id: 'T01',
42
+ title: 'Test Task',
43
+ status: 'pending',
44
+ one_liner: '',
45
+ narrative: '',
46
+ verification_result: '',
47
+ duration: '',
48
+ completed_at: null,
49
+ blocker_discovered: false,
50
+ deviations: '',
51
+ known_issues: '',
52
+ key_files: [],
53
+ key_decisions: [],
54
+ full_summary_md: '',
55
+ full_plan_md: '',
56
+ description: 'Test description',
57
+ estimate: '30m',
58
+ files: ['src/test.ts'],
59
+ verify: 'npm test',
60
+ inputs: [],
61
+ expected_output: [],
62
+ observability_impact: '',
63
+ sequence: 0,
64
+ ...overrides,
65
+ };
66
+ }
67
+
68
+ function makeMilestoneRow() {
69
+ return {
70
+ id: 'M001',
71
+ title: 'Test Milestone',
72
+ status: 'active',
73
+ depends_on: [],
74
+ created_at: '2026-01-01T00:00:00Z',
75
+ completed_at: null,
76
+ vision: 'Test vision',
77
+ success_criteria: [],
78
+ key_risks: [],
79
+ proof_strategy: [],
80
+ verification_contract: '',
81
+ verification_integration: '',
82
+ verification_operational: '',
83
+ verification_uat: '',
84
+ definition_of_done: [],
85
+ requirement_coverage: '',
86
+ boundary_map_markdown: '',
87
+ };
88
+ }
89
+
90
+ // ─── renderPlanContent: checkbox regression ──────────────────────────────
91
+
92
+ test('renderPlanContent: task with status "complete" renders [x] checkbox', () => {
93
+ const slice = makeSliceRow();
94
+ const tasks = [makeTaskRow({ id: 'T01', status: 'complete', title: 'Completed Task' })];
95
+
96
+ const content = renderPlanContent(slice, tasks);
97
+
98
+ assert.match(content, /\[x\]\s+\*\*T01:/, 'complete task should have [x] checkbox');
99
+ });
100
+
101
+ test('renderPlanContent: task with status "done" renders [x] checkbox', () => {
102
+ const slice = makeSliceRow();
103
+ const tasks = [makeTaskRow({ id: 'T01', status: 'done', title: 'Done Task' })];
104
+
105
+ const content = renderPlanContent(slice, tasks);
106
+
107
+ assert.match(content, /\[x\]\s+\*\*T01:/, 'done task should have [x] checkbox');
108
+ });
109
+
110
+ test('renderPlanContent: task with status "pending" renders [ ] checkbox', () => {
111
+ const slice = makeSliceRow();
112
+ const tasks = [makeTaskRow({ id: 'T01', status: 'pending', title: 'Pending Task' })];
113
+
114
+ const content = renderPlanContent(slice, tasks);
115
+
116
+ assert.match(content, /\[ \]\s+\*\*T01:/, 'pending task should have [ ] checkbox');
117
+ });
118
+
119
+ test('renderPlanContent: mixed statuses render correct checkboxes', () => {
120
+ const slice = makeSliceRow();
121
+ const tasks = [
122
+ makeTaskRow({ id: 'T01', status: 'complete', title: 'Done One' }),
123
+ makeTaskRow({ id: 'T02', status: 'pending', title: 'Pending One' }),
124
+ makeTaskRow({ id: 'T03', status: 'done', title: 'Done Two' }),
125
+ ];
126
+
127
+ const content = renderPlanContent(slice, tasks);
128
+
129
+ assert.match(content, /\[x\]\s+\*\*T01:/, 'T01 (complete) should be checked');
130
+ assert.match(content, /\[ \]\s+\*\*T02:/, 'T02 (pending) should be unchecked');
131
+ assert.match(content, /\[x\]\s+\*\*T03:/, 'T03 (done) should be checked');
132
+ });
133
+
134
+ // ─── renderPlanContent: format regression (parsePlan compatibility) ──────
135
+
136
+ test('renderPlanContent: format matches parsePlan regex **ID: title**', () => {
137
+ const slice = makeSliceRow();
138
+ const tasks = [makeTaskRow({ id: 'T01', status: 'pending', title: 'My Task' })];
139
+
140
+ const content = renderPlanContent(slice, tasks);
141
+
142
+ // parsePlan expects: **T01: My Task** (both ID and title inside bold)
143
+ // NOT: **T01:** My Task (only ID in bold)
144
+ assert.match(content, /\*\*T01: My Task\*\*/, 'ID and title should both be inside bold markers');
145
+ });
146
+
147
+ // ─── renderRoadmapContent: status regression ─────────────────────────────
148
+
149
+ test('renderRoadmapContent: slice with status "complete" shows ✅', () => {
150
+ const milestone = makeMilestoneRow();
151
+ const slices = [makeSliceRow({ id: 'S01', status: 'complete' })];
152
+
153
+ const content = renderRoadmapContent(milestone, slices);
154
+
155
+ assert.ok(content.includes('✅'), 'complete slice should show ✅');
156
+ });
157
+
158
+ test('renderRoadmapContent: slice with status "done" shows ✅', () => {
159
+ const milestone = makeMilestoneRow();
160
+ const slices = [makeSliceRow({ id: 'S01', status: 'done' })];
161
+
162
+ const content = renderRoadmapContent(milestone, slices);
163
+
164
+ assert.ok(content.includes('✅'), 'done slice should show ✅');
165
+ });
166
+
167
+ test('renderRoadmapContent: slice with status "pending" shows ⬜', () => {
168
+ const milestone = makeMilestoneRow();
169
+ const slices = [makeSliceRow({ id: 'S01', status: 'pending' })];
170
+
171
+ const content = renderRoadmapContent(milestone, slices);
172
+
173
+ assert.ok(content.includes('⬜'), 'pending slice should show ⬜');
174
+ });
@@ -58,17 +58,18 @@ test("guided-resume-task prompt preserves recovery state until work is supersede
58
58
  assert.doesNotMatch(prompt, /Delete the continue file after reading it/i);
59
59
  });
60
60
 
61
- // ─── Prompt migration: execute-task → gsd_task_complete ───────────────
61
+ // ─── Prompt migration: execute-task → gsd_complete_task ───────────────
62
62
 
63
- test("execute-task prompt references gsd_task_complete tool", () => {
63
+ test("execute-task prompt references gsd_complete_task tool", () => {
64
64
  const prompt = readPrompt("execute-task");
65
- assert.match(prompt, /gsd_task_complete/);
65
+ assert.match(prompt, /gsd_complete_task/);
66
66
  });
67
67
 
68
- test("execute-task prompt does not instruct LLM to write summary file manually", () => {
68
+ test("execute-task prompt instructs writing task summary before tool call", () => {
69
69
  const prompt = readPrompt("execute-task");
70
- // Should not contain "Write {{taskSummaryPath}}" as an action instruction
71
- assert.doesNotMatch(prompt, /^\d+\.\s+Write `?\{\{taskSummaryPath\}\}`?/m);
70
+ // The prompt instructs writing the summary file AND calling the tool
71
+ assert.match(prompt, /\{\{taskSummaryPath\}\}/);
72
+ assert.match(prompt, /gsd_complete_task/);
72
73
  });
73
74
 
74
75
  test("execute-task prompt does not instruct LLM to toggle checkboxes manually", () => {
@@ -93,12 +94,11 @@ test("guided-execute-task prompt does not instruct manual file write", () => {
93
94
  assert.doesNotMatch(prompt, /Write `?\{\{taskId\}\}-SUMMARY\.md`?.*mark it done/i);
94
95
  });
95
96
 
96
- // ─── Prompt migration: complete-slice → gsd_slice_complete ────────────
97
- // These tests are for T02 — expected to fail until that task runs.
97
+ // ─── Prompt migration: complete-slice → gsd_complete_slice ────────────
98
98
 
99
- test("complete-slice prompt references gsd_slice_complete tool", () => {
99
+ test("complete-slice prompt references gsd_complete_slice tool", () => {
100
100
  const prompt = readPrompt("complete-slice");
101
- assert.match(prompt, /gsd_slice_complete/);
101
+ assert.match(prompt, /gsd_complete_slice/);
102
102
  });
103
103
 
104
104
  test("complete-slice prompt does not instruct LLM to toggle checkboxes manually", () => {
@@ -111,10 +111,12 @@ test("guided-complete-slice prompt references gsd_slice_complete tool", () => {
111
111
  assert.match(prompt, /gsd_slice_complete/);
112
112
  });
113
113
 
114
- test("complete-slice prompt does not instruct LLM to write summary/UAT files manually", () => {
114
+ test("complete-slice prompt instructs writing summary and UAT files before tool call", () => {
115
115
  const prompt = readPrompt("complete-slice");
116
- assert.doesNotMatch(prompt, /^\d+\.\s+Write `?\{\{sliceSummaryPath\}\}/m);
117
- assert.doesNotMatch(prompt, /^\d+\.\s+Write `?\{\{sliceUatPath\}\}/m);
116
+ // The prompt instructs writing the summary AND UAT files, then calling the tool
117
+ assert.match(prompt, /\{\{sliceSummaryPath\}\}/);
118
+ assert.match(prompt, /\{\{sliceUatPath\}\}/);
119
+ assert.match(prompt, /gsd_complete_slice/);
118
120
  });
119
121
 
120
122
  test("complete-slice prompt preserves decisions and knowledge review steps", () => {
@@ -127,7 +129,6 @@ test("complete-slice prompt still contains template variables for context", () =
127
129
  const prompt = readPrompt("complete-slice");
128
130
  assert.match(prompt, /\{\{sliceSummaryPath\}\}/);
129
131
  assert.match(prompt, /\{\{sliceUatPath\}\}/);
130
- assert.match(prompt, /\{\{roadmapPath\}\}/);
131
132
  });
132
133
 
133
134
  test("plan-milestone prompt references DB-backed planning tool and explicitly forbids manual roadmap writes", () => {
@@ -147,12 +148,12 @@ test("plan-slice prompt no longer frames direct PLAN writes as the source of tru
147
148
  assert.match(prompt, /Do \*\*not\*\* rely on direct `PLAN\.md` writes as the source of truth/i);
148
149
  });
149
150
 
150
- test("plan-slice prompt explicitly names gsd_plan_slice and gsd_plan_task as DB-backed planning tools", () => {
151
+ test("plan-slice prompt explicitly names gsd_plan_slice as DB-backed planning tool", () => {
151
152
  const prompt = readPrompt("plan-slice");
152
153
  assert.match(prompt, /gsd_plan_slice/);
153
154
  assert.match(prompt, /gsd_plan_task/);
154
- // The prompt should describe these as the canonical write path
155
- assert.match(prompt, /DB-backed tools are the canonical write path/i);
155
+ // The prompt should describe the DB-backed tool as the canonical write path
156
+ assert.match(prompt, /DB-backed tool is the canonical write path/i);
156
157
  });
157
158
 
158
159
  test("plan-slice prompt does not instruct direct file writes as a primary step", () => {
@@ -161,14 +162,18 @@ test("plan-slice prompt does not instruct direct file writes as a primary step",
161
162
  assert.doesNotMatch(prompt, /^\d+\.\s+Write `?\{\{outputPath\}\}`?\s*$/m);
162
163
  });
163
164
 
164
- test("plan-slice prompt instructs calling gsd_plan_task for each task", () => {
165
+ test("plan-slice prompt clarifies gsd_plan_slice handles task persistence", () => {
165
166
  const prompt = readPrompt("plan-slice");
166
- assert.match(prompt, /call `gsd_plan_task` for each task/i);
167
+ // gsd_plan_slice persists tasks in its transaction — no separate gsd_plan_task calls needed
168
+ assert.match(prompt, /gsd_plan_task/);
169
+ assert.match(prompt, /gsd_plan_slice` handles task persistence/i);
167
170
  });
168
171
 
169
- test("replan-slice prompt requires DB-backed planning state when available", () => {
172
+ test("replan-slice prompt uses gsd_replan_slice as canonical DB-backed tool", () => {
170
173
  const prompt = readPrompt("replan-slice");
171
- assert.match(prompt, /DB-backed planning tool exists for this phase, use it as the source of truth/i);
174
+ assert.match(prompt, /gsd_replan_slice/);
175
+ // Degraded fallback (direct file writes) was removed — DB tools are always available
176
+ assert.doesNotMatch(prompt, /Degraded fallback/i);
172
177
  });
173
178
 
174
179
  test("reassess-roadmap prompt references gsd_reassess_roadmap tool", () => {