@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
@@ -280,6 +280,31 @@ describe('gsd-db', () => {
280
280
  }
281
281
  });
282
282
 
283
+ test("gsd-db: insertTask stamps completed_at for every complete-alias but not for skipped", () => {
284
+ openDatabase(":memory:");
285
+
286
+ try {
287
+ insertMilestone({ id: "M001", title: "Completion stamp", status: "active" });
288
+ insertSlice({ id: "S01", milestoneId: "M001", title: "Slice", status: "active", sequence: 1 });
289
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", title: "Closed", status: "closed", sequence: 1 });
290
+ insertTask({ id: "T02", sliceId: "S01", milestoneId: "M001", title: "Done", status: "done", sequence: 2 });
291
+ insertTask({ id: "T03", sliceId: "S01", milestoneId: "M001", title: "Skipped", status: "skipped", sequence: 3 });
292
+
293
+ assert.ok(
294
+ getTask("M001", "S01", "T01")?.completed_at,
295
+ "a task imported as 'closed' is terminal and must carry a completed_at",
296
+ );
297
+ assert.ok(getTask("M001", "S01", "T02")?.completed_at, "'done' alias must stamp completed_at");
298
+ assert.equal(
299
+ getTask("M001", "S01", "T03")?.completed_at,
300
+ null,
301
+ "a skipped task was never completed and must have null completed_at",
302
+ );
303
+ } finally {
304
+ closeDatabase();
305
+ }
306
+ });
307
+
283
308
  test('gsd-db: active_decisions view excludes superseded', () => {
284
309
  openDatabase(':memory:');
285
310
 
@@ -0,0 +1,116 @@
1
+ // Project/App: gsd-pi
2
+ // File Purpose: Regression for #1291 — a full markdown re-import must NOT rewrite
3
+ // the completed_at of an already-complete slice or milestone with the current
4
+ // import time. The task path was fixed for this (#1222/#1228) via
5
+ // preserveCompletionMetadata; the slice and milestone backfills in
6
+ // migrateHierarchyToDb had no such guard, so every re-import re-stamped every
7
+ // complete slice/milestone. The fix threads preserveCompletion through
8
+ // updateSliceStatus/updateMilestoneStatus so an existing completed_at survives.
9
+
10
+ import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
11
+ import { join } from 'node:path';
12
+ import { tmpdir } from 'node:os';
13
+
14
+ import {
15
+ openDatabase,
16
+ closeDatabase,
17
+ getAllMilestones,
18
+ getMilestoneSlices,
19
+ updateSliceStatus,
20
+ updateMilestoneStatus,
21
+ } from '../gsd-db.ts';
22
+ import { migrateHierarchyToDb } from '../md-importer.ts';
23
+ import { describe, test, afterEach } from 'node:test';
24
+ import assert from 'node:assert/strict';
25
+
26
+ const tmpDirs: string[] = [];
27
+ afterEach(() => {
28
+ closeDatabase();
29
+ for (const d of tmpDirs) { try { rmSync(d, { recursive: true, force: true }); } catch { /* */ } }
30
+ tmpDirs.length = 0;
31
+ });
32
+
33
+ function createFixtureBase(): string {
34
+ const base = mkdtempSync(join(tmpdir(), 'gsd-preserve-completion-'));
35
+ tmpDirs.push(base);
36
+ return base;
37
+ }
38
+
39
+ function writeFile(base: string, relativePath: string, content: string): void {
40
+ const full = join(base, '.gsd', relativePath);
41
+ mkdirSync(join(full, '..'), { recursive: true });
42
+ writeFileSync(full, content);
43
+ }
44
+
45
+ // All slices [x] → milestone imports complete, slices import complete.
46
+ const ROADMAP_ALL_DONE = `# M001: Finished Milestone
47
+
48
+ **Vision:** Done work.
49
+
50
+ ## Slices
51
+
52
+ - [x] **S01: First Slice** \`risk:low\` \`depends:[]\`
53
+ > After this: Done.
54
+
55
+ - [x] **S02: Second Slice** \`risk:medium\` \`depends:[S01]\`
56
+ > After this: Also done.
57
+ `;
58
+
59
+ const REAL_S01 = '2026-07-05T19:52:04.672Z';
60
+ const REAL_S02 = '2026-07-05T20:36:51.313Z';
61
+ const REAL_M001 = '2026-07-05T21:00:00.000Z';
62
+
63
+ describe('migrateHierarchyToDb: re-import preserves existing completion timestamps (#1291)', () => {
64
+ test('a re-import does not rewrite already-complete slice completed_at', () => {
65
+ const base = createFixtureBase();
66
+ writeFile(base, 'milestones/M001/M001-ROADMAP.md', ROADMAP_ALL_DONE);
67
+
68
+ openDatabase(join(base, '.gsd', 'gsd.db'));
69
+ migrateHierarchyToDb(base);
70
+
71
+ // Simulate the durable completion timestamps the real run wrote hours apart.
72
+ updateSliceStatus('M001', 'S01', 'complete', REAL_S01);
73
+ updateSliceStatus('M001', 'S02', 'complete', REAL_S02);
74
+
75
+ // A second full re-import (the class of event that bit the reporter).
76
+ migrateHierarchyToDb(base);
77
+
78
+ const slices = getMilestoneSlices('M001');
79
+ const s01 = slices.find((s) => s.id === 'S01')!;
80
+ const s02 = slices.find((s) => s.id === 'S02')!;
81
+ assert.equal(s01.completed_at, REAL_S01, 'S01 completed_at must survive re-import unchanged');
82
+ assert.equal(s02.completed_at, REAL_S02, 'S02 completed_at must survive re-import unchanged');
83
+ });
84
+
85
+ test('a re-import does not rewrite an already-complete milestone completed_at', () => {
86
+ const base = createFixtureBase();
87
+ writeFile(base, 'milestones/M001/M001-ROADMAP.md', ROADMAP_ALL_DONE);
88
+
89
+ openDatabase(join(base, '.gsd', 'gsd.db'));
90
+ migrateHierarchyToDb(base);
91
+
92
+ updateMilestoneStatus('M001', 'complete', REAL_M001);
93
+
94
+ migrateHierarchyToDb(base);
95
+
96
+ const m001 = getAllMilestones().find((m) => m.id === 'M001')!;
97
+ assert.equal(m001.completed_at, REAL_M001, 'M001 completed_at must survive re-import unchanged');
98
+ });
99
+
100
+ test('an initial import of a complete slice still backfills a completed_at when the row has none', () => {
101
+ // The guard preserves an existing timestamp but must not suppress the
102
+ // legitimate first-time backfill for a slice imported as complete.
103
+ const base = createFixtureBase();
104
+ writeFile(base, 'milestones/M001/M001-ROADMAP.md', ROADMAP_ALL_DONE);
105
+
106
+ openDatabase(join(base, '.gsd', 'gsd.db'));
107
+ migrateHierarchyToDb(base);
108
+
109
+ const slices = getMilestoneSlices('M001');
110
+ for (const s of slices) {
111
+ assert.ok(s.completed_at, `complete slice ${s.id} should receive a backfilled completed_at on first import`);
112
+ }
113
+ const m001 = getAllMilestones().find((m) => m.id === 'M001')!;
114
+ assert.ok(m001.completed_at, 'complete milestone should receive a backfilled completed_at on first import');
115
+ });
116
+ });
@@ -1,6 +1,6 @@
1
1
  import { describe, test } from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
- import { mkdtempSync, mkdirSync, rmSync, realpathSync, symlinkSync, writeFileSync } from "node:fs";
3
+ import { mkdtempSync, mkdirSync, rmSync, realpathSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs";
4
4
  import { join } from "node:path";
5
5
  import { tmpdir } from "node:os";
6
6
  import { spawnSync } from "node:child_process";
@@ -12,6 +12,8 @@ import {
12
12
  resolveGsdPathContract,
13
13
  resolveSliceFile,
14
14
  resolveTaskFile,
15
+ resolveTaskFiles,
16
+ taskIdFromTaskFileName,
15
17
  _clearGsdRootCache,
16
18
  } from "../../paths.ts";
17
19
  /** Create a tmp dir and resolve symlinks + 8.3 short names (macOS /var→/private/var, Windows RUNNER~1→runneradmin). */
@@ -171,21 +173,37 @@ describe('paths', () => {
171
173
  test('Case 9: flat-phase task SUMMARY resolves at phase root despite a stray slices/SID/ dir', () => {
172
174
  const root = tmp();
173
175
  try {
174
- // Hybrid flat-phase milestone: phase dir holds flat TID-SUMMARY.md, but a
176
+ // Hybrid flat-phase milestone: phase dir holds flat task summaries, but a
175
177
  // stray slices/S01/ folder also exists on disk. resolveSlicePath then points
176
178
  // under slices/, so layout (phases/ vs milestones/) — not slicePath===phaseDir
177
179
  // — must decide the flat-phase task summary location.
178
180
  const phaseDir = join(root, ".gsd", "phases", "01-foo");
179
181
  mkdirSync(join(phaseDir, "slices", "S01"), { recursive: true });
180
- const flatSummary = join(phaseDir, "T01-SUMMARY.md");
182
+ const flatSummary = join(phaseDir, "S01-T01-SUMMARY.md");
183
+ const legacyFlatSummary = join(phaseDir, "T01-SUMMARY.md");
181
184
  writeFileSync(flatSummary, "# task summary\n");
185
+ writeFileSync(legacyFlatSummary, "# legacy task summary\n");
182
186
 
183
187
  _clearGsdRootCache();
184
188
 
189
+ assert.deepStrictEqual(resolveTaskFiles(phaseDir, "SUMMARY").sort(), [
190
+ "S01-T01-SUMMARY.md",
191
+ "T01-SUMMARY.md",
192
+ ]);
193
+ assert.equal(taskIdFromTaskFileName("S01-T01-SUMMARY.md", "SUMMARY"), "T01");
194
+ assert.equal(taskIdFromTaskFileName("T01-SUMMARY.md", "SUMMARY"), "T01");
195
+
185
196
  assert.deepStrictEqual(
186
197
  resolveTaskFile(root, "M001", "S01", "T01", "SUMMARY"),
187
198
  flatSummary,
188
- "flat-phase TID-SUMMARY.md at phase root is found even when slices/S01/ exists",
199
+ "flat-phase S01-T01-SUMMARY.md at phase root is preferred even when slices/S01/ exists",
200
+ );
201
+
202
+ unlinkSync(flatSummary);
203
+ assert.deepStrictEqual(
204
+ resolveTaskFile(root, "M001", "S01", "T01", "SUMMARY"),
205
+ legacyFlatSummary,
206
+ "legacy flat T01-SUMMARY.md is still found as a fallback",
189
207
  );
190
208
  } finally { cleanup(root); }
191
209
  });
@@ -0,0 +1,62 @@
1
+ // gsd-pi — Integration-branch META lives OUTSIDE milestones/<MID>/ (ADR-045).
2
+ // Verifies the relocation from milestones/<MID>/<MID>-META.json to the flat
3
+ // .gsd/<MID>-META.json so it can never poison isLegacyMilestonesLayout.
4
+
5
+ import assert from "node:assert/strict";
6
+ import { afterEach, beforeEach, test } from "node:test";
7
+ import { existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
8
+ import { join } from "node:path";
9
+ import { tmpdir } from "node:os";
10
+
11
+ import { readIntegrationBranch, writeIntegrationBranch } from "../git-service.js";
12
+ import { gsdRoot, isLegacyMilestonesLayout } from "../paths.js";
13
+
14
+ let repo: string;
15
+
16
+ beforeEach(() => {
17
+ repo = mkdtempSync(join(tmpdir(), "gsd-meta-loc-"));
18
+ });
19
+
20
+ afterEach(() => {
21
+ rmSync(repo, { recursive: true, force: true });
22
+ });
23
+
24
+ test("write goes to the new flat .gsd/<MID>-META.json, not milestones/<MID>/", () => {
25
+ writeIntegrationBranch(repo, "M001", "main");
26
+
27
+ assert.ok(
28
+ existsSync(join(gsdRoot(repo), "M001-META.json")),
29
+ "META written to flat .gsd/<MID>-META.json",
30
+ );
31
+ assert.ok(
32
+ !existsSync(join(gsdRoot(repo), "milestones", "M001", "M001-META.json")),
33
+ "no META in legacy milestones/<MID>/ location",
34
+ );
35
+ });
36
+
37
+ test("round-trip: read returns what write recorded", () => {
38
+ writeIntegrationBranch(repo, "M001", "main");
39
+ assert.equal(readIntegrationBranch(repo, "M001"), "main");
40
+ });
41
+
42
+ test("read falls back to the legacy milestones/<MID>/ location", () => {
43
+ const legacyDir = join(gsdRoot(repo), "milestones", "M001");
44
+ mkdirSync(legacyDir, { recursive: true });
45
+ writeFileSync(
46
+ join(legacyDir, "M001-META.json"),
47
+ JSON.stringify({ integrationBranch: "develop" }) + "\n",
48
+ "utf-8",
49
+ );
50
+
51
+ assert.equal(readIntegrationBranch(repo, "M001"), "develop");
52
+ });
53
+
54
+ test("writing META does not create milestones/<MID>/ or flip layout detection", () => {
55
+ assert.equal(isLegacyMilestonesLayout(repo), false, "clean tree is not legacy layout");
56
+ writeIntegrationBranch(repo, "M001", "main");
57
+ assert.equal(
58
+ isLegacyMilestonesLayout(repo),
59
+ false,
60
+ "writing integration-branch META must not poison layout detection",
61
+ );
62
+ });
@@ -824,9 +824,9 @@ test('── markdown-renderer: renderTaskSummary round-trip ──', async () =
824
824
 
825
825
  // Verify file exists on disk
826
826
  const summaryPath = path.join(
827
- tmpDir, '.gsd', 'phases', '01-test', 'T01-SUMMARY.md',
827
+ tmpDir, '.gsd', 'phases', '01-test', 'S01-T01-SUMMARY.md',
828
828
  );
829
- assert.ok(fs.existsSync(summaryPath), 'T01-SUMMARY.md written to disk');
829
+ assert.ok(fs.existsSync(summaryPath), 'S01-T01-SUMMARY.md written to disk');
830
830
 
831
831
  // Parse and verify
832
832
  const rendered = fs.readFileSync(summaryPath, 'utf-8');
@@ -1020,7 +1020,7 @@ test('── markdown-renderer: renderAllFromDb produces all files ──', asyn
1020
1020
 
1021
1021
  // Verify task summary written
1022
1022
  const taskSummaryPath = path.join(
1023
- tmpDir, '.gsd', 'phases', '01-test', 'T01-SUMMARY.md',
1023
+ tmpDir, '.gsd', 'phases', '01-test', 'S01-T01-SUMMARY.md',
1024
1024
  );
1025
1025
  assert.ok(fs.existsSync(taskSummaryPath), 'T01 summary written by renderAll');
1026
1026
  } finally {
@@ -1546,9 +1546,9 @@ test('── markdown-renderer: repairStaleRenders writes missing task summary
1546
1546
 
1547
1547
  // Verify file written
1548
1548
  const summaryPath = path.join(
1549
- tmpDir, '.gsd', 'phases', '01-test', 'T01-SUMMARY.md',
1549
+ tmpDir, '.gsd', 'phases', '01-test', 'S01-T01-SUMMARY.md',
1550
1550
  );
1551
- assert.ok(fs.existsSync(summaryPath), 'T01-SUMMARY.md should exist after repair');
1551
+ assert.ok(fs.existsSync(summaryPath), 'S01-T01-SUMMARY.md should exist after repair');
1552
1552
 
1553
1553
  // Second detect should be empty
1554
1554
  clearAllCaches();
@@ -0,0 +1,68 @@
1
+ import assert from "node:assert/strict";
2
+ import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import test from "node:test";
6
+
7
+ import { createMigrationPlan, splitValidationIssues } from "../migrate/plan.ts";
8
+ import type { ValidationResult } from "../migrate/types.ts";
9
+
10
+ function makeBase(prefix: string): string {
11
+ return mkdtempSync(join(tmpdir(), prefix));
12
+ }
13
+
14
+ function write(path: string, content: string): void {
15
+ mkdirSync(join(path, ".."), { recursive: true });
16
+ writeFileSync(path, content);
17
+ }
18
+
19
+ test("splitValidationIssues separates warnings from fatals without dropping issue order", () => {
20
+ const validation: ValidationResult = {
21
+ valid: false,
22
+ issues: [
23
+ { file: "ROADMAP.md", severity: "warning", message: "missing roadmap" },
24
+ { file: ".planning", severity: "fatal", message: "missing directory" },
25
+ { file: "PROJECT.md", severity: "warning", message: "missing project" },
26
+ ],
27
+ };
28
+
29
+ assert.deepEqual(splitValidationIssues(validation), {
30
+ warnings: [
31
+ { file: "ROADMAP.md", severity: "warning", message: "missing roadmap" },
32
+ { file: "PROJECT.md", severity: "warning", message: "missing project" },
33
+ ],
34
+ fatals: [
35
+ { file: ".planning", severity: "fatal", message: "missing directory" },
36
+ ],
37
+ });
38
+ });
39
+
40
+ test("createMigrationPlan reports a missing .planning source without parsing", async () => {
41
+ const base = makeBase("gsd-migrate-plan-missing-");
42
+ try {
43
+ const result = await createMigrationPlan(base);
44
+
45
+ assert.equal(result.status, "missing-source");
46
+ assert.equal(result.sourcePath, join(base, ".planning"));
47
+ assert.equal(result.targetRoot, base);
48
+ } finally {
49
+ rmSync(base, { recursive: true, force: true });
50
+ }
51
+ });
52
+
53
+ test("createMigrationPlan reports zero-slice migrations as blocked after validation", async () => {
54
+ const base = makeBase("gsd-migrate-plan-blocked-");
55
+ try {
56
+ mkdirSync(join(base, ".planning"), { recursive: true });
57
+ write(join(base, ".planning", "PROJECT.md"), "# Legacy Project\n");
58
+
59
+ const result = await createMigrationPlan(base);
60
+
61
+ assert.equal(result.status, "blocked");
62
+ assert.match(result.message, /zero slices/);
63
+ assert.equal(result.validation.valid, true);
64
+ assert.ok(result.warnings.some((issue) => issue.file === "ROADMAP.md"));
65
+ } finally {
66
+ rmSync(base, { recursive: true, force: true });
67
+ }
68
+ });
@@ -0,0 +1,98 @@
1
+ import assert from "node:assert/strict";
2
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import test from "node:test";
6
+
7
+ import {
8
+ buildMigrationPreviewSummary,
9
+ buildReviewPrompt,
10
+ formatMigrationPreviewStats,
11
+ } from "../migrate/presentation.ts";
12
+ import { gsdRoot } from "../paths.ts";
13
+ import type { MigrationPreview } from "../migrate/writer.ts";
14
+
15
+ function previewFixture(overrides: Partial<MigrationPreview> = {}): MigrationPreview {
16
+ return {
17
+ decisions: { total: 2 },
18
+ migrationInputs: {
19
+ milestonePhaseDirs: 3,
20
+ decisions: 2,
21
+ seeds: 1,
22
+ },
23
+ milestoneCount: 1,
24
+ totalSlices: 2,
25
+ totalTasks: 5,
26
+ doneSlices: 1,
27
+ doneTasks: 3,
28
+ sliceCompletionPct: 50,
29
+ taskCompletionPct: 60,
30
+ requirements: {
31
+ active: 1,
32
+ validated: 2,
33
+ deferred: 1,
34
+ outOfScope: 1,
35
+ total: 5,
36
+ },
37
+ ...overrides,
38
+ };
39
+ }
40
+
41
+ test("buildMigrationPreviewSummary includes counts, legacy inputs, and existing-target warning", () => {
42
+ const base = mkdtempSync(join(tmpdir(), "gsd-migrate-presentation-"));
43
+ try {
44
+ mkdirSync(join(base, ".gsd"), { recursive: true });
45
+
46
+ assert.deepEqual(buildMigrationPreviewSummary(previewFixture(), base), [
47
+ "Decisions: 2",
48
+ "Milestones: 1",
49
+ "Slices: 2 (1 done — 50%)",
50
+ "Tasks: 5 (3 done — 60%)",
51
+ "Requirements: 5 (2 validated, 1 active, 1 deferred, 1 out of scope)",
52
+ "Legacy inputs: 3 milestone phase dir(s), 2 decision file(s), 1 seed file(s)",
53
+ "",
54
+ `⚠ A .gsd directory already exists at ${gsdRoot(base)}.`,
55
+ "It will be backed up, deleted, and rewritten fresh before DB import.",
56
+ ]);
57
+ } finally {
58
+ rmSync(base, { recursive: true, force: true });
59
+ }
60
+ });
61
+
62
+ test("formatMigrationPreviewStats uses bullet formatting for review prompts", () => {
63
+ assert.equal(
64
+ formatMigrationPreviewStats(previewFixture({ requirements: { active: 0, validated: 0, deferred: 0, outOfScope: 0, total: 0 } })),
65
+ [
66
+ "- Decisions: 2",
67
+ "- Milestones: 1",
68
+ "- Slices: 2 (1 done — 50%)",
69
+ "- Tasks: 5 (3 done — 60%)",
70
+ "- Legacy inputs: 3 milestone phase dir(s), 2 decision file(s), 1 seed file(s)",
71
+ ].join("\n"),
72
+ );
73
+ });
74
+
75
+ test("buildReviewPrompt interpolates source, target, and preview stats", () => {
76
+ const base = mkdtempSync(join(tmpdir(), "gsd-migrate-prompt-"));
77
+ try {
78
+ const promptsDir = join(base, "prompts");
79
+ mkdirSync(promptsDir, { recursive: true });
80
+ writeFileSync(
81
+ join(promptsDir, "review-migration.md"),
82
+ "Source={{sourcePath}}\nTarget={{gsdPath}}\nStats:\n{{previewStats}}\n",
83
+ );
84
+
85
+ const prompt = buildReviewPrompt({
86
+ sourcePath: "/legacy/.planning",
87
+ gsdPath: "/project/.gsd",
88
+ preview: previewFixture(),
89
+ templatePath: join(promptsDir, "review-migration.md"),
90
+ });
91
+
92
+ assert.match(prompt, /Source=\/legacy\/\.planning/);
93
+ assert.match(prompt, /Target=\/project\/\.gsd/);
94
+ assert.match(prompt, /- Requirements: 5 \(2 validated, 1 active, 1 deferred, 1 out of scope\)/);
95
+ } finally {
96
+ rmSync(base, { recursive: true, force: true });
97
+ }
98
+ });
@@ -19,7 +19,7 @@ import {
19
19
  archiveLegacyPlanningDirectory,
20
20
  verifyMigrationProjection,
21
21
  } from "../migrate/audit.ts";
22
- import { assertMigrationDbReadiness, executeMigrationWrite, importWrittenMigrationToDb } from "../migrate/command.ts";
22
+ import { assertMigrationDbReadiness, executeMigrationWrite, importWrittenMigrationToDb } from "../migrate/execution.ts";
23
23
  import { writeGSDDirectory } from "../migrate/writer.ts";
24
24
  import { closeDatabase, getArtifact } from "../gsd-db.ts";
25
25
  import type { GSDProject } from "../migrate/types.ts";
@@ -18,6 +18,7 @@ import {
18
18
  releaseMilestoneLease,
19
19
  refreshMilestoneLease,
20
20
  getMilestoneLease,
21
+ forceReleaseLeasesForWorker,
21
22
  } from "../db/milestone-leases.ts";
22
23
 
23
24
  function makeBase(): string {
@@ -163,6 +164,60 @@ test("refreshMilestoneLease only succeeds with the matching fencing token", (t)
163
164
  assert.equal(refreshMilestoneLease(w1, "M001", claim.token - 1), false);
164
165
  });
165
166
 
167
+ test("forceReleaseLeasesForWorker frees only the dead worker's leases, not a live peer's", (t) => {
168
+ const base = makeBase();
169
+ t.after(() => cleanup(base));
170
+ openDatabase(join(base, ".gsd", "gsd.db"));
171
+ insertMilestone({ id: "M001", title: "One", status: "active" });
172
+ insertMilestone({ id: "M002", title: "Two", status: "active" });
173
+
174
+ // Distinct project roots → distinct processes (not re-entrant peers).
175
+ const wA = registerAutoWorker({ projectRootRealpath: base });
176
+ const wB = registerAutoWorker({ projectRootRealpath: join(base, "peer") });
177
+ assert.equal(claimMilestoneLease(wA, "M001").ok, true);
178
+ assert.equal(claimMilestoneLease(wB, "M002").ok, true);
179
+
180
+ const freed = forceReleaseLeasesForWorker(wA);
181
+ assert.equal(freed, 1, "exactly A's one held lease is released");
182
+
183
+ assert.equal(getMilestoneLease("M001")!.status, "released", "A's M001 lease is released");
184
+ const m2 = getMilestoneLease("M002")!;
185
+ assert.equal(m2.status, "held", "B's M002 lease must stay held (no over-release)");
186
+ assert.equal(m2.worker_id, wB);
187
+ });
188
+
189
+ test("after force release a fresh claim on the freed milestone gets a larger fencing token", (t) => {
190
+ const base = makeBase();
191
+ t.after(() => cleanup(base));
192
+ openDatabase(join(base, ".gsd", "gsd.db"));
193
+ insertMilestone({ id: "M001", title: "One", status: "active" });
194
+
195
+ const wA = registerAutoWorker({ projectRootRealpath: base });
196
+ const wB = registerAutoWorker({ projectRootRealpath: join(base, "peer") });
197
+ const first = claimMilestoneLease(wA, "M001");
198
+ assert.equal(first.ok, true);
199
+ const releasedToken = first.ok ? first.token : 0;
200
+
201
+ assert.equal(forceReleaseLeasesForWorker(wA), 1);
202
+
203
+ const takeover = claimMilestoneLease(wB, "M001");
204
+ assert.equal(takeover.ok, true);
205
+ if (takeover.ok) {
206
+ assert.ok(takeover.token > releasedToken, "takeover token must exceed the released lease's token");
207
+ }
208
+ assert.equal(getMilestoneLease("M001")!.worker_id, wB);
209
+ });
210
+
211
+ test("forceReleaseLeasesForWorker returns 0 for a worker holding no leases", (t) => {
212
+ const base = makeBase();
213
+ t.after(() => cleanup(base));
214
+ openDatabase(join(base, ".gsd", "gsd.db"));
215
+ insertMilestone({ id: "M001", title: "One", status: "active" });
216
+
217
+ const wA = registerAutoWorker({ projectRootRealpath: base });
218
+ assert.equal(forceReleaseLeasesForWorker(wA), 0);
219
+ });
220
+
166
221
  test("claimMilestoneLease rethrows foreign-key failures instead of treating them as lease contention", (t) => {
167
222
  const base = makeBase();
168
223
  t.after(() => cleanup(base));
@@ -74,7 +74,7 @@ test("#2885: cost table includes openai-codex provider models", () => {
74
74
  const ids = BUNDLED_COST_TABLE.map(e => e.id);
75
75
  const codexModels = [
76
76
  "gpt-5.1", "gpt-5.1-codex-max", "gpt-5.1-codex-mini",
77
- "gpt-5.2", "gpt-5.2-codex", "gpt-5.3-codex", "gpt-5.3-codex-spark", "gpt-5.4", "gpt-5.4-mini", "gpt-5.5",
77
+ "gpt-5.2", "gpt-5.2-codex", "gpt-5.3-codex", "gpt-5.3-codex-spark", "gpt-5.4", "gpt-5.4-mini", "gpt-5.5", "gpt-5.6",
78
78
  ];
79
79
  for (const model of codexModels) {
80
80
  assert.ok(ids.includes(model), `cost table should include openai-codex model "${model}"`);
@@ -109,3 +109,11 @@ test("gpt-5.5 uses official OpenAI list pricing", () => {
109
109
  assert.equal(entry.outputPer1k, 0.03);
110
110
  assert.equal(entry.updatedAt, "2026-04-23");
111
111
  });
112
+
113
+ test("gpt-5.6 mirrors gpt-5.5 pricing until official pricing is published", () => {
114
+ const entry = lookupModelCost("gpt-5.6");
115
+ assert.ok(entry, "lookupModelCost should find gpt-5.6");
116
+ assert.equal(entry.inputPer1k, 0.005);
117
+ assert.equal(entry.outputPer1k, 0.03);
118
+ assert.equal(entry.updatedAt, "2026-07-08");
119
+ });
@@ -900,7 +900,7 @@ test("#2885: openai-codex standard-tier models are recognized", () => {
900
900
 
901
901
  test("#2885: openai-codex heavy-tier models are recognized", () => {
902
902
  const config = { ...defaultRoutingConfig(), enabled: true };
903
- const heavyModels = ["gpt-5", "gpt-5-pro", "gpt-5.1", "gpt-5.2", "gpt-5.2-codex", "gpt-5.3-codex", "gpt-5.4", "gpt-5.5", "o4-mini", "o4-mini-deep-research"];
903
+ const heavyModels = ["gpt-5", "gpt-5-pro", "gpt-5.1", "gpt-5.2", "gpt-5.2-codex", "gpt-5.3-codex", "gpt-5.4", "gpt-5.5", "gpt-5.6", "o4-mini", "o4-mini-deep-research"];
904
904
  for (const model of heavyModels) {
905
905
  const result = resolveModelForComplexity(
906
906
  makeClassification("heavy"),