@opengsd/gsd-pi 1.7.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 (465) hide show
  1. package/README.md +8 -6
  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 +9 -9
  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 +9 -9
  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 +30 -8
  226. package/packages/daemon/dist/cloud-config.js.map +1 -1
  227. package/packages/daemon/dist/cloud-config.test.js +69 -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/README.md +18 -4
  236. package/packages/gsd-cloud/bin/gsd-cloud.js +6 -5
  237. package/packages/gsd-cloud/dist/cli.d.ts +5 -0
  238. package/packages/gsd-cloud/dist/cli.d.ts.map +1 -0
  239. package/packages/gsd-cloud/dist/cli.js +160 -0
  240. package/packages/gsd-cloud/dist/cli.js.map +1 -0
  241. package/packages/gsd-cloud/dist/cloud-config.d.ts +19 -0
  242. package/packages/gsd-cloud/dist/cloud-config.d.ts.map +1 -0
  243. package/packages/gsd-cloud/dist/cloud-config.js +231 -0
  244. package/packages/gsd-cloud/dist/cloud-config.js.map +1 -0
  245. package/packages/gsd-cloud/dist/cloud-config.test.d.ts +2 -0
  246. package/packages/gsd-cloud/dist/cloud-config.test.d.ts.map +1 -0
  247. package/packages/gsd-cloud/dist/cloud-config.test.js +118 -0
  248. package/packages/gsd-cloud/dist/cloud-config.test.js.map +1 -0
  249. package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.d.ts +2 -0
  250. package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.d.ts.map +1 -0
  251. package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.js +37 -0
  252. package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.js.map +1 -0
  253. package/packages/gsd-cloud/dist/cloud-runtime.d.ts +35 -0
  254. package/packages/gsd-cloud/dist/cloud-runtime.d.ts.map +1 -0
  255. package/packages/gsd-cloud/dist/cloud-runtime.js +258 -0
  256. package/packages/gsd-cloud/dist/cloud-runtime.js.map +1 -0
  257. package/packages/gsd-cloud/dist/cloud-runtime.test.d.ts +2 -0
  258. package/packages/gsd-cloud/dist/cloud-runtime.test.d.ts.map +1 -0
  259. package/packages/gsd-cloud/dist/cloud-runtime.test.js +88 -0
  260. package/packages/gsd-cloud/dist/cloud-runtime.test.js.map +1 -0
  261. package/packages/gsd-cloud/dist/cloud-token.d.ts +3 -0
  262. package/packages/gsd-cloud/dist/cloud-token.d.ts.map +1 -0
  263. package/packages/gsd-cloud/dist/cloud-token.js +37 -0
  264. package/packages/gsd-cloud/dist/cloud-token.js.map +1 -0
  265. package/packages/gsd-cloud/dist/config.d.ts +17 -0
  266. package/packages/gsd-cloud/dist/config.d.ts.map +1 -0
  267. package/packages/gsd-cloud/dist/config.js +146 -0
  268. package/packages/gsd-cloud/dist/config.js.map +1 -0
  269. package/packages/gsd-cloud/dist/device-flow.d.ts +24 -0
  270. package/packages/gsd-cloud/dist/device-flow.d.ts.map +1 -0
  271. package/packages/gsd-cloud/dist/device-flow.js +128 -0
  272. package/packages/gsd-cloud/dist/device-flow.js.map +1 -0
  273. package/packages/gsd-cloud/dist/device-flow.test.d.ts +2 -0
  274. package/packages/gsd-cloud/dist/device-flow.test.d.ts.map +1 -0
  275. package/packages/gsd-cloud/dist/device-flow.test.js +155 -0
  276. package/packages/gsd-cloud/dist/device-flow.test.js.map +1 -0
  277. package/packages/gsd-cloud/dist/executors/claude-executor.d.ts +6 -0
  278. package/packages/gsd-cloud/dist/executors/claude-executor.d.ts.map +1 -0
  279. package/packages/gsd-cloud/dist/executors/claude-executor.js +15 -0
  280. package/packages/gsd-cloud/dist/executors/claude-executor.js.map +1 -0
  281. package/packages/gsd-cloud/dist/executors/codex-executor.d.ts +6 -0
  282. package/packages/gsd-cloud/dist/executors/codex-executor.d.ts.map +1 -0
  283. package/packages/gsd-cloud/dist/executors/codex-executor.js +15 -0
  284. package/packages/gsd-cloud/dist/executors/codex-executor.js.map +1 -0
  285. package/packages/gsd-cloud/dist/executors/executor.d.ts +28 -0
  286. package/packages/gsd-cloud/dist/executors/executor.d.ts.map +1 -0
  287. package/packages/gsd-cloud/dist/executors/executor.js +11 -0
  288. package/packages/gsd-cloud/dist/executors/executor.js.map +1 -0
  289. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.d.ts +34 -0
  290. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.d.ts.map +1 -0
  291. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.js +179 -0
  292. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.js.map +1 -0
  293. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.d.ts +2 -0
  294. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.d.ts.map +1 -0
  295. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.js +44 -0
  296. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.js.map +1 -0
  297. package/packages/gsd-cloud/dist/executors/index.d.ts +17 -0
  298. package/packages/gsd-cloud/dist/executors/index.d.ts.map +1 -0
  299. package/packages/gsd-cloud/dist/executors/index.js +29 -0
  300. package/packages/gsd-cloud/dist/executors/index.js.map +1 -0
  301. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.d.ts +36 -0
  302. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.d.ts.map +1 -0
  303. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.js +176 -0
  304. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.js.map +1 -0
  305. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.d.ts +2 -0
  306. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.d.ts.map +1 -0
  307. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.js +34 -0
  308. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.js.map +1 -0
  309. package/packages/gsd-cloud/dist/index.d.ts +7 -0
  310. package/packages/gsd-cloud/dist/index.d.ts.map +1 -0
  311. package/packages/gsd-cloud/dist/index.js +8 -0
  312. package/packages/gsd-cloud/dist/index.js.map +1 -0
  313. package/packages/gsd-cloud/dist/inject-gateway.d.ts +16 -0
  314. package/packages/gsd-cloud/dist/inject-gateway.d.ts.map +1 -0
  315. package/packages/gsd-cloud/dist/inject-gateway.js +29 -0
  316. package/packages/gsd-cloud/dist/inject-gateway.js.map +1 -0
  317. package/packages/gsd-cloud/dist/inject-gateway.test.d.ts +2 -0
  318. package/packages/gsd-cloud/dist/inject-gateway.test.d.ts.map +1 -0
  319. package/packages/gsd-cloud/dist/inject-gateway.test.js +41 -0
  320. package/packages/gsd-cloud/dist/inject-gateway.test.js.map +1 -0
  321. package/packages/gsd-cloud/dist/logger.d.ts +25 -0
  322. package/packages/gsd-cloud/dist/logger.d.ts.map +1 -0
  323. package/packages/gsd-cloud/dist/logger.js +72 -0
  324. package/packages/gsd-cloud/dist/logger.js.map +1 -0
  325. package/packages/gsd-cloud/dist/types.d.ts +51 -0
  326. package/packages/gsd-cloud/dist/types.d.ts.map +1 -0
  327. package/packages/gsd-cloud/dist/types.js +9 -0
  328. package/packages/gsd-cloud/dist/types.js.map +1 -0
  329. package/packages/gsd-cloud/package.json +7 -5
  330. package/packages/mcp-server/README.md +8 -0
  331. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  332. package/packages/mcp-server/dist/workflow-tools.js +64 -2
  333. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  334. package/packages/mcp-server/package.json +4 -4
  335. package/packages/native/package.json +1 -1
  336. package/packages/pi-agent-core/package.json +1 -1
  337. package/packages/pi-ai/dist/models.generated.d.ts +60 -0
  338. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  339. package/packages/pi-ai/dist/models.generated.js +54 -0
  340. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  341. package/packages/pi-ai/dist/providers/amazon-bedrock.js +1 -0
  342. package/packages/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
  343. package/packages/pi-ai/dist/providers/anthropic.js +19 -0
  344. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  345. package/packages/pi-ai/package.json +1 -1
  346. package/packages/pi-coding-agent/package.json +7 -7
  347. package/packages/pi-tui/package.json +2 -2
  348. package/packages/rpc-client/package.json +2 -2
  349. package/pkg/package.json +1 -1
  350. package/src/resources/GSD-WORKFLOW.md +16 -47
  351. package/src/resources/extensions/browser-tools/capture.ts +2 -86
  352. package/src/resources/extensions/browser-tools/screenshot-constraints.ts +94 -0
  353. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +18 -1
  354. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +108 -0
  355. package/src/resources/extensions/claude-code-cli/turn-assembler.ts +30 -2
  356. package/src/resources/extensions/gsd/auto-artifact-paths.ts +2 -2
  357. package/src/resources/extensions/gsd/auto-dispatch.ts +86 -19
  358. package/src/resources/extensions/gsd/auto-post-unit.ts +4 -0
  359. package/src/resources/extensions/gsd/auto-prompts.ts +38 -1
  360. package/src/resources/extensions/gsd/auto.ts +5 -1
  361. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +91 -4
  362. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +80 -24
  363. package/src/resources/extensions/gsd/command-feedback.ts +19 -12
  364. package/src/resources/extensions/gsd/compat/compat-marker.ts +21 -4
  365. package/src/resources/extensions/gsd/db/command-queue.ts +7 -1
  366. package/src/resources/extensions/gsd/db/engine.ts +53 -17
  367. package/src/resources/extensions/gsd/db/writers/cascades.ts +5 -1
  368. package/src/resources/extensions/gsd/db/writers/status.ts +25 -8
  369. package/src/resources/extensions/gsd/db-base-schema.ts +30 -0
  370. package/src/resources/extensions/gsd/db-migration-steps.ts +32 -0
  371. package/src/resources/extensions/gsd/db-schema-metadata.ts +4 -1
  372. package/src/resources/extensions/gsd/docs/preferences-reference.md +4 -4
  373. package/src/resources/extensions/gsd/doctor-history.ts +81 -0
  374. package/src/resources/extensions/gsd/doctor-state-checks.ts +527 -0
  375. package/src/resources/extensions/gsd/doctor-workspace-checks.ts +97 -0
  376. package/src/resources/extensions/gsd/doctor.ts +14 -673
  377. package/src/resources/extensions/gsd/flat-phase-migration.ts +160 -19
  378. package/src/resources/extensions/gsd/gsd-db.ts +255 -52
  379. package/src/resources/extensions/gsd/guided-flow.ts +39 -10
  380. package/src/resources/extensions/gsd/markdown-renderer.ts +23 -7
  381. package/src/resources/extensions/gsd/md-importer.ts +116 -13
  382. package/src/resources/extensions/gsd/migrate/command.ts +21 -227
  383. package/src/resources/extensions/gsd/migrate/execution.ts +136 -0
  384. package/src/resources/extensions/gsd/migrate/plan.ts +101 -0
  385. package/src/resources/extensions/gsd/migrate/planning-writer.ts +21 -23
  386. package/src/resources/extensions/gsd/migrate/presentation.ts +83 -0
  387. package/src/resources/extensions/gsd/migration-auto-check.ts +3 -0
  388. package/src/resources/extensions/gsd/parallel-eligibility.ts +5 -4
  389. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +37 -40
  390. package/src/resources/extensions/gsd/paths.ts +4 -1
  391. package/src/resources/extensions/gsd/phase-anchor.ts +8 -2
  392. package/src/resources/extensions/gsd/post-execution-checks.ts +4 -4
  393. package/src/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  394. package/src/resources/extensions/gsd/safety/evidence-collector.ts +28 -1
  395. package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +31 -5
  396. package/src/resources/extensions/gsd/state-reconciliation/drift/external-markdown-edit.ts +30 -13
  397. package/src/resources/extensions/gsd/state-reconciliation/drift/external-planning-edit.ts +16 -3
  398. package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +67 -20
  399. package/src/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.ts +47 -5
  400. package/src/resources/extensions/gsd/state-reconciliation/types.ts +2 -2
  401. package/src/resources/extensions/gsd/stop-notice.ts +18 -1
  402. package/src/resources/extensions/gsd/sync-lock.ts +14 -6
  403. package/src/resources/extensions/gsd/tests/closeout-git-deferral.test.ts +96 -1
  404. package/src/resources/extensions/gsd/tests/command-feedback.test.ts +12 -0
  405. package/src/resources/extensions/gsd/tests/compat-marker.test.ts +104 -0
  406. package/src/resources/extensions/gsd/tests/complete-task.test.ts +286 -0
  407. package/src/resources/extensions/gsd/tests/db-authority-regression.test.ts +76 -1
  408. package/src/resources/extensions/gsd/tests/db-engine-migrate-guards.test.ts +186 -0
  409. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +29 -0
  410. package/src/resources/extensions/gsd/tests/discuss-routing-fixes.test.ts +123 -0
  411. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +50 -0
  412. package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +49 -0
  413. package/src/resources/extensions/gsd/tests/doctor-history-public-api.test.ts +25 -0
  414. package/src/resources/extensions/gsd/tests/evidence-cross-ref.test.ts +81 -0
  415. package/src/resources/extensions/gsd/tests/evidence-xref-gsd-exec.test.ts +22 -0
  416. package/src/resources/extensions/gsd/tests/external-edit-scoped-import.test.ts +262 -0
  417. package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +202 -0
  418. package/src/resources/extensions/gsd/tests/gate-storage.test.ts +29 -0
  419. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +25 -0
  420. package/src/resources/extensions/gsd/tests/import-slice-milestone-completion-preserve.test.ts +116 -0
  421. package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +53 -0
  422. package/src/resources/extensions/gsd/tests/migrate-plan.test.ts +68 -0
  423. package/src/resources/extensions/gsd/tests/migrate-presentation.test.ts +98 -0
  424. package/src/resources/extensions/gsd/tests/migrate-safety-audit.test.ts +1 -1
  425. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +53 -0
  426. package/src/resources/extensions/gsd/tests/milestone-leases.test.ts +55 -0
  427. package/src/resources/extensions/gsd/tests/parallel-eligibility-file-overlap.test.ts +146 -0
  428. package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +59 -0
  429. package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +4 -0
  430. package/src/resources/extensions/gsd/tests/phase-anchor.test.ts +32 -4
  431. package/src/resources/extensions/gsd/tests/plan-task.test.ts +26 -23
  432. package/src/resources/extensions/gsd/tests/planning-writer.test.ts +47 -1
  433. package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +22 -0
  434. package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +18 -3
  435. package/src/resources/extensions/gsd/tests/reassess-handler.test.ts +50 -0
  436. package/src/resources/extensions/gsd/tests/replan-task-handler.test.ts +103 -0
  437. package/src/resources/extensions/gsd/tests/rework-brief.test.ts +197 -0
  438. package/src/resources/extensions/gsd/tests/skip-slice-cascades-tasks.test.ts +21 -0
  439. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +177 -25
  440. package/src/resources/extensions/gsd/tests/stop-notice.test.ts +17 -0
  441. package/src/resources/extensions/gsd/tests/sync-lock.test.ts +19 -0
  442. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +34 -0
  443. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +93 -1
  444. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +2 -0
  445. package/src/resources/extensions/gsd/tests/workflow-migration-gates.test.ts +139 -0
  446. package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +36 -0
  447. package/src/resources/extensions/gsd/tests/write-gate-seam.test.ts +52 -0
  448. package/src/resources/extensions/gsd/tools/complete-task.ts +120 -0
  449. package/src/resources/extensions/gsd/tools/plan-task.ts +14 -16
  450. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +18 -17
  451. package/src/resources/extensions/gsd/tools/replan-task.ts +160 -0
  452. package/src/resources/extensions/gsd/tools/rework-brief.ts +91 -0
  453. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +92 -0
  454. package/src/resources/extensions/gsd/types.ts +11 -0
  455. package/src/resources/extensions/gsd/unit-registry.ts +4 -0
  456. package/src/resources/extensions/gsd/uok/plan-v2.ts +20 -3
  457. package/src/resources/extensions/gsd/worktree-state-projection.ts +12 -0
  458. package/src/resources/extensions/mac-tools/index.ts +52 -9
  459. package/src/resources/extensions/mac-tools/tests/mac-screenshot-payload.test.cjs +70 -0
  460. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-49f565245e1e4afe.js +0 -1
  461. package/dist/web/standalone/.next/static/chunks/app/page-bc4c723c6a19c6f0.js +0 -1
  462. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ec3eaffc9785ba48.js +0 -1
  463. package/dist/web/standalone/.next/static/css/18c2fdf261bfc1b7.css +0 -1
  464. /package/dist/web/standalone/.next/static/{enWQFRY-aLTUq3wmxG2Qz → TezjdjSHBVRRr54XjAvte}/_buildManifest.js +0 -0
  465. /package/dist/web/standalone/.next/static/{enWQFRY-aLTUq3wmxG2Qz → TezjdjSHBVRRr54XjAvte}/_ssgManifest.js +0 -0
@@ -11,6 +11,7 @@ import {
11
11
  notifySmartEntryNeedsInteractiveMenu,
12
12
  requiresInteractiveMenu,
13
13
  } from "../command-feedback.js";
14
+ import { isBlockedNoticeMessage, isInteractiveMenuUnavailableNotice } from "../stop-notice.js";
14
15
  import type { ExtensionCommandContext } from "@gsd/pi-coding-agent";
15
16
 
16
17
  function makeCtx(overrides: {
@@ -87,6 +88,17 @@ describe("notifyQueueHubNeedsInteractiveMenu", () => {
87
88
  assert.match(notes[0]!.message, /\/gsd queue/);
88
89
  assert.match(notes[0]!.message, /reorder/i);
89
90
  });
91
+
92
+ // /gsd queue continues headless with the add-work flow after this notice, so
93
+ // it must NOT be classified as a blocked dead-end (would exit 10 early). (#1294)
94
+ it("emits a notice the headless host does not treat as a dead-end", () => {
95
+ const ctx = makeCtx({ hasUI: false });
96
+ notifyQueueHubNeedsInteractiveMenu(ctx, "this session has no interactive menu");
97
+ const notes = (ctx as typeof ctx & { _notifications: Array<{ message: string }> })._notifications;
98
+ const message = notes[0]!.message.toLowerCase();
99
+ assert.equal(isInteractiveMenuUnavailableNotice(message), false);
100
+ assert.equal(isBlockedNoticeMessage(message), false);
101
+ });
90
102
  });
91
103
 
92
104
  describe("notifyInitNeedsInteractiveMenu", () => {
@@ -16,6 +16,9 @@ import {
16
16
  EMPTY_MARKER,
17
17
  compatMarkerPath,
18
18
  } from "../compat/compat-marker.ts";
19
+ import { externalMarkdownEditHandler } from "../state-reconciliation/drift/external-markdown-edit.ts";
20
+ import type { DriftContext } from "../state-reconciliation/types.ts";
21
+ import type { GSDState } from "../types.ts";
19
22
 
20
23
  const tmpDirs: string[] = [];
21
24
 
@@ -188,3 +191,104 @@ test("pruneOrphanedProjectionEntries returns 0 and writes nothing when marker is
188
191
  const files = readdirSync(join(base, ".gsd"));
189
192
  assert.ok(!files.includes(".compat.json"), "must not create a marker where none existed");
190
193
  });
194
+
195
+ // --- Path-traversal containment (plan 029) ---------------------------------
196
+ //
197
+ // The marker is repo-controlled content whose projection-map keys are joined
198
+ // with basePath and readFileSync'd by the drift detectors. A key that escapes
199
+ // .gsd/ must invalidate the whole marker so readCompatMarker fails safe to the
200
+ // empty marker (detectors see no entries → nothing outside the repo is read).
201
+
202
+ for (const badKey of ["../outside.md", "/etc/hosts", "C:/x.md", "..\\x.md"]) {
203
+ test(`readCompatMarker rejects a projection key that escapes the root: ${JSON.stringify(badKey)}`, () => {
204
+ const base = makeTmpBase();
205
+ // Write the hostile marker directly (writeCompatMarker does not validate).
206
+ writeCompatMarker(base, {
207
+ schema: 2,
208
+ lastWriter: "gsd-pi",
209
+ lastProjectedAt: "2026-07-07T00:00:00.000Z",
210
+ projections: { [badKey]: { sha: "deadbeefdeadbeef", entities: ["m1"] } },
211
+ piVersion: "1.8.1",
212
+ });
213
+
214
+ const marker = readCompatMarker(base);
215
+ assert.equal(
216
+ Object.keys(marker.projections).length,
217
+ 0,
218
+ "a marker with an escaping key must fall back to the empty marker",
219
+ );
220
+ });
221
+ }
222
+
223
+ test("readCompatMarker preserves legitimate nested projection keys", () => {
224
+ const base = makeTmpBase();
225
+ const roadmap = "milestones/M001/M001-ROADMAP.md";
226
+ const context = "phases/01-foo/01-CONTEXT.md";
227
+ writeCompatMarker(base, {
228
+ schema: 2,
229
+ lastWriter: "gsd-pi",
230
+ lastProjectedAt: "2026-07-07T00:00:00.000Z",
231
+ projections: {
232
+ [roadmap]: { sha: "aaaaaaaaaaaaaaaa", entities: ["M001"] },
233
+ [context]: { sha: "bbbbbbbbbbbbbbbb", entities: ["P01"] },
234
+ },
235
+ planning: { active: false, layout: null, projections: {}, passthrough: {} },
236
+ piVersion: "1.8.1",
237
+ });
238
+
239
+ const marker = readCompatMarker(base);
240
+ assert.ok(marker.projections[roadmap], "roadmap key must round-trip");
241
+ assert.ok(marker.projections[context], "nested phase key must round-trip");
242
+ assert.equal(Object.keys(marker.projections).length, 2);
243
+ });
244
+
245
+ test("an escaping key in planning.passthrough also invalidates the whole marker", () => {
246
+ const base = makeTmpBase();
247
+ writeCompatMarker(base, {
248
+ schema: 2,
249
+ lastWriter: "gsd-pi",
250
+ lastProjectedAt: "2026-07-07T00:00:00.000Z",
251
+ projections: {},
252
+ planning: {
253
+ active: true,
254
+ layout: "flat-phases",
255
+ projections: {},
256
+ passthrough: { "../../secret.md": { sha: "cccccccccccccccc", entities: [] } },
257
+ },
258
+ piVersion: "1.8.1",
259
+ });
260
+
261
+ const marker = readCompatMarker(base);
262
+ assert.equal(Object.keys(marker.projections).length, 0);
263
+ assert.equal(marker.planning!.active, false, "planning falls back to inactive default");
264
+ });
265
+
266
+ test("hostile marker makes the drift detector read nothing outside the project", async () => {
267
+ const base = makeTmpBase();
268
+ // Sentinel lives OUTSIDE the project dir; a `../` traversal from .gsd/ would
269
+ // reach it if the key were trusted.
270
+ const sentinelDir = mkdtempSync(join(tmpdir(), `gsd-sentinel-${randomUUID()}`));
271
+ tmpDirs.push(sentinelDir);
272
+ const sentinelName = "known_hosts";
273
+ writeFileSync(join(sentinelDir, sentinelName), "SECRET\n", "utf-8");
274
+ const escapeKey = `../../${sentinelName}`; // e.g. ../../known_hosts
275
+
276
+ writeCompatMarker(base, {
277
+ schema: 2,
278
+ lastWriter: "gsd-pi",
279
+ lastProjectedAt: "2026-07-07T00:00:00.000Z",
280
+ projections: { [escapeKey]: { sha: "0000000000000000", entities: ["m1"] } },
281
+ piVersion: "1.8.1",
282
+ });
283
+
284
+ const stubState = { phase: "idle" } as unknown as GSDState;
285
+ const ctx: DriftContext = { basePath: base, state: stubState };
286
+
287
+ // Must not throw and must not emit a record referencing the sentinel.
288
+ const drift = await externalMarkdownEditHandler.detect(stubState, ctx);
289
+ assert.equal(drift.length, 0, "no drift record from a rejected hostile marker");
290
+ assert.ok(
291
+ !drift.some((d) => d.projectionPath.includes(sentinelName)),
292
+ "detector must not reference the out-of-project sentinel",
293
+ );
294
+ });
@@ -17,6 +17,7 @@ import {
17
17
  insertVerificationEvidence,
18
18
  insertGateRow,
19
19
  getGateResults,
20
+ saveReworkBrief,
20
21
  updateMilestoneStatus,
21
22
  updateSliceStatus,
22
23
  SCHEMA_VERSION,
@@ -507,6 +508,77 @@ console.log('\n=== complete-task: disabled hard-blocker escalation rolls back co
507
508
  cleanup(dbPath);
508
509
  }
509
510
 
511
+ // ═══════════════════════════════════════════════════════════════════════════
512
+ // complete-task: rollback reverts applied rework resolutions
513
+ // ═══════════════════════════════════════════════════════════════════════════
514
+
515
+ console.log('\n=== complete-task: rollback reverts applied rework resolutions ===');
516
+ {
517
+ const dbPath = tempDbPath();
518
+ openDatabase(dbPath);
519
+
520
+ const { basePath } = createTempProject();
521
+ writeProjectPreferences(basePath, 'phases:\n mid_execution_escalation: false\n');
522
+
523
+ insertMilestone({ id: 'M001', title: 'Test Milestone' });
524
+ insertSlice({ id: 'S01', milestoneId: 'M001', title: 'Test Slice' });
525
+ insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', title: 'Test task', status: 'pending' });
526
+ saveReworkBrief({
527
+ briefId: 'RB-001',
528
+ milestoneId: 'M001',
529
+ sliceId: 'S01',
530
+ taskId: 'T01',
531
+ findings: [{
532
+ findingId: 'F1',
533
+ severity: 'blocking',
534
+ description: 'Compile regression',
535
+ requiredFix: 'Fix compile error',
536
+ verificationCommands: ['pnpm run typecheck:extensions'],
537
+ }],
538
+ });
539
+
540
+ // Completion resolves the blocking finding but then rolls back because the
541
+ // hard-blocker escalation is disabled. The rollback must also revert the
542
+ // finding. Otherwise a retry would see no unresolved blocking findings and
543
+ // silently skip the blocking gate.
544
+ const result = await withWorkingDirectory(basePath, () => handleCompleteTask({
545
+ ...makeValidParams(),
546
+ blockerDiscovered: true,
547
+ reworkResolution: [{
548
+ findingId: 'F1',
549
+ status: 'resolved',
550
+ evidence: 'Fixed compile error and reran pnpm run typecheck:extensions.',
551
+ }],
552
+ escalation: {
553
+ question: 'Should execution pause for the hard blocker?',
554
+ options: makeEscalationOptions(),
555
+ recommendation: 'pause',
556
+ recommendationRationale: 'The blocker should not be silently advanced.',
557
+ continueWithDefault: false,
558
+ },
559
+ }, basePath));
560
+
561
+ assertTrue('error' in result, 'completion should roll back when hard-blocker escalation is disabled');
562
+ assertEq(getTask('M001', 'S01', 'T01')?.status, 'pending', 'task status should roll back to pending');
563
+
564
+ const finding = _getAdapter()!.prepare(
565
+ "SELECT status, evidence, decision_ref FROM rework_brief_findings WHERE brief_id = 'RB-001' AND finding_id = 'F1'"
566
+ ).get() as { status: string; evidence: string; decision_ref: string };
567
+ assertEq(finding.status, 'pending', 'rework finding should revert to pending after rollback');
568
+ assertEq(finding.evidence, '', 'rework finding evidence should be cleared after rollback');
569
+
570
+ // Retry-safety invariant: the blocking gate must fire again because the
571
+ // finding is unresolved once more.
572
+ const retry = await withWorkingDirectory(basePath, () => handleCompleteTask(makeValidParams(), basePath));
573
+ assertTrue('error' in retry, 'retry without reworkResolution should be blocked again');
574
+ if ('error' in retry) {
575
+ assertMatch(retry.error, /unresolved blocking rework finding/i, 'retry should re-trigger the blocking gate');
576
+ }
577
+
578
+ cleanupDir(basePath);
579
+ cleanup(dbPath);
580
+ }
581
+
510
582
  // ═══════════════════════════════════════════════════════════════════════════
511
583
  // complete-task: soft escalation with mid-execution escalation disabled
512
584
  // ═══════════════════════════════════════════════════════════════════════════
@@ -838,6 +910,220 @@ console.log('\n=== complete-task: closes Q5/Q6/Q7 gates (pass vs omitted) ===');
838
910
  cleanup(dbPath);
839
911
  }
840
912
 
913
+
914
+ // ═══════════════════════════════════════════════════════════════════════════
915
+ // complete-task: unresolved blocking rework findings reject completion
916
+ // ═══════════════════════════════════════════════════════════════════════════
917
+
918
+ console.log('\n=== complete-task: rejects unresolved blocking rework findings ===');
919
+ {
920
+ const dbPath = tempDbPath();
921
+ openDatabase(dbPath);
922
+ const { basePath } = createTempProject();
923
+
924
+ insertMilestone({ id: 'M001', title: 'Test Milestone' });
925
+ insertSlice({ id: 'S01', milestoneId: 'M001', title: 'Test Slice' });
926
+ insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', title: 'Test task', status: 'pending' });
927
+
928
+ saveReworkBrief({
929
+ briefId: 'RB-001',
930
+ milestoneId: 'M001',
931
+ sliceId: 'S01',
932
+ taskId: 'T01',
933
+ findings: [{
934
+ findingId: 'F1',
935
+ severity: 'blocking',
936
+ description: 'Compile regression',
937
+ requiredFix: 'Fix compile error',
938
+ verificationCommands: ['pnpm run typecheck:extensions'],
939
+ }],
940
+ });
941
+
942
+ const result = await handleCompleteTask(makeValidParams(), basePath);
943
+ assertTrue('error' in result, 'completion should reject unresolved blocking rework findings');
944
+ if ('error' in result) {
945
+ assertMatch(result.error, /unresolved blocking rework finding/i, 'error should explain unresolved rework');
946
+ assertMatch(result.error, /F1/, 'error should name the unresolved finding id');
947
+ }
948
+
949
+ cleanupDir(basePath);
950
+ cleanup(dbPath);
951
+ }
952
+
953
+
954
+ console.log('\n=== complete-task: accepts resolved blocking rework evidence ===');
955
+ {
956
+ const dbPath = tempDbPath();
957
+ openDatabase(dbPath);
958
+ const { basePath } = createTempProject();
959
+
960
+ insertMilestone({ id: 'M001', title: 'Test Milestone' });
961
+ insertSlice({ id: 'S01', milestoneId: 'M001', title: 'Test Slice' });
962
+ insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', title: 'Test task', status: 'pending' });
963
+ saveReworkBrief({
964
+ briefId: 'RB-001',
965
+ milestoneId: 'M001',
966
+ sliceId: 'S01',
967
+ taskId: 'T01',
968
+ findings: [{
969
+ findingId: 'F1',
970
+ severity: 'blocking',
971
+ description: 'Compile regression',
972
+ requiredFix: 'Fix compile error',
973
+ verificationCommands: ['pnpm run typecheck:extensions'],
974
+ }],
975
+ });
976
+
977
+ const result = await handleCompleteTask({
978
+ ...makeValidParams(),
979
+ reworkResolution: [{
980
+ findingId: 'F1',
981
+ status: 'resolved',
982
+ evidence: 'Fixed compile error and reran pnpm run typecheck:extensions.',
983
+ }],
984
+ }, basePath);
985
+
986
+ assertTrue(!('error' in result), 'completion should accept resolved blocking rework evidence');
987
+ assertEq(getTask('M001', 'S01', 'T01')?.status, 'complete', 'task should complete after resolving rework');
988
+ const finding = _getAdapter()!.prepare("SELECT status, evidence FROM rework_brief_findings WHERE brief_id = 'RB-001' AND finding_id = 'F1'").get() as { status: string; evidence: string };
989
+ assertEq(finding.status, 'resolved', 'finding status should be updated');
990
+ assertMatch(finding.evidence, /Fixed compile error/, 'resolution evidence should be persisted');
991
+
992
+ cleanupDir(basePath);
993
+ cleanup(dbPath);
994
+ }
995
+
996
+ console.log('\n=== complete-task: accepts deferred blocking rework with decision reference ===');
997
+ {
998
+ const dbPath = tempDbPath();
999
+ openDatabase(dbPath);
1000
+ const { basePath } = createTempProject();
1001
+
1002
+ insertMilestone({ id: 'M001', title: 'Test Milestone' });
1003
+ insertSlice({ id: 'S01', milestoneId: 'M001', title: 'Test Slice' });
1004
+ insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', title: 'Test task', status: 'pending' });
1005
+ saveReworkBrief({
1006
+ briefId: 'RB-001',
1007
+ milestoneId: 'M001',
1008
+ sliceId: 'S01',
1009
+ taskId: 'T01',
1010
+ findings: [{
1011
+ findingId: 'F1',
1012
+ severity: 'blocking',
1013
+ description: 'Compile regression',
1014
+ requiredFix: 'Fix compile error',
1015
+ verificationCommands: ['pnpm run typecheck:extensions'],
1016
+ }],
1017
+ });
1018
+
1019
+ const result = await handleCompleteTask({
1020
+ ...makeValidParams(),
1021
+ reworkResolution: [{
1022
+ findingId: 'F1',
1023
+ status: 'deferred-with-override',
1024
+ evidence: 'Maintainer accepted temporary deferral.',
1025
+ decisionRef: 'DEC-2026-07-07-rework-deferral',
1026
+ }],
1027
+ }, basePath);
1028
+
1029
+ assertTrue(!('error' in result), 'completion should accept deferred blocking rework with decision reference');
1030
+ const finding = _getAdapter()!.prepare("SELECT status, decision_ref FROM rework_brief_findings WHERE brief_id = 'RB-001' AND finding_id = 'F1'").get() as { status: string; decision_ref: string };
1031
+ assertEq(finding.status, 'deferred-with-override', 'finding status should record the override');
1032
+ assertEq(finding.decision_ref, 'DEC-2026-07-07-rework-deferral', 'decision reference should be persisted');
1033
+
1034
+ cleanupDir(basePath);
1035
+ cleanup(dbPath);
1036
+ }
1037
+
1038
+ console.log('\n=== complete-task: invalid duplicate rework resolution cannot overwrite a valid one ===');
1039
+ {
1040
+ const dbPath = tempDbPath();
1041
+ openDatabase(dbPath);
1042
+ const { basePath } = createTempProject();
1043
+
1044
+ insertMilestone({ id: 'M001', title: 'Test Milestone' });
1045
+ insertSlice({ id: 'S01', milestoneId: 'M001', title: 'Test Slice' });
1046
+ insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', title: 'Test task', status: 'pending' });
1047
+ saveReworkBrief({
1048
+ briefId: 'RB-001',
1049
+ milestoneId: 'M001',
1050
+ sliceId: 'S01',
1051
+ taskId: 'T01',
1052
+ findings: [{
1053
+ findingId: 'F1',
1054
+ severity: 'blocking',
1055
+ description: 'Compile regression',
1056
+ requiredFix: 'Fix compile error',
1057
+ verificationCommands: ['pnpm run typecheck:extensions'],
1058
+ }],
1059
+ });
1060
+
1061
+ // The guard admits F1 because a satisfying entry exists, but a later
1062
+ // non-satisfying duplicate for the same finding must NOT overwrite the valid
1063
+ // resolution and leave F1 resolved with no evidence.
1064
+ const result = await handleCompleteTask({
1065
+ ...makeValidParams(),
1066
+ reworkResolution: [
1067
+ { findingId: 'F1', status: 'resolved', evidence: 'Fixed compile error and reran pnpm run typecheck:extensions.' },
1068
+ { findingId: 'F1', status: 'resolved', evidence: '' },
1069
+ ],
1070
+ }, basePath);
1071
+
1072
+ assertTrue(!('error' in result), 'completion should succeed on the valid resolution');
1073
+ const finding = _getAdapter()!.prepare(
1074
+ "SELECT status, evidence FROM rework_brief_findings WHERE brief_id = 'RB-001' AND finding_id = 'F1'"
1075
+ ).get() as { status: string; evidence: string };
1076
+ assertEq(finding.status, 'resolved', 'finding should remain resolved');
1077
+ assertMatch(finding.evidence, /Fixed compile error/, 'valid evidence must survive the invalid duplicate');
1078
+
1079
+ cleanupDir(basePath);
1080
+ cleanup(dbPath);
1081
+ }
1082
+
1083
+ console.log('\n=== complete-task: invalid deferred duplicate cannot strip decisionRef ===');
1084
+ {
1085
+ const dbPath = tempDbPath();
1086
+ openDatabase(dbPath);
1087
+ const { basePath } = createTempProject();
1088
+
1089
+ insertMilestone({ id: 'M001', title: 'Test Milestone' });
1090
+ insertSlice({ id: 'S01', milestoneId: 'M001', title: 'Test Slice' });
1091
+ insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', title: 'Test task', status: 'pending' });
1092
+ saveReworkBrief({
1093
+ briefId: 'RB-001',
1094
+ milestoneId: 'M001',
1095
+ sliceId: 'S01',
1096
+ taskId: 'T01',
1097
+ findings: [{
1098
+ findingId: 'F1',
1099
+ severity: 'blocking',
1100
+ description: 'Compile regression',
1101
+ requiredFix: 'Fix compile error',
1102
+ verificationCommands: ['pnpm run typecheck:extensions'],
1103
+ }],
1104
+ });
1105
+
1106
+ // A deferred-with-override duplicate that omits decisionRef is non-satisfying
1107
+ // and must not overwrite the valid deferral.
1108
+ const result = await handleCompleteTask({
1109
+ ...makeValidParams(),
1110
+ reworkResolution: [
1111
+ { findingId: 'F1', status: 'deferred-with-override', evidence: 'Maintainer accepted temporary deferral.', decisionRef: 'DEC-2026-07-07-rework-deferral' },
1112
+ { findingId: 'F1', status: 'deferred-with-override', evidence: 'Maintainer accepted temporary deferral.' },
1113
+ ],
1114
+ }, basePath);
1115
+
1116
+ assertTrue(!('error' in result), 'completion should succeed on the valid deferral');
1117
+ const finding = _getAdapter()!.prepare(
1118
+ "SELECT status, decision_ref FROM rework_brief_findings WHERE brief_id = 'RB-001' AND finding_id = 'F1'"
1119
+ ).get() as { status: string; decision_ref: string };
1120
+ assertEq(finding.status, 'deferred-with-override', 'finding should remain deferred-with-override');
1121
+ assertEq(finding.decision_ref, 'DEC-2026-07-07-rework-deferral', 'valid decisionRef must survive the invalid duplicate');
1122
+
1123
+ cleanupDir(basePath);
1124
+ cleanup(dbPath);
1125
+ }
1126
+
841
1127
  // ═══════════════════════════════════════════════════════════════════════════
842
1128
 
843
1129
  report();
@@ -17,7 +17,7 @@ import {
17
17
  openDatabase,
18
18
  } from "../gsd-db.ts";
19
19
  import { migrateHierarchyToDb } from "../md-importer.ts";
20
- import { checkMarkdownHierarchyAgainstDb } from "../migration-auto-check.ts";
20
+ import { checkMarkdownHierarchyAgainstDb, countMarkdownHierarchy } from "../migration-auto-check.ts";
21
21
  import { queryDecisions } from "../context-store.ts";
22
22
  import { deriveStateFromDb, invalidateStateCache } from "../state.ts";
23
23
  import type { Requirement } from "../types.ts";
@@ -206,3 +206,78 @@ test("explicit markdown import remains opt-in and is not run by startup mismatch
206
206
  assert.equal(getAllMilestones().length, 1);
207
207
  assert.equal(getSliceTasks("M001", "S01").length, 1);
208
208
  });
209
+
210
+ // #1286: migrateHierarchyToDb skips a `[sketch]` slice's stub PLAN tasks, so
211
+ // scanMarkdownHierarchy must skip counting them too. Otherwise the markdown
212
+ // scan claims task rows the DB authoritatively omits, and the startup drift
213
+ // check perpetually reports recovery-required / recommends
214
+ // `/gsd recover --confirm` — which re-skips the stub tasks and never converges.
215
+ test("sketch slice stub tasks are not treated as markdown/DB drift", async (t) => {
216
+ const base = makeBase();
217
+ t.after(() => cleanup(base));
218
+
219
+ const milestoneDir = join(base, ".gsd", "milestones", "M001");
220
+ const sketchSliceDir = join(milestoneDir, "slices", "S01");
221
+ const realSliceDir = join(milestoneDir, "slices", "S02");
222
+ mkdirSync(sketchSliceDir, { recursive: true });
223
+ mkdirSync(realSliceDir, { recursive: true });
224
+
225
+ // S01 is a sketch (badge before risk, per ADR-011 render); S02 is refined.
226
+ writeFileSync(
227
+ join(milestoneDir, "M001-ROADMAP.md"),
228
+ [
229
+ "# M001: Sketch Drift",
230
+ "",
231
+ "**Vision:** Sketch stub tasks must not count as drift",
232
+ "",
233
+ "## Slices",
234
+ "- [ ] **S01: Sketch Slice** `[sketch]` `risk:low` `depends:[]`",
235
+ " > After this: Sketch decomposed.",
236
+ "",
237
+ "- [ ] **S02: Real Slice** `risk:low` `depends:[]`",
238
+ " > After this: Real work done.",
239
+ "",
240
+ ].join("\n"),
241
+ );
242
+ // The sketch slice still carries a stub PLAN with a placeholder <tasks> block.
243
+ writeFileSync(
244
+ join(sketchSliceDir, "S01-PLAN.md"),
245
+ [
246
+ "# S01: Sketch Slice",
247
+ "",
248
+ "**Goal:** Placeholder.",
249
+ "",
250
+ "## Tasks",
251
+ "- [ ] **T01: Plan 01**",
252
+ " Stub placeholder task.",
253
+ "",
254
+ ].join("\n"),
255
+ );
256
+ writeFileSync(
257
+ join(realSliceDir, "S02-PLAN.md"),
258
+ [
259
+ "# S02: Real Slice",
260
+ "",
261
+ "**Goal:** Real work.",
262
+ "",
263
+ "## Tasks",
264
+ "- [ ] **T01: Task** `est:5m`",
265
+ "",
266
+ ].join("\n"),
267
+ );
268
+
269
+ openProjectDb(base);
270
+ // The importer seeds S02's task but skips S01's stub (1 task total).
271
+ const imported = migrateHierarchyToDb(base);
272
+ assert.deepEqual(imported, { milestones: 1, slices: 2, tasks: 1 });
273
+ assert.equal(getSliceTasks("M001", "S01").length, 0, "sketch slice seeds no tasks");
274
+ assert.equal(getSliceTasks("M001", "S02").length, 1, "real slice seeds its task");
275
+
276
+ // The markdown scan must mirror the importer: the sketch stub task is not
277
+ // counted, so markdown (1 task) matches the DB (1 task) and the check is
278
+ // in-sync rather than recommending a recover that would never converge.
279
+ assert.deepEqual(countMarkdownHierarchy(base), { milestones: 1, slices: 2, tasks: 1 });
280
+ const check = await checkMarkdownHierarchyAgainstDb(base);
281
+ assert.equal(check.action, "none", "sketch stub tasks must not be flagged as drift");
282
+ assert.equal(check.reason, "in-sync");
283
+ });