@opengsd/gsd-pi 1.8.0 → 1.8.1-dev.897b3c90

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 (463) hide show
  1. package/README.md +8 -3
  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 +16 -47
  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/auto-artifact-paths.js +2 -2
  17. package/dist/resources/extensions/gsd/auto-dispatch.js +74 -19
  18. package/dist/resources/extensions/gsd/auto-post-unit.js +4 -0
  19. package/dist/resources/extensions/gsd/auto-prompts.js +35 -1
  20. package/dist/resources/extensions/gsd/auto.js +5 -1
  21. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +78 -4
  22. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +84 -26
  23. package/dist/resources/extensions/gsd/command-feedback.js +16 -12
  24. package/dist/resources/extensions/gsd/compat/compat-marker.js +19 -2
  25. package/dist/resources/extensions/gsd/db/command-queue.js +7 -2
  26. package/dist/resources/extensions/gsd/db/engine.js +51 -16
  27. package/dist/resources/extensions/gsd/db/writers/cascades.js +5 -1
  28. package/dist/resources/extensions/gsd/db/writers/status.js +13 -3
  29. package/dist/resources/extensions/gsd/db-base-schema.js +28 -0
  30. package/dist/resources/extensions/gsd/db-migration-steps.js +30 -0
  31. package/dist/resources/extensions/gsd/db-schema-metadata.js +4 -1
  32. package/dist/resources/extensions/gsd/docs/preferences-reference.md +4 -4
  33. package/dist/resources/extensions/gsd/doctor-history.js +65 -0
  34. package/dist/resources/extensions/gsd/doctor-state-checks.js +509 -0
  35. package/dist/resources/extensions/gsd/doctor-workspace-checks.js +91 -0
  36. package/dist/resources/extensions/gsd/doctor.js +14 -653
  37. package/dist/resources/extensions/gsd/flat-phase-migration.js +156 -21
  38. package/dist/resources/extensions/gsd/gsd-db.js +187 -45
  39. package/dist/resources/extensions/gsd/guided-flow.js +29 -10
  40. package/dist/resources/extensions/gsd/markdown-renderer.js +16 -2
  41. package/dist/resources/extensions/gsd/md-importer.js +109 -16
  42. package/dist/resources/extensions/gsd/migrate/command.js +19 -162
  43. package/dist/resources/extensions/gsd/migrate/execution.js +98 -0
  44. package/dist/resources/extensions/gsd/migrate/plan.js +49 -0
  45. package/dist/resources/extensions/gsd/migrate/planning-writer.js +20 -19
  46. package/dist/resources/extensions/gsd/migrate/presentation.js +64 -0
  47. package/dist/resources/extensions/gsd/migration-auto-check.js +4 -0
  48. package/dist/resources/extensions/gsd/parallel-eligibility.js +5 -4
  49. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +28 -43
  50. package/dist/resources/extensions/gsd/paths.js +4 -1
  51. package/dist/resources/extensions/gsd/phase-anchor.js +7 -2
  52. package/dist/resources/extensions/gsd/post-execution-checks.js +4 -4
  53. package/dist/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  54. package/dist/resources/extensions/gsd/safety/evidence-collector.js +26 -1
  55. package/dist/resources/extensions/gsd/safety/evidence-cross-ref.js +30 -5
  56. package/dist/resources/extensions/gsd/state-reconciliation/drift/external-markdown-edit.js +27 -13
  57. package/dist/resources/extensions/gsd/state-reconciliation/drift/external-planning-edit.js +13 -3
  58. package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +54 -14
  59. package/dist/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.js +48 -5
  60. package/dist/resources/extensions/gsd/stop-notice.js +15 -1
  61. package/dist/resources/extensions/gsd/sync-lock.js +13 -7
  62. package/dist/resources/extensions/gsd/tools/complete-task.js +82 -1
  63. package/dist/resources/extensions/gsd/tools/plan-task.js +13 -15
  64. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +18 -15
  65. package/dist/resources/extensions/gsd/tools/replan-task.js +128 -0
  66. package/dist/resources/extensions/gsd/tools/rework-brief.js +74 -0
  67. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +81 -0
  68. package/dist/resources/extensions/gsd/unit-registry.js +4 -0
  69. package/dist/resources/extensions/gsd/uok/plan-v2.js +19 -3
  70. package/dist/resources/extensions/gsd/worktree-state-projection.js +6 -0
  71. package/dist/resources/extensions/mac-tools/index.js +31 -9
  72. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  73. package/dist/web/standalone/.next/BUILD_ID +1 -1
  74. package/dist/web/standalone/.next/app-path-routes-manifest.json +5 -5
  75. package/dist/web/standalone/.next/build-manifest.json +3 -3
  76. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  77. package/dist/web/standalone/.next/required-server-files.json +3 -3
  78. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  79. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  80. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  81. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  89. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  90. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  91. package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -4
  92. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -4
  93. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -4
  95. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  98. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  99. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  100. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  101. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  105. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  106. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  110. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  117. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/mcp-connections/route_client-reference-manifest.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  139. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  149. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  155. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  166. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  171. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  172. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  175. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  181. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  182. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  183. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  184. package/dist/web/standalone/.next/server/app/index.html +1 -1
  185. package/dist/web/standalone/.next/server/app/index.rsc +5 -5
  186. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  187. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +5 -5
  188. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  189. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -4
  190. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  191. package/dist/web/standalone/.next/server/app/page.js +2 -2
  192. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  193. package/dist/web/standalone/.next/server/app-paths-manifest.json +5 -5
  194. package/dist/web/standalone/.next/server/chunks/2842.js +4 -4
  195. package/dist/web/standalone/.next/server/chunks/8357.js +3 -3
  196. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  197. package/dist/web/standalone/.next/server/middleware.js +3 -3
  198. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  199. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  200. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  201. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-a6fb1847f67f167c.js +1 -0
  202. package/dist/web/standalone/.next/static/chunks/app/{layout-b35cbfff38aaf4cf.js → layout-4ae2d68984392bbf.js} +1 -1
  203. package/dist/web/standalone/.next/static/chunks/app/page-72a856634ad14c10.js +1 -0
  204. package/dist/web/standalone/.next/static/chunks/{main-app-590a74400e35f685.js → main-app-90d1d8d5e5d2dc6b.js} +1 -1
  205. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-1115d46ac61b9823.js +1 -0
  206. package/dist/web/standalone/.next/static/css/3b1ceb7abfb9a230.css +1 -0
  207. package/dist/web/standalone/node_modules/@gsd/native/package.json +1 -1
  208. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  209. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  210. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  211. package/dist/web/standalone/package.json +0 -1
  212. package/dist/web/standalone/server.js +1 -1
  213. package/dist/web-mode.js +31 -3
  214. package/integrations/hermes/open_gsd_hermes/gsd_client.py +1 -1
  215. package/integrations/hermes/pyproject.toml +1 -1
  216. package/package.json +12 -10
  217. package/packages/cloud-mcp-gateway/package.json +2 -2
  218. package/packages/contracts/dist/workflow.d.ts +14 -0
  219. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  220. package/packages/contracts/dist/workflow.js +16 -0
  221. package/packages/contracts/dist/workflow.js.map +1 -1
  222. package/packages/contracts/package.json +1 -1
  223. package/packages/daemon/dist/cloud-config.d.ts +1 -1
  224. package/packages/daemon/dist/cloud-config.d.ts.map +1 -1
  225. package/packages/daemon/dist/cloud-config.js +5 -1
  226. package/packages/daemon/dist/cloud-config.js.map +1 -1
  227. package/packages/daemon/dist/cloud-config.test.js +51 -1
  228. package/packages/daemon/dist/cloud-config.test.js.map +1 -1
  229. package/packages/daemon/dist/local-tool-executor.d.ts.map +1 -1
  230. package/packages/daemon/dist/local-tool-executor.js +2 -0
  231. package/packages/daemon/dist/local-tool-executor.js.map +1 -1
  232. package/packages/daemon/package.json +6 -6
  233. package/packages/gsd-agent-core/package.json +5 -5
  234. package/packages/gsd-agent-modes/package.json +7 -7
  235. package/packages/gsd-cloud/dist/cli.d.ts +5 -0
  236. package/packages/gsd-cloud/dist/cli.d.ts.map +1 -0
  237. package/packages/gsd-cloud/dist/cli.js +160 -0
  238. package/packages/gsd-cloud/dist/cli.js.map +1 -0
  239. package/packages/gsd-cloud/dist/cloud-config.d.ts +19 -0
  240. package/packages/gsd-cloud/dist/cloud-config.d.ts.map +1 -0
  241. package/packages/gsd-cloud/dist/cloud-config.js +231 -0
  242. package/packages/gsd-cloud/dist/cloud-config.js.map +1 -0
  243. package/packages/gsd-cloud/dist/cloud-config.test.d.ts +2 -0
  244. package/packages/gsd-cloud/dist/cloud-config.test.d.ts.map +1 -0
  245. package/packages/gsd-cloud/dist/cloud-config.test.js +118 -0
  246. package/packages/gsd-cloud/dist/cloud-config.test.js.map +1 -0
  247. package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.d.ts +2 -0
  248. package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.d.ts.map +1 -0
  249. package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.js +37 -0
  250. package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.js.map +1 -0
  251. package/packages/gsd-cloud/dist/cloud-runtime.d.ts +35 -0
  252. package/packages/gsd-cloud/dist/cloud-runtime.d.ts.map +1 -0
  253. package/packages/gsd-cloud/dist/cloud-runtime.js +258 -0
  254. package/packages/gsd-cloud/dist/cloud-runtime.js.map +1 -0
  255. package/packages/gsd-cloud/dist/cloud-runtime.test.d.ts +2 -0
  256. package/packages/gsd-cloud/dist/cloud-runtime.test.d.ts.map +1 -0
  257. package/packages/gsd-cloud/dist/cloud-runtime.test.js +88 -0
  258. package/packages/gsd-cloud/dist/cloud-runtime.test.js.map +1 -0
  259. package/packages/gsd-cloud/dist/cloud-token.d.ts +3 -0
  260. package/packages/gsd-cloud/dist/cloud-token.d.ts.map +1 -0
  261. package/packages/gsd-cloud/dist/cloud-token.js +37 -0
  262. package/packages/gsd-cloud/dist/cloud-token.js.map +1 -0
  263. package/packages/gsd-cloud/dist/config.d.ts +17 -0
  264. package/packages/gsd-cloud/dist/config.d.ts.map +1 -0
  265. package/packages/gsd-cloud/dist/config.js +146 -0
  266. package/packages/gsd-cloud/dist/config.js.map +1 -0
  267. package/packages/gsd-cloud/dist/device-flow.d.ts +24 -0
  268. package/packages/gsd-cloud/dist/device-flow.d.ts.map +1 -0
  269. package/packages/gsd-cloud/dist/device-flow.js +128 -0
  270. package/packages/gsd-cloud/dist/device-flow.js.map +1 -0
  271. package/packages/gsd-cloud/dist/device-flow.test.d.ts +2 -0
  272. package/packages/gsd-cloud/dist/device-flow.test.d.ts.map +1 -0
  273. package/packages/gsd-cloud/dist/device-flow.test.js +155 -0
  274. package/packages/gsd-cloud/dist/device-flow.test.js.map +1 -0
  275. package/packages/gsd-cloud/dist/executors/claude-executor.d.ts +6 -0
  276. package/packages/gsd-cloud/dist/executors/claude-executor.d.ts.map +1 -0
  277. package/packages/gsd-cloud/dist/executors/claude-executor.js +15 -0
  278. package/packages/gsd-cloud/dist/executors/claude-executor.js.map +1 -0
  279. package/packages/gsd-cloud/dist/executors/codex-executor.d.ts +6 -0
  280. package/packages/gsd-cloud/dist/executors/codex-executor.d.ts.map +1 -0
  281. package/packages/gsd-cloud/dist/executors/codex-executor.js +15 -0
  282. package/packages/gsd-cloud/dist/executors/codex-executor.js.map +1 -0
  283. package/packages/gsd-cloud/dist/executors/executor.d.ts +28 -0
  284. package/packages/gsd-cloud/dist/executors/executor.d.ts.map +1 -0
  285. package/packages/gsd-cloud/dist/executors/executor.js +11 -0
  286. package/packages/gsd-cloud/dist/executors/executor.js.map +1 -0
  287. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.d.ts +34 -0
  288. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.d.ts.map +1 -0
  289. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.js +179 -0
  290. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.js.map +1 -0
  291. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.d.ts +2 -0
  292. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.d.ts.map +1 -0
  293. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.js +44 -0
  294. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.js.map +1 -0
  295. package/packages/gsd-cloud/dist/executors/index.d.ts +17 -0
  296. package/packages/gsd-cloud/dist/executors/index.d.ts.map +1 -0
  297. package/packages/gsd-cloud/dist/executors/index.js +29 -0
  298. package/packages/gsd-cloud/dist/executors/index.js.map +1 -0
  299. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.d.ts +36 -0
  300. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.d.ts.map +1 -0
  301. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.js +176 -0
  302. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.js.map +1 -0
  303. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.d.ts +2 -0
  304. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.d.ts.map +1 -0
  305. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.js +34 -0
  306. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.js.map +1 -0
  307. package/packages/gsd-cloud/dist/index.d.ts +7 -0
  308. package/packages/gsd-cloud/dist/index.d.ts.map +1 -0
  309. package/packages/gsd-cloud/dist/index.js +8 -0
  310. package/packages/gsd-cloud/dist/index.js.map +1 -0
  311. package/packages/gsd-cloud/dist/inject-gateway.d.ts +16 -0
  312. package/packages/gsd-cloud/dist/inject-gateway.d.ts.map +1 -0
  313. package/packages/gsd-cloud/dist/inject-gateway.js +29 -0
  314. package/packages/gsd-cloud/dist/inject-gateway.js.map +1 -0
  315. package/packages/gsd-cloud/dist/inject-gateway.test.d.ts +2 -0
  316. package/packages/gsd-cloud/dist/inject-gateway.test.d.ts.map +1 -0
  317. package/packages/gsd-cloud/dist/inject-gateway.test.js +41 -0
  318. package/packages/gsd-cloud/dist/inject-gateway.test.js.map +1 -0
  319. package/packages/gsd-cloud/dist/logger.d.ts +25 -0
  320. package/packages/gsd-cloud/dist/logger.d.ts.map +1 -0
  321. package/packages/gsd-cloud/dist/logger.js +72 -0
  322. package/packages/gsd-cloud/dist/logger.js.map +1 -0
  323. package/packages/gsd-cloud/dist/types.d.ts +51 -0
  324. package/packages/gsd-cloud/dist/types.d.ts.map +1 -0
  325. package/packages/gsd-cloud/dist/types.js +9 -0
  326. package/packages/gsd-cloud/dist/types.js.map +1 -0
  327. package/packages/gsd-cloud/package.json +3 -3
  328. package/packages/mcp-server/README.md +8 -0
  329. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  330. package/packages/mcp-server/dist/workflow-tools.js +64 -2
  331. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  332. package/packages/mcp-server/package.json +4 -4
  333. package/packages/native/package.json +1 -1
  334. package/packages/pi-agent-core/package.json +1 -1
  335. package/packages/pi-ai/dist/models.generated.d.ts +60 -0
  336. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  337. package/packages/pi-ai/dist/models.generated.js +54 -0
  338. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  339. package/packages/pi-ai/dist/providers/amazon-bedrock.js +1 -0
  340. package/packages/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
  341. package/packages/pi-ai/dist/providers/anthropic.js +19 -0
  342. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  343. package/packages/pi-ai/package.json +1 -1
  344. package/packages/pi-coding-agent/package.json +7 -7
  345. package/packages/pi-tui/package.json +2 -2
  346. package/packages/rpc-client/package.json +2 -2
  347. package/pkg/package.json +1 -1
  348. package/src/resources/GSD-WORKFLOW.md +16 -47
  349. package/src/resources/extensions/browser-tools/capture.ts +2 -86
  350. package/src/resources/extensions/browser-tools/screenshot-constraints.ts +94 -0
  351. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +18 -1
  352. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +108 -0
  353. package/src/resources/extensions/claude-code-cli/turn-assembler.ts +30 -2
  354. package/src/resources/extensions/gsd/auto-artifact-paths.ts +2 -2
  355. package/src/resources/extensions/gsd/auto-dispatch.ts +86 -19
  356. package/src/resources/extensions/gsd/auto-post-unit.ts +4 -0
  357. package/src/resources/extensions/gsd/auto-prompts.ts +38 -1
  358. package/src/resources/extensions/gsd/auto.ts +5 -1
  359. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +91 -4
  360. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +80 -24
  361. package/src/resources/extensions/gsd/command-feedback.ts +19 -12
  362. package/src/resources/extensions/gsd/compat/compat-marker.ts +21 -4
  363. package/src/resources/extensions/gsd/db/command-queue.ts +7 -1
  364. package/src/resources/extensions/gsd/db/engine.ts +53 -17
  365. package/src/resources/extensions/gsd/db/writers/cascades.ts +5 -1
  366. package/src/resources/extensions/gsd/db/writers/status.ts +25 -8
  367. package/src/resources/extensions/gsd/db-base-schema.ts +30 -0
  368. package/src/resources/extensions/gsd/db-migration-steps.ts +32 -0
  369. package/src/resources/extensions/gsd/db-schema-metadata.ts +4 -1
  370. package/src/resources/extensions/gsd/docs/preferences-reference.md +4 -4
  371. package/src/resources/extensions/gsd/doctor-history.ts +81 -0
  372. package/src/resources/extensions/gsd/doctor-state-checks.ts +527 -0
  373. package/src/resources/extensions/gsd/doctor-workspace-checks.ts +97 -0
  374. package/src/resources/extensions/gsd/doctor.ts +14 -673
  375. package/src/resources/extensions/gsd/flat-phase-migration.ts +160 -19
  376. package/src/resources/extensions/gsd/gsd-db.ts +255 -52
  377. package/src/resources/extensions/gsd/guided-flow.ts +39 -10
  378. package/src/resources/extensions/gsd/markdown-renderer.ts +23 -7
  379. package/src/resources/extensions/gsd/md-importer.ts +116 -13
  380. package/src/resources/extensions/gsd/migrate/command.ts +21 -227
  381. package/src/resources/extensions/gsd/migrate/execution.ts +136 -0
  382. package/src/resources/extensions/gsd/migrate/plan.ts +101 -0
  383. package/src/resources/extensions/gsd/migrate/planning-writer.ts +21 -23
  384. package/src/resources/extensions/gsd/migrate/presentation.ts +83 -0
  385. package/src/resources/extensions/gsd/migration-auto-check.ts +3 -0
  386. package/src/resources/extensions/gsd/parallel-eligibility.ts +5 -4
  387. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +37 -40
  388. package/src/resources/extensions/gsd/paths.ts +4 -1
  389. package/src/resources/extensions/gsd/phase-anchor.ts +8 -2
  390. package/src/resources/extensions/gsd/post-execution-checks.ts +4 -4
  391. package/src/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  392. package/src/resources/extensions/gsd/safety/evidence-collector.ts +28 -1
  393. package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +31 -5
  394. package/src/resources/extensions/gsd/state-reconciliation/drift/external-markdown-edit.ts +30 -13
  395. package/src/resources/extensions/gsd/state-reconciliation/drift/external-planning-edit.ts +16 -3
  396. package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +67 -20
  397. package/src/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.ts +47 -5
  398. package/src/resources/extensions/gsd/state-reconciliation/types.ts +2 -2
  399. package/src/resources/extensions/gsd/stop-notice.ts +18 -1
  400. package/src/resources/extensions/gsd/sync-lock.ts +14 -6
  401. package/src/resources/extensions/gsd/tests/closeout-git-deferral.test.ts +96 -1
  402. package/src/resources/extensions/gsd/tests/command-feedback.test.ts +12 -0
  403. package/src/resources/extensions/gsd/tests/compat-marker.test.ts +104 -0
  404. package/src/resources/extensions/gsd/tests/complete-task.test.ts +286 -0
  405. package/src/resources/extensions/gsd/tests/db-authority-regression.test.ts +76 -1
  406. package/src/resources/extensions/gsd/tests/db-engine-migrate-guards.test.ts +186 -0
  407. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +29 -0
  408. package/src/resources/extensions/gsd/tests/discuss-routing-fixes.test.ts +123 -0
  409. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +50 -0
  410. package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +49 -0
  411. package/src/resources/extensions/gsd/tests/doctor-history-public-api.test.ts +25 -0
  412. package/src/resources/extensions/gsd/tests/evidence-cross-ref.test.ts +81 -0
  413. package/src/resources/extensions/gsd/tests/evidence-xref-gsd-exec.test.ts +22 -0
  414. package/src/resources/extensions/gsd/tests/external-edit-scoped-import.test.ts +262 -0
  415. package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +202 -0
  416. package/src/resources/extensions/gsd/tests/gate-storage.test.ts +29 -0
  417. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +25 -0
  418. package/src/resources/extensions/gsd/tests/import-slice-milestone-completion-preserve.test.ts +116 -0
  419. package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +53 -0
  420. package/src/resources/extensions/gsd/tests/migrate-plan.test.ts +68 -0
  421. package/src/resources/extensions/gsd/tests/migrate-presentation.test.ts +98 -0
  422. package/src/resources/extensions/gsd/tests/migrate-safety-audit.test.ts +1 -1
  423. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +53 -0
  424. package/src/resources/extensions/gsd/tests/milestone-leases.test.ts +55 -0
  425. package/src/resources/extensions/gsd/tests/parallel-eligibility-file-overlap.test.ts +146 -0
  426. package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +59 -0
  427. package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +4 -0
  428. package/src/resources/extensions/gsd/tests/phase-anchor.test.ts +32 -4
  429. package/src/resources/extensions/gsd/tests/plan-task.test.ts +26 -23
  430. package/src/resources/extensions/gsd/tests/planning-writer.test.ts +47 -1
  431. package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +22 -0
  432. package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +18 -3
  433. package/src/resources/extensions/gsd/tests/reassess-handler.test.ts +50 -0
  434. package/src/resources/extensions/gsd/tests/replan-task-handler.test.ts +103 -0
  435. package/src/resources/extensions/gsd/tests/rework-brief.test.ts +197 -0
  436. package/src/resources/extensions/gsd/tests/skip-slice-cascades-tasks.test.ts +21 -0
  437. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +177 -25
  438. package/src/resources/extensions/gsd/tests/stop-notice.test.ts +17 -0
  439. package/src/resources/extensions/gsd/tests/sync-lock.test.ts +19 -0
  440. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +34 -0
  441. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +93 -1
  442. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +2 -0
  443. package/src/resources/extensions/gsd/tests/workflow-migration-gates.test.ts +139 -0
  444. package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +36 -0
  445. package/src/resources/extensions/gsd/tests/write-gate-seam.test.ts +52 -0
  446. package/src/resources/extensions/gsd/tools/complete-task.ts +120 -0
  447. package/src/resources/extensions/gsd/tools/plan-task.ts +14 -16
  448. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +18 -17
  449. package/src/resources/extensions/gsd/tools/replan-task.ts +160 -0
  450. package/src/resources/extensions/gsd/tools/rework-brief.ts +91 -0
  451. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +92 -0
  452. package/src/resources/extensions/gsd/types.ts +11 -0
  453. package/src/resources/extensions/gsd/unit-registry.ts +4 -0
  454. package/src/resources/extensions/gsd/uok/plan-v2.ts +20 -3
  455. package/src/resources/extensions/gsd/worktree-state-projection.ts +12 -0
  456. package/src/resources/extensions/mac-tools/index.ts +52 -9
  457. package/src/resources/extensions/mac-tools/tests/mac-screenshot-payload.test.cjs +70 -0
  458. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-49f565245e1e4afe.js +0 -1
  459. package/dist/web/standalone/.next/static/chunks/app/page-bc4c723c6a19c6f0.js +0 -1
  460. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ec3eaffc9785ba48.js +0 -1
  461. package/dist/web/standalone/.next/static/css/18c2fdf261bfc1b7.css +0 -1
  462. /package/dist/web/standalone/.next/static/{seHIUVbR1mm7LfG83nWJO → TezjdjSHBVRRr54XjAvte}/_buildManifest.js +0 -0
  463. /package/dist/web/standalone/.next/static/{seHIUVbR1mm7LfG83nWJO → TezjdjSHBVRRr54XjAvte}/_ssgManifest.js +0 -0
@@ -0,0 +1,186 @@
1
+ // GSD Extension - Migration guard tests (plan 026).
2
+ // Covers the newer-DB refusal in migrateSchema, whole-chain rollback atomicity
3
+ // via the _setMigrationFaultForTest seam, the legacy-data guard in initSchema,
4
+ // and getCurrentSchemaVersion's empty-table NULL handling.
5
+
6
+ import { describe, test } from 'node:test';
7
+ import assert from 'node:assert/strict';
8
+ import * as fs from 'node:fs';
9
+ import * as path from 'node:path';
10
+ import * as os from 'node:os';
11
+ import { createRequire } from 'node:module';
12
+
13
+ import {
14
+ openDatabase,
15
+ closeDatabase,
16
+ isDbAvailable,
17
+ SCHEMA_VERSION,
18
+ _setMigrationFaultForTest,
19
+ } from '../gsd-db.ts';
20
+ import { createDbAdapter } from '../db-adapter.ts';
21
+ import { getCurrentSchemaVersion } from '../db-schema-metadata.ts';
22
+
23
+ const _require = createRequire(import.meta.url);
24
+
25
+ function tempDbPath(): string {
26
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-migrate-guards-'));
27
+ return path.join(dir, 'gsd.db');
28
+ }
29
+
30
+ function cleanup(dbPath: string): void {
31
+ closeDatabase();
32
+ fs.rmSync(path.dirname(dbPath), { recursive: true, force: true });
33
+ }
34
+
35
+ interface RawDb {
36
+ exec(sql: string): void;
37
+ prepare(sql: string): { get(...args: unknown[]): Record<string, unknown> | undefined; all(...args: unknown[]): Array<Record<string, unknown>> };
38
+ close(): void;
39
+ }
40
+
41
+ function openRawSqliteForTest(dbPath: string): RawDb {
42
+ try {
43
+ const mod = _require('node:sqlite') as { DatabaseSync: new (path: string) => RawDb };
44
+ return new mod.DatabaseSync(dbPath);
45
+ } catch {
46
+ type SqliteCtor = new (path: string) => RawDb;
47
+ const mod = _require('better-sqlite3') as SqliteCtor | { default: SqliteCtor };
48
+ const DatabaseCtor: SqliteCtor = typeof mod === 'function' ? mod : mod.default;
49
+ return new DatabaseCtor(dbPath);
50
+ }
51
+ }
52
+
53
+ function rawColumnNames(raw: RawDb, table: string): string[] {
54
+ return raw.prepare(`PRAGMA table_info(${table})`).all().map((r) => r['name'] as string);
55
+ }
56
+
57
+ function rawHasTable(raw: RawDb, table: string): boolean {
58
+ const row = raw.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?").get(table);
59
+ return Boolean(row);
60
+ }
61
+
62
+ function rawMaxVersion(raw: RawDb): number | null {
63
+ const row = raw.prepare('SELECT MAX(version) as v FROM schema_version').get();
64
+ return (row?.['v'] as number | null) ?? null;
65
+ }
66
+
67
+ describe('db-engine migrate guards', () => {
68
+ test('getCurrentSchemaVersion returns 0 on an empty schema_version table', () => {
69
+ const sqlite = _require('node:sqlite') as { DatabaseSync: new (path: string) => unknown };
70
+ const adapter = createDbAdapter(new sqlite.DatabaseSync(':memory:'));
71
+ try {
72
+ adapter.exec('CREATE TABLE schema_version (version INTEGER NOT NULL, applied_at TEXT NOT NULL)');
73
+ assert.equal(getCurrentSchemaVersion(adapter), 0);
74
+ } finally {
75
+ adapter.close();
76
+ }
77
+ });
78
+
79
+ test('refuses to open a DB whose schema is newer than this binary', () => {
80
+ const dbPath = tempDbPath();
81
+ try {
82
+ assert.ok(openDatabase(dbPath), 'fresh open should succeed');
83
+ closeDatabase();
84
+
85
+ const raw = openRawSqliteForTest(dbPath);
86
+ raw.exec(
87
+ `INSERT INTO schema_version (version, applied_at) VALUES (${SCHEMA_VERSION + 1}, '2026-01-01T00:00:00Z')`,
88
+ );
89
+ raw.close();
90
+
91
+ assert.throws(() => openDatabase(dbPath), /newer than/);
92
+ assert.equal(isDbAvailable(), false, 'no connection may stay open on refusal');
93
+ } finally {
94
+ cleanup(dbPath);
95
+ }
96
+ });
97
+
98
+ test('a mid-migration failure rolls back to the starting schema version', () => {
99
+ const dbPath = tempDbPath();
100
+ try {
101
+ assert.ok(openDatabase(dbPath), 'fresh open should succeed');
102
+ closeDatabase();
103
+
104
+ // Rewind the DB to v(SCHEMA_VERSION-1): stamp the prior version and drop
105
+ // the objects the last migration adds, so the re-run has real work to redo.
106
+ const startVersion = SCHEMA_VERSION - 2;
107
+ const raw = openRawSqliteForTest(dbPath);
108
+ raw.exec('DELETE FROM schema_version');
109
+ raw.exec(`INSERT INTO schema_version (version, applied_at) VALUES (${startVersion}, '2026-01-01T00:00:00Z')`);
110
+ raw.exec('ALTER TABLE slices DROP COLUMN target_repositories');
111
+ raw.exec('ALTER TABLE tasks DROP COLUMN target_repositories');
112
+ raw.close();
113
+
114
+ _setMigrationFaultForTest(true);
115
+ try {
116
+ assert.throws(() => openDatabase(dbPath), /migration fault injected/);
117
+ } finally {
118
+ _setMigrationFaultForTest(false);
119
+ }
120
+ assert.equal(isDbAvailable(), false, 'no connection may stay open on migration failure');
121
+
122
+ const inspect = openRawSqliteForTest(dbPath);
123
+ try {
124
+ assert.equal(rawMaxVersion(inspect), startVersion, 'version must roll back to the starting version');
125
+ assert.ok(
126
+ !rawColumnNames(inspect, 'slices').includes('target_repositories'),
127
+ 'column added by the failed migration must be rolled back',
128
+ );
129
+ } finally {
130
+ inspect.close();
131
+ }
132
+
133
+ // The DB is intact — a clean re-open migrates to the current version.
134
+ assert.ok(openDatabase(dbPath), 're-open without the fault should succeed');
135
+ closeDatabase();
136
+ const after = openRawSqliteForTest(dbPath);
137
+ try {
138
+ assert.equal(rawMaxVersion(after), SCHEMA_VERSION);
139
+ assert.ok(rawColumnNames(after, 'slices').includes('target_repositories'));
140
+ assert.equal(rawHasTable(after, 'rework_briefs'), true);
141
+ assert.equal(rawHasTable(after, 'rework_brief_findings'), true);
142
+ } finally {
143
+ after.close();
144
+ }
145
+ } finally {
146
+ cleanup(dbPath);
147
+ }
148
+ });
149
+
150
+ test('a DB with data but no version rows migrates from v1 instead of being stamped current', () => {
151
+ const dbPath = tempDbPath();
152
+ try {
153
+ assert.ok(openDatabase(dbPath), 'fresh open should succeed');
154
+ closeDatabase();
155
+
156
+ // Simulate a legacy DB: user data present, version table empty, and a
157
+ // migration-added column missing so we can observe the chain actually run.
158
+ const raw = openRawSqliteForTest(dbPath);
159
+ raw.exec("INSERT INTO milestones (id, title) VALUES ('M001', 'Legacy milestone')");
160
+ raw.exec('DELETE FROM schema_version');
161
+ raw.exec('ALTER TABLE milestones DROP COLUMN vision');
162
+ raw.close();
163
+
164
+ assert.ok(openDatabase(dbPath), 'legacy DB open should succeed');
165
+ closeDatabase();
166
+
167
+ const inspect = openRawSqliteForTest(dbPath);
168
+ try {
169
+ const versions = inspect.prepare('SELECT version FROM schema_version ORDER BY version').all()
170
+ .map((r) => r['version'] as number);
171
+ assert.equal(versions[0], 1, 'baseline v1 must be recorded, not a fresh-install stamp');
172
+ assert.equal(versions[versions.length - 1], SCHEMA_VERSION, 'migration chain must reach the current version');
173
+ assert.ok(
174
+ rawColumnNames(inspect, 'milestones').includes('vision'),
175
+ 'migration-added column must be restored by the chain',
176
+ );
177
+ const row = inspect.prepare('SELECT count(*) as cnt FROM milestones').get();
178
+ assert.equal(row?.['cnt'], 1, 'existing data must survive');
179
+ } finally {
180
+ inspect.close();
181
+ }
182
+ } finally {
183
+ cleanup(dbPath);
184
+ }
185
+ });
186
+ });
@@ -7,6 +7,8 @@ import { join } from 'node:path';
7
7
  import { tmpdir } from 'node:os';
8
8
 
9
9
  import { deriveState, invalidateStateCache, _deriveStateImpl, deriveStateFromDb, isGhostMilestone } from '../state.ts';
10
+ import { readCachedDeriveState, writeCachedDeriveState } from '../state/derive/cache.ts';
11
+ import type { GSDState } from '../types.ts';
10
12
  import {
11
13
  openDatabase,
12
14
  closeDatabase,
@@ -582,6 +584,33 @@ describe('derive-state-db', async () => {
582
584
  }
583
585
  });
584
586
 
587
+ // ─── Test 7b: lock flip must not serve a basePath-keyed cache hit ─────
588
+ // The derive cache is keyed on basePath only, but deriveStateFromDb filters
589
+ // by GSD_MILESTONE_LOCK. auto.ts's capture/restoreMilestoneLockEnv call
590
+ // invalidateStateCache() on every flip; this guards that the cache is
591
+ // genuinely lock-blind (so that invalidate call is load-bearing, not
592
+ // redundant) and that invalidation defeats the stale read.
593
+ test('derive-state-db: a milestone-lock flip needs explicit cache invalidation', () => {
594
+ const prevLock = process.env.GSD_MILESTONE_LOCK;
595
+ try {
596
+ const base = '/tmp/gsd-lock-flip-fixture';
597
+ const stateA = { phase: 'planning' } as unknown as GSDState;
598
+ process.env.GSD_MILESTONE_LOCK = 'M001';
599
+ writeCachedDeriveState(base, stateA);
600
+
601
+ // Lock flips but basePath is unchanged → the cache still hits.
602
+ process.env.GSD_MILESTONE_LOCK = 'M002';
603
+ assert.strictEqual(readCachedDeriveState(base), stateA, 'basePath-only cache ignores the lock flip');
604
+
605
+ // What the lock-env functions do on flip:
606
+ invalidateStateCache();
607
+ assert.strictEqual(readCachedDeriveState(base), null, 'invalidation defeats the stale-lock read');
608
+ } finally {
609
+ if (prevLock === undefined) delete process.env.GSD_MILESTONE_LOCK;
610
+ else process.env.GSD_MILESTONE_LOCK = prevLock;
611
+ }
612
+ });
613
+
585
614
  // ═════════════════════════════════════════════════════════════════════════
586
615
  // New: deriveStateFromDb() cross-validation tests
587
616
  // ═════════════════════════════════════════════════════════════════════════
@@ -80,6 +80,43 @@ function makeDiscussCtx(notifications: Array<{ message: string; level?: string }
80
80
  };
81
81
  }
82
82
 
83
+ async function runDiscussTargetFixture(
84
+ target: string,
85
+ milestones: Array<{ id: string; title?: string; status?: string }>,
86
+ writeArtifacts?: (base: string) => void,
87
+ ) {
88
+ const base = mkdtempSync(join(tmpdir(), "gsd-discuss-target-"));
89
+ const notifications: Array<{ message: string; level?: string }> = [];
90
+ const harness = makeDiscussPi();
91
+ try {
92
+ mkdirSync(join(base, ".gsd", "milestones"), { recursive: true });
93
+ writeArtifacts?.(base);
94
+ const dbPath = join(base, ".gsd", "gsd.db");
95
+ assert.equal(openDatabase(dbPath), true);
96
+ for (const milestone of milestones) {
97
+ insertMilestone(milestone);
98
+ }
99
+
100
+ await showDiscuss(
101
+ makeDiscussCtx(notifications) as any,
102
+ harness.pi as any,
103
+ base,
104
+ { target },
105
+ );
106
+
107
+ return {
108
+ notifications: [...notifications],
109
+ sent: [...harness.sent],
110
+ };
111
+ } finally {
112
+ harness.restore();
113
+ if (isDbAvailable()) closeDatabase();
114
+ invalidateStateCache();
115
+ clearGuidedUnitContext();
116
+ rmSync(base, { recursive: true, force: true });
117
+ }
118
+ }
119
+
83
120
  describe("discuss target normalization", () => {
84
121
  test("canonicalizes milestone and slice casing", () => {
85
122
  assert.equal(normalizeDiscussTarget("m014"), "M014");
@@ -90,6 +127,92 @@ describe("discuss target normalization", () => {
90
127
  });
91
128
  });
92
129
 
130
+ describe("showDiscuss targeted milestone guardrails (#1320)", () => {
131
+ test("missing, complete, and parked milestone targets get actionable messages", async () => {
132
+ const cases = [
133
+ {
134
+ target: "M006",
135
+ milestones: [{ id: "M005", title: "Current", status: "active" }],
136
+ level: "warning",
137
+ message: /Milestone M006 was not found in the roadmap\. Use \/gsd new-milestone to add it, or \/gsd status to see available milestones\./,
138
+ },
139
+ {
140
+ target: "M006/S01",
141
+ milestones: [{ id: "M005", title: "Current", status: "active" }],
142
+ level: "warning",
143
+ message: /Milestone M006 was not found in the roadmap\. Use \/gsd new-milestone to add it, or \/gsd status to see available milestones\./,
144
+ },
145
+ {
146
+ target: "M006",
147
+ milestones: [{ id: "M006", title: "Done", status: "complete" }],
148
+ level: "info",
149
+ message: /Milestone M006 is already complete\./,
150
+ },
151
+ {
152
+ target: "M006/S01",
153
+ milestones: [{ id: "M006", title: "Done", status: "complete" }],
154
+ level: "info",
155
+ message: /Milestone M006 is already complete\./,
156
+ },
157
+ {
158
+ target: "M006",
159
+ milestones: [{ id: "M006", title: "Deferred", status: "parked" }],
160
+ level: "warning",
161
+ message: /Milestone M006 is parked\. Run \/gsd unpark M006 to reactivate\./,
162
+ },
163
+ {
164
+ target: "M006/S01",
165
+ milestones: [{ id: "M006", title: "Deferred", status: "parked" }],
166
+ level: "warning",
167
+ message: /Milestone M006 is parked\. Run \/gsd unpark M006 to reactivate\./,
168
+ },
169
+ ];
170
+
171
+ for (const testCase of cases) {
172
+ const result = await runDiscussTargetFixture(testCase.target, testCase.milestones);
173
+ assert.equal(result.sent.length, 0, `${testCase.target} must not dispatch`);
174
+ assert.equal(result.notifications.length, 1, `${testCase.target} must emit one notification`);
175
+ assert.equal(result.notifications[0]?.level, testCase.level);
176
+ assert.match(result.notifications[0]?.message ?? "", testCase.message);
177
+ assert.doesNotMatch(result.notifications[0]?.message ?? "", /not discussable/i);
178
+ }
179
+ });
180
+
181
+ test("bare milestone targets match unique-suffix milestone IDs", async () => {
182
+ const result = await runDiscussTargetFixture("M006", [
183
+ { id: "M006-abc123", title: "Unique milestone", status: "active" },
184
+ ]);
185
+
186
+ assert.equal(result.notifications.length, 0);
187
+ assert.equal(result.sent.length, 1, "bare ID must dispatch the suffixed milestone");
188
+ assert.match(String(result.sent[0]?.content), /M006-abc123|Unique milestone|guided-discuss-milestone/i);
189
+ });
190
+
191
+ test("bare slice targets match unique-suffix milestone IDs", async () => {
192
+ const result = await runDiscussTargetFixture(
193
+ "M006/S01",
194
+ [{ id: "M006-abc123", title: "Unique milestone", status: "active" }],
195
+ (base) => {
196
+ mkdirSync(join(base, ".gsd", "milestones", "M006-abc123"), { recursive: true });
197
+ writeFileSync(
198
+ join(base, ".gsd", "milestones", "M006-abc123", "M006-abc123-ROADMAP.md"),
199
+ `# M006-abc123 Roadmap
200
+
201
+ ## Slices
202
+ - [ ] **S01: Unique slice** \`risk:medium\` \`depends:[]\`
203
+ > After this: the suffixed milestone slice can be discussed
204
+ `,
205
+ "utf-8",
206
+ );
207
+ },
208
+ );
209
+
210
+ assert.equal(result.notifications.length, 0);
211
+ assert.equal(result.sent.length, 1, "bare ID slice target must dispatch through the suffixed milestone");
212
+ assert.match(String(result.sent[0]?.content), /M006-abc123|S01|Unique slice|guided-discuss-slice/i);
213
+ });
214
+ });
215
+
93
216
  describe("loadDiscussNormSlices roadmap fallback (#2892)", () => {
94
217
  test("falls back to ROADMAP when DB has no slice rows", async () => {
95
218
  const base = mkdtempSync(join(tmpdir(), "gsd-discuss-slices-"));
@@ -330,6 +330,56 @@ test("dispatch: session milestone mismatch stops before missing-task-plan recove
330
330
  assert.match(result.reason, /context mid "M001" does not match session\.currentMilestoneId "M002"/);
331
331
  });
332
332
 
333
+ test("dispatch: bare context milestone maps to suffixed active session milestone", async (t) => {
334
+ const tmp = mkdtempSync(join(tmpdir(), "gsd-suffixed-session-milestone-"));
335
+ t.after(() => rmSync(tmp, { recursive: true, force: true }));
336
+
337
+ const worktreeRoot = join(tmp, ".gsd", "worktrees", "M003-vaz73w");
338
+ scaffoldLegacyMilestoneContext(worktreeRoot, "M003-vaz73w");
339
+ scaffoldLegacySlicePlan(worktreeRoot, "M003-vaz73w", "S01");
340
+ scaffoldLegacyTaskPlan(worktreeRoot, "M003-vaz73w", "S01", "T02");
341
+
342
+ const ctx = makeContextFor(tmp, "M003", "S01", "T02", {
343
+ basePath: worktreeRoot,
344
+ originalBasePath: tmp,
345
+ currentMilestoneId: "M003-vaz73w",
346
+ });
347
+ const result = await resolveDispatch(ctx);
348
+
349
+ assert.equal(result.action, "dispatch");
350
+ assert.ok(result.action === "dispatch" && result.unitType === "execute-task",
351
+ `unitType should be execute-task, got: ${result.action === "dispatch" ? result.unitType : "(stop)"}`);
352
+ assert.ok(result.action === "dispatch" && result.unitId === "M003-vaz73w/S01/T02",
353
+ `unitId should use suffixed milestone, got: ${result.action === "dispatch" ? result.unitId : "(stop)"}`);
354
+ });
355
+
356
+ test("dispatch: suffixed context milestone keeps suffix when scoped alias is bare", async (t) => {
357
+ // Inverse of the case above: dispatch context carries the suffixed id but the
358
+ // scoped alias (session.currentMilestoneId) is bare. resolveEffectiveDispatchMilestoneId
359
+ // must keep the suffixed id so slice/task artifacts resolve under the suffixed
360
+ // worktree layout (milestones/M003-xxxxxx/) rather than the bare milestones/M003/.
361
+ const tmp = mkdtempSync(join(tmpdir(), "gsd-suffixed-context-bare-scope-"));
362
+ t.after(() => rmSync(tmp, { recursive: true, force: true }));
363
+
364
+ const worktreeRoot = join(tmp, ".gsd", "worktrees", "M003-vaz73w");
365
+ scaffoldLegacyMilestoneContext(worktreeRoot, "M003-vaz73w");
366
+ scaffoldLegacySlicePlan(worktreeRoot, "M003-vaz73w", "S01");
367
+ scaffoldLegacyTaskPlan(worktreeRoot, "M003-vaz73w", "S01", "T02");
368
+
369
+ const ctx = makeContextFor(tmp, "M003-vaz73w", "S01", "T02", {
370
+ basePath: worktreeRoot,
371
+ originalBasePath: tmp,
372
+ currentMilestoneId: "M003",
373
+ });
374
+ const result = await resolveDispatch(ctx);
375
+
376
+ assert.equal(result.action, "dispatch");
377
+ assert.ok(result.action === "dispatch" && result.unitType === "execute-task",
378
+ `unitType should be execute-task, got: ${result.action === "dispatch" ? result.unitType : "(stop)"}`);
379
+ assert.ok(result.action === "dispatch" && result.unitId === "M003-vaz73w/S01/T02",
380
+ `unitId should keep suffixed milestone, got: ${result.action === "dispatch" ? result.unitId : "(stop)"}`);
381
+ });
382
+
333
383
  test("dispatch: worktree path mismatch stops before planning a different milestone", async (t) => {
334
384
  const tmp = mkdtempSync(join(tmpdir(), "gsd-worktree-path-milestone-mismatch-"));
335
385
  t.after(() => rmSync(tmp, { recursive: true, force: true }));
@@ -146,6 +146,55 @@ test("dispatch-rule-coverage: pre-planning, no CONTEXT → discuss-milestone", a
146
146
  );
147
147
  });
148
148
 
149
+ test("dispatch-rule-coverage: pre-planning worktree sees project-root CONTEXT", async (t) => {
150
+ const tmp = mkdtempSync(join(tmpdir(), "gsd-disp-cov-wt-context-"));
151
+ t.after(() => rmSync(tmp, { recursive: true, force: true }));
152
+
153
+ const projectPhaseDir = join(tmp, ".gsd", "phases", "01-foundation");
154
+ mkdirSync(projectPhaseDir, { recursive: true });
155
+ writeFileSync(join(projectPhaseDir, "01-CONTEXT.md"), "# Context\n");
156
+
157
+ const worktree = join(tmp, ".gsd", "worktrees", "M001");
158
+ mkdirSync(join(worktree, ".gsd", "milestones", "M001"), { recursive: true });
159
+ writeFileSync(
160
+ join(worktree, ".gsd", "milestones", "M001", "M001-META.json"),
161
+ '{"branch":"milestone/M001"}',
162
+ );
163
+
164
+ const rule = DISPATCH_RULES.find(
165
+ (candidate) => candidate.name === "pre-planning (no context) → discuss-milestone",
166
+ );
167
+ assert.ok(rule, "pre-planning missing-context rule should exist");
168
+
169
+ const result = await rule.match(makeCtx(worktree, makeState({ phase: "pre-planning" })));
170
+ assert.equal(result, null, "project-root CONTEXT must prevent a second discuss-milestone dispatch");
171
+ });
172
+
173
+ test("dispatch-rule-coverage: pre-planning worktree sees worktree-only CONTEXT", async (t) => {
174
+ // Mirror image of the project-root test: discuss-milestone mirrors CONTEXT into
175
+ // the worktree's own .gsd, and it may not yet exist at the project root (the
176
+ // worktree→root sync deliberately does not flow markdown projections back).
177
+ // A project-root-only check would miss it and re-fire discuss-milestone.
178
+ const tmp = mkdtempSync(join(tmpdir(), "gsd-disp-cov-wt-only-context-"));
179
+ t.after(() => rmSync(tmp, { recursive: true, force: true }));
180
+
181
+ // No CONTEXT at the project root — only the milestone dir exists there.
182
+ mkdirSync(join(tmp, ".gsd", "phases"), { recursive: true });
183
+
184
+ const worktree = join(tmp, ".gsd", "worktrees", "M001");
185
+ const worktreePhaseDir = join(worktree, ".gsd", "phases", "01-foundation");
186
+ mkdirSync(worktreePhaseDir, { recursive: true });
187
+ writeFileSync(join(worktreePhaseDir, "01-CONTEXT.md"), "# WT Context\n");
188
+
189
+ const rule = DISPATCH_RULES.find(
190
+ (candidate) => candidate.name === "pre-planning (no context) → discuss-milestone",
191
+ );
192
+ assert.ok(rule, "pre-planning missing-context rule should exist");
193
+
194
+ const result = await rule.match(makeCtx(worktree, makeState({ phase: "pre-planning" })));
195
+ assert.equal(result, null, "worktree-only CONTEXT must prevent a second discuss-milestone dispatch");
196
+ });
197
+
149
198
  test("dispatch-rule-coverage: pre-planning, has CONTEXT, no RESEARCH → research-milestone", async (t) => {
150
199
  const tmp = mkdtempSync(join(tmpdir(), "gsd-disp-cov-res-"));
151
200
  t.after(() => rmSync(tmp, { recursive: true, force: true }));
@@ -0,0 +1,25 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { mkdirSync, mkdtempSync, rmSync } from "node:fs";
4
+ import { tmpdir } from "node:os";
5
+ import { join } from "node:path";
6
+
7
+ import { readDoctorHistory, runGSDDoctor, type DoctorHistoryEntry } from "../doctor.ts";
8
+
9
+ test("doctor.ts preserves readDoctorHistory public API and records doctor runs", async (t) => {
10
+ const base = mkdtempSync(join(tmpdir(), "gsd-doctor-history-api-"));
11
+ mkdirSync(join(base, ".gsd"), { recursive: true });
12
+
13
+ t.after(() => rmSync(base, { recursive: true, force: true }));
14
+
15
+ const report = await runGSDDoctor(base, { fix: false });
16
+ const history: DoctorHistoryEntry[] = await readDoctorHistory(base, 1);
17
+
18
+ assert.equal(history.length, 1);
19
+ assert.equal(history[0].ok, report.ok);
20
+ assert.equal(history[0].errors, report.issues.filter(issue => issue.severity === "error").length);
21
+ assert.equal(history[0].warnings, report.issues.filter(issue => issue.severity === "warning").length);
22
+ assert.equal(history[0].fixes, 0);
23
+ assert.ok(Array.isArray(history[0].codes));
24
+ assert.equal(typeof history[0].summary, "string");
25
+ });
@@ -54,6 +54,87 @@ test("passing retry evidence is not invalidated by an earlier failed run of the
54
54
  assert.deepEqual(mismatches, []);
55
55
  });
56
56
 
57
+ test("newer script-wrapped pass is not shadowed by a stale exact failing run", () => {
58
+ const command = "npm test";
59
+ const mismatches = crossReferenceEvidence(
60
+ [{ command, exitCode: 0, verdict: "passed after retry" }],
61
+ [
62
+ {
63
+ kind: "bash",
64
+ toolCallId: "call-1",
65
+ command,
66
+ exitCode: 1,
67
+ outputSnippet: "failed",
68
+ timestamp: 1,
69
+ },
70
+ {
71
+ kind: "bash",
72
+ toolCallId: "call-2",
73
+ command: `cd /work && ${command}`,
74
+ exitCode: 0,
75
+ outputSnippet: "passed",
76
+ timestamp: 2,
77
+ },
78
+ ] as EvidenceEntry[],
79
+ );
80
+
81
+ assert.deepEqual(mismatches, []);
82
+ });
83
+
84
+ test("later containing script does not override an exact successful run", () => {
85
+ const command = "npm test";
86
+ const mismatches = crossReferenceEvidence(
87
+ [{ command, exitCode: 0, verdict: "passed" }],
88
+ [
89
+ {
90
+ kind: "bash",
91
+ toolCallId: "call-1",
92
+ command,
93
+ exitCode: 0,
94
+ outputSnippet: "passed",
95
+ timestamp: 1,
96
+ },
97
+ {
98
+ kind: "bash",
99
+ toolCallId: "call-2",
100
+ command: `cd /work && ${command} && npm run lint`,
101
+ exitCode: 1,
102
+ outputSnippet: "lint failed",
103
+ timestamp: 2,
104
+ },
105
+ ] as EvidenceEntry[],
106
+ );
107
+
108
+ assert.deepEqual(mismatches, []);
109
+ });
110
+
111
+ test("same-timestamp retry evidence prefers the later recorded run", () => {
112
+ const command = "npm test";
113
+ const mismatches = crossReferenceEvidence(
114
+ [{ command, exitCode: 0, verdict: "passed after retry" }],
115
+ [
116
+ {
117
+ kind: "bash",
118
+ toolCallId: "call-1",
119
+ command,
120
+ exitCode: 1,
121
+ outputSnippet: "failed",
122
+ timestamp: 1,
123
+ },
124
+ {
125
+ kind: "bash",
126
+ toolCallId: "call-2",
127
+ command,
128
+ exitCode: 0,
129
+ outputSnippet: "passed",
130
+ timestamp: 1,
131
+ },
132
+ ] as EvidenceEntry[],
133
+ );
134
+
135
+ assert.deepEqual(mismatches, []);
136
+ });
137
+
57
138
  test("stale verification evidence batches are ignored when a newer completion batch exists", () => {
58
139
  const command = "node todo.js add 'Task A' && node todo.js add 'Task B' && node todo.js done 1";
59
140
  const resetCommand = `rm -f "$HOME/.config/todo/data.json" && ${command}`;
@@ -60,6 +60,28 @@ test("evidence-xref: verification run through gsd_exec script matches the claime
60
60
  assert.deepEqual(mismatches, [], "gsd_exec-executed verification must not be flagged as missing");
61
61
  });
62
62
 
63
+ test("evidence-xref: gsd_exec runtime-purpose label matches the recorded sandbox run", () => {
64
+ resetEvidence();
65
+
66
+ recordToolCall("tc-exec-label", "gsd_exec", {
67
+ runtime: "node",
68
+ code: "const plan = 'T02-PLAN'; if (!plan.includes('T02')) process.exit(1);",
69
+ purpose: "validate T02-PLAN contains canonical Cargo command, state seam, d",
70
+ });
71
+ recordToolResult("tc-exec-label", "gsd_exec", gsdExecResult(0), false);
72
+
73
+ const mismatches = crossReferenceEvidence(
74
+ [{
75
+ command: "gsd_exec node: validate T02-PLAN contains canonical Cargo command, state seam, d",
76
+ exitCode: 0,
77
+ verdict: "passed",
78
+ }],
79
+ getEvidence(),
80
+ );
81
+
82
+ assert.deepEqual(mismatches, [], "gsd_exec purpose labels must match sandbox evidence");
83
+ });
84
+
63
85
  test("evidence-xref: multi-line gsd_exec script matches claims for each embedded command", () => {
64
86
  resetEvidence();
65
87