@opengsd/gsd-pi 1.9.0 → 1.10.0-dev.a5e42e99

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 (502) hide show
  1. package/README.md +10 -9
  2. package/dist/headless.js +2 -1
  3. package/dist/resources/.managed-resources-content-hash +1 -1
  4. package/dist/resources/GSD-WORKFLOW.md +2 -2
  5. package/dist/resources/extensions/gsd/artifact-verification.js +3 -4
  6. package/dist/resources/extensions/gsd/auto/loop.js +24 -4
  7. package/dist/resources/extensions/gsd/auto/run-unit.js +19 -1
  8. package/dist/resources/extensions/gsd/auto/unit-phase.js +37 -5
  9. package/dist/resources/extensions/gsd/auto-artifact-paths.js +14 -8
  10. package/dist/resources/extensions/gsd/auto-dispatch.js +2 -0
  11. package/dist/resources/extensions/gsd/auto-model-selection.js +1 -0
  12. package/dist/resources/extensions/gsd/auto-prompts.js +102 -21
  13. package/dist/resources/extensions/gsd/auto-recovery.js +10 -5
  14. package/dist/resources/extensions/gsd/auto-runtime-state.js +5 -5
  15. package/dist/resources/extensions/gsd/auto-start.js +30 -10
  16. package/dist/resources/extensions/gsd/auto-tool-tracking.js +40 -0
  17. package/dist/resources/extensions/gsd/auto-verification.js +25 -12
  18. package/dist/resources/extensions/gsd/auto-worktree-cleanup.js +4 -0
  19. package/dist/resources/extensions/gsd/auto-worktree-sync.js +7 -3
  20. package/dist/resources/extensions/gsd/auto-worktree-teardown.js +1 -1
  21. package/dist/resources/extensions/gsd/auto.js +15 -5
  22. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +2 -0
  23. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +33 -7
  24. package/dist/resources/extensions/gsd/bootstrap/system-context.js +10 -3
  25. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +7 -26
  26. package/dist/resources/extensions/gsd/commands-verdict.js +10 -9
  27. package/dist/resources/extensions/gsd/compat/compat-marker.js +80 -5
  28. package/dist/resources/extensions/gsd/constants.js +12 -13
  29. package/dist/resources/extensions/gsd/context-masker.js +97 -21
  30. package/dist/resources/extensions/gsd/db/engine.js +5 -2
  31. package/dist/resources/extensions/gsd/docs/preferences-reference.md +33 -2
  32. package/dist/resources/extensions/gsd/doctor-engine-checks.js +40 -12
  33. package/dist/resources/extensions/gsd/error-classifier.js +12 -2
  34. package/dist/resources/extensions/gsd/exec-sandbox.js +1 -0
  35. package/dist/resources/extensions/gsd/flat-phase-migration.js +12 -0
  36. package/dist/resources/extensions/gsd/git-service.js +19 -7
  37. package/dist/resources/extensions/gsd/gsd-db.js +75 -31
  38. package/dist/resources/extensions/gsd/guided-flow.js +11 -5
  39. package/dist/resources/extensions/gsd/markdown-renderer.js +5 -21
  40. package/dist/resources/extensions/gsd/md-importer.js +5 -6
  41. package/dist/resources/extensions/gsd/model-cost-table.js +6 -1
  42. package/dist/resources/extensions/gsd/model-router.js +16 -0
  43. package/dist/resources/extensions/gsd/paths.js +66 -15
  44. package/dist/resources/extensions/gsd/planning-subagent-policy.js +37 -0
  45. package/dist/resources/extensions/gsd/planning-subagent-registry.js +33 -0
  46. package/dist/resources/extensions/gsd/preferences-models.js +50 -10
  47. package/dist/resources/extensions/gsd/preferences-types.js +6 -0
  48. package/dist/resources/extensions/gsd/preferences-validation.js +86 -4
  49. package/dist/resources/extensions/gsd/preferences.js +24 -0
  50. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +5 -5
  51. package/dist/resources/extensions/gsd/provider-payload-policy.js +16 -5
  52. package/dist/resources/extensions/gsd/safety/destructive-guard.js +1 -1
  53. package/dist/resources/extensions/gsd/skill-activation.js +17 -3
  54. package/dist/resources/extensions/gsd/state-reconciliation/drift/external-markdown-edit.js +98 -2
  55. package/dist/resources/extensions/gsd/state-reconciliation/drift/external-planning-edit.js +4 -1
  56. package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +5 -2
  57. package/dist/resources/extensions/gsd/stop-notice.js +9 -0
  58. package/dist/resources/extensions/gsd/templates/PREFERENCES.md +8 -0
  59. package/dist/resources/extensions/gsd/tools/complete-task.js +12 -5
  60. package/dist/resources/extensions/gsd/tools/plan-slice.js +5 -1
  61. package/dist/resources/extensions/gsd/tools/reopen-milestone.js +14 -5
  62. package/dist/resources/extensions/gsd/tools/reopen-slice.js +15 -5
  63. package/dist/resources/extensions/gsd/tools/reopen-task.js +16 -10
  64. package/dist/resources/extensions/gsd/unit-context-composer.js +28 -5
  65. package/dist/resources/extensions/gsd/verification-evidence.js +5 -3
  66. package/dist/resources/extensions/gsd/workflow-projections.js +2 -3
  67. package/dist/resources/extensions/gsd/workspace.js +2 -1
  68. package/dist/resources/extensions/gsd/worktree-state-projection.js +20 -18
  69. package/dist/resources/extensions/ollama/ollama-chat-provider.js +2 -2
  70. package/dist/resources/extensions/shared/interview-ui.js +43 -6
  71. package/dist/resources/extensions/subagent/index.js +1 -1
  72. package/dist/startup-model-validation.d.ts +1 -1
  73. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  74. package/dist/web/standalone/.next/BUILD_ID +1 -1
  75. package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
  76. package/dist/web/standalone/.next/build-manifest.json +3 -3
  77. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  78. package/dist/web/standalone/.next/required-server-files.json +3 -3
  79. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  80. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  81. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  82. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  90. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  91. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  92. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  93. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  94. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  96. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  100. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  101. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  105. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  106. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  110. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  118. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/mcp-connections/route_client-reference-manifest.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  140. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  150. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  156. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  166. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  172. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  175. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  176. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  181. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  182. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  183. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  184. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  185. package/dist/web/standalone/.next/server/app/index.html +1 -1
  186. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  187. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  188. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  189. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  190. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  191. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  192. package/dist/web/standalone/.next/server/app/page.js +2 -2
  193. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  194. package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
  195. package/dist/web/standalone/.next/server/chunks/1991.js +2 -2
  196. package/dist/web/standalone/.next/server/chunks/2842.js +4 -4
  197. package/dist/web/standalone/.next/server/chunks/5124.js +1 -1
  198. package/dist/web/standalone/.next/server/chunks/8357.js +3 -3
  199. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  200. package/dist/web/standalone/.next/server/middleware.js +3 -3
  201. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  202. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  203. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  204. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-a6fb1847f67f167c.js +1 -0
  205. package/dist/web/standalone/.next/static/chunks/app/{layout-b35cbfff38aaf4cf.js → layout-4ae2d68984392bbf.js} +1 -1
  206. package/dist/web/standalone/.next/static/chunks/app/page-72a856634ad14c10.js +1 -0
  207. package/dist/web/standalone/.next/static/chunks/{main-app-590a74400e35f685.js → main-app-90d1d8d5e5d2dc6b.js} +1 -1
  208. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-1115d46ac61b9823.js +1 -0
  209. package/dist/web/standalone/node_modules/@gsd/native/package.json +1 -1
  210. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  211. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  212. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  213. package/dist/web/standalone/server.js +1 -1
  214. package/integrations/hermes/open_gsd_hermes/gsd_client.py +1 -1
  215. package/integrations/hermes/pyproject.toml +1 -1
  216. package/package.json +8 -6
  217. package/packages/cloud-mcp-gateway/package.json +2 -2
  218. package/packages/contracts/dist/rpc.d.ts +1 -1
  219. package/packages/contracts/dist/rpc.d.ts.map +1 -1
  220. package/packages/contracts/dist/rpc.js +1 -1
  221. package/packages/contracts/dist/rpc.js.map +1 -1
  222. package/packages/contracts/dist/rpc.test.js +1 -1
  223. package/packages/contracts/dist/rpc.test.js.map +1 -1
  224. package/packages/contracts/package.json +1 -1
  225. package/packages/daemon/package.json +4 -4
  226. package/packages/gsd-agent-core/dist/compaction/compaction.d.ts.map +1 -1
  227. package/packages/gsd-agent-core/dist/compaction/compaction.js +36 -4
  228. package/packages/gsd-agent-core/dist/compaction/compaction.js.map +1 -1
  229. package/packages/gsd-agent-core/dist/sdk.d.ts.map +1 -1
  230. package/packages/gsd-agent-core/dist/sdk.js +1 -0
  231. package/packages/gsd-agent-core/dist/sdk.js.map +1 -1
  232. package/packages/gsd-agent-core/package.json +5 -5
  233. package/packages/gsd-agent-modes/dist/cli/args.js +2 -2
  234. package/packages/gsd-agent-modes/dist/cli/args.js.map +1 -1
  235. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  236. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js +1 -0
  237. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js.map +1 -1
  238. package/packages/gsd-agent-modes/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  239. package/packages/gsd-agent-modes/dist/modes/interactive/components/thinking-selector.js +1 -0
  240. package/packages/gsd-agent-modes/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  241. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-autocomplete.d.ts.map +1 -1
  242. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-autocomplete.js +1 -0
  243. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-autocomplete.js.map +1 -1
  244. package/packages/gsd-agent-modes/package.json +7 -7
  245. package/packages/gsd-cloud/README.md +21 -5
  246. package/packages/gsd-cloud/dist/background-cli.test.d.ts +2 -0
  247. package/packages/gsd-cloud/dist/background-cli.test.d.ts.map +1 -0
  248. package/packages/gsd-cloud/dist/background-cli.test.js +325 -0
  249. package/packages/gsd-cloud/dist/background-cli.test.js.map +1 -0
  250. package/packages/gsd-cloud/dist/cli.d.ts.map +1 -1
  251. package/packages/gsd-cloud/dist/cli.js +146 -16
  252. package/packages/gsd-cloud/dist/cli.js.map +1 -1
  253. package/packages/gsd-cloud/dist/cloud-config.d.ts +1 -1
  254. package/packages/gsd-cloud/dist/cloud-config.d.ts.map +1 -1
  255. package/packages/gsd-cloud/dist/cloud-config.js +7 -1
  256. package/packages/gsd-cloud/dist/cloud-config.js.map +1 -1
  257. package/packages/gsd-cloud/dist/cloud-runtime.d.ts +7 -4
  258. package/packages/gsd-cloud/dist/cloud-runtime.d.ts.map +1 -1
  259. package/packages/gsd-cloud/dist/cloud-runtime.js +115 -31
  260. package/packages/gsd-cloud/dist/cloud-runtime.js.map +1 -1
  261. package/packages/gsd-cloud/dist/cloud-runtime.test.js +224 -59
  262. package/packages/gsd-cloud/dist/cloud-runtime.test.js.map +1 -1
  263. package/packages/gsd-cloud/dist/runtime-artifacts.d.ts +3 -0
  264. package/packages/gsd-cloud/dist/runtime-artifacts.d.ts.map +1 -0
  265. package/packages/gsd-cloud/dist/runtime-artifacts.js +36 -0
  266. package/packages/gsd-cloud/dist/runtime-artifacts.js.map +1 -0
  267. package/packages/gsd-cloud/dist/runtime-process.d.ts +32 -0
  268. package/packages/gsd-cloud/dist/runtime-process.d.ts.map +1 -0
  269. package/packages/gsd-cloud/dist/runtime-process.js +640 -0
  270. package/packages/gsd-cloud/dist/runtime-process.js.map +1 -0
  271. package/packages/gsd-cloud/dist/runtime-process.test.d.ts +2 -0
  272. package/packages/gsd-cloud/dist/runtime-process.test.d.ts.map +1 -0
  273. package/packages/gsd-cloud/dist/runtime-process.test.js +543 -0
  274. package/packages/gsd-cloud/dist/runtime-process.test.js.map +1 -0
  275. package/packages/gsd-cloud/dist/runtime-telemetry.d.ts +117 -0
  276. package/packages/gsd-cloud/dist/runtime-telemetry.d.ts.map +1 -0
  277. package/packages/gsd-cloud/dist/runtime-telemetry.js +291 -0
  278. package/packages/gsd-cloud/dist/runtime-telemetry.js.map +1 -0
  279. package/packages/gsd-cloud/dist/runtime-telemetry.test.d.ts +2 -0
  280. package/packages/gsd-cloud/dist/runtime-telemetry.test.d.ts.map +1 -0
  281. package/packages/gsd-cloud/dist/runtime-telemetry.test.js +434 -0
  282. package/packages/gsd-cloud/dist/runtime-telemetry.test.js.map +1 -0
  283. package/packages/gsd-cloud/package.json +2 -2
  284. package/packages/mcp-server/README.md +7 -2
  285. package/packages/mcp-server/dist/cli-runner.d.ts +3 -0
  286. package/packages/mcp-server/dist/cli-runner.d.ts.map +1 -1
  287. package/packages/mcp-server/dist/cli-runner.js +119 -33
  288. package/packages/mcp-server/dist/cli-runner.js.map +1 -1
  289. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  290. package/packages/mcp-server/dist/server.js +5 -5
  291. package/packages/mcp-server/dist/server.js.map +1 -1
  292. package/packages/mcp-server/dist/workflow-tools.d.ts +4 -3
  293. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  294. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  295. package/packages/mcp-server/package.json +4 -4
  296. package/packages/native/package.json +1 -1
  297. package/packages/pi-agent-core/dist/agent.d.ts +5 -1
  298. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  299. package/packages/pi-agent-core/dist/agent.js +2 -0
  300. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  301. package/packages/pi-agent-core/dist/types.d.ts +2 -2
  302. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  303. package/packages/pi-agent-core/dist/types.js.map +1 -1
  304. package/packages/pi-agent-core/package.json +1 -1
  305. package/packages/pi-ai/dist/models.d.ts.map +1 -1
  306. package/packages/pi-ai/dist/models.generated.d.ts +187 -0
  307. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  308. package/packages/pi-ai/dist/models.generated.js +145 -0
  309. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  310. package/packages/pi-ai/dist/models.js +18 -6
  311. package/packages/pi-ai/dist/models.js.map +1 -1
  312. package/packages/pi-ai/dist/providers/amazon-bedrock.js +3 -2
  313. package/packages/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
  314. package/packages/pi-ai/dist/providers/anthropic.js +6 -1
  315. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  316. package/packages/pi-ai/dist/providers/azure-openai-responses.d.ts +1 -1
  317. package/packages/pi-ai/dist/providers/azure-openai-responses.d.ts.map +1 -1
  318. package/packages/pi-ai/dist/providers/azure-openai-responses.js.map +1 -1
  319. package/packages/pi-ai/dist/providers/google-vertex.js.map +1 -1
  320. package/packages/pi-ai/dist/providers/google.js.map +1 -1
  321. package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts +1 -1
  322. package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
  323. package/packages/pi-ai/dist/providers/openai-codex-responses.js +1 -1
  324. package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
  325. package/packages/pi-ai/dist/providers/openai-completions.d.ts +1 -1
  326. package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  327. package/packages/pi-ai/dist/providers/openai-completions.js +103 -0
  328. package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
  329. package/packages/pi-ai/dist/providers/openai-responses.d.ts +1 -1
  330. package/packages/pi-ai/dist/providers/openai-responses.d.ts.map +1 -1
  331. package/packages/pi-ai/dist/providers/openai-responses.js +1 -1
  332. package/packages/pi-ai/dist/providers/openai-responses.js.map +1 -1
  333. package/packages/pi-ai/dist/providers/simple-options.d.ts +1 -1
  334. package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  335. package/packages/pi-ai/dist/providers/simple-options.js +1 -1
  336. package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
  337. package/packages/pi-ai/dist/types.d.ts +9 -1
  338. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  339. package/packages/pi-ai/dist/types.js.map +1 -1
  340. package/packages/pi-ai/package.json +1 -1
  341. package/packages/pi-coding-agent/dist/core/capability-patches.js +1 -1
  342. package/packages/pi-coding-agent/dist/core/capability-patches.js.map +1 -1
  343. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  344. package/packages/pi-coding-agent/dist/core/model-registry.js +1 -0
  345. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  346. package/packages/pi-coding-agent/dist/core/model-resolver.js +2 -2
  347. package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
  348. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +14 -4
  349. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  350. package/packages/pi-coding-agent/dist/core/settings-manager.js +8 -0
  351. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  352. package/packages/pi-coding-agent/dist/core/skills.d.ts +5 -0
  353. package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
  354. package/packages/pi-coding-agent/dist/core/skills.js +54 -0
  355. package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
  356. package/packages/pi-coding-agent/dist/theme/theme.d.ts +1 -1
  357. package/packages/pi-coding-agent/dist/theme/theme.d.ts.map +1 -1
  358. package/packages/pi-coding-agent/dist/theme/theme.js +1 -0
  359. package/packages/pi-coding-agent/dist/theme/theme.js.map +1 -1
  360. package/packages/pi-coding-agent/package.json +7 -7
  361. package/packages/pi-tui/package.json +2 -2
  362. package/packages/rpc-client/package.json +2 -2
  363. package/pkg/dist/theme/theme.d.ts +1 -1
  364. package/pkg/dist/theme/theme.d.ts.map +1 -1
  365. package/pkg/dist/theme/theme.js +1 -0
  366. package/pkg/dist/theme/theme.js.map +1 -1
  367. package/pkg/package.json +1 -1
  368. package/src/resources/GSD-WORKFLOW.md +2 -2
  369. package/src/resources/extensions/gsd/artifact-verification.ts +3 -8
  370. package/src/resources/extensions/gsd/auto/loop.ts +48 -4
  371. package/src/resources/extensions/gsd/auto/run-unit.ts +20 -1
  372. package/src/resources/extensions/gsd/auto/unit-phase.ts +41 -5
  373. package/src/resources/extensions/gsd/auto-artifact-paths.ts +14 -7
  374. package/src/resources/extensions/gsd/auto-dispatch.ts +1 -0
  375. package/src/resources/extensions/gsd/auto-model-selection.ts +1 -0
  376. package/src/resources/extensions/gsd/auto-prompts.ts +118 -19
  377. package/src/resources/extensions/gsd/auto-recovery.ts +10 -8
  378. package/src/resources/extensions/gsd/auto-runtime-state.ts +12 -7
  379. package/src/resources/extensions/gsd/auto-start.ts +32 -9
  380. package/src/resources/extensions/gsd/auto-tool-tracking.ts +56 -0
  381. package/src/resources/extensions/gsd/auto-verification.ts +46 -12
  382. package/src/resources/extensions/gsd/auto-worktree-cleanup.ts +4 -0
  383. package/src/resources/extensions/gsd/auto-worktree-sync.ts +10 -3
  384. package/src/resources/extensions/gsd/auto-worktree-teardown.ts +1 -1
  385. package/src/resources/extensions/gsd/auto.ts +20 -7
  386. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +1 -0
  387. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +41 -12
  388. package/src/resources/extensions/gsd/bootstrap/system-context.ts +11 -3
  389. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +10 -31
  390. package/src/resources/extensions/gsd/commands-verdict.ts +16 -9
  391. package/src/resources/extensions/gsd/compat/compat-marker.ts +99 -5
  392. package/src/resources/extensions/gsd/constants.ts +14 -13
  393. package/src/resources/extensions/gsd/context-masker.ts +98 -2
  394. package/src/resources/extensions/gsd/db/engine.ts +5 -2
  395. package/src/resources/extensions/gsd/docs/preferences-reference.md +33 -2
  396. package/src/resources/extensions/gsd/doctor-engine-checks.ts +45 -11
  397. package/src/resources/extensions/gsd/error-classifier.ts +13 -2
  398. package/src/resources/extensions/gsd/exec-sandbox.ts +1 -0
  399. package/src/resources/extensions/gsd/flat-phase-migration.ts +14 -0
  400. package/src/resources/extensions/gsd/git-service.ts +19 -6
  401. package/src/resources/extensions/gsd/gsd-db.ts +85 -33
  402. package/src/resources/extensions/gsd/guided-flow.ts +11 -4
  403. package/src/resources/extensions/gsd/markdown-renderer.ts +5 -23
  404. package/src/resources/extensions/gsd/md-importer.ts +5 -5
  405. package/src/resources/extensions/gsd/model-cost-table.ts +14 -1
  406. package/src/resources/extensions/gsd/model-router.ts +17 -0
  407. package/src/resources/extensions/gsd/paths.ts +73 -15
  408. package/src/resources/extensions/gsd/planning-subagent-policy.ts +58 -0
  409. package/src/resources/extensions/gsd/planning-subagent-registry.ts +45 -0
  410. package/src/resources/extensions/gsd/preferences-models.ts +54 -10
  411. package/src/resources/extensions/gsd/preferences-types.ts +26 -2
  412. package/src/resources/extensions/gsd/preferences-validation.ts +108 -3
  413. package/src/resources/extensions/gsd/preferences.ts +38 -0
  414. package/src/resources/extensions/gsd/prompts/validate-milestone.md +5 -5
  415. package/src/resources/extensions/gsd/provider-payload-policy.ts +18 -4
  416. package/src/resources/extensions/gsd/safety/destructive-guard.ts +1 -1
  417. package/src/resources/extensions/gsd/skill-activation.ts +17 -3
  418. package/src/resources/extensions/gsd/state-reconciliation/drift/external-markdown-edit.ts +132 -2
  419. package/src/resources/extensions/gsd/state-reconciliation/drift/external-planning-edit.ts +4 -1
  420. package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +4 -2
  421. package/src/resources/extensions/gsd/stop-notice.ts +11 -0
  422. package/src/resources/extensions/gsd/templates/PREFERENCES.md +8 -0
  423. package/src/resources/extensions/gsd/tests/auto-artifact-paths.test.ts +7 -7
  424. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +264 -0
  425. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +39 -0
  426. package/src/resources/extensions/gsd/tests/auto-start-index-lock.test.ts +21 -1
  427. package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +74 -1
  428. package/src/resources/extensions/gsd/tests/before-provider-context-management.test.ts +55 -0
  429. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +10 -0
  430. package/src/resources/extensions/gsd/tests/compat-marker.test.ts +25 -0
  431. package/src/resources/extensions/gsd/tests/complete-task.test.ts +76 -1
  432. package/src/resources/extensions/gsd/tests/context-masker.test.ts +204 -8
  433. package/src/resources/extensions/gsd/tests/db-engine-cjs-compat.test.ts +12 -0
  434. package/src/resources/extensions/gsd/tests/db-tools-alias-suppression.test.ts +62 -0
  435. package/src/resources/extensions/gsd/tests/destructive-confirmation.test.ts +33 -0
  436. package/src/resources/extensions/gsd/tests/destructive-guard.test.ts +14 -0
  437. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +147 -0
  438. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +33 -1
  439. package/src/resources/extensions/gsd/tests/external-markdown-edit.test.ts +38 -1
  440. package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +8 -9
  441. package/src/resources/extensions/gsd/tests/flat-phase-validation-path.test.ts +20 -1
  442. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +32 -0
  443. package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +22 -0
  444. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +13 -0
  445. package/src/resources/extensions/gsd/tests/integration/paths.test.ts +22 -4
  446. package/src/resources/extensions/gsd/tests/integration-branch-meta-location.test.ts +62 -0
  447. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +5 -5
  448. package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +23 -0
  449. package/src/resources/extensions/gsd/tests/model-isolation.test.ts +55 -0
  450. package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
  451. package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +7 -5
  452. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +24 -0
  453. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +38 -1
  454. package/src/resources/extensions/gsd/tests/preferences.test.ts +151 -0
  455. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +7 -0
  456. package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +87 -0
  457. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +121 -1
  458. package/src/resources/extensions/gsd/tests/reactive-executor.test.ts +39 -0
  459. package/src/resources/extensions/gsd/tests/register-hooks-loop-guard-auto.test.ts +105 -0
  460. package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
  461. package/src/resources/extensions/gsd/tests/single-writer-v3-tool-surface.test.ts +33 -7
  462. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +20 -16
  463. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +52 -0
  464. package/src/resources/extensions/gsd/tests/stop-notice.test.ts +21 -1
  465. package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +13 -7
  466. package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +14 -0
  467. package/src/resources/extensions/gsd/tests/thinking-level-resolution.test.ts +1 -1
  468. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +19 -0
  469. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -0
  470. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +39 -0
  471. package/src/resources/extensions/gsd/tests/validate-milestone-prompt-verification-classes.test.ts +7 -0
  472. package/src/resources/extensions/gsd/tests/verification-evidence.test.ts +12 -0
  473. package/src/resources/extensions/gsd/tests/workflow-authority-faults.test.ts +238 -0
  474. package/src/resources/extensions/gsd/tests/workflow-authority-fixture.test.ts +48 -0
  475. package/src/resources/extensions/gsd/tests/workflow-authority-fixture.ts +141 -0
  476. package/src/resources/extensions/gsd/tests/workflow-authority-projection-conflict.test.ts +177 -0
  477. package/src/resources/extensions/gsd/tests/workflow-fault-harness.test.ts +39 -0
  478. package/src/resources/extensions/gsd/tests/workflow-fault-harness.ts +72 -0
  479. package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +4 -4
  480. package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +2 -2
  481. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +60 -0
  482. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +74 -0
  483. package/src/resources/extensions/gsd/tools/complete-task.ts +20 -5
  484. package/src/resources/extensions/gsd/tools/plan-slice.ts +5 -1
  485. package/src/resources/extensions/gsd/tools/reopen-milestone.ts +24 -5
  486. package/src/resources/extensions/gsd/tools/reopen-slice.ts +25 -5
  487. package/src/resources/extensions/gsd/tools/reopen-task.ts +23 -9
  488. package/src/resources/extensions/gsd/unit-context-composer.ts +34 -8
  489. package/src/resources/extensions/gsd/verification-evidence.ts +5 -2
  490. package/src/resources/extensions/gsd/workflow-projections.ts +2 -3
  491. package/src/resources/extensions/gsd/workspace.ts +2 -1
  492. package/src/resources/extensions/gsd/worktree-state-projection.ts +21 -24
  493. package/src/resources/extensions/ollama/ollama-chat-provider.ts +2 -2
  494. package/src/resources/extensions/ollama/tests/ollama-chat-provider-think.test.ts +4 -0
  495. package/src/resources/extensions/shared/interview-ui.ts +47 -8
  496. package/src/resources/extensions/shared/tests/interview-ui-border.test.ts +29 -0
  497. package/src/resources/extensions/subagent/index.ts +1 -1
  498. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-49f565245e1e4afe.js +0 -1
  499. package/dist/web/standalone/.next/static/chunks/app/page-bc4c723c6a19c6f0.js +0 -1
  500. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ec3eaffc9785ba48.js +0 -1
  501. /package/dist/web/standalone/.next/static/{BE5XoklToI6lZjRzpXih8 → xwUaOqui04jIIFVsIBLiL}/_buildManifest.js +0 -0
  502. /package/dist/web/standalone/.next/static/{BE5XoklToI6lZjRzpXih8 → xwUaOqui04jIIFVsIBLiL}/_ssgManifest.js +0 -0
@@ -9,13 +9,15 @@
9
9
  // refreshes the marker entry, closing the loop.
10
10
 
11
11
  import { existsSync, readFileSync } from "node:fs";
12
- import { join } from "node:path";
12
+ import { basename, join } from "node:path";
13
13
 
14
14
  import {
15
15
  computeProjectionSha,
16
16
  readCompatMarker,
17
17
  writeCompatMarker,
18
+ type ProjectionEntry,
18
19
  } from "../../compat/compat-marker.js";
20
+ import { _getAdapter } from "../../gsd-db.js";
19
21
  import { logWarning } from "../../workflow-logger.js";
20
22
  import type { GSDState } from "../../types.js";
21
23
  import type { DriftContext, DriftHandler, DriftRecord } from "../types.js";
@@ -25,6 +27,102 @@ type ExternalMarkdownEditDrift = Extract<
25
27
  { kind: "external-markdown-edit" }
26
28
  >;
27
29
 
30
+ type ArtifactContentRow = {
31
+ full_content: string;
32
+ };
33
+
34
+ type ProjectionScope = {
35
+ milestoneId: string;
36
+ sliceId: string | null;
37
+ taskId: string | null;
38
+ };
39
+
40
+ function deepestProjectionScope(entities: readonly string[]): ProjectionScope | null {
41
+ let best: string[] | null = null;
42
+ for (const entity of entities) {
43
+ const parts = entity.split("/").filter(Boolean);
44
+ if (parts.length === 0) continue;
45
+ if (!best || parts.length > best.length) best = parts;
46
+ }
47
+ if (!best) return null;
48
+ return {
49
+ milestoneId: best[0]!,
50
+ sliceId: best[1] ?? null,
51
+ taskId: best[2] ?? null,
52
+ };
53
+ }
54
+
55
+ function artifactTypeFromProjectionPath(projectionPath: string): string | null {
56
+ const name = basename(projectionPath);
57
+ const match = name.match(/^(?:[A-Za-z]\d+|\d+(?:-\d+)?)-(.+)\.md$/);
58
+ return match?.[1]?.toUpperCase() ?? null;
59
+ }
60
+
61
+ function dbProjectionMatches(
62
+ projectionPath: string,
63
+ entry: ProjectionEntry,
64
+ actualSha: string,
65
+ ): boolean {
66
+ const adapter = _getAdapter();
67
+ if (!adapter) return false;
68
+
69
+ try {
70
+ const rows: ArtifactContentRow[] = adapter
71
+ .prepare("SELECT full_content FROM artifacts WHERE path = :path")
72
+ .all({ ":path": projectionPath }) as ArtifactContentRow[];
73
+
74
+ const scope = deepestProjectionScope(entry.entities);
75
+ const artifactType = artifactTypeFromProjectionPath(projectionPath);
76
+ if (scope?.taskId) {
77
+ rows.push(
78
+ ...(adapter
79
+ .prepare(
80
+ `SELECT full_content
81
+ FROM artifacts
82
+ WHERE milestone_id = :mid AND slice_id = :sid AND task_id = :tid
83
+ AND (:type IS NULL OR artifact_type = :type)`,
84
+ )
85
+ .all({
86
+ ":mid": scope.milestoneId,
87
+ ":sid": scope.sliceId,
88
+ ":tid": scope.taskId,
89
+ ":type": artifactType,
90
+ }) as ArtifactContentRow[]),
91
+ );
92
+ } else if (scope?.sliceId) {
93
+ rows.push(
94
+ ...(adapter
95
+ .prepare(
96
+ `SELECT full_content
97
+ FROM artifacts
98
+ WHERE milestone_id = :mid AND slice_id = :sid AND task_id IS NULL
99
+ AND (:type IS NULL OR artifact_type = :type)`,
100
+ )
101
+ .all({
102
+ ":mid": scope.milestoneId,
103
+ ":sid": scope.sliceId,
104
+ ":type": artifactType,
105
+ }) as ArtifactContentRow[]),
106
+ );
107
+ } else if (scope) {
108
+ rows.push(
109
+ ...(adapter
110
+ .prepare(
111
+ `SELECT full_content
112
+ FROM artifacts
113
+ WHERE milestone_id = :mid AND slice_id IS NULL AND task_id IS NULL
114
+ AND (:type IS NULL OR artifact_type = :type)`,
115
+ )
116
+ .all({ ":mid": scope.milestoneId, ":type": artifactType }) as ArtifactContentRow[]),
117
+ );
118
+ }
119
+
120
+ return rows.some((row) => computeProjectionSha(row.full_content) === actualSha);
121
+ } catch {
122
+ return false;
123
+ }
124
+ }
125
+
28
126
  /**
29
127
  * Detect sha drift between the marker baseline and current file contents.
30
128
  *
@@ -38,16 +136,43 @@ function detectExternalMarkdownEdit(
38
136
  _state: GSDState,
39
137
  ctx: DriftContext,
40
138
  ): ExternalMarkdownEditDrift[] {
41
- const marker = readCompatMarker(ctx.basePath);
139
+ const marker = readCompatMarker(ctx.basePath, {
140
+ healInvalidKeys: !ctx.dryRun,
141
+ quarantineInvalid: !ctx.dryRun,
142
+ });
42
143
  const entries = Object.entries(marker.projections);
43
144
  if (entries.length === 0) return [];
44
145
 
45
146
  const records: ExternalMarkdownEditDrift[] = [];
147
+ let markerChanged = false;
46
148
  for (const [projectionPath, entry] of entries) {
47
149
  const abs = join(ctx.basePath, ".gsd", projectionPath);
48
150
  if (!existsSync(abs)) continue;
49
151
  const actual = computeProjectionSha(readFileSync(abs, "utf-8"));
50
152
  if (actual === entry.sha) continue;
153
+ if (dbProjectionMatches(projectionPath, entry, actual)) {
154
+ if (!ctx.dryRun) {
155
+ marker.projections[projectionPath] = {
156
+ sha: actual,
157
+ entities: entry.entities,
158
+ };
159
+ markerChanged = true;
160
+ logWarning(
161
+ "reconcile",
162
+ `external-markdown-edit: refreshed stale compat marker for ${projectionPath} (expectedSha=${entry.sha}, actualSha=${actual})`,
163
+ );
164
+ } else {
165
+ logWarning(
166
+ "reconcile",
167
+ `external-markdown-edit: stale compat marker for ${projectionPath} (expectedSha=${entry.sha}, actualSha=${actual})`,
168
+ );
169
+ }
170
+ continue;
171
+ }
172
+ logWarning(
173
+ "reconcile",
174
+ `external-markdown-edit drift for ${projectionPath} (expectedSha=${entry.sha}, actualSha=${actual})`,
175
+ );
51
176
  records.push({
52
177
  kind: "external-markdown-edit",
53
178
  projectionPath,
@@ -56,6 +181,11 @@ function detectExternalMarkdownEdit(
56
181
  entities: entry.entities,
57
182
  });
58
183
  }
184
+ if (markerChanged) {
185
+ marker.lastWriter = "gsd-pi";
186
+ marker.lastProjectedAt = new Date().toISOString();
187
+ writeCompatMarker(ctx.basePath, marker);
188
+ }
59
189
  return records;
60
190
  }
61
191
 
@@ -82,7 +82,10 @@ async function detectExternalPlanningEdit(
82
82
  _state: GSDState,
83
83
  ctx: DriftContext,
84
84
  ): Promise<ExternalPlanningEditDrift[]> {
85
- const marker = readCompatMarker(ctx.basePath);
85
+ const marker = readCompatMarker(ctx.basePath, {
86
+ healInvalidKeys: !ctx.dryRun,
87
+ quarantineInvalid: !ctx.dryRun,
88
+ });
86
89
  if (!marker.planning?.active) {
87
90
  // Not yet activated. Activation (layout parse + DB import) is owned by
88
91
  // capturePlanningCompatIfNeeded, called from reconcileBeforeDispatch when
@@ -16,7 +16,7 @@ import { renderRoadmapFromDb } from "../../markdown-renderer.js";
16
16
  import { findMilestoneIds } from "../../milestone-ids.js";
17
17
  import { parseRoadmap } from "../../parsers-legacy.js";
18
18
  import { resolveMilestoneFile } from "../../paths.js";
19
- import { isClosedStatus } from "../../status-guards.js";
19
+ import { isClosedStatus, isSkippedForDispatch } from "../../status-guards.js";
20
20
  import type { GSDState } from "../../types.js";
21
21
  import type { DriftContext, DriftHandler, DriftRecord } from "../types.js";
22
22
 
@@ -94,7 +94,9 @@ export function detectRoadmapDivergenceDrift(
94
94
  for (const milestoneId of findMilestoneIds(ctx.basePath)) {
95
95
  // Skip milestones that don't yet have a DB row — that's the
96
96
  // unregistered-milestone drift handler's responsibility.
97
- if (!getMilestone(milestoneId)) continue;
97
+ const milestone = getMilestone(milestoneId);
98
+ if (!milestone) continue;
99
+ if (isSkippedForDispatch(milestone.status)) continue;
98
100
  if (milestoneHasDivergence(ctx.basePath, milestoneId)) {
99
101
  drifts.push({ kind: "roadmap-divergence", milestoneId });
100
102
  }
@@ -29,6 +29,14 @@ export function formatStopNoticePrefix(reason?: string | null): string {
29
29
  return displayReason ? `${prefix} — ${displayReason}` : prefix;
30
30
  }
31
31
 
32
+ export function formatVerdictRecordedNotice(message: string): string {
33
+ return `Verdict recorded: ${message}`;
34
+ }
35
+
36
+ export function formatVerdictRejectedNotice(message: string): string {
37
+ return `Verdict rejected: ${message}`;
38
+ }
39
+
32
40
  // ─── Classification (headless host side) ────────────────────────────────
33
41
  // The canonical lowercase prefixes the headless event loop recognizes in
34
42
  // notify messages. Emitters above and ad-hoc emitters elsewhere must start
@@ -42,6 +50,8 @@ export const TERMINAL_NOTICE_PREFIXES = [
42
50
  "auto-mode complete",
43
51
  "no active milestone",
44
52
  "auto-mode idle",
53
+ "verdict recorded",
54
+ "verdict rejected",
45
55
  ] as const;
46
56
 
47
57
  /** Manual-resolution notices emitted before auto-mode can formally pause/stop. */
@@ -85,6 +95,7 @@ export function isInteractiveMenuUnavailableNotice(message: string): boolean {
85
95
  export function isBlockedNoticeMessage(message: string): boolean {
86
96
  return (
87
97
  message.includes("blocked:") ||
98
+ message.startsWith("verdict rejected") ||
88
99
  (isPauseNotice(message) && !isNonBlockingPauseNotice(message)) ||
89
100
  isManualResolutionNotice(message) ||
90
101
  isInteractiveMenuUnavailableNotice(message)
@@ -92,6 +92,14 @@ remote_questions:
92
92
  uat_dispatch:
93
93
  post_unit_hooks: []
94
94
  pre_dispatch_hooks: []
95
+ # planning_subagent_registry:
96
+ # my-custom-planner:
97
+ # read_only_specialist: true
98
+ # planning_subagents:
99
+ # plan-milestone:
100
+ # allowed: [scout, planner, security]
101
+ # plan-slice:
102
+ # allowed: [scout, planner, reviewer, security]
95
103
  # language:
96
104
  # experimental:
97
105
  # rtk: false
@@ -442,11 +442,11 @@ test("bare milestone id still falls back to a lone team-suffix projection (#1195
442
442
  // ── #1208: flat-phase execute-task summaries resolve at the phase root ────────
443
443
  //
444
444
  // In flat-phase layout task summaries are written beside the plan files
445
- // (phases/<phase>/T##-SUMMARY.md), NOT under a tasks/ subdir. A tasks/ dir may
446
- // still exist to hold auxiliary task-scoped gate artifacts (e.g. T01-VERIFY.json).
445
+ // (phases/<phase>/S##-T##-SUMMARY.md), NOT under a tasks/ subdir. A tasks/ dir
446
+ // may still exist to hold auxiliary task-scoped gate artifacts (e.g. T01-VERIFY.json).
447
447
  // Before the fix, the mere existence of that tasks/ dir redirected summary
448
- // verification into tasks/T##-SUMMARY.md — which never exists — trapping auto-mode
449
- // in a false verification retry that eventually paused after a successful task.
448
+ // verification into tasks/S##-T##-SUMMARY.md — which never exists — trapping
449
+ // auto-mode in a false verification retry after a successful task.
450
450
 
451
451
  test("flat-phase execute-task summary resolves at phase root when no tasks/ dir exists (#1208)", () => {
452
452
  const root = realpathSync(mkdtempSync(join(tmpdir(), "gsd-flat-task-summary-")));
@@ -461,7 +461,7 @@ test("flat-phase execute-task summary resolves at phase root when no tasks/ dir
461
461
 
462
462
  assert.equal(
463
463
  resolveExpectedArtifactPath("execute-task", "M049/S03/T02", root),
464
- join(phaseDir, "T02-SUMMARY.md"),
464
+ join(phaseDir, "S03-T02-SUMMARY.md"),
465
465
  );
466
466
  } finally {
467
467
  _clearGsdRootCache();
@@ -489,12 +489,12 @@ test("flat-phase execute-task summary resolves at phase root even when tasks/ di
489
489
  const resolved = resolveExpectedArtifactPath("execute-task", "M049/S03/T02", root);
490
490
  assert.equal(
491
491
  resolved,
492
- join(phaseDir, "T02-SUMMARY.md"),
492
+ join(phaseDir, "S03-T02-SUMMARY.md"),
493
493
  "flat-phase task summary must resolve at the phase root, not tasks/",
494
494
  );
495
495
  assert.notEqual(
496
496
  resolved,
497
- join(tasksDir, "T02-SUMMARY.md"),
497
+ join(tasksDir, "S03-T02-SUMMARY.md"),
498
498
  "a tasks/ dir with gate artifacts must NOT redirect summary resolution into tasks/",
499
499
  );
500
500
  } finally {
@@ -41,6 +41,7 @@ import { claimMilestoneLease } from "../db/milestone-leases.js";
41
41
  import { recordDispatchClaim, markCanceled } from "../db/unit-dispatches.js";
42
42
  import { setRuntimeKv, getRuntimeKv } from "../db/runtime-kv.js";
43
43
  import { SourceObservationStore } from "../source-observations.js";
44
+ import { autoCommitCurrentBranch } from "../worktree.js";
44
45
 
45
46
  // ─── Helpers ─────────────────────────────────────────────────────────────────
46
47
 
@@ -832,6 +833,37 @@ test("runUnit returns cancelled when session creation fails", async () => {
832
833
  assert.equal(pi.calls.length, 0);
833
834
  });
834
835
 
836
+ test("runUnit returns cancelled when command context lacks newSession", async () => {
837
+ _resetPendingResolve();
838
+
839
+ const ctx = {
840
+ ...makeMockCtx(),
841
+ ui: {
842
+ notify: () => {},
843
+ setStatus: () => {},
844
+ setWorkingMessage: () => {},
845
+ },
846
+ sessionManager: {
847
+ getEntries: () => [],
848
+ },
849
+ modelRegistry: {
850
+ getProviderAuthMode: () => undefined,
851
+ isProviderRequestReady: () => true,
852
+ },
853
+ } as any;
854
+ const pi = makeMockPi();
855
+ const s = makeMockSession();
856
+ s.cmdCtx = {} as any;
857
+
858
+ const result = await runUnit(ctx, pi, s, "task", "T01", "prompt");
859
+
860
+ assert.equal(result.status, "cancelled");
861
+ assert.equal(result.errorContext?.category, "session-failed");
862
+ assert.equal(result.errorContext?.isTransient, false);
863
+ assert.match(result.errorContext?.message ?? "", /missing newSession/);
864
+ assert.equal(pi.calls.length, 0);
865
+ });
866
+
835
867
  test("runUnit: TypeError from newSession is classified as structural (isTransient: false)", async () => {
836
868
  // Regression for #572: a TypeError thrown from newSession (e.g. "something is
837
869
  // not a function") indicates a programming error, not a transient provider
@@ -1582,6 +1614,130 @@ test("autoLoop exits when s.active is set to false", async (t) => {
1582
1614
  );
1583
1615
  });
1584
1616
 
1617
+ test("autoLoop stops before dispatch when command context lacks newSession", async () => {
1618
+ _resetPendingResolve();
1619
+
1620
+ const ctx = makeMockCtx();
1621
+ ctx.ui.setStatus = () => {};
1622
+ const pi = makeMockPi();
1623
+ const s = makeLoopSession({
1624
+ cmdCtx: {
1625
+ getContextUsage: () => ({ percent: 10, tokens: 1000, limit: 10000 }),
1626
+ },
1627
+ });
1628
+ let stopReason: string | undefined;
1629
+ let preserveWorktree: boolean | undefined;
1630
+ let deriveCalled = false;
1631
+
1632
+ try {
1633
+ const deps = makeMockDeps({
1634
+ stopAuto: async (_ctx, _pi, reason, options) => {
1635
+ stopReason = reason;
1636
+ preserveWorktree = options?.preserveWorktree;
1637
+ s.active = false;
1638
+ },
1639
+ deriveState: async () => {
1640
+ deriveCalled = true;
1641
+ throw new Error("deriveState should not run without command session support");
1642
+ },
1643
+ });
1644
+
1645
+ await autoLoop(ctx, pi, s, deps);
1646
+
1647
+ assert.equal(stopReason, "Auto-mode has no command context for dispatch.");
1648
+ assert.equal(preserveWorktree, true);
1649
+ assert.equal(deriveCalled, false);
1650
+ assert.equal(pi.calls.length, 0);
1651
+ } finally {
1652
+ rmSync(s.basePath, { recursive: true, force: true });
1653
+ }
1654
+ });
1655
+
1656
+ test("autoLoop commits open unit work when command context lacks newSession", async () => {
1657
+ _resetPendingResolve();
1658
+
1659
+ const ctx = makeMockCtx();
1660
+ ctx.ui.setStatus = () => {};
1661
+ const pi = makeMockPi();
1662
+ const s = makeLoopSession({
1663
+ cmdCtx: {
1664
+ getContextUsage: () => ({ percent: 10, tokens: 1000, limit: 10000 }),
1665
+ },
1666
+ currentUnit: { type: "execute-task", id: "T01", startedAt: Date.now() },
1667
+ });
1668
+ const outputPath = join(s.basePath, "executor-output.txt");
1669
+ let autoCommitArgs: { unitType: string; unitId: string } | undefined;
1670
+ let preserveWorktree: boolean | undefined;
1671
+
1672
+ try {
1673
+ const deps = makeMockDeps({
1674
+ autoCommitUnit: async (basePath, unitType, unitId) => {
1675
+ autoCommitArgs = { unitType, unitId };
1676
+ return autoCommitCurrentBranch(basePath, unitType, unitId);
1677
+ },
1678
+ stopAuto: async (_ctx, _pi, _reason, options) => {
1679
+ preserveWorktree = options?.preserveWorktree;
1680
+ s.active = false;
1681
+ },
1682
+ deriveState: async () => {
1683
+ throw new Error("deriveState should not run without command session support");
1684
+ },
1685
+ });
1686
+
1687
+ writeFileSync(outputPath, "open unit work before stop\n", "utf-8");
1688
+
1689
+ await autoLoop(ctx, pi, s, deps);
1690
+
1691
+ assert.deepEqual(autoCommitArgs, { unitType: "execute-task", unitId: "T01" });
1692
+ assert.equal(preserveWorktree, true);
1693
+ const committed = execSync("git show HEAD:executor-output.txt", {
1694
+ cwd: s.basePath,
1695
+ encoding: "utf-8",
1696
+ });
1697
+ assert.equal(committed, "open unit work before stop\n");
1698
+ assert.equal(pi.calls.length, 0);
1699
+ } finally {
1700
+ rmSync(s.basePath, { recursive: true, force: true });
1701
+ }
1702
+ });
1703
+
1704
+ test("autoLoop snapshots dirty work when unit dispatch crashes", async () => {
1705
+ _resetPendingResolve();
1706
+
1707
+ const ctx = makeMockCtx();
1708
+ ctx.ui.setStatus = () => {};
1709
+ const pi = makeMockPi();
1710
+ const s = makeLoopSession();
1711
+ const outputPath = join(s.basePath, "executor-output.txt");
1712
+ let autoCommitCalls = 0;
1713
+
1714
+ try {
1715
+ const deps = makeMockDeps({
1716
+ ensurePreconditions: () => {
1717
+ writeFileSync(outputPath, "saved before crash\n", "utf-8");
1718
+ throw new Error("dispatch crash after file write");
1719
+ },
1720
+ autoCommitUnit: async (basePath, unitType, unitId) => {
1721
+ autoCommitCalls++;
1722
+ const commitMsg = autoCommitCurrentBranch(basePath, unitType, unitId);
1723
+ s.active = false;
1724
+ return commitMsg;
1725
+ },
1726
+ });
1727
+
1728
+ await autoLoop(ctx, pi, s, deps);
1729
+
1730
+ assert.equal(autoCommitCalls, 1);
1731
+ const committed = execSync("git show HEAD:executor-output.txt", {
1732
+ cwd: s.basePath,
1733
+ encoding: "utf-8",
1734
+ });
1735
+ assert.equal(committed, "saved before crash\n");
1736
+ } finally {
1737
+ rmSync(s.basePath, { recursive: true, force: true });
1738
+ }
1739
+ });
1740
+
1585
1741
  test("autoLoop pauses visibly when Auto Orchestration Module is not wired", async () => {
1586
1742
  _resetPendingResolve();
1587
1743
 
@@ -5421,6 +5577,114 @@ test("runUnitPhase retries 0-tool units with ordinary network-related assistant
5421
5577
  assert.equal(deps.callLog.includes("pauseAuto"), false);
5422
5578
  });
5423
5579
 
5580
+ test("runUnitPhase pauses 0-tool units with pseudo tool-call text as serialization drift", async (t) => {
5581
+ _resetPendingResolve();
5582
+
5583
+ const basePath = makeLoopTestBase("gsd-zero-tool-pseudo-tool-");
5584
+ t.after(() => {
5585
+ rmSync(basePath, { recursive: true, force: true });
5586
+ });
5587
+
5588
+ const notifications: string[] = [];
5589
+ const ctx = {
5590
+ ...makeMockCtx(),
5591
+ ui: {
5592
+ notify: (msg: string) => { notifications.push(msg); },
5593
+ setStatus: () => {},
5594
+ setWorkingMessage: () => {},
5595
+ },
5596
+ sessionManager: {
5597
+ getEntries: () => [],
5598
+ },
5599
+ modelRegistry: {
5600
+ getProviderAuthMode: () => undefined,
5601
+ isProviderRequestReady: () => true,
5602
+ },
5603
+ } as any;
5604
+ const pi = {
5605
+ ...makeMockPi(),
5606
+ sendMessage: () => {
5607
+ queueMicrotask(() => resolveAgentEnd(makeEvent([
5608
+ {
5609
+ role: "assistant",
5610
+ content: [
5611
+ {
5612
+ type: "text",
5613
+ text: 'bash<arg_key>command</arg_key><arg_value>ls -la /tmp && echo "---SRC---"</arg_value></tool_call>',
5614
+ },
5615
+ ],
5616
+ },
5617
+ ])));
5618
+ },
5619
+ } as any;
5620
+ const s = makeLoopSession({
5621
+ basePath,
5622
+ canonicalProjectRoot: basePath,
5623
+ originalBasePath: basePath,
5624
+ });
5625
+ const mockLedger = {
5626
+ version: 1,
5627
+ projectStartedAt: Date.now(),
5628
+ units: [] as any[],
5629
+ };
5630
+ const deps = makeMockDeps({
5631
+ closeoutUnit: async () => {
5632
+ mockLedger.units.push({
5633
+ type: "execute-task",
5634
+ id: "M001/S01/T01",
5635
+ startedAt: s.currentUnit?.startedAt ?? Date.now(),
5636
+ toolCalls: 0,
5637
+ assistantMessages: 1,
5638
+ tokens: { input: 100, output: 20, total: 120, cacheRead: 0, cacheWrite: 0 },
5639
+ cost: 0.01,
5640
+ });
5641
+ },
5642
+ getLedger: () => mockLedger,
5643
+ });
5644
+ let seq = 0;
5645
+
5646
+ const result = await runUnitPhase(
5647
+ { ctx, pi, s, deps, prefs: undefined, iteration: 1, flowId: "flow-zero-tool-pseudo-tool", nextSeq: () => ++seq },
5648
+ {
5649
+ unitType: "execute-task",
5650
+ unitId: "M001/S01/T01",
5651
+ prompt: "do work",
5652
+ finalPrompt: "do work",
5653
+ pauseAfterUatDispatch: false,
5654
+ state: {
5655
+ phase: "executing",
5656
+ activeMilestone: { id: "M001", title: "Milestone" },
5657
+ activeSlice: { id: "S01", title: "Slice" },
5658
+ activeTask: { id: "T01", title: "Task" },
5659
+ registry: [{ id: "M001", title: "Milestone", status: "active" }],
5660
+ recentDecisions: [],
5661
+ blockers: [],
5662
+ nextAction: "",
5663
+ progress: { milestones: { done: 0, total: 1 } },
5664
+ requirements: { active: 0, validated: 0, deferred: 0, outOfScope: 0, blocked: 0, total: 0 },
5665
+ } as any,
5666
+ mid: "M001",
5667
+ midTitle: "Milestone",
5668
+ isRetry: false,
5669
+ previousTier: undefined,
5670
+ },
5671
+ { recentUnits: [{ key: "execute-task/M001/S01/T01" }], stuckRecoveryAttempts: 0, consecutiveFinalizeTimeouts: 0 },
5672
+ );
5673
+
5674
+ assert.equal(result.action, "break");
5675
+ assert.equal((result as any).reason, "zero-tool-serialization-drift");
5676
+ assert.equal(deps.callLog.includes("pauseAuto"), true);
5677
+ assert.equal(s.zeroToolRetryCount.has("execute-task/M001/S01/T01"), false);
5678
+ assert.ok(
5679
+ notifications.some((msg) => msg.includes("serialization drift") && msg.includes("bash<arg_key>command")),
5680
+ "serialization drift notification should include a snippet of the pseudo tool-call text",
5681
+ );
5682
+ assert.ok(
5683
+ !notifications.some((msg) => msg.includes("context exhaustion")),
5684
+ "pseudo tool-call text should not be labeled as context exhaustion",
5685
+ );
5686
+ });
5687
+
5424
5688
  test("runUnitPhase pauses auto-mode when zero-tool-call retry is exhausted", async (t) => {
5425
5689
  _resetPendingResolve();
5426
5690
 
@@ -1218,6 +1218,10 @@ test("hasImplementationArtifacts finds integration implementation-only commits w
1218
1218
 
1219
1219
  execFileSync("git", ["checkout", "-b", "milestone/M001"], { cwd: base, stdio: "ignore" });
1220
1220
  writeIntegrationBranch(base, "M001", "main");
1221
+ // ADR-045: writeIntegrationBranch no longer creates milestones/<MID>/ as a
1222
+ // side effect (META is now flat at .gsd/<MID>-META.json), so scaffold the
1223
+ // legacy summary dir explicitly.
1224
+ mkdirSync(join(base, ".gsd", "milestones", "M001"), { recursive: true });
1221
1225
  writeFileSync(join(base, ".gsd", "milestones", "M001", "M001-SUMMARY.md"), "# Milestone Summary\nDone.");
1222
1226
  execFileSync("git", ["add", "."], { cwd: base, stdio: "ignore" });
1223
1227
  execFileSync("git", ["commit", "-m", "chore: auto-commit after complete-milestone\n\nGSD-Unit: M001"], { cwd: base, stdio: "ignore" });
@@ -2063,6 +2067,41 @@ test("#1088: writeReactiveExecuteBlocker preserves deferred batch task statuses"
2063
2067
  }
2064
2068
  });
2065
2069
 
2070
+ test("#1343: writeReactiveExecuteBlocker uses slice-qualified summaries in flat-phase (no cross-slice collision)", () => {
2071
+ const base = join(tmpdir(), `gsd-test-${randomUUID()}`);
2072
+ try {
2073
+ // Flat-phase layout: slices S01 and S02 share the phase dir and reuse task
2074
+ // id T03. Only the sibling slice S01 produced a summary.
2075
+ const phaseDir = join(base, ".gsd", "phases", "01-test");
2076
+ mkdirSync(phaseDir, { recursive: true });
2077
+ writeFileSync(join(phaseDir, "01-01-PLAN.md"), "# S01: First\n", "utf-8");
2078
+ writeFileSync(join(phaseDir, "01-02-PLAN.md"), "# S02: Second\n", "utf-8");
2079
+ writeFileSync(join(phaseDir, "S01-T03-SUMMARY.md"), "# S01 T03 Summary\n", "utf-8");
2080
+
2081
+ openDatabase(join(base, ".gsd", "gsd.db"));
2082
+ insertMilestone({ id: "M001", title: "Milestone", status: "active" });
2083
+ insertSlice({ id: "S01", milestoneId: "M001", title: "First", status: "pending" });
2084
+ insertSlice({ id: "S02", milestoneId: "M001", title: "Second", status: "pending" });
2085
+ insertTask({ id: "T03", milestoneId: "M001", sliceId: "S02", title: "Shared id", status: "pending" });
2086
+
2087
+ const recovery = writeReactiveExecuteBlocker(
2088
+ "M001/S02/reactive+T03",
2089
+ base,
2090
+ "verification retries exhausted",
2091
+ );
2092
+
2093
+ assert.ok(recovery, "recovery should run with DB available");
2094
+ // S02 never wrote S02-T03-SUMMARY.md; the sibling S01-T03-SUMMARY.md must
2095
+ // NOT make S02/T03 look complete. It has to be skipped.
2096
+ assert.deepEqual(recovery!.completedTaskIds, []);
2097
+ assert.deepEqual(recovery!.skippedTaskIds, ["T03"]);
2098
+ assert.equal(getTask("M001", "S02", "T03")?.status, "skipped");
2099
+ } finally {
2100
+ closeDatabase();
2101
+ cleanup(base);
2102
+ }
2103
+ });
2104
+
2066
2105
  test("#4414: verifyExpectedArtifact parallel-research succeeds when all research-ready slices have RESEARCH", () => {
2067
2106
  const base = makeTmpBase();
2068
2107
  try {
@@ -4,7 +4,7 @@ import { existsSync, mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:
4
4
  import { join } from "node:path";
5
5
  import { tmpdir } from "node:os";
6
6
 
7
- import { hasGitIndexLockForTest } from "../auto-start.ts";
7
+ import { hasGitIndexLockForTest, reconcileFlatPhaseBootstrapLayout } from "../auto-start.ts";
8
8
 
9
9
  test("bootstrapAutoSession detects .git/index.lock without deleting it", (t) => {
10
10
  const base = mkdtempSync(join(tmpdir(), "gsd-index-lock-"));
@@ -24,3 +24,23 @@ test("bootstrapAutoSession reports no index lock when the lock file is absent",
24
24
 
25
25
  assert.equal(hasGitIndexLockForTest(base), false);
26
26
  });
27
+
28
+ test("bootstrapAutoSession removes empty legacy milestones dir in flat-phase projects", (t) => {
29
+ const base = mkdtempSync(join(tmpdir(), "gsd-flat-bootstrap-clean-"));
30
+ t.after(() => rmSync(base, { recursive: true, force: true }));
31
+ mkdirSync(join(base, ".gsd", "phases"), { recursive: true });
32
+ mkdirSync(join(base, ".gsd", "milestones"), { recursive: true });
33
+
34
+ assert.equal(reconcileFlatPhaseBootstrapLayout(base), true);
35
+ assert.equal(existsSync(join(base, ".gsd", "phases")), true);
36
+ assert.equal(existsSync(join(base, ".gsd", "milestones")), false);
37
+ });
38
+
39
+ test("bootstrapAutoSession creates phases instead of milestones for empty GSD state", (t) => {
40
+ const base = mkdtempSync(join(tmpdir(), "gsd-flat-bootstrap-init-"));
41
+ t.after(() => rmSync(base, { recursive: true, force: true }));
42
+
43
+ assert.equal(reconcileFlatPhaseBootstrapLayout(base), true);
44
+ assert.equal(existsSync(join(base, ".gsd", "phases")), true);
45
+ assert.equal(existsSync(join(base, ".gsd", "milestones")), false);
46
+ });