@opengsd/gsd-pi 1.8.1 → 1.9.0-dev.5c1a3ff2

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 (546) hide show
  1. package/README.md +10 -8
  2. package/dist/cli.js +5 -1
  3. package/dist/headless-events.d.ts +2 -1
  4. package/dist/headless-events.js +11 -3
  5. package/dist/headless-milestone-readiness.d.ts +29 -0
  6. package/dist/headless-milestone-readiness.js +161 -0
  7. package/dist/headless.js +25 -2
  8. package/dist/print-mode-exit.d.ts +12 -0
  9. package/dist/print-mode-exit.js +14 -0
  10. package/dist/resources/.managed-resources-content-hash +1 -1
  11. package/dist/resources/GSD-WORKFLOW.md +18 -49
  12. package/dist/resources/extensions/browser-tools/capture.js +2 -77
  13. package/dist/resources/extensions/browser-tools/screenshot-constraints.js +83 -0
  14. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +17 -2
  15. package/dist/resources/extensions/claude-code-cli/turn-assembler.js +30 -2
  16. package/dist/resources/extensions/gsd/artifact-verification.js +3 -4
  17. package/dist/resources/extensions/gsd/auto-artifact-paths.js +16 -10
  18. package/dist/resources/extensions/gsd/auto-dispatch.js +74 -19
  19. package/dist/resources/extensions/gsd/auto-post-unit.js +4 -0
  20. package/dist/resources/extensions/gsd/auto-prompts.js +125 -18
  21. package/dist/resources/extensions/gsd/auto-recovery.js +10 -5
  22. package/dist/resources/extensions/gsd/auto-worktree-cleanup.js +4 -0
  23. package/dist/resources/extensions/gsd/auto-worktree-teardown.js +1 -1
  24. package/dist/resources/extensions/gsd/auto.js +5 -1
  25. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +80 -4
  26. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +31 -5
  27. package/dist/resources/extensions/gsd/bootstrap/system-context.js +10 -3
  28. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +88 -50
  29. package/dist/resources/extensions/gsd/command-feedback.js +16 -12
  30. package/dist/resources/extensions/gsd/compat/compat-marker.js +19 -2
  31. package/dist/resources/extensions/gsd/constants.js +12 -13
  32. package/dist/resources/extensions/gsd/context-masker.js +97 -21
  33. package/dist/resources/extensions/gsd/db/command-queue.js +7 -2
  34. package/dist/resources/extensions/gsd/db/engine.js +51 -16
  35. package/dist/resources/extensions/gsd/db/writers/cascades.js +5 -1
  36. package/dist/resources/extensions/gsd/db/writers/status.js +13 -3
  37. package/dist/resources/extensions/gsd/db-base-schema.js +28 -0
  38. package/dist/resources/extensions/gsd/db-migration-steps.js +30 -0
  39. package/dist/resources/extensions/gsd/db-schema-metadata.js +4 -1
  40. package/dist/resources/extensions/gsd/docs/preferences-reference.md +26 -4
  41. package/dist/resources/extensions/gsd/doctor-engine-checks.js +3 -6
  42. package/dist/resources/extensions/gsd/flat-phase-migration.js +156 -21
  43. package/dist/resources/extensions/gsd/git-service.js +19 -7
  44. package/dist/resources/extensions/gsd/gsd-db.js +187 -45
  45. package/dist/resources/extensions/gsd/guided-flow.js +38 -13
  46. package/dist/resources/extensions/gsd/markdown-renderer.js +17 -13
  47. package/dist/resources/extensions/gsd/md-importer.js +107 -20
  48. package/dist/resources/extensions/gsd/migrate/command.js +19 -162
  49. package/dist/resources/extensions/gsd/migrate/execution.js +98 -0
  50. package/dist/resources/extensions/gsd/migrate/plan.js +49 -0
  51. package/dist/resources/extensions/gsd/migrate/planning-writer.js +12 -17
  52. package/dist/resources/extensions/gsd/migrate/presentation.js +64 -0
  53. package/dist/resources/extensions/gsd/model-cost-table.js +2 -0
  54. package/dist/resources/extensions/gsd/model-router.js +11 -0
  55. package/dist/resources/extensions/gsd/parallel-eligibility.js +5 -4
  56. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +28 -43
  57. package/dist/resources/extensions/gsd/paths.js +55 -11
  58. package/dist/resources/extensions/gsd/phase-anchor.js +7 -2
  59. package/dist/resources/extensions/gsd/planning-subagent-policy.js +37 -0
  60. package/dist/resources/extensions/gsd/planning-subagent-registry.js +25 -0
  61. package/dist/resources/extensions/gsd/post-execution-checks.js +4 -4
  62. package/dist/resources/extensions/gsd/preferences-types.js +5 -0
  63. package/dist/resources/extensions/gsd/preferences-validation.js +48 -1
  64. package/dist/resources/extensions/gsd/preferences.js +17 -0
  65. package/dist/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  66. package/dist/resources/extensions/gsd/provider-payload-policy.js +16 -5
  67. package/dist/resources/extensions/gsd/safety/destructive-guard.js +1 -1
  68. package/dist/resources/extensions/gsd/safety/evidence-collector.js +26 -1
  69. package/dist/resources/extensions/gsd/safety/evidence-cross-ref.js +30 -5
  70. package/dist/resources/extensions/gsd/skill-activation.js +17 -3
  71. package/dist/resources/extensions/gsd/state-reconciliation/drift/external-markdown-edit.js +27 -13
  72. package/dist/resources/extensions/gsd/state-reconciliation/drift/external-planning-edit.js +13 -3
  73. package/dist/resources/extensions/gsd/stop-notice.js +15 -1
  74. package/dist/resources/extensions/gsd/sync-lock.js +13 -7
  75. package/dist/resources/extensions/gsd/templates/PREFERENCES.md +5 -0
  76. package/dist/resources/extensions/gsd/tools/complete-task.js +94 -6
  77. package/dist/resources/extensions/gsd/tools/plan-task.js +13 -15
  78. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +18 -15
  79. package/dist/resources/extensions/gsd/tools/reopen-milestone.js +14 -5
  80. package/dist/resources/extensions/gsd/tools/reopen-slice.js +15 -5
  81. package/dist/resources/extensions/gsd/tools/reopen-task.js +16 -10
  82. package/dist/resources/extensions/gsd/tools/replan-task.js +128 -0
  83. package/dist/resources/extensions/gsd/tools/rework-brief.js +74 -0
  84. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +81 -0
  85. package/dist/resources/extensions/gsd/unit-context-composer.js +28 -5
  86. package/dist/resources/extensions/gsd/unit-registry.js +4 -0
  87. package/dist/resources/extensions/gsd/uok/plan-v2.js +19 -3
  88. package/dist/resources/extensions/gsd/workflow-projections.js +2 -3
  89. package/dist/resources/extensions/gsd/workspace.js +2 -1
  90. package/dist/resources/extensions/gsd/worktree-state-projection.js +6 -0
  91. package/dist/resources/extensions/mac-tools/index.js +31 -9
  92. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  93. package/dist/web/standalone/.next/BUILD_ID +1 -1
  94. package/dist/web/standalone/.next/app-path-routes-manifest.json +8 -8
  95. package/dist/web/standalone/.next/build-manifest.json +3 -3
  96. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  97. package/dist/web/standalone/.next/required-server-files.json +3 -3
  98. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  99. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  100. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  101. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  105. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  108. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  109. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  110. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  111. package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -4
  112. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -4
  113. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  114. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -4
  115. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  116. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  117. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  118. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  125. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  137. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/mcp-connections/route_client-reference-manifest.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  159. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  166. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  169. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  172. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  175. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  181. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  182. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  183. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  184. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  185. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  186. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  187. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  188. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  189. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  190. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  191. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  192. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  193. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  194. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  195. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  196. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  197. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  198. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  199. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  200. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  201. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  202. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  203. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  204. package/dist/web/standalone/.next/server/app/index.html +1 -1
  205. package/dist/web/standalone/.next/server/app/index.rsc +5 -5
  206. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  207. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +5 -5
  208. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  209. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -4
  210. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  211. package/dist/web/standalone/.next/server/app/page.js +2 -2
  212. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  213. package/dist/web/standalone/.next/server/app-paths-manifest.json +8 -8
  214. package/dist/web/standalone/.next/server/chunks/2842.js +4 -4
  215. package/dist/web/standalone/.next/server/chunks/8357.js +3 -3
  216. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  217. package/dist/web/standalone/.next/server/middleware.js +3 -3
  218. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  219. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  220. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  221. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-a6fb1847f67f167c.js +1 -0
  222. package/dist/web/standalone/.next/static/chunks/app/{layout-b35cbfff38aaf4cf.js → layout-4ae2d68984392bbf.js} +1 -1
  223. package/dist/web/standalone/.next/static/chunks/app/page-72a856634ad14c10.js +1 -0
  224. package/dist/web/standalone/.next/static/chunks/{main-app-590a74400e35f685.js → main-app-90d1d8d5e5d2dc6b.js} +1 -1
  225. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-1115d46ac61b9823.js +1 -0
  226. package/dist/web/standalone/.next/static/css/3b1ceb7abfb9a230.css +1 -0
  227. package/dist/web/standalone/node_modules/@gsd/native/package.json +1 -1
  228. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  229. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  230. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  231. package/dist/web/standalone/package.json +0 -1
  232. package/dist/web/standalone/server.js +1 -1
  233. package/dist/web-mode.js +31 -3
  234. package/integrations/hermes/open_gsd_hermes/gsd_client.py +1 -1
  235. package/integrations/hermes/pyproject.toml +1 -1
  236. package/package.json +12 -10
  237. package/packages/cloud-mcp-gateway/package.json +2 -2
  238. package/packages/contracts/dist/workflow.d.ts +14 -0
  239. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  240. package/packages/contracts/dist/workflow.js +16 -0
  241. package/packages/contracts/dist/workflow.js.map +1 -1
  242. package/packages/contracts/package.json +1 -1
  243. package/packages/daemon/dist/cloud-config.d.ts +1 -1
  244. package/packages/daemon/dist/cloud-config.d.ts.map +1 -1
  245. package/packages/daemon/dist/cloud-config.js +5 -1
  246. package/packages/daemon/dist/cloud-config.js.map +1 -1
  247. package/packages/daemon/dist/cloud-config.test.js +51 -1
  248. package/packages/daemon/dist/cloud-config.test.js.map +1 -1
  249. package/packages/daemon/dist/local-tool-executor.d.ts.map +1 -1
  250. package/packages/daemon/dist/local-tool-executor.js +2 -0
  251. package/packages/daemon/dist/local-tool-executor.js.map +1 -1
  252. package/packages/daemon/package.json +6 -6
  253. package/packages/gsd-agent-core/dist/compaction/compaction.d.ts.map +1 -1
  254. package/packages/gsd-agent-core/dist/compaction/compaction.js +36 -4
  255. package/packages/gsd-agent-core/dist/compaction/compaction.js.map +1 -1
  256. package/packages/gsd-agent-core/dist/sdk.d.ts.map +1 -1
  257. package/packages/gsd-agent-core/dist/sdk.js +1 -0
  258. package/packages/gsd-agent-core/dist/sdk.js.map +1 -1
  259. package/packages/gsd-agent-core/package.json +5 -5
  260. package/packages/gsd-agent-modes/package.json +7 -7
  261. package/packages/gsd-cloud/dist/cli.d.ts +5 -0
  262. package/packages/gsd-cloud/dist/cli.d.ts.map +1 -0
  263. package/packages/gsd-cloud/dist/cli.js +160 -0
  264. package/packages/gsd-cloud/dist/cli.js.map +1 -0
  265. package/packages/gsd-cloud/dist/cloud-config.d.ts +19 -0
  266. package/packages/gsd-cloud/dist/cloud-config.d.ts.map +1 -0
  267. package/packages/gsd-cloud/dist/cloud-config.js +231 -0
  268. package/packages/gsd-cloud/dist/cloud-config.js.map +1 -0
  269. package/packages/gsd-cloud/dist/cloud-config.test.d.ts +2 -0
  270. package/packages/gsd-cloud/dist/cloud-config.test.d.ts.map +1 -0
  271. package/packages/gsd-cloud/dist/cloud-config.test.js +118 -0
  272. package/packages/gsd-cloud/dist/cloud-config.test.js.map +1 -0
  273. package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.d.ts +2 -0
  274. package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.d.ts.map +1 -0
  275. package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.js +37 -0
  276. package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.js.map +1 -0
  277. package/packages/gsd-cloud/dist/cloud-runtime.d.ts +35 -0
  278. package/packages/gsd-cloud/dist/cloud-runtime.d.ts.map +1 -0
  279. package/packages/gsd-cloud/dist/cloud-runtime.js +258 -0
  280. package/packages/gsd-cloud/dist/cloud-runtime.js.map +1 -0
  281. package/packages/gsd-cloud/dist/cloud-runtime.test.d.ts +2 -0
  282. package/packages/gsd-cloud/dist/cloud-runtime.test.d.ts.map +1 -0
  283. package/packages/gsd-cloud/dist/cloud-runtime.test.js +88 -0
  284. package/packages/gsd-cloud/dist/cloud-runtime.test.js.map +1 -0
  285. package/packages/gsd-cloud/dist/cloud-token.d.ts +3 -0
  286. package/packages/gsd-cloud/dist/cloud-token.d.ts.map +1 -0
  287. package/packages/gsd-cloud/dist/cloud-token.js +37 -0
  288. package/packages/gsd-cloud/dist/cloud-token.js.map +1 -0
  289. package/packages/gsd-cloud/dist/config.d.ts +17 -0
  290. package/packages/gsd-cloud/dist/config.d.ts.map +1 -0
  291. package/packages/gsd-cloud/dist/config.js +146 -0
  292. package/packages/gsd-cloud/dist/config.js.map +1 -0
  293. package/packages/gsd-cloud/dist/device-flow.d.ts +24 -0
  294. package/packages/gsd-cloud/dist/device-flow.d.ts.map +1 -0
  295. package/packages/gsd-cloud/dist/device-flow.js +128 -0
  296. package/packages/gsd-cloud/dist/device-flow.js.map +1 -0
  297. package/packages/gsd-cloud/dist/device-flow.test.d.ts +2 -0
  298. package/packages/gsd-cloud/dist/device-flow.test.d.ts.map +1 -0
  299. package/packages/gsd-cloud/dist/device-flow.test.js +155 -0
  300. package/packages/gsd-cloud/dist/device-flow.test.js.map +1 -0
  301. package/packages/gsd-cloud/dist/executors/claude-executor.d.ts +6 -0
  302. package/packages/gsd-cloud/dist/executors/claude-executor.d.ts.map +1 -0
  303. package/packages/gsd-cloud/dist/executors/claude-executor.js +15 -0
  304. package/packages/gsd-cloud/dist/executors/claude-executor.js.map +1 -0
  305. package/packages/gsd-cloud/dist/executors/codex-executor.d.ts +6 -0
  306. package/packages/gsd-cloud/dist/executors/codex-executor.d.ts.map +1 -0
  307. package/packages/gsd-cloud/dist/executors/codex-executor.js +15 -0
  308. package/packages/gsd-cloud/dist/executors/codex-executor.js.map +1 -0
  309. package/packages/gsd-cloud/dist/executors/executor.d.ts +28 -0
  310. package/packages/gsd-cloud/dist/executors/executor.d.ts.map +1 -0
  311. package/packages/gsd-cloud/dist/executors/executor.js +11 -0
  312. package/packages/gsd-cloud/dist/executors/executor.js.map +1 -0
  313. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.d.ts +34 -0
  314. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.d.ts.map +1 -0
  315. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.js +179 -0
  316. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.js.map +1 -0
  317. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.d.ts +2 -0
  318. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.d.ts.map +1 -0
  319. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.js +44 -0
  320. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.js.map +1 -0
  321. package/packages/gsd-cloud/dist/executors/index.d.ts +17 -0
  322. package/packages/gsd-cloud/dist/executors/index.d.ts.map +1 -0
  323. package/packages/gsd-cloud/dist/executors/index.js +29 -0
  324. package/packages/gsd-cloud/dist/executors/index.js.map +1 -0
  325. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.d.ts +36 -0
  326. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.d.ts.map +1 -0
  327. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.js +176 -0
  328. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.js.map +1 -0
  329. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.d.ts +2 -0
  330. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.d.ts.map +1 -0
  331. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.js +34 -0
  332. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.js.map +1 -0
  333. package/packages/gsd-cloud/dist/index.d.ts +7 -0
  334. package/packages/gsd-cloud/dist/index.d.ts.map +1 -0
  335. package/packages/gsd-cloud/dist/index.js +8 -0
  336. package/packages/gsd-cloud/dist/index.js.map +1 -0
  337. package/packages/gsd-cloud/dist/inject-gateway.d.ts +16 -0
  338. package/packages/gsd-cloud/dist/inject-gateway.d.ts.map +1 -0
  339. package/packages/gsd-cloud/dist/inject-gateway.js +29 -0
  340. package/packages/gsd-cloud/dist/inject-gateway.js.map +1 -0
  341. package/packages/gsd-cloud/dist/inject-gateway.test.d.ts +2 -0
  342. package/packages/gsd-cloud/dist/inject-gateway.test.d.ts.map +1 -0
  343. package/packages/gsd-cloud/dist/inject-gateway.test.js +41 -0
  344. package/packages/gsd-cloud/dist/inject-gateway.test.js.map +1 -0
  345. package/packages/gsd-cloud/dist/logger.d.ts +25 -0
  346. package/packages/gsd-cloud/dist/logger.d.ts.map +1 -0
  347. package/packages/gsd-cloud/dist/logger.js +72 -0
  348. package/packages/gsd-cloud/dist/logger.js.map +1 -0
  349. package/packages/gsd-cloud/dist/types.d.ts +51 -0
  350. package/packages/gsd-cloud/dist/types.d.ts.map +1 -0
  351. package/packages/gsd-cloud/dist/types.js +9 -0
  352. package/packages/gsd-cloud/dist/types.js.map +1 -0
  353. package/packages/gsd-cloud/package.json +3 -3
  354. package/packages/mcp-server/README.md +15 -2
  355. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  356. package/packages/mcp-server/dist/server.js +5 -5
  357. package/packages/mcp-server/dist/server.js.map +1 -1
  358. package/packages/mcp-server/dist/workflow-tools.d.ts +4 -3
  359. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  360. package/packages/mcp-server/dist/workflow-tools.js +64 -2
  361. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  362. package/packages/mcp-server/package.json +4 -4
  363. package/packages/native/package.json +1 -1
  364. package/packages/pi-agent-core/dist/agent.d.ts +5 -1
  365. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  366. package/packages/pi-agent-core/dist/agent.js +2 -0
  367. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  368. package/packages/pi-agent-core/package.json +1 -1
  369. package/packages/pi-ai/dist/models.generated.d.ts +119 -0
  370. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  371. package/packages/pi-ai/dist/models.generated.js +107 -0
  372. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  373. package/packages/pi-ai/dist/providers/amazon-bedrock.js +1 -0
  374. package/packages/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
  375. package/packages/pi-ai/dist/providers/anthropic.js +25 -1
  376. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  377. package/packages/pi-ai/dist/providers/openai-codex-responses.js +1 -1
  378. package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
  379. package/packages/pi-ai/dist/providers/openai-responses.js +1 -1
  380. package/packages/pi-ai/dist/providers/openai-responses.js.map +1 -1
  381. package/packages/pi-ai/package.json +1 -1
  382. package/packages/pi-coding-agent/dist/core/capability-patches.js +1 -1
  383. package/packages/pi-coding-agent/dist/core/capability-patches.js.map +1 -1
  384. package/packages/pi-coding-agent/dist/core/model-resolver.js +1 -1
  385. package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
  386. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +11 -1
  387. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  388. package/packages/pi-coding-agent/dist/core/settings-manager.js +8 -0
  389. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  390. package/packages/pi-coding-agent/package.json +7 -7
  391. package/packages/pi-tui/package.json +2 -2
  392. package/packages/rpc-client/package.json +2 -2
  393. package/pkg/package.json +1 -1
  394. package/src/resources/GSD-WORKFLOW.md +18 -49
  395. package/src/resources/extensions/browser-tools/capture.ts +2 -86
  396. package/src/resources/extensions/browser-tools/screenshot-constraints.ts +94 -0
  397. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +18 -1
  398. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +108 -0
  399. package/src/resources/extensions/claude-code-cli/turn-assembler.ts +30 -2
  400. package/src/resources/extensions/gsd/artifact-verification.ts +3 -8
  401. package/src/resources/extensions/gsd/auto-artifact-paths.ts +16 -9
  402. package/src/resources/extensions/gsd/auto-dispatch.ts +86 -19
  403. package/src/resources/extensions/gsd/auto-post-unit.ts +4 -0
  404. package/src/resources/extensions/gsd/auto-prompts.ts +142 -16
  405. package/src/resources/extensions/gsd/auto-recovery.ts +10 -8
  406. package/src/resources/extensions/gsd/auto-worktree-cleanup.ts +4 -0
  407. package/src/resources/extensions/gsd/auto-worktree-teardown.ts +1 -1
  408. package/src/resources/extensions/gsd/auto.ts +5 -1
  409. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +92 -4
  410. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +39 -10
  411. package/src/resources/extensions/gsd/bootstrap/system-context.ts +11 -3
  412. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +87 -53
  413. package/src/resources/extensions/gsd/command-feedback.ts +19 -12
  414. package/src/resources/extensions/gsd/compat/compat-marker.ts +21 -4
  415. package/src/resources/extensions/gsd/constants.ts +14 -13
  416. package/src/resources/extensions/gsd/context-masker.ts +98 -2
  417. package/src/resources/extensions/gsd/db/command-queue.ts +7 -1
  418. package/src/resources/extensions/gsd/db/engine.ts +53 -17
  419. package/src/resources/extensions/gsd/db/writers/cascades.ts +5 -1
  420. package/src/resources/extensions/gsd/db/writers/status.ts +25 -8
  421. package/src/resources/extensions/gsd/db-base-schema.ts +30 -0
  422. package/src/resources/extensions/gsd/db-migration-steps.ts +32 -0
  423. package/src/resources/extensions/gsd/db-schema-metadata.ts +4 -1
  424. package/src/resources/extensions/gsd/docs/preferences-reference.md +26 -4
  425. package/src/resources/extensions/gsd/doctor-engine-checks.ts +3 -5
  426. package/src/resources/extensions/gsd/flat-phase-migration.ts +160 -19
  427. package/src/resources/extensions/gsd/git-service.ts +19 -6
  428. package/src/resources/extensions/gsd/gsd-db.ts +255 -52
  429. package/src/resources/extensions/gsd/guided-flow.ts +48 -12
  430. package/src/resources/extensions/gsd/markdown-renderer.ts +25 -21
  431. package/src/resources/extensions/gsd/md-importer.ts +114 -16
  432. package/src/resources/extensions/gsd/migrate/command.ts +21 -227
  433. package/src/resources/extensions/gsd/migrate/execution.ts +136 -0
  434. package/src/resources/extensions/gsd/migrate/plan.ts +101 -0
  435. package/src/resources/extensions/gsd/migrate/planning-writer.ts +12 -20
  436. package/src/resources/extensions/gsd/migrate/presentation.ts +83 -0
  437. package/src/resources/extensions/gsd/model-cost-table.ts +2 -0
  438. package/src/resources/extensions/gsd/model-router.ts +12 -0
  439. package/src/resources/extensions/gsd/parallel-eligibility.ts +5 -4
  440. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +37 -40
  441. package/src/resources/extensions/gsd/paths.ts +62 -11
  442. package/src/resources/extensions/gsd/phase-anchor.ts +8 -2
  443. package/src/resources/extensions/gsd/planning-subagent-policy.ts +58 -0
  444. package/src/resources/extensions/gsd/planning-subagent-registry.ts +31 -0
  445. package/src/resources/extensions/gsd/post-execution-checks.ts +4 -4
  446. package/src/resources/extensions/gsd/preferences-types.ts +16 -0
  447. package/src/resources/extensions/gsd/preferences-validation.ts +62 -0
  448. package/src/resources/extensions/gsd/preferences.ts +25 -0
  449. package/src/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  450. package/src/resources/extensions/gsd/provider-payload-policy.ts +18 -4
  451. package/src/resources/extensions/gsd/safety/destructive-guard.ts +1 -1
  452. package/src/resources/extensions/gsd/safety/evidence-collector.ts +28 -1
  453. package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +31 -5
  454. package/src/resources/extensions/gsd/skill-activation.ts +17 -3
  455. package/src/resources/extensions/gsd/state-reconciliation/drift/external-markdown-edit.ts +30 -13
  456. package/src/resources/extensions/gsd/state-reconciliation/drift/external-planning-edit.ts +16 -3
  457. package/src/resources/extensions/gsd/state-reconciliation/types.ts +2 -2
  458. package/src/resources/extensions/gsd/stop-notice.ts +18 -1
  459. package/src/resources/extensions/gsd/sync-lock.ts +14 -6
  460. package/src/resources/extensions/gsd/templates/PREFERENCES.md +5 -0
  461. package/src/resources/extensions/gsd/tests/auto-artifact-paths.test.ts +7 -7
  462. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +39 -0
  463. package/src/resources/extensions/gsd/tests/before-provider-context-management.test.ts +55 -0
  464. package/src/resources/extensions/gsd/tests/closeout-git-deferral.test.ts +96 -1
  465. package/src/resources/extensions/gsd/tests/command-feedback.test.ts +12 -0
  466. package/src/resources/extensions/gsd/tests/compat-marker.test.ts +104 -0
  467. package/src/resources/extensions/gsd/tests/complete-task.test.ts +362 -1
  468. package/src/resources/extensions/gsd/tests/context-masker.test.ts +204 -8
  469. package/src/resources/extensions/gsd/tests/db-engine-migrate-guards.test.ts +186 -0
  470. package/src/resources/extensions/gsd/tests/db-tools-alias-suppression.test.ts +62 -0
  471. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +29 -0
  472. package/src/resources/extensions/gsd/tests/destructive-confirmation.test.ts +33 -0
  473. package/src/resources/extensions/gsd/tests/destructive-guard.test.ts +14 -0
  474. package/src/resources/extensions/gsd/tests/discuss-routing-fixes.test.ts +123 -0
  475. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +50 -0
  476. package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +49 -0
  477. package/src/resources/extensions/gsd/tests/evidence-cross-ref.test.ts +81 -0
  478. package/src/resources/extensions/gsd/tests/evidence-xref-gsd-exec.test.ts +22 -0
  479. package/src/resources/extensions/gsd/tests/external-edit-scoped-import.test.ts +262 -0
  480. package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +202 -0
  481. package/src/resources/extensions/gsd/tests/gate-storage.test.ts +29 -0
  482. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +25 -0
  483. package/src/resources/extensions/gsd/tests/import-slice-milestone-completion-preserve.test.ts +116 -0
  484. package/src/resources/extensions/gsd/tests/integration/paths.test.ts +22 -4
  485. package/src/resources/extensions/gsd/tests/integration-branch-meta-location.test.ts +62 -0
  486. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +5 -5
  487. package/src/resources/extensions/gsd/tests/migrate-plan.test.ts +68 -0
  488. package/src/resources/extensions/gsd/tests/migrate-presentation.test.ts +98 -0
  489. package/src/resources/extensions/gsd/tests/migrate-safety-audit.test.ts +1 -1
  490. package/src/resources/extensions/gsd/tests/milestone-leases.test.ts +55 -0
  491. package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
  492. package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
  493. package/src/resources/extensions/gsd/tests/parallel-eligibility-file-overlap.test.ts +146 -0
  494. package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +59 -0
  495. package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +7 -5
  496. package/src/resources/extensions/gsd/tests/phase-anchor.test.ts +32 -4
  497. package/src/resources/extensions/gsd/tests/plan-task.test.ts +26 -23
  498. package/src/resources/extensions/gsd/tests/planning-writer.test.ts +29 -0
  499. package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +22 -0
  500. package/src/resources/extensions/gsd/tests/preferences.test.ts +84 -0
  501. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +4 -0
  502. package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +66 -0
  503. package/src/resources/extensions/gsd/tests/reactive-executor.test.ts +39 -0
  504. package/src/resources/extensions/gsd/tests/reassess-handler.test.ts +50 -0
  505. package/src/resources/extensions/gsd/tests/replan-task-handler.test.ts +103 -0
  506. package/src/resources/extensions/gsd/tests/rework-brief.test.ts +197 -0
  507. package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
  508. package/src/resources/extensions/gsd/tests/single-writer-v3-tool-surface.test.ts +33 -7
  509. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +20 -16
  510. package/src/resources/extensions/gsd/tests/skip-slice-cascades-tasks.test.ts +21 -0
  511. package/src/resources/extensions/gsd/tests/stop-notice.test.ts +17 -0
  512. package/src/resources/extensions/gsd/tests/sync-lock.test.ts +19 -0
  513. package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +13 -7
  514. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -0
  515. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +73 -0
  516. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +93 -1
  517. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +2 -0
  518. package/src/resources/extensions/gsd/tests/workflow-migration-gates.test.ts +139 -0
  519. package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +4 -4
  520. package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +36 -0
  521. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +34 -0
  522. package/src/resources/extensions/gsd/tests/write-gate-seam.test.ts +52 -0
  523. package/src/resources/extensions/gsd/tools/complete-task.ts +140 -5
  524. package/src/resources/extensions/gsd/tools/plan-task.ts +14 -16
  525. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +18 -17
  526. package/src/resources/extensions/gsd/tools/reopen-milestone.ts +24 -5
  527. package/src/resources/extensions/gsd/tools/reopen-slice.ts +25 -5
  528. package/src/resources/extensions/gsd/tools/reopen-task.ts +23 -9
  529. package/src/resources/extensions/gsd/tools/replan-task.ts +160 -0
  530. package/src/resources/extensions/gsd/tools/rework-brief.ts +91 -0
  531. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +92 -0
  532. package/src/resources/extensions/gsd/types.ts +11 -0
  533. package/src/resources/extensions/gsd/unit-context-composer.ts +34 -8
  534. package/src/resources/extensions/gsd/unit-registry.ts +4 -0
  535. package/src/resources/extensions/gsd/uok/plan-v2.ts +20 -3
  536. package/src/resources/extensions/gsd/workflow-projections.ts +2 -3
  537. package/src/resources/extensions/gsd/workspace.ts +2 -1
  538. package/src/resources/extensions/gsd/worktree-state-projection.ts +12 -0
  539. package/src/resources/extensions/mac-tools/index.ts +52 -9
  540. package/src/resources/extensions/mac-tools/tests/mac-screenshot-payload.test.cjs +70 -0
  541. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-49f565245e1e4afe.js +0 -1
  542. package/dist/web/standalone/.next/static/chunks/app/page-bc4c723c6a19c6f0.js +0 -1
  543. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ec3eaffc9785ba48.js +0 -1
  544. package/dist/web/standalone/.next/static/css/18c2fdf261bfc1b7.css +0 -1
  545. /package/dist/web/standalone/.next/static/{UaXRrOYxBpG9QBINKhZkg → 6YWV7VAPg-jqjfPswrKZb}/_buildManifest.js +0 -0
  546. /package/dist/web/standalone/.next/static/{UaXRrOYxBpG9QBINKhZkg → 6YWV7VAPg-jqjfPswrKZb}/_ssgManifest.js +0 -0
@@ -17,6 +17,8 @@ import {
17
17
  transaction,
18
18
  updateMilestoneStatus,
19
19
  updateSliceStatus,
20
+ getMilestoneSlices,
21
+ getSliceTasks,
20
22
  _getAdapter,
21
23
  } from './gsd-db.js';
22
24
  import { openWorkflowDatabasePath } from './db-workspace.js';
@@ -29,6 +31,7 @@ import {
29
31
  legacyMilestonesDir,
30
32
  gsdRoot,
31
33
  resolveTaskFiles,
34
+ resolveTaskFile,
32
35
  resolveMilestonePath,
33
36
  } from './paths.js';
34
37
  import { findMilestoneIds } from './guided-flow.js';
@@ -43,6 +46,26 @@ const VALID_MADE_BY = new Set(['human', 'agent', 'collaborative']);
43
46
 
44
47
  const IMPORT_COMPLETE_STATUSES = new Set(['complete', 'done']);
45
48
 
49
+ /**
50
+ * Derive the set of milestone ids a projection entry's `entities` touch. Marker
51
+ * entity ids are fully-qualified DB ids (`M001`, `M001/S01`, `M001/S01/T01`), so
52
+ * the milestone id is always the first `/`-segment — independent of the on-disk
53
+ * layout (legacy `milestones/<MID>/…` vs flat `phases/NN-slug/…`). The
54
+ * external-edit drift repairs (#027) feed this into
55
+ * `migrateHierarchyToDb(..., { statusAuthoritativeMilestones })` to scope status
56
+ * authority to exactly the milestone(s) a drifted file projects. Empty/blank
57
+ * entries are dropped, so an entity-less entry yields an empty set (repair then
58
+ * preserves DB status everywhere — fail toward the DB, not markdown).
59
+ */
60
+ export function milestoneIdsFromEntities(entities: readonly string[]): Set<string> {
61
+ const ids = new Set<string>();
62
+ for (const e of entities) {
63
+ const milestoneId = e.split('/')[0];
64
+ if (milestoneId) ids.add(milestoneId);
65
+ }
66
+ return ids;
67
+ }
68
+
46
69
  /**
47
70
  * Completion timestamp for an entity imported as complete: the SUMMARY.md mtime
48
71
  * when one exists (deterministic, matches the completion drift handler), else
@@ -676,15 +699,35 @@ function findFileByPrefixAndSuffix(dir: string, idPrefix: string, suffix: string
676
699
  * Uses INSERT OR IGNORE for idempotency. Insert order: milestones → slices → tasks.
677
700
  * Ghost milestones (dirs with no CONTEXT, ROADMAP, or SUMMARY) are skipped.
678
701
  *
702
+ * `opts.statusAuthoritativeMilestones` narrows *status* authority. It exists for
703
+ * the scoped external-edit drift repair: detection knows exactly which
704
+ * projection file drifted, but this import walks the whole tree. Without scoping,
705
+ * an unrelated file that is stale from gsd-pi's own miss (a forgotten render)
706
+ * rides along with markdown authority it was never granted and its stale checked
707
+ * checkbox silently reverts a reopened slice/milestone in the DB (#027).
708
+ *
709
+ * - opts absent → full markdown authority for every milestone (initial migration,
710
+ * gsd-core full import, /gsd recover rebuild). Behavior is identical to before.
711
+ * - opts present → for a milestone NOT in the set whose DB row *already exists*,
712
+ * the existing DB status is preserved: the slice upsert is fed the current DB
713
+ * status (so a stale `complete` checkbox can't overwrite a reopened `pending`),
714
+ * and the complete-status backfills are skipped. Milestone rows are already
715
+ * protected by INSERT OR IGNORE. Rows that do not exist yet are inserted with
716
+ * the parsed status regardless of scope (new content is new content).
717
+ *
679
718
  * Returns count of inserted hierarchy items.
680
719
  */
681
- export function migrateHierarchyToDb(basePath: string): {
720
+ export function migrateHierarchyToDb(
721
+ basePath: string,
722
+ opts?: { statusAuthoritativeMilestones?: ReadonlySet<string> },
723
+ ): {
682
724
  milestones: number;
683
725
  slices: number;
684
726
  tasks: number;
685
727
  } {
686
728
  const counts = { milestones: 0, slices: 0, tasks: 0 };
687
729
  const milestoneIds = findMilestoneIds(basePath);
730
+ const statusScope = opts?.statusAuthoritativeMilestones;
688
731
 
689
732
  for (const milestoneId of milestoneIds) {
690
733
  // Check for ghost milestones — skip dirs with no meaningful content
@@ -745,8 +788,30 @@ export function migrateHierarchyToDb(basePath: string): {
745
788
  }
746
789
  }
747
790
 
748
- // Insert milestone (FK parent must come first)
749
- insertMilestone({
791
+ // #027: when a status scope is supplied, a milestone outside it keeps DB
792
+ // status authority for rows that already exist — only the drifted file's
793
+ // milestone(s) may drive status closes from checkboxes. Absent scope, every
794
+ // milestone is authoritative (unchanged full-import behavior).
795
+ const milestoneStatusAuthoritative = !statusScope || statusScope.has(milestoneId);
796
+ // Snapshot existing slice statuses once (only needed when preserving DB
797
+ // authority for this milestone) so the upsert can echo them back instead of
798
+ // flipping an open slice closed from a stale checkbox.
799
+ const existingSliceStatus = new Map<string, string>();
800
+ const existingTaskStatus = new Map<string, string>();
801
+ if (!milestoneStatusAuthoritative) {
802
+ for (const s of getMilestoneSlices(milestoneId)) {
803
+ existingSliceStatus.set(s.id, s.status);
804
+ for (const t of getSliceTasks(milestoneId, s.id)) {
805
+ existingTaskStatus.set(`${s.id}/${t.id}`, t.status);
806
+ }
807
+ }
808
+ }
809
+
810
+ // Insert milestone (FK parent — must come first). INSERT OR IGNORE: an
811
+ // existing milestone row is never overwritten, so DB status is already
812
+ // preserved for out-of-scope milestones. `inserted` tells us whether this
813
+ // row is new (parsed status applies) vs pre-existing (backfill gated below).
814
+ const milestoneInserted = insertMilestone({
750
815
  id: milestoneId,
751
816
  title: milestoneTitle,
752
817
  status: milestoneStatus,
@@ -760,10 +825,14 @@ export function migrateHierarchyToDb(basePath: string): {
760
825
  // insertMilestone never sets completed_at; backfill it now for milestones
761
826
  // imported as complete so the DB is internally coherent immediately after
762
827
  // import (rather than relying on a later reconciliation pass that can't even
763
- // see the drift when no SUMMARY file exists).
764
- if (IMPORT_COMPLETE_STATUSES.has(milestoneStatus)) {
828
+ // see the drift when no SUMMARY file exists). #027: skip the backfill for an
829
+ // out-of-scope milestone that already existed — its DB status is authoritative.
830
+ if (IMPORT_COMPLETE_STATUSES.has(milestoneStatus) && (milestoneStatusAuthoritative || milestoneInserted)) {
765
831
  const summaryPath = resolveMilestoneFile(basePath, milestoneId, 'SUMMARY');
766
- updateMilestoneStatus(milestoneId, milestoneStatus, importCompletionTimestamp(summaryPath));
832
+ // #1291: preserve an existing completion timestamp so a re-import backfills
833
+ // only rows that lack one, never re-stamping an already-complete milestone
834
+ // with the current import time. Same guard as the task path below.
835
+ updateMilestoneStatus(milestoneId, milestoneStatus, importCompletionTimestamp(summaryPath), true);
767
836
  }
768
837
  counts.milestones++;
769
838
 
@@ -783,11 +852,22 @@ export function migrateHierarchyToDb(basePath: string): {
783
852
  plan = parsePlan(planContent);
784
853
  }
785
854
 
855
+ // #027: for an out-of-scope milestone, echo the existing DB status of a
856
+ // slice that already exists so the upsert's `ELSE excluded.status` branch
857
+ // becomes a no-op instead of flipping a reopened `pending` slice back to
858
+ // `complete` from a stale checkbox. New slices (not yet in the DB) take the
859
+ // parsed status regardless of scope.
860
+ const sliceRowExists = existingSliceStatus.has(sliceEntry.id);
861
+ const sliceStatusAuthoritative = milestoneStatusAuthoritative || !sliceRowExists;
862
+ const effectiveSliceStatus = sliceStatusAuthoritative
863
+ ? sliceStatus
864
+ : existingSliceStatus.get(sliceEntry.id)!;
865
+
786
866
  insertSlice({
787
867
  id: sliceEntry.id,
788
868
  milestoneId: milestoneId,
789
869
  title: sliceEntry.title,
790
- status: sliceStatus,
870
+ status: effectiveSliceStatus,
791
871
  risk: sliceEntry.risk,
792
872
  depends: (sliceEntry.depends ?? []).map(d => d.replace(/^\[|\]$/g, '')).filter(d => /^[A-Za-z0-9][A-Za-z0-9-]*$/.test(d)),
793
873
  demo: sliceEntry.demo,
@@ -798,14 +878,19 @@ export function migrateHierarchyToDb(basePath: string): {
798
878
  },
799
879
  });
800
880
  // insertSlice never sets completed_at; backfill it for slices imported as
801
- // complete (same rationale as milestones above).
802
- if (IMPORT_COMPLETE_STATUSES.has(sliceStatus)) {
881
+ // complete (same rationale as milestones above). #027: skip when preserving
882
+ // an out-of-scope slice's existing DB status.
883
+ if (IMPORT_COMPLETE_STATUSES.has(sliceStatus) && sliceStatusAuthoritative) {
803
884
  const sliceSummary = resolveSliceFile(basePath, milestoneId, sliceEntry.id, 'SUMMARY');
885
+ // #1291: preserve an existing completion timestamp so a re-import backfills
886
+ // only slices that lack one, never re-stamping an already-complete slice
887
+ // with the current import time. Same guard as the task path below.
804
888
  updateSliceStatus(
805
889
  milestoneId,
806
890
  sliceEntry.id,
807
891
  sliceStatus,
808
892
  importCompletionTimestamp(sliceSummary),
893
+ true,
809
894
  );
810
895
  }
811
896
  counts.slices++;
@@ -841,8 +926,7 @@ export function migrateHierarchyToDb(basePath: string): {
841
926
  legacyTasksDir = isLegacySlice
842
927
  ? resolveTasksDir(basePath, milestoneId, sliceEntry.id)
843
928
  : null;
844
- const summaryDir = legacyTasksDir ?? slicePath;
845
- taskSummaryFile = join(summaryDir, `${taskEntry.id}-SUMMARY.md`);
929
+ taskSummaryFile = resolveTaskFile(basePath, milestoneId, sliceEntry.id, taskEntry.id, 'SUMMARY');
846
930
  }
847
931
  const hasTaskSummary = taskSummaryFile !== null && existsSync(taskSummaryFile);
848
932
 
@@ -866,9 +950,9 @@ export function migrateHierarchyToDb(basePath: string): {
866
950
  // first execute-task. The surviving SUMMARY wins over a stale checkbox.
867
951
  // reopen-task removes the SUMMARY, so this never re-completes an
868
952
  // intentionally reopened task.
869
- // Flat-phase summaries are phase-scoped (T01-SUMMARY.md); when a milestone
870
- // has multiple slices, require the summary parent frontmatter to match so
871
- // one slice's completion does not attest a sibling's same-named task.
953
+ // Flat-phase summaries are phase-scoped; when a milestone has multiple
954
+ // slices, require the summary parent frontmatter to match so one slice's
955
+ // completion does not attest a sibling's same-named task.
872
956
  let summaryAttestsCompletion = hasTaskSummary;
873
957
  if (summaryAttestsCompletion && !isLegacySlice && roadmap.slices.length > 1 && taskSummaryFile) {
874
958
  try {
@@ -885,12 +969,20 @@ export function migrateHierarchyToDb(basePath: string): {
885
969
  );
886
970
  }
887
971
 
972
+ // #027: same scope guard as slices — out-of-scope milestones echo existing
973
+ // DB task status so stale plan checkboxes cannot re-complete reopened tasks.
974
+ const taskRowExists = existingTaskStatus.has(`${sliceEntry.id}/${taskEntry.id}`);
975
+ const taskStatusAuthoritative = milestoneStatusAuthoritative || !taskRowExists;
976
+ const effectiveTaskStatus = taskStatusAuthoritative
977
+ ? taskStatus
978
+ : existingTaskStatus.get(`${sliceEntry.id}/${taskEntry.id}`)!;
979
+
888
980
  insertTask({
889
981
  id: taskEntry.id,
890
982
  sliceId: sliceEntry.id,
891
983
  milestoneId: milestoneId,
892
984
  title: taskEntry.title,
893
- status: taskStatus,
985
+ status: effectiveTaskStatus,
894
986
  planning: {
895
987
  files: taskEntry.files ?? [],
896
988
  verify: taskEntry.verify ?? '',
@@ -940,13 +1032,19 @@ export function migrateHierarchyToDb(basePath: string): {
940
1032
  // checkbox (#1222); flat-phase checkboxes are authoritative without summary.
941
1033
  return summaryAttestsCompletion || (t.done && !isLegacySliceLayout);
942
1034
  });
943
- if (allTasksDone && hasSliceSummary) {
1035
+ // #027: the same close guard as the backfill above — a stale slice
1036
+ // SUMMARY under an out-of-scope milestone must not upgrade a reopened
1037
+ // slice to complete. New slices stay authoritative.
1038
+ if (allTasksDone && hasSliceSummary && sliceStatusAuthoritative) {
944
1039
  if (_getAdapter()) {
1040
+ // #1291: preserve an existing completion timestamp — this consistency
1041
+ // upgrade sets a completion time only when the row lacks one.
945
1042
  updateSliceStatus(
946
1043
  milestoneId,
947
1044
  sliceEntry.id,
948
1045
  'complete',
949
1046
  importCompletionTimestamp(sliceSummaryPath),
1047
+ true,
950
1048
  );
951
1049
  process.stderr.write(
952
1050
  `gsd-migrate: ${milestoneId}/${sliceEntry.id} all tasks + slice summary complete — upgrading slice to complete\n`,
@@ -10,198 +10,24 @@
10
10
  */
11
11
 
12
12
  import type { ExtensionAPI, ExtensionCommandContext } from "@gsd/pi-coding-agent";
13
- import { existsSync, readFileSync } from "node:fs";
14
- import { join, dirname } from "node:path";
15
13
  import { gsdRoot } from "../paths.js";
16
- import { fileURLToPath } from "node:url";
17
14
  import { showNextAction } from "../../shared/tui.js";
18
15
  import {
19
16
  notifyMigrateNeedsInteractiveMenu,
20
17
  requiresInteractiveMenu,
21
18
  } from "../command-feedback.js";
22
- import {
23
- validatePlanningDirectory,
24
- parsePlanningDirectory,
25
- transformToGSD,
26
- generatePreview,
27
- writeGSDDirectory,
28
- } from "./index.js";
29
-
30
- import type { MigrationPreview, WrittenFiles } from "./writer.js";
31
- import { ensureDbOpen } from "../bootstrap/dynamic-tools.js";
32
- import { clearArtifacts, clearDecisions, clearRequirements, clearEngineHierarchy, transaction } from "../gsd-db.js";
33
- import { migrateFromMarkdown } from "../md-importer.js";
34
- import { deriveState, invalidateStateCache } from "../state.js";
35
- import {
36
- archiveLegacyPlanningDirectory,
37
- verifyMigrationProjection,
38
- writeMigrationAudit,
39
- type LegacyArchiveResult,
40
- type MigrationAuditResult,
41
- type MigrationProjectionVerification,
42
- } from "./audit.js";
43
- import {
44
- assertMigrationHasSlices,
45
- assertMigrationTargetAvailable,
46
- prepareMigrationTarget,
47
- resolveMigrationPaths,
48
- restoreMigrationTarget,
49
- type MigrationBackup,
50
- } from "./safety.js";
51
-
52
- export type MigrationImportCounts = ReturnType<typeof migrateFromMarkdown>;
53
-
54
- export interface MigrationExecutionResult {
55
- backup: MigrationBackup;
56
- written: WrittenFiles;
57
- imported: MigrationImportCounts;
58
- legacyArchive: LegacyArchiveResult;
59
- verification: MigrationProjectionVerification;
60
- audit: MigrationAuditResult;
61
- }
62
-
63
- function assertMigrationImportMatchesPreview(imported: MigrationImportCounts, preview: MigrationPreview): void {
64
- const mismatches: string[] = [];
65
- if (imported.decisions !== preview.decisions.total) {
66
- mismatches.push(`decisions ${imported.decisions}/${preview.decisions.total}`);
67
- }
68
- if (imported.hierarchy.milestones !== preview.milestoneCount) {
69
- mismatches.push(`milestones ${imported.hierarchy.milestones}/${preview.milestoneCount}`);
70
- }
71
- if (imported.hierarchy.slices !== preview.totalSlices) {
72
- mismatches.push(`slices ${imported.hierarchy.slices}/${preview.totalSlices}`);
73
- }
74
- if (imported.hierarchy.tasks !== preview.totalTasks) {
75
- mismatches.push(`tasks ${imported.hierarchy.tasks}/${preview.totalTasks}`);
76
- }
77
- if (imported.requirements !== preview.requirements.total) {
78
- mismatches.push(`requirements ${imported.requirements}/${preview.requirements.total}`);
79
- }
80
- if (mismatches.length > 0) {
81
- throw new Error(`migration DB import verification failed: ${mismatches.join(", ")}`);
82
- }
83
- }
19
+ import { executeMigrationWrite, type MigrationExecutionResult } from "./execution.js";
20
+ import { createMigrationPlan } from "./plan.js";
21
+ import { buildMigrationPreviewSummary, buildReviewPrompt } from "./presentation.js";
22
+ import type { MigrationPreview } from "./writer.js";
84
23
 
85
- export async function importWrittenMigrationToDb(
86
- basePath: string,
87
- preview?: MigrationPreview,
88
- ): Promise<MigrationImportCounts> {
89
- const opened = await ensureDbOpen(basePath);
90
- if (!opened) {
91
- throw new Error(`failed to open or create the GSD database at ${basePath}`);
92
- }
93
-
94
- const counts = transaction(() => {
95
- clearEngineHierarchy();
96
- clearArtifacts();
97
- clearDecisions();
98
- clearRequirements();
99
- const imported = migrateFromMarkdown(basePath);
100
- if (preview) assertMigrationImportMatchesPreview(imported, preview);
101
- return imported;
102
- });
103
- invalidateStateCache();
104
- return counts;
105
- }
106
-
107
- export async function assertMigrationDbReadiness(
108
- targetRoot: string,
109
- preview: MigrationPreview,
110
- ): Promise<{ phase: string; registry: number }> {
111
- invalidateStateCache();
112
- const state = await deriveState(targetRoot);
113
- const dbUnavailable = state.blockers.some((blocker) => blocker.includes("DB unavailable"));
114
- if (dbUnavailable) {
115
- throw new Error(`migration DB readiness failed: ${state.blockers.join("; ")}`);
116
- }
117
- if (state.registry.length !== preview.milestoneCount) {
118
- throw new Error(`migration DB readiness failed: registry ${state.registry.length}/${preview.milestoneCount}`);
119
- }
120
- return {
121
- phase: state.phase,
122
- registry: state.registry.length,
123
- };
124
- }
125
-
126
- export async function executeMigrationWrite(
127
- sourcePath: string,
128
- targetRoot: string,
129
- project: ReturnType<typeof transformToGSD>,
130
- preview: MigrationPreview,
131
- startedAt: string = new Date().toISOString(),
132
- ): Promise<MigrationExecutionResult> {
133
- const backup = prepareMigrationTarget(targetRoot);
134
-
135
- try {
136
- const written = await writeGSDDirectory(project, targetRoot);
137
- const legacyArchive = await archiveLegacyPlanningDirectory(sourcePath, targetRoot);
138
- const imported = await importWrittenMigrationToDb(targetRoot, preview);
139
- const verification = await verifyMigrationProjection(targetRoot, preview);
140
- verification.dbReadiness = await assertMigrationDbReadiness(targetRoot, preview);
141
- const audit = await writeMigrationAudit({
142
- sourcePath,
143
- targetRoot,
144
- backupPath: backup.backupPath,
145
- preview,
146
- written,
147
- imported,
148
- legacyArchive,
149
- verification,
150
- startedAt,
151
- completedAt: new Date().toISOString(),
152
- });
153
-
154
- return { backup, written, imported, legacyArchive, verification, audit };
155
- } catch (err) {
156
- restoreMigrationTarget(backup);
157
- throw err;
158
- }
159
- }
160
-
161
- /** Format preview stats for embedding in the review prompt. */
162
- function formatPreviewStats(preview: MigrationPreview): string {
163
- const lines = [
164
- `- Decisions: ${preview.decisions.total}`,
165
- `- Milestones: ${preview.milestoneCount}`,
166
- `- Slices: ${preview.totalSlices} (${preview.doneSlices} done — ${preview.sliceCompletionPct}%)`,
167
- `- Tasks: ${preview.totalTasks} (${preview.doneTasks} done — ${preview.taskCompletionPct}%)`,
168
- ];
169
- if (preview.requirements.total > 0) {
170
- lines.push(
171
- `- Requirements: ${preview.requirements.total} (${preview.requirements.validated} validated, ${preview.requirements.active} active, ${preview.requirements.deferred} deferred, ${preview.requirements.outOfScope} out of scope)`,
172
- );
173
- }
174
- if (preview.migrationInputs) {
175
- lines.push(`- Legacy inputs: ${preview.migrationInputs.milestonePhaseDirs} milestone phase dir(s), ${preview.migrationInputs.decisions} decision file(s), ${preview.migrationInputs.seeds} seed file(s)`);
176
- }
177
- return lines.join("\n");
178
- }
179
-
180
- /** Load and interpolate the review-migration prompt template. */
181
- function buildReviewPrompt(
182
- sourcePath: string,
183
- gsdPath: string,
184
- preview: MigrationPreview,
185
- ): string {
186
- const promptsDir = join(dirname(fileURLToPath(import.meta.url)), "..", "prompts");
187
- const templatePath = join(promptsDir, "review-migration.md");
188
- let content = readFileSync(templatePath, "utf-8");
189
-
190
- content = content.replaceAll("{{sourcePath}}", sourcePath);
191
- content = content.replaceAll("{{gsdPath}}", gsdPath);
192
- content = content.replaceAll("{{previewStats}}", formatPreviewStats(preview));
193
-
194
- return content.trim();
195
- }
196
-
197
- /** Dispatch the review prompt to the agent. */
198
24
  function dispatchReview(
199
25
  pi: ExtensionAPI,
200
26
  sourcePath: string,
201
27
  gsdPath: string,
202
28
  preview: MigrationPreview,
203
29
  ): void {
204
- const prompt = buildReviewPrompt(sourcePath, gsdPath, preview);
30
+ const prompt = buildReviewPrompt({ sourcePath, gsdPath, preview });
205
31
 
206
32
  pi.sendMessage(
207
33
  {
@@ -218,34 +44,28 @@ export async function handleMigrate(
218
44
  ctx: ExtensionCommandContext,
219
45
  pi: ExtensionAPI,
220
46
  ): Promise<void> {
221
- // ── Resolve source path ────────────────────────────────────────────────────
222
- const { sourcePath, targetRoot } = resolveMigrationPaths(args);
47
+ const plan = await createMigrationPlan(args);
48
+ const { sourcePath, targetRoot } = plan;
223
49
 
224
- if (!existsSync(sourcePath)) {
50
+ if (plan.status === "missing-source") {
225
51
  ctx.ui.notify(
226
52
  `Directory not found: ${sourcePath}\n\n` +
227
- 'Migration converts a .planning/ directory (from older GSD versions) into .gsd/ format.\n' +
228
- 'If you are starting a new project, use /gsd:new-project instead.\n' +
229
- 'If migrating, ensure the path contains a .planning/ directory.',
53
+ "Migration converts a .planning/ directory (from older GSD versions) into .gsd/ format.\n" +
54
+ "If you are starting a new project, use /gsd:new-project instead.\n" +
55
+ "If migrating, ensure the path contains a .planning/ directory.",
230
56
  "error",
231
57
  );
232
58
  return;
233
59
  }
234
60
 
235
- // ── Validate ───────────────────────────────────────────────────────────────
236
- const validation = await validatePlanningDirectory(sourcePath);
237
-
238
- const warnings = validation.issues.filter((i) => i.severity === "warning");
239
- const fatals = validation.issues.filter((i) => i.severity === "fatal");
240
-
241
- for (const w of warnings) {
242
- ctx.ui.notify(`⚠ ${w.message} (${w.file})`, "warning");
61
+ for (const warning of plan.warnings) {
62
+ ctx.ui.notify(`⚠ ${warning.message} (${warning.file})`, "warning");
243
63
  }
244
- for (const f of fatals) {
245
- ctx.ui.notify(`✖ ${f.message} (${f.file})`, "error");
64
+ for (const fatal of plan.fatals) {
65
+ ctx.ui.notify(`✖ ${fatal.message} (${fatal.file})`, "error");
246
66
  }
247
67
 
248
- if (!validation.valid) {
68
+ if (plan.status === "invalid") {
249
69
  ctx.ui.notify(
250
70
  "Migration blocked — fix the fatal issues above before retrying.",
251
71
  "error",
@@ -253,41 +73,15 @@ export async function handleMigrate(
253
73
  return;
254
74
  }
255
75
 
256
- // ── Parse Transform → Preview ───────────────────────────────────────────
257
- const parsed = await parsePlanningDirectory(sourcePath);
258
- const project = transformToGSD(parsed);
259
- const preview = generatePreview(project);
260
- try {
261
- assertMigrationHasSlices(preview);
262
- await assertMigrationTargetAvailable(targetRoot);
263
- } catch (err) {
264
- ctx.ui.notify((err as Error).message, "error");
76
+ if (plan.status === "blocked") {
77
+ ctx.ui.notify(plan.message, "error");
265
78
  return;
266
79
  }
267
80
 
268
- // ── Build preview text ─────────────────────────────────────────────────────
269
- const lines: string[] = [
270
- `Decisions: ${preview.decisions.total}`,
271
- `Milestones: ${preview.milestoneCount}`,
272
- `Slices: ${preview.totalSlices} (${preview.doneSlices} done — ${preview.sliceCompletionPct}%)`,
273
- `Tasks: ${preview.totalTasks} (${preview.doneTasks} done — ${preview.taskCompletionPct}%)`,
274
- ];
81
+ const { project, preview } = plan;
275
82
 
276
- if (preview.requirements.total > 0) {
277
- lines.push(
278
- `Requirements: ${preview.requirements.total} (${preview.requirements.validated} validated, ${preview.requirements.active} active, ${preview.requirements.deferred} deferred, ${preview.requirements.outOfScope} out of scope)`,
279
- );
280
- }
281
- if (preview.migrationInputs) {
282
- lines.push(`Legacy inputs: ${preview.migrationInputs.milestonePhaseDirs} milestone phase dir(s), ${preview.migrationInputs.decisions} decision file(s), ${preview.migrationInputs.seeds} seed file(s)`);
283
- }
284
-
285
- const targetGsdExists = existsSync(gsdRoot(targetRoot));
286
- if (targetGsdExists) {
287
- lines.push("");
288
- lines.push(`⚠ A .gsd directory already exists at ${gsdRoot(targetRoot)}.`);
289
- lines.push("It will be backed up, deleted, and rewritten fresh before DB import.");
290
- }
83
+ // ── Build preview text ─────────────────────────────────────────────────────
84
+ const lines = buildMigrationPreviewSummary(preview, targetRoot);
291
85
 
292
86
  // ── Confirmation via showNextAction ────────────────────────────────────────
293
87
  if (requiresInteractiveMenu(ctx, false)) {
@@ -0,0 +1,136 @@
1
+ // gsd-pi - /gsd migrate execution service.
2
+ // File Purpose: Write migrated .gsd files, import them into the DB, verify projection/readiness, and rollback on failure.
3
+
4
+ import { ensureDbOpen } from "../bootstrap/dynamic-tools.js";
5
+ import { closeWorkflowDatabase } from "../db-workspace.js";
6
+ import { clearArtifacts, clearDecisions, clearEngineHierarchy, clearRequirements, transaction } from "../gsd-db.js";
7
+ import { migrateFromMarkdown } from "../md-importer.js";
8
+ import { deriveState, invalidateStateCache } from "../state.js";
9
+ import {
10
+ archiveLegacyPlanningDirectory,
11
+ verifyMigrationProjection,
12
+ writeMigrationAudit,
13
+ type LegacyArchiveResult,
14
+ type MigrationAuditResult,
15
+ type MigrationProjectionVerification,
16
+ } from "./audit.js";
17
+ import {
18
+ prepareMigrationTarget,
19
+ restoreMigrationTarget,
20
+ type MigrationBackup,
21
+ } from "./safety.js";
22
+ import { writeGSDDirectory, type MigrationPreview, type WrittenFiles } from "./writer.js";
23
+ import type { GSDProject } from "./types.js";
24
+
25
+ export type MigrationImportCounts = ReturnType<typeof migrateFromMarkdown>;
26
+
27
+ export interface MigrationExecutionResult {
28
+ backup: MigrationBackup;
29
+ written: WrittenFiles;
30
+ imported: MigrationImportCounts;
31
+ legacyArchive: LegacyArchiveResult;
32
+ verification: MigrationProjectionVerification;
33
+ audit: MigrationAuditResult;
34
+ }
35
+
36
+ function assertMigrationImportMatchesPreview(imported: MigrationImportCounts, preview: MigrationPreview): void {
37
+ const mismatches: string[] = [];
38
+ if (imported.decisions !== preview.decisions.total) {
39
+ mismatches.push(`decisions ${imported.decisions}/${preview.decisions.total}`);
40
+ }
41
+ if (imported.hierarchy.milestones !== preview.milestoneCount) {
42
+ mismatches.push(`milestones ${imported.hierarchy.milestones}/${preview.milestoneCount}`);
43
+ }
44
+ if (imported.hierarchy.slices !== preview.totalSlices) {
45
+ mismatches.push(`slices ${imported.hierarchy.slices}/${preview.totalSlices}`);
46
+ }
47
+ if (imported.hierarchy.tasks !== preview.totalTasks) {
48
+ mismatches.push(`tasks ${imported.hierarchy.tasks}/${preview.totalTasks}`);
49
+ }
50
+ if (imported.requirements !== preview.requirements.total) {
51
+ mismatches.push(`requirements ${imported.requirements}/${preview.requirements.total}`);
52
+ }
53
+ if (mismatches.length > 0) {
54
+ throw new Error(`migration DB import verification failed: ${mismatches.join(", ")}`);
55
+ }
56
+ }
57
+
58
+ export async function importWrittenMigrationToDb(
59
+ basePath: string,
60
+ preview?: MigrationPreview,
61
+ ): Promise<MigrationImportCounts> {
62
+ const opened = await ensureDbOpen(basePath);
63
+ if (!opened) {
64
+ throw new Error(`failed to open or create the GSD database at ${basePath}`);
65
+ }
66
+
67
+ const counts = transaction(() => {
68
+ clearEngineHierarchy();
69
+ clearArtifacts();
70
+ clearDecisions();
71
+ clearRequirements();
72
+ const imported = migrateFromMarkdown(basePath);
73
+ if (preview) assertMigrationImportMatchesPreview(imported, preview);
74
+ return imported;
75
+ });
76
+ invalidateStateCache();
77
+ return counts;
78
+ }
79
+
80
+ export async function assertMigrationDbReadiness(
81
+ targetRoot: string,
82
+ preview: MigrationPreview,
83
+ ): Promise<{ phase: string; registry: number }> {
84
+ invalidateStateCache();
85
+ const state = await deriveState(targetRoot);
86
+ const dbUnavailable = state.blockers.some((blocker) => blocker.includes("DB unavailable"));
87
+ if (dbUnavailable) {
88
+ throw new Error(`migration DB readiness failed: ${state.blockers.join("; ")}`);
89
+ }
90
+ if (state.registry.length !== preview.milestoneCount) {
91
+ throw new Error(`migration DB readiness failed: registry ${state.registry.length}/${preview.milestoneCount}`);
92
+ }
93
+ return {
94
+ phase: state.phase,
95
+ registry: state.registry.length,
96
+ };
97
+ }
98
+
99
+ export async function executeMigrationWrite(
100
+ sourcePath: string,
101
+ targetRoot: string,
102
+ project: GSDProject,
103
+ preview: MigrationPreview,
104
+ startedAt: string = new Date().toISOString(),
105
+ ): Promise<MigrationExecutionResult> {
106
+ const backup = prepareMigrationTarget(targetRoot);
107
+
108
+ try {
109
+ const written = await writeGSDDirectory(project, targetRoot);
110
+ const legacyArchive = await archiveLegacyPlanningDirectory(sourcePath, targetRoot);
111
+ const imported = await importWrittenMigrationToDb(targetRoot, preview);
112
+ const verification = await verifyMigrationProjection(targetRoot, preview);
113
+ verification.dbReadiness = await assertMigrationDbReadiness(targetRoot, preview);
114
+ const audit = await writeMigrationAudit({
115
+ sourcePath,
116
+ targetRoot,
117
+ backupPath: backup.backupPath,
118
+ preview,
119
+ written,
120
+ imported,
121
+ legacyArchive,
122
+ verification,
123
+ startedAt,
124
+ completedAt: new Date().toISOString(),
125
+ });
126
+
127
+ return { backup, written, imported, legacyArchive, verification, audit };
128
+ } catch (error) {
129
+ // The import transaction may have committed and the process may hold an
130
+ // open handle to the target gsd.db; close before the restore replaces the
131
+ // file on disk, and leave closed so the next open rebinds to the restored file.
132
+ try { closeWorkflowDatabase(); } catch { /* best-effort: restore must proceed */ }
133
+ restoreMigrationTarget(backup);
134
+ throw error;
135
+ }
136
+ }