@opengsd/gsd-pi 1.8.1 → 1.9.0-dev.97ef11e3

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 (613) hide show
  1. package/README.md +10 -8
  2. package/dist/cli.js +5 -1
  3. package/dist/headless-events.d.ts +2 -1
  4. package/dist/headless-events.js +11 -3
  5. package/dist/headless-milestone-readiness.d.ts +29 -0
  6. package/dist/headless-milestone-readiness.js +161 -0
  7. package/dist/headless.js +27 -3
  8. package/dist/print-mode-exit.d.ts +12 -0
  9. package/dist/print-mode-exit.js +14 -0
  10. package/dist/resources/.managed-resources-content-hash +1 -1
  11. package/dist/resources/GSD-WORKFLOW.md +18 -49
  12. package/dist/resources/extensions/browser-tools/capture.js +2 -77
  13. package/dist/resources/extensions/browser-tools/screenshot-constraints.js +83 -0
  14. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +17 -2
  15. package/dist/resources/extensions/claude-code-cli/turn-assembler.js +30 -2
  16. package/dist/resources/extensions/gsd/artifact-verification.js +3 -4
  17. package/dist/resources/extensions/gsd/auto/loop.js +24 -4
  18. package/dist/resources/extensions/gsd/auto/run-unit.js +19 -1
  19. package/dist/resources/extensions/gsd/auto/unit-phase.js +37 -5
  20. package/dist/resources/extensions/gsd/auto-artifact-paths.js +16 -10
  21. package/dist/resources/extensions/gsd/auto-dispatch.js +76 -19
  22. package/dist/resources/extensions/gsd/auto-post-unit.js +4 -0
  23. package/dist/resources/extensions/gsd/auto-prompts.js +137 -22
  24. package/dist/resources/extensions/gsd/auto-recovery.js +10 -5
  25. package/dist/resources/extensions/gsd/auto-runtime-state.js +5 -5
  26. package/dist/resources/extensions/gsd/auto-start.js +29 -9
  27. package/dist/resources/extensions/gsd/auto-tool-tracking.js +40 -0
  28. package/dist/resources/extensions/gsd/auto-worktree-cleanup.js +4 -0
  29. package/dist/resources/extensions/gsd/auto-worktree-sync.js +7 -3
  30. package/dist/resources/extensions/gsd/auto-worktree-teardown.js +1 -1
  31. package/dist/resources/extensions/gsd/auto.js +20 -6
  32. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +80 -4
  33. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +33 -7
  34. package/dist/resources/extensions/gsd/bootstrap/system-context.js +10 -3
  35. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +88 -50
  36. package/dist/resources/extensions/gsd/command-feedback.js +16 -12
  37. package/dist/resources/extensions/gsd/commands-verdict.js +10 -9
  38. package/dist/resources/extensions/gsd/compat/compat-marker.js +98 -6
  39. package/dist/resources/extensions/gsd/constants.js +12 -13
  40. package/dist/resources/extensions/gsd/context-masker.js +97 -21
  41. package/dist/resources/extensions/gsd/db/command-queue.js +7 -2
  42. package/dist/resources/extensions/gsd/db/engine.js +56 -18
  43. package/dist/resources/extensions/gsd/db/writers/cascades.js +5 -1
  44. package/dist/resources/extensions/gsd/db/writers/status.js +13 -3
  45. package/dist/resources/extensions/gsd/db-base-schema.js +28 -0
  46. package/dist/resources/extensions/gsd/db-migration-steps.js +30 -0
  47. package/dist/resources/extensions/gsd/db-schema-metadata.js +4 -1
  48. package/dist/resources/extensions/gsd/docs/preferences-reference.md +26 -4
  49. package/dist/resources/extensions/gsd/doctor-engine-checks.js +24 -8
  50. package/dist/resources/extensions/gsd/error-classifier.js +12 -2
  51. package/dist/resources/extensions/gsd/exec-sandbox.js +1 -0
  52. package/dist/resources/extensions/gsd/flat-phase-migration.js +168 -21
  53. package/dist/resources/extensions/gsd/git-service.js +19 -7
  54. package/dist/resources/extensions/gsd/gsd-db.js +262 -76
  55. package/dist/resources/extensions/gsd/guided-flow.js +40 -15
  56. package/dist/resources/extensions/gsd/markdown-renderer.js +20 -22
  57. package/dist/resources/extensions/gsd/md-importer.js +107 -20
  58. package/dist/resources/extensions/gsd/migrate/command.js +19 -162
  59. package/dist/resources/extensions/gsd/migrate/execution.js +98 -0
  60. package/dist/resources/extensions/gsd/migrate/plan.js +49 -0
  61. package/dist/resources/extensions/gsd/migrate/planning-writer.js +12 -17
  62. package/dist/resources/extensions/gsd/migrate/presentation.js +64 -0
  63. package/dist/resources/extensions/gsd/model-cost-table.js +2 -0
  64. package/dist/resources/extensions/gsd/model-router.js +11 -0
  65. package/dist/resources/extensions/gsd/parallel-eligibility.js +5 -4
  66. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +28 -43
  67. package/dist/resources/extensions/gsd/paths.js +70 -16
  68. package/dist/resources/extensions/gsd/phase-anchor.js +7 -2
  69. package/dist/resources/extensions/gsd/planning-subagent-policy.js +37 -0
  70. package/dist/resources/extensions/gsd/planning-subagent-registry.js +25 -0
  71. package/dist/resources/extensions/gsd/post-execution-checks.js +4 -4
  72. package/dist/resources/extensions/gsd/preferences-types.js +5 -0
  73. package/dist/resources/extensions/gsd/preferences-validation.js +48 -1
  74. package/dist/resources/extensions/gsd/preferences.js +17 -0
  75. package/dist/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  76. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +5 -5
  77. package/dist/resources/extensions/gsd/provider-payload-policy.js +16 -5
  78. package/dist/resources/extensions/gsd/safety/destructive-guard.js +1 -1
  79. package/dist/resources/extensions/gsd/safety/evidence-collector.js +26 -1
  80. package/dist/resources/extensions/gsd/safety/evidence-cross-ref.js +30 -5
  81. package/dist/resources/extensions/gsd/skill-activation.js +17 -3
  82. package/dist/resources/extensions/gsd/state-reconciliation/drift/external-markdown-edit.js +125 -15
  83. package/dist/resources/extensions/gsd/state-reconciliation/drift/external-planning-edit.js +17 -4
  84. package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +5 -2
  85. package/dist/resources/extensions/gsd/stop-notice.js +24 -1
  86. package/dist/resources/extensions/gsd/sync-lock.js +13 -7
  87. package/dist/resources/extensions/gsd/templates/PREFERENCES.md +5 -0
  88. package/dist/resources/extensions/gsd/tools/complete-task.js +94 -6
  89. package/dist/resources/extensions/gsd/tools/plan-task.js +13 -15
  90. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +18 -15
  91. package/dist/resources/extensions/gsd/tools/reopen-milestone.js +14 -5
  92. package/dist/resources/extensions/gsd/tools/reopen-slice.js +15 -5
  93. package/dist/resources/extensions/gsd/tools/reopen-task.js +16 -10
  94. package/dist/resources/extensions/gsd/tools/replan-task.js +128 -0
  95. package/dist/resources/extensions/gsd/tools/rework-brief.js +74 -0
  96. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +81 -0
  97. package/dist/resources/extensions/gsd/unit-context-composer.js +28 -5
  98. package/dist/resources/extensions/gsd/unit-registry.js +4 -0
  99. package/dist/resources/extensions/gsd/uok/plan-v2.js +19 -3
  100. package/dist/resources/extensions/gsd/workflow-projections.js +2 -3
  101. package/dist/resources/extensions/gsd/workspace.js +2 -1
  102. package/dist/resources/extensions/gsd/worktree-state-projection.js +26 -18
  103. package/dist/resources/extensions/mac-tools/index.js +31 -9
  104. package/dist/resources/extensions/shared/interview-ui.js +43 -6
  105. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  106. package/dist/web/standalone/.next/BUILD_ID +1 -1
  107. package/dist/web/standalone/.next/app-path-routes-manifest.json +7 -7
  108. package/dist/web/standalone/.next/build-manifest.json +3 -3
  109. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  110. package/dist/web/standalone/.next/required-server-files.json +3 -3
  111. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  112. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  113. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  114. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  115. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  116. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  117. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  118. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  119. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  120. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  121. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  122. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  124. package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -4
  125. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -4
  126. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  127. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -4
  128. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  129. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  130. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  131. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  138. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  150. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  166. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/mcp-connections/route_client-reference-manifest.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  172. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  175. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  181. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  182. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  183. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  184. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  185. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  186. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  187. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  188. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  189. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  190. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  191. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  192. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  193. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  194. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  195. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  196. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  197. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  198. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  199. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  200. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  201. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  202. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  203. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  204. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  205. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  206. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  207. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  208. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  209. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  210. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  211. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  212. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  213. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  214. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  215. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  216. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  217. package/dist/web/standalone/.next/server/app/index.html +1 -1
  218. package/dist/web/standalone/.next/server/app/index.rsc +5 -5
  219. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  220. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +5 -5
  221. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  222. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -4
  223. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  224. package/dist/web/standalone/.next/server/app/page.js +2 -2
  225. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  226. package/dist/web/standalone/.next/server/app-paths-manifest.json +7 -7
  227. package/dist/web/standalone/.next/server/chunks/1991.js +2 -2
  228. package/dist/web/standalone/.next/server/chunks/2842.js +4 -4
  229. package/dist/web/standalone/.next/server/chunks/5124.js +1 -1
  230. package/dist/web/standalone/.next/server/chunks/8357.js +3 -3
  231. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  232. package/dist/web/standalone/.next/server/middleware.js +3 -3
  233. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  234. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  235. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  236. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-a6fb1847f67f167c.js +1 -0
  237. package/dist/web/standalone/.next/static/chunks/app/{layout-b35cbfff38aaf4cf.js → layout-4ae2d68984392bbf.js} +1 -1
  238. package/dist/web/standalone/.next/static/chunks/app/page-72a856634ad14c10.js +1 -0
  239. package/dist/web/standalone/.next/static/chunks/{main-app-590a74400e35f685.js → main-app-90d1d8d5e5d2dc6b.js} +1 -1
  240. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-1115d46ac61b9823.js +1 -0
  241. package/dist/web/standalone/.next/static/css/3b1ceb7abfb9a230.css +1 -0
  242. package/dist/web/standalone/node_modules/@gsd/native/package.json +1 -1
  243. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  244. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  245. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  246. package/dist/web/standalone/package.json +0 -1
  247. package/dist/web/standalone/server.js +1 -1
  248. package/dist/web-mode.js +31 -3
  249. package/integrations/hermes/open_gsd_hermes/gsd_client.py +1 -1
  250. package/integrations/hermes/pyproject.toml +1 -1
  251. package/package.json +13 -10
  252. package/packages/cloud-mcp-gateway/package.json +2 -2
  253. package/packages/contracts/dist/workflow.d.ts +14 -0
  254. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  255. package/packages/contracts/dist/workflow.js +16 -0
  256. package/packages/contracts/dist/workflow.js.map +1 -1
  257. package/packages/contracts/package.json +1 -1
  258. package/packages/daemon/dist/cloud-config.d.ts +1 -1
  259. package/packages/daemon/dist/cloud-config.d.ts.map +1 -1
  260. package/packages/daemon/dist/cloud-config.js +5 -1
  261. package/packages/daemon/dist/cloud-config.js.map +1 -1
  262. package/packages/daemon/dist/cloud-config.test.js +51 -1
  263. package/packages/daemon/dist/cloud-config.test.js.map +1 -1
  264. package/packages/daemon/dist/local-tool-executor.d.ts.map +1 -1
  265. package/packages/daemon/dist/local-tool-executor.js +2 -0
  266. package/packages/daemon/dist/local-tool-executor.js.map +1 -1
  267. package/packages/daemon/package.json +6 -6
  268. package/packages/gsd-agent-core/dist/compaction/compaction.d.ts.map +1 -1
  269. package/packages/gsd-agent-core/dist/compaction/compaction.js +36 -4
  270. package/packages/gsd-agent-core/dist/compaction/compaction.js.map +1 -1
  271. package/packages/gsd-agent-core/dist/sdk.d.ts.map +1 -1
  272. package/packages/gsd-agent-core/dist/sdk.js +1 -0
  273. package/packages/gsd-agent-core/dist/sdk.js.map +1 -1
  274. package/packages/gsd-agent-core/package.json +5 -5
  275. package/packages/gsd-agent-modes/package.json +7 -7
  276. package/packages/gsd-cloud/README.md +9 -3
  277. package/packages/gsd-cloud/dist/background-cli.test.d.ts +2 -0
  278. package/packages/gsd-cloud/dist/background-cli.test.d.ts.map +1 -0
  279. package/packages/gsd-cloud/dist/background-cli.test.js +248 -0
  280. package/packages/gsd-cloud/dist/background-cli.test.js.map +1 -0
  281. package/packages/gsd-cloud/dist/cli.d.ts +5 -0
  282. package/packages/gsd-cloud/dist/cli.d.ts.map +1 -0
  283. package/packages/gsd-cloud/dist/cli.js +266 -0
  284. package/packages/gsd-cloud/dist/cli.js.map +1 -0
  285. package/packages/gsd-cloud/dist/cloud-config.d.ts +19 -0
  286. package/packages/gsd-cloud/dist/cloud-config.d.ts.map +1 -0
  287. package/packages/gsd-cloud/dist/cloud-config.js +237 -0
  288. package/packages/gsd-cloud/dist/cloud-config.js.map +1 -0
  289. package/packages/gsd-cloud/dist/cloud-config.test.d.ts +2 -0
  290. package/packages/gsd-cloud/dist/cloud-config.test.d.ts.map +1 -0
  291. package/packages/gsd-cloud/dist/cloud-config.test.js +118 -0
  292. package/packages/gsd-cloud/dist/cloud-config.test.js.map +1 -0
  293. package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.d.ts +2 -0
  294. package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.d.ts.map +1 -0
  295. package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.js +37 -0
  296. package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.js.map +1 -0
  297. package/packages/gsd-cloud/dist/cloud-runtime.d.ts +33 -0
  298. package/packages/gsd-cloud/dist/cloud-runtime.d.ts.map +1 -0
  299. package/packages/gsd-cloud/dist/cloud-runtime.js +260 -0
  300. package/packages/gsd-cloud/dist/cloud-runtime.js.map +1 -0
  301. package/packages/gsd-cloud/dist/cloud-runtime.test.d.ts +2 -0
  302. package/packages/gsd-cloud/dist/cloud-runtime.test.d.ts.map +1 -0
  303. package/packages/gsd-cloud/dist/cloud-runtime.test.js +88 -0
  304. package/packages/gsd-cloud/dist/cloud-runtime.test.js.map +1 -0
  305. package/packages/gsd-cloud/dist/cloud-token.d.ts +3 -0
  306. package/packages/gsd-cloud/dist/cloud-token.d.ts.map +1 -0
  307. package/packages/gsd-cloud/dist/cloud-token.js +37 -0
  308. package/packages/gsd-cloud/dist/cloud-token.js.map +1 -0
  309. package/packages/gsd-cloud/dist/config.d.ts +17 -0
  310. package/packages/gsd-cloud/dist/config.d.ts.map +1 -0
  311. package/packages/gsd-cloud/dist/config.js +146 -0
  312. package/packages/gsd-cloud/dist/config.js.map +1 -0
  313. package/packages/gsd-cloud/dist/device-flow.d.ts +24 -0
  314. package/packages/gsd-cloud/dist/device-flow.d.ts.map +1 -0
  315. package/packages/gsd-cloud/dist/device-flow.js +128 -0
  316. package/packages/gsd-cloud/dist/device-flow.js.map +1 -0
  317. package/packages/gsd-cloud/dist/device-flow.test.d.ts +2 -0
  318. package/packages/gsd-cloud/dist/device-flow.test.d.ts.map +1 -0
  319. package/packages/gsd-cloud/dist/device-flow.test.js +155 -0
  320. package/packages/gsd-cloud/dist/device-flow.test.js.map +1 -0
  321. package/packages/gsd-cloud/dist/executors/claude-executor.d.ts +6 -0
  322. package/packages/gsd-cloud/dist/executors/claude-executor.d.ts.map +1 -0
  323. package/packages/gsd-cloud/dist/executors/claude-executor.js +15 -0
  324. package/packages/gsd-cloud/dist/executors/claude-executor.js.map +1 -0
  325. package/packages/gsd-cloud/dist/executors/codex-executor.d.ts +6 -0
  326. package/packages/gsd-cloud/dist/executors/codex-executor.d.ts.map +1 -0
  327. package/packages/gsd-cloud/dist/executors/codex-executor.js +15 -0
  328. package/packages/gsd-cloud/dist/executors/codex-executor.js.map +1 -0
  329. package/packages/gsd-cloud/dist/executors/executor.d.ts +28 -0
  330. package/packages/gsd-cloud/dist/executors/executor.d.ts.map +1 -0
  331. package/packages/gsd-cloud/dist/executors/executor.js +11 -0
  332. package/packages/gsd-cloud/dist/executors/executor.js.map +1 -0
  333. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.d.ts +34 -0
  334. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.d.ts.map +1 -0
  335. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.js +179 -0
  336. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.js.map +1 -0
  337. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.d.ts +2 -0
  338. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.d.ts.map +1 -0
  339. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.js +44 -0
  340. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.js.map +1 -0
  341. package/packages/gsd-cloud/dist/executors/index.d.ts +17 -0
  342. package/packages/gsd-cloud/dist/executors/index.d.ts.map +1 -0
  343. package/packages/gsd-cloud/dist/executors/index.js +29 -0
  344. package/packages/gsd-cloud/dist/executors/index.js.map +1 -0
  345. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.d.ts +36 -0
  346. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.d.ts.map +1 -0
  347. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.js +176 -0
  348. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.js.map +1 -0
  349. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.d.ts +2 -0
  350. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.d.ts.map +1 -0
  351. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.js +34 -0
  352. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.js.map +1 -0
  353. package/packages/gsd-cloud/dist/index.d.ts +7 -0
  354. package/packages/gsd-cloud/dist/index.d.ts.map +1 -0
  355. package/packages/gsd-cloud/dist/index.js +8 -0
  356. package/packages/gsd-cloud/dist/index.js.map +1 -0
  357. package/packages/gsd-cloud/dist/inject-gateway.d.ts +16 -0
  358. package/packages/gsd-cloud/dist/inject-gateway.d.ts.map +1 -0
  359. package/packages/gsd-cloud/dist/inject-gateway.js +29 -0
  360. package/packages/gsd-cloud/dist/inject-gateway.js.map +1 -0
  361. package/packages/gsd-cloud/dist/inject-gateway.test.d.ts +2 -0
  362. package/packages/gsd-cloud/dist/inject-gateway.test.d.ts.map +1 -0
  363. package/packages/gsd-cloud/dist/inject-gateway.test.js +41 -0
  364. package/packages/gsd-cloud/dist/inject-gateway.test.js.map +1 -0
  365. package/packages/gsd-cloud/dist/logger.d.ts +25 -0
  366. package/packages/gsd-cloud/dist/logger.d.ts.map +1 -0
  367. package/packages/gsd-cloud/dist/logger.js +72 -0
  368. package/packages/gsd-cloud/dist/logger.js.map +1 -0
  369. package/packages/gsd-cloud/dist/runtime-process.d.ts +27 -0
  370. package/packages/gsd-cloud/dist/runtime-process.d.ts.map +1 -0
  371. package/packages/gsd-cloud/dist/runtime-process.js +272 -0
  372. package/packages/gsd-cloud/dist/runtime-process.js.map +1 -0
  373. package/packages/gsd-cloud/dist/runtime-process.test.d.ts +2 -0
  374. package/packages/gsd-cloud/dist/runtime-process.test.d.ts.map +1 -0
  375. package/packages/gsd-cloud/dist/runtime-process.test.js +97 -0
  376. package/packages/gsd-cloud/dist/runtime-process.test.js.map +1 -0
  377. package/packages/gsd-cloud/dist/types.d.ts +51 -0
  378. package/packages/gsd-cloud/dist/types.d.ts.map +1 -0
  379. package/packages/gsd-cloud/dist/types.js +9 -0
  380. package/packages/gsd-cloud/dist/types.js.map +1 -0
  381. package/packages/gsd-cloud/package.json +3 -3
  382. package/packages/mcp-server/README.md +15 -2
  383. package/packages/mcp-server/dist/cli-runner.d.ts +3 -0
  384. package/packages/mcp-server/dist/cli-runner.d.ts.map +1 -1
  385. package/packages/mcp-server/dist/cli-runner.js +119 -33
  386. package/packages/mcp-server/dist/cli-runner.js.map +1 -1
  387. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  388. package/packages/mcp-server/dist/server.js +5 -5
  389. package/packages/mcp-server/dist/server.js.map +1 -1
  390. package/packages/mcp-server/dist/workflow-tools.d.ts +4 -3
  391. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  392. package/packages/mcp-server/dist/workflow-tools.js +64 -2
  393. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  394. package/packages/mcp-server/package.json +4 -4
  395. package/packages/native/package.json +1 -1
  396. package/packages/pi-agent-core/dist/agent.d.ts +5 -1
  397. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  398. package/packages/pi-agent-core/dist/agent.js +2 -0
  399. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  400. package/packages/pi-agent-core/package.json +1 -1
  401. package/packages/pi-ai/dist/models.generated.d.ts +136 -0
  402. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  403. package/packages/pi-ai/dist/models.generated.js +124 -0
  404. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  405. package/packages/pi-ai/dist/providers/amazon-bedrock.js +1 -0
  406. package/packages/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
  407. package/packages/pi-ai/dist/providers/anthropic.js +25 -1
  408. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  409. package/packages/pi-ai/dist/providers/openai-codex-responses.js +1 -1
  410. package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
  411. package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  412. package/packages/pi-ai/dist/providers/openai-completions.js +103 -0
  413. package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
  414. package/packages/pi-ai/dist/providers/openai-responses.js +1 -1
  415. package/packages/pi-ai/dist/providers/openai-responses.js.map +1 -1
  416. package/packages/pi-ai/package.json +1 -1
  417. package/packages/pi-coding-agent/dist/core/capability-patches.js +1 -1
  418. package/packages/pi-coding-agent/dist/core/capability-patches.js.map +1 -1
  419. package/packages/pi-coding-agent/dist/core/model-resolver.js +1 -1
  420. package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
  421. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +11 -1
  422. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  423. package/packages/pi-coding-agent/dist/core/settings-manager.js +8 -0
  424. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  425. package/packages/pi-coding-agent/package.json +7 -7
  426. package/packages/pi-tui/package.json +2 -2
  427. package/packages/rpc-client/package.json +2 -2
  428. package/pkg/package.json +1 -1
  429. package/src/resources/GSD-WORKFLOW.md +18 -49
  430. package/src/resources/extensions/browser-tools/capture.ts +2 -86
  431. package/src/resources/extensions/browser-tools/screenshot-constraints.ts +94 -0
  432. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +18 -1
  433. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +108 -0
  434. package/src/resources/extensions/claude-code-cli/turn-assembler.ts +30 -2
  435. package/src/resources/extensions/gsd/artifact-verification.ts +3 -8
  436. package/src/resources/extensions/gsd/auto/loop.ts +48 -4
  437. package/src/resources/extensions/gsd/auto/run-unit.ts +20 -1
  438. package/src/resources/extensions/gsd/auto/unit-phase.ts +41 -5
  439. package/src/resources/extensions/gsd/auto-artifact-paths.ts +16 -9
  440. package/src/resources/extensions/gsd/auto-dispatch.ts +87 -19
  441. package/src/resources/extensions/gsd/auto-post-unit.ts +4 -0
  442. package/src/resources/extensions/gsd/auto-prompts.ts +156 -20
  443. package/src/resources/extensions/gsd/auto-recovery.ts +10 -8
  444. package/src/resources/extensions/gsd/auto-runtime-state.ts +12 -7
  445. package/src/resources/extensions/gsd/auto-start.ts +31 -8
  446. package/src/resources/extensions/gsd/auto-tool-tracking.ts +56 -0
  447. package/src/resources/extensions/gsd/auto-worktree-cleanup.ts +4 -0
  448. package/src/resources/extensions/gsd/auto-worktree-sync.ts +10 -3
  449. package/src/resources/extensions/gsd/auto-worktree-teardown.ts +1 -1
  450. package/src/resources/extensions/gsd/auto.ts +25 -8
  451. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +92 -4
  452. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +41 -12
  453. package/src/resources/extensions/gsd/bootstrap/system-context.ts +11 -3
  454. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +87 -53
  455. package/src/resources/extensions/gsd/command-feedback.ts +19 -12
  456. package/src/resources/extensions/gsd/commands-verdict.ts +16 -9
  457. package/src/resources/extensions/gsd/compat/compat-marker.ts +119 -8
  458. package/src/resources/extensions/gsd/constants.ts +14 -13
  459. package/src/resources/extensions/gsd/context-masker.ts +98 -2
  460. package/src/resources/extensions/gsd/db/command-queue.ts +7 -1
  461. package/src/resources/extensions/gsd/db/engine.ts +58 -19
  462. package/src/resources/extensions/gsd/db/writers/cascades.ts +5 -1
  463. package/src/resources/extensions/gsd/db/writers/status.ts +25 -8
  464. package/src/resources/extensions/gsd/db-base-schema.ts +30 -0
  465. package/src/resources/extensions/gsd/db-migration-steps.ts +32 -0
  466. package/src/resources/extensions/gsd/db-schema-metadata.ts +4 -1
  467. package/src/resources/extensions/gsd/docs/preferences-reference.md +26 -4
  468. package/src/resources/extensions/gsd/doctor-engine-checks.ts +30 -7
  469. package/src/resources/extensions/gsd/error-classifier.ts +13 -2
  470. package/src/resources/extensions/gsd/exec-sandbox.ts +1 -0
  471. package/src/resources/extensions/gsd/flat-phase-migration.ts +174 -19
  472. package/src/resources/extensions/gsd/git-service.ts +19 -6
  473. package/src/resources/extensions/gsd/gsd-db.ts +340 -85
  474. package/src/resources/extensions/gsd/guided-flow.ts +50 -14
  475. package/src/resources/extensions/gsd/markdown-renderer.ts +28 -30
  476. package/src/resources/extensions/gsd/md-importer.ts +114 -16
  477. package/src/resources/extensions/gsd/migrate/command.ts +21 -227
  478. package/src/resources/extensions/gsd/migrate/execution.ts +136 -0
  479. package/src/resources/extensions/gsd/migrate/plan.ts +101 -0
  480. package/src/resources/extensions/gsd/migrate/planning-writer.ts +12 -20
  481. package/src/resources/extensions/gsd/migrate/presentation.ts +83 -0
  482. package/src/resources/extensions/gsd/model-cost-table.ts +2 -0
  483. package/src/resources/extensions/gsd/model-router.ts +12 -0
  484. package/src/resources/extensions/gsd/parallel-eligibility.ts +5 -4
  485. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +37 -40
  486. package/src/resources/extensions/gsd/paths.ts +77 -16
  487. package/src/resources/extensions/gsd/phase-anchor.ts +8 -2
  488. package/src/resources/extensions/gsd/planning-subagent-policy.ts +58 -0
  489. package/src/resources/extensions/gsd/planning-subagent-registry.ts +31 -0
  490. package/src/resources/extensions/gsd/post-execution-checks.ts +4 -4
  491. package/src/resources/extensions/gsd/preferences-types.ts +16 -0
  492. package/src/resources/extensions/gsd/preferences-validation.ts +62 -0
  493. package/src/resources/extensions/gsd/preferences.ts +25 -0
  494. package/src/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  495. package/src/resources/extensions/gsd/prompts/validate-milestone.md +5 -5
  496. package/src/resources/extensions/gsd/provider-payload-policy.ts +18 -4
  497. package/src/resources/extensions/gsd/safety/destructive-guard.ts +1 -1
  498. package/src/resources/extensions/gsd/safety/evidence-collector.ts +28 -1
  499. package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +31 -5
  500. package/src/resources/extensions/gsd/skill-activation.ts +17 -3
  501. package/src/resources/extensions/gsd/state-reconciliation/drift/external-markdown-edit.ts +162 -15
  502. package/src/resources/extensions/gsd/state-reconciliation/drift/external-planning-edit.ts +20 -4
  503. package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +4 -2
  504. package/src/resources/extensions/gsd/state-reconciliation/types.ts +2 -2
  505. package/src/resources/extensions/gsd/stop-notice.ts +29 -1
  506. package/src/resources/extensions/gsd/sync-lock.ts +14 -6
  507. package/src/resources/extensions/gsd/templates/PREFERENCES.md +5 -0
  508. package/src/resources/extensions/gsd/tests/auto-artifact-paths.test.ts +7 -7
  509. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +264 -0
  510. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +39 -0
  511. package/src/resources/extensions/gsd/tests/auto-start-index-lock.test.ts +21 -1
  512. package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +74 -1
  513. package/src/resources/extensions/gsd/tests/before-provider-context-management.test.ts +55 -0
  514. package/src/resources/extensions/gsd/tests/closeout-git-deferral.test.ts +96 -1
  515. package/src/resources/extensions/gsd/tests/command-feedback.test.ts +12 -0
  516. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +10 -0
  517. package/src/resources/extensions/gsd/tests/compat-marker.test.ts +129 -0
  518. package/src/resources/extensions/gsd/tests/complete-task.test.ts +362 -1
  519. package/src/resources/extensions/gsd/tests/context-masker.test.ts +204 -8
  520. package/src/resources/extensions/gsd/tests/db-engine-cjs-compat.test.ts +12 -0
  521. package/src/resources/extensions/gsd/tests/db-engine-migrate-guards.test.ts +186 -0
  522. package/src/resources/extensions/gsd/tests/db-tools-alias-suppression.test.ts +62 -0
  523. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +29 -0
  524. package/src/resources/extensions/gsd/tests/destructive-confirmation.test.ts +33 -0
  525. package/src/resources/extensions/gsd/tests/destructive-guard.test.ts +14 -0
  526. package/src/resources/extensions/gsd/tests/discuss-routing-fixes.test.ts +123 -0
  527. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +50 -0
  528. package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +49 -0
  529. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +83 -0
  530. package/src/resources/extensions/gsd/tests/evidence-cross-ref.test.ts +81 -0
  531. package/src/resources/extensions/gsd/tests/evidence-xref-gsd-exec.test.ts +22 -0
  532. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +33 -1
  533. package/src/resources/extensions/gsd/tests/external-edit-scoped-import.test.ts +262 -0
  534. package/src/resources/extensions/gsd/tests/external-markdown-edit.test.ts +38 -1
  535. package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +201 -0
  536. package/src/resources/extensions/gsd/tests/flat-phase-validation-path.test.ts +20 -1
  537. package/src/resources/extensions/gsd/tests/gate-storage.test.ts +29 -0
  538. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +57 -0
  539. package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +22 -0
  540. package/src/resources/extensions/gsd/tests/import-slice-milestone-completion-preserve.test.ts +116 -0
  541. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +13 -0
  542. package/src/resources/extensions/gsd/tests/integration/paths.test.ts +22 -4
  543. package/src/resources/extensions/gsd/tests/integration-branch-meta-location.test.ts +62 -0
  544. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +5 -5
  545. package/src/resources/extensions/gsd/tests/migrate-plan.test.ts +68 -0
  546. package/src/resources/extensions/gsd/tests/migrate-presentation.test.ts +98 -0
  547. package/src/resources/extensions/gsd/tests/migrate-safety-audit.test.ts +1 -1
  548. package/src/resources/extensions/gsd/tests/milestone-leases.test.ts +55 -0
  549. package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
  550. package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
  551. package/src/resources/extensions/gsd/tests/parallel-eligibility-file-overlap.test.ts +146 -0
  552. package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +59 -0
  553. package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +7 -5
  554. package/src/resources/extensions/gsd/tests/phase-anchor.test.ts +32 -4
  555. package/src/resources/extensions/gsd/tests/plan-task.test.ts +26 -23
  556. package/src/resources/extensions/gsd/tests/planning-writer.test.ts +29 -0
  557. package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +22 -0
  558. package/src/resources/extensions/gsd/tests/preferences.test.ts +84 -0
  559. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +4 -0
  560. package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +87 -0
  561. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +121 -1
  562. package/src/resources/extensions/gsd/tests/reactive-executor.test.ts +39 -0
  563. package/src/resources/extensions/gsd/tests/reassess-handler.test.ts +50 -0
  564. package/src/resources/extensions/gsd/tests/register-hooks-loop-guard-auto.test.ts +105 -0
  565. package/src/resources/extensions/gsd/tests/replan-task-handler.test.ts +103 -0
  566. package/src/resources/extensions/gsd/tests/rework-brief.test.ts +197 -0
  567. package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
  568. package/src/resources/extensions/gsd/tests/single-writer-v3-tool-surface.test.ts +33 -7
  569. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +20 -16
  570. package/src/resources/extensions/gsd/tests/skip-slice-cascades-tasks.test.ts +21 -0
  571. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +52 -0
  572. package/src/resources/extensions/gsd/tests/stop-notice.test.ts +38 -1
  573. package/src/resources/extensions/gsd/tests/sync-lock.test.ts +19 -0
  574. package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +13 -7
  575. package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +14 -0
  576. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +19 -0
  577. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -0
  578. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +73 -0
  579. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +93 -1
  580. package/src/resources/extensions/gsd/tests/validate-milestone-prompt-verification-classes.test.ts +7 -0
  581. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +2 -0
  582. package/src/resources/extensions/gsd/tests/workflow-migration-gates.test.ts +139 -0
  583. package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +4 -4
  584. package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +36 -0
  585. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +60 -0
  586. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +34 -0
  587. package/src/resources/extensions/gsd/tests/write-gate-seam.test.ts +52 -0
  588. package/src/resources/extensions/gsd/tools/complete-task.ts +140 -5
  589. package/src/resources/extensions/gsd/tools/plan-task.ts +14 -16
  590. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +18 -17
  591. package/src/resources/extensions/gsd/tools/reopen-milestone.ts +24 -5
  592. package/src/resources/extensions/gsd/tools/reopen-slice.ts +25 -5
  593. package/src/resources/extensions/gsd/tools/reopen-task.ts +23 -9
  594. package/src/resources/extensions/gsd/tools/replan-task.ts +160 -0
  595. package/src/resources/extensions/gsd/tools/rework-brief.ts +91 -0
  596. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +92 -0
  597. package/src/resources/extensions/gsd/types.ts +11 -0
  598. package/src/resources/extensions/gsd/unit-context-composer.ts +34 -8
  599. package/src/resources/extensions/gsd/unit-registry.ts +4 -0
  600. package/src/resources/extensions/gsd/uok/plan-v2.ts +20 -3
  601. package/src/resources/extensions/gsd/workflow-projections.ts +2 -3
  602. package/src/resources/extensions/gsd/workspace.ts +2 -1
  603. package/src/resources/extensions/gsd/worktree-state-projection.ts +33 -24
  604. package/src/resources/extensions/mac-tools/index.ts +52 -9
  605. package/src/resources/extensions/mac-tools/tests/mac-screenshot-payload.test.cjs +70 -0
  606. package/src/resources/extensions/shared/interview-ui.ts +47 -8
  607. package/src/resources/extensions/shared/tests/interview-ui-border.test.ts +29 -0
  608. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-49f565245e1e4afe.js +0 -1
  609. package/dist/web/standalone/.next/static/chunks/app/page-bc4c723c6a19c6f0.js +0 -1
  610. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ec3eaffc9785ba48.js +0 -1
  611. package/dist/web/standalone/.next/static/css/18c2fdf261bfc1b7.css +0 -1
  612. /package/dist/web/standalone/.next/static/{UaXRrOYxBpG9QBINKhZkg → DXD9fZPnqtjZSlT5xdC3v}/_buildManifest.js +0 -0
  613. /package/dist/web/standalone/.next/static/{UaXRrOYxBpG9QBINKhZkg → DXD9fZPnqtjZSlT5xdC3v}/_ssgManifest.js +0 -0
@@ -7,7 +7,9 @@ import { canonicalToolName } from "../engine-hook-contract.js";
7
7
  import { loadJsonFileOrNull } from "../json-persistence.js";
8
8
  import { getIsolationMode } from "../preferences.js";
9
9
  import { compileSubagentPermissionContract } from "../unit-context-manifest.js";
10
+ import { allowedPlanningDispatchAgentsList, isReadOnlyPlanningDispatchAgent, } from "../planning-subagent-registry.js";
10
11
  import { logWarning } from "../workflow-logger.js";
12
+ import { acquireSyncLock, releaseSyncLock } from "../sync-lock.js";
11
13
  import { isGsdWorktreePath, resolveWorktreeProjectRoot } from "../worktree-root.js";
12
14
  import { worktreesDirs } from "../worktree-placement.js";
13
15
  import { bashReferencesProjectRootOutsideWorktree } from "../worktree-shell-guard.js";
@@ -318,12 +320,65 @@ export function refreshWriteGateStateFromDisk(basePath) {
318
320
  }
319
321
  return currentWriteGateSnapshot(basePath);
320
322
  }
323
+ const WRITE_GATE_LOCK_NAME = "write-gate.lock";
324
+ /**
325
+ * Test-only seam: fires once inside the held cross-process lock (after acquire,
326
+ * before the read-merge-write body) with the resolved lock root. Lets a
327
+ * regression test observe that a concurrent process is genuinely locked out of
328
+ * the critical section. Production leaves it null. Follows the repo's
329
+ * `_setGhAvailableForTest` naming convention.
330
+ */
331
+ let interleaveHookForTest = null;
332
+ export function _setWriteGateInterleaveHookForTest(fn) {
333
+ interleaveHookForTest = fn;
334
+ }
335
+ /**
336
+ * Serialize the read-merge-write critical section across the two processes
337
+ * that share the snapshot file (extension host + workflow MCP child). Atomic
338
+ * rename prevents torn files but not lost updates: without this lock the host
339
+ * can read the snapshot, the child can arm a gate and persist, then the host's
340
+ * later persist overwrites `pendingGateId`/`activeQueuePhase` (last-writer-wins
341
+ * fields) and silently drops the armed HARD-BLOCK gate.
342
+ *
343
+ * Fail-OPEN by contract: if a live peer holds the lock we proceed WITHOUT it —
344
+ * exactly the racy-but-functional behavior that shipped before this lock — and
345
+ * log once. The lock shrinks the race window to ~zero; it must never block,
346
+ * throw, or refuse a gate mutation. The lock is skipped entirely when snapshot
347
+ * persistence is off (no disk file, no cross-process seam).
348
+ */
349
+ function withWriteGateLock(basePath, fn) {
350
+ if (!shouldPersistWriteGateSnapshot())
351
+ return fn();
352
+ const lockRoot = resolveWriteGateSnapshotRoot(basePath);
353
+ // Materialize `.gsd/` (including a dangling external-state symlink target)
354
+ // before locking. acquireSyncLock's own mkdir does NOT follow a symlink to
355
+ // create its target, so without this the O_EXCL open lands on a missing
356
+ // parent and the lock silently fails open — leaving the seam unserialized
357
+ // for exactly the external-state projects that need it. This is the same
358
+ // directory the persist path ensures anyway.
359
+ try {
360
+ ensureWriteGateSnapshotDirectory(basePath);
361
+ }
362
+ catch { /* best-effort; acquire fails-open below */ }
363
+ const { acquired } = acquireSyncLock(lockRoot, 0, WRITE_GATE_LOCK_NAME);
364
+ if (!acquired) {
365
+ logWarning("intercept", "write-gate: proceeding without cross-process lock (held by live peer)", { lockRoot });
366
+ return fn();
367
+ }
368
+ try {
369
+ interleaveHookForTest?.(lockRoot);
370
+ return fn();
371
+ }
372
+ finally {
373
+ releaseSyncLock(lockRoot, WRITE_GATE_LOCK_NAME);
374
+ }
375
+ }
321
376
  /**
322
377
  * Read-modify-write primitive for gate mutations. Reconciles the disk
323
378
  * snapshot into memory (union merge), applies the mutation on top, then
324
- * persists. The whole sequence is synchronous, so the reconcile read
325
- * doubles as the pre-persist merge of concurrent writes there is no
326
- * version field; the read-merge-write is simply unconditional.
379
+ * persists all under the cross-process lock (withWriteGateLock). The whole
380
+ * sequence is synchronous, so the reconcile read doubles as the pre-persist
381
+ * merge of concurrent writes; there is no version field.
327
382
  *
328
383
  * The mutate callback sees the already-reconciled state, so policy checks
329
384
  * (e.g. host setPending's verified-on-disk-wins guard) can live inside it
@@ -335,23 +390,25 @@ export function refreshWriteGateStateFromDisk(basePath) {
335
390
  */
336
391
  function mutateWriteGateState(basePath, mutate, opts) {
337
392
  const state = getWriteGateState(basePath);
338
- if (shouldPersistWriteGateSnapshot() && (opts?.reconcile ?? true)) {
339
- const disk = readDiskSnapshot(basePath);
340
- if (disk) {
341
- mergeSnapshotIntoState(state, disk);
342
- }
343
- else {
344
- // Missing OR unparseable on disk: treat as a full reset. Keeping
345
- // stale in-memory state across a corrupt snapshot would persist it
346
- // back on this very mutation and defeat the documented
347
- // "delete the file to clear the HARD BLOCK gate" escape hatch.
348
- replaceStateFromSnapshot(state, EMPTY_SNAPSHOT);
393
+ return withWriteGateLock(basePath, () => {
394
+ if (shouldPersistWriteGateSnapshot() && (opts?.reconcile ?? true)) {
395
+ const disk = readDiskSnapshot(basePath);
396
+ if (disk) {
397
+ mergeSnapshotIntoState(state, disk);
398
+ }
399
+ else {
400
+ // Missing OR unparseable on disk: treat as a full reset. Keeping
401
+ // stale in-memory state across a corrupt snapshot would persist it
402
+ // back on this very mutation and defeat the documented
403
+ // "delete the file to clear the HARD BLOCK gate" escape hatch.
404
+ replaceStateFromSnapshot(state, EMPTY_SNAPSHOT);
405
+ }
349
406
  }
350
- }
351
- if (mutate(state) === false)
352
- return false;
353
- persistWriteGateSnapshot(basePath, opts?.writer ?? defaultWriteGateWriter());
354
- return true;
407
+ if (mutate(state) === false)
408
+ return false;
409
+ persistWriteGateSnapshot(basePath, opts?.writer ?? defaultWriteGateWriter());
410
+ return true;
411
+ });
355
412
  }
356
413
  export function isDepthVerified(basePath = process.cwd()) {
357
414
  return getWriteGateState(basePath).verifiedDepthMilestones.size > 0;
@@ -550,13 +607,15 @@ export const childWriteGateAdapter = {
550
607
  };
551
608
  function childMutate(basePath, mutate) {
552
609
  const state = getWriteGateState(basePath);
553
- if (shouldPersistWriteGateSnapshot()) {
554
- // Always-fresh: disk is the only truth for the child; discard any
555
- // cross-turn in-memory residue before mutating.
556
- replaceStateFromSnapshot(state, readDiskSnapshot(basePath) ?? EMPTY_SNAPSHOT);
557
- }
558
- mutate(state);
559
- persistWriteGateSnapshot(basePath, "child");
610
+ withWriteGateLock(basePath, () => {
611
+ if (shouldPersistWriteGateSnapshot()) {
612
+ // Always-fresh: disk is the only truth for the child; discard any
613
+ // cross-turn in-memory residue before mutating.
614
+ replaceStateFromSnapshot(state, readDiskSnapshot(basePath) ?? EMPTY_SNAPSHOT);
615
+ }
616
+ mutate(state);
617
+ persistWriteGateSnapshot(basePath, "child");
618
+ });
560
619
  }
561
620
  /**
562
621
  * Which adapter the module-level convenience exports (markDepthVerified,
@@ -923,29 +982,8 @@ export function shouldBlockQueueExecutionInSnapshot(snapshot, toolName, input, q
923
982
  // guards.
924
983
  const PLANNING_WRITE_TOOLS = new Set(["write", "edit", "multi_edit", "notebook_edit"]);
925
984
  const PLANNING_SUBAGENT_TOOLS = new Set(["subagent", "task"]);
926
- /**
927
- * Canonical registry for agents that planning-dispatch may consider. Unit
928
- * manifests still declare per-unit subsets via ToolsPolicy.allowedSubagents.
929
- */
930
- const PLANNING_DISPATCH_AGENT_REGISTRY = {
931
- mnemo: { readOnlySpecialist: true },
932
- scout: { readOnlySpecialist: true },
933
- planner: { readOnlySpecialist: true },
934
- reviewer: { readOnlySpecialist: true },
935
- security: { readOnlySpecialist: true },
936
- tester: { readOnlySpecialist: true },
937
- };
938
- export const ALLOWED_PLANNING_DISPATCH_AGENTS = new Set(Object.entries(PLANNING_DISPATCH_AGENT_REGISTRY)
939
- .filter(([, metadata]) => metadata.readOnlySpecialist)
940
- .map(([agentId]) => agentId));
985
+ export { ALLOWED_PLANNING_DISPATCH_AGENTS } from "../planning-subagent-registry.js";
941
986
  let warnedMissingControlledDispatchAgentClasses = false;
942
- function isReadOnlySpecialist(agentId) {
943
- const metadata = PLANNING_DISPATCH_AGENT_REGISTRY[agentId];
944
- return metadata?.readOnlySpecialist === true;
945
- }
946
- function allowedPlanningDispatchAgentsList() {
947
- return [...ALLOWED_PLANNING_DISPATCH_AGENTS].join(", ");
948
- }
949
987
  function allowsControlledSubagentDispatch(policy) {
950
988
  return ((policy.mode === "planning-dispatch" || policy.mode === "verification" || policy.mode === "workflow-only") &&
951
989
  Array.isArray(policy.allowedSubagents));
@@ -1093,13 +1131,13 @@ export function shouldBlockPlanningUnit(toolName, pathOrCommand, basePath, unitT
1093
1131
  if (requested.length === 0) {
1094
1132
  return { block: false };
1095
1133
  }
1096
- const globallyDisallowed = requested.find(a => !isReadOnlySpecialist(a));
1134
+ const globallyDisallowed = requested.find(a => !isReadOnlyPlanningDispatchAgent(a));
1097
1135
  if (globallyDisallowed) {
1098
1136
  return planningBlock(unitType, policy.mode, `subagent dispatch of "${globallyDisallowed}" not permitted; only read-only specialists (${allowedPlanningDispatchAgentsList()}) may be dispatched from ${policy.mode} units`);
1099
1137
  }
1100
1138
  const disallowedByPolicy = requested.find(a => !allowed.has(a));
1101
1139
  if (disallowedByPolicy) {
1102
- return planningBlock(unitType, policy.mode, `subagent dispatch of "${disallowedByPolicy}" not permitted by ToolsPolicy.allowedSubagents; permitted agents for this unit: ${allowedSubagents.join(", ")}`);
1140
+ return planningBlock(unitType, policy.mode, `subagent dispatch of "${disallowedByPolicy}" not permitted by unit allowlist (ToolsPolicy.allowedSubagents/planning_subagents); permitted agents for this unit: ${allowedSubagents.join(", ")}`);
1103
1141
  }
1104
1142
  return { block: false };
1105
1143
  }
@@ -57,19 +57,23 @@ export function notifyDiscussNeedsInteractiveMenu(ctx, reason) {
57
57
  hints: DISCUSS_HINTS,
58
58
  });
59
59
  }
60
- /** Hub picker for /gsd queue (reorder vs add) is unavailable. */
60
+ /**
61
+ * Hub picker for /gsd queue (reorder vs add) is unavailable.
62
+ *
63
+ * Unlike the other picker-guidance notices, /gsd queue does NOT dead-end here:
64
+ * the caller falls through to the add-work flow, which runs headlessly. So this
65
+ * notice must avoid the "did not start:" picker-failure phrasing — the headless
66
+ * host classifies that as a blocked dead-end (see stop-notice.ts / #1294) and
67
+ * would exit 10 before the add-work run starts.
68
+ */
61
69
  export function notifyQueueHubNeedsInteractiveMenu(ctx, reason) {
62
- notifyPickerCommandNeedsInteractiveMenu(ctx, {
63
- command: "/gsd queue",
64
- reason,
65
- alternatives: [
66
- "Add-work flow can run headless continuing with queue discussion.",
67
- ],
68
- hints: [
69
- "/gsd queue — run from the GSD TUI to reorder pending milestones",
70
- "/gsd status — see milestone order and phase",
71
- ],
72
- });
70
+ ctx.ui.notify([
71
+ `/gsd queue reorder menu needs an interactive session (${reason}).`,
72
+ "Continuing headless with the add-work flow.",
73
+ "",
74
+ " /gsd queue run from the GSD TUI to reorder pending milestones",
75
+ " • /gsd status — see milestone order and phase",
76
+ ].join("\n"), "warning");
73
77
  }
74
78
  /** /gsd, /gsd new-milestone, /gsd new-project wizard menus. */
75
79
  export function notifySmartEntryNeedsInteractiveMenu(ctx, reason) {
@@ -8,6 +8,7 @@ import { executeValidateMilestone } from "./tools/workflow-tool-executors.js";
8
8
  import { ensureDbOpen } from "./bootstrap/dynamic-tools.js";
9
9
  import { getLatestAssessmentByScope } from "./gsd-db.js";
10
10
  import { checkpointWorkflowDatabase } from "./db-workspace.js";
11
+ import { formatVerdictRecordedNotice, formatVerdictRejectedNotice } from "./stop-notice.js";
11
12
  import { VALIDATION_VERDICTS, extractVerdict, isValidMilestoneVerdict, } from "./verdict-parser.js";
12
13
  const USAGE = 'Usage: /gsd verdict <pass|needs-attention|needs-remediation> [--milestone Mxxx] [--rationale "..."]';
13
14
  function tokenize(raw) {
@@ -123,35 +124,35 @@ async function loadExistingValidation(basePath, milestoneId) {
123
124
  }
124
125
  export async function handleVerdict(rawArgs, ctx, basePath) {
125
126
  if (!rawArgs.trim()) {
126
- ctx.ui.notify(USAGE, "warning");
127
+ ctx.ui.notify(formatVerdictRejectedNotice(USAGE), "warning");
127
128
  return;
128
129
  }
129
130
  const parsed = parseArgs(rawArgs);
130
131
  if ("error" in parsed) {
131
- ctx.ui.notify(`${parsed.error}\n${USAGE}`, "warning");
132
+ ctx.ui.notify(formatVerdictRejectedNotice(`${parsed.error}\n${USAGE}`), "warning");
132
133
  return;
133
134
  }
134
135
  if (!parsed.verdict) {
135
- ctx.ui.notify(USAGE, "warning");
136
+ ctx.ui.notify(formatVerdictRejectedNotice(USAGE), "warning");
136
137
  return;
137
138
  }
138
139
  let milestoneId = parsed.milestoneId;
139
140
  if (!milestoneId) {
140
141
  const state = await deriveState(basePath);
141
142
  if (!state.activeMilestone) {
142
- ctx.ui.notify("No active milestone — pass --milestone Mxxx to target a specific milestone.", "warning");
143
+ ctx.ui.notify(formatVerdictRejectedNotice("No active milestone — pass --milestone Mxxx to target a specific milestone."), "warning");
143
144
  return;
144
145
  }
145
146
  milestoneId = state.activeMilestone.id;
146
147
  }
147
148
  const existingValidation = await loadExistingValidation(basePath, milestoneId);
148
149
  if (!existingValidation) {
149
- ctx.ui.notify(`No milestone validation found for ${milestoneId}. Run /gsd auto to validate first, then retry /gsd verdict.`, "warning");
150
+ ctx.ui.notify(formatVerdictRejectedNotice(`No milestone validation found for ${milestoneId}. Run /gsd auto to validate first, then retry /gsd verdict.`), "warning");
150
151
  return;
151
152
  }
152
153
  const current = parseValidationFile(existingValidation.content);
153
154
  if (parsed.verdict !== "pass" && !parsed.rationale) {
154
- ctx.ui.notify(`--rationale is required when overriding to ${parsed.verdict}.`, "warning");
155
+ ctx.ui.notify(formatVerdictRejectedNotice(`--rationale is required when overriding to ${parsed.verdict}.`), "warning");
155
156
  return;
156
157
  }
157
158
  const verdictRationale = parsed.rationale ?? "Manually overridden via /gsd verdict";
@@ -169,17 +170,17 @@ export async function handleVerdict(rawArgs, ctx, basePath) {
169
170
  }, basePath, parsed.verdict === "pass" ? { skipBrowserEvidenceGate: true } : undefined);
170
171
  if (result.isError) {
171
172
  const msg = result.content[0]?.type === "text" ? result.content[0].text : "Unknown error";
172
- ctx.ui.notify(msg, "error");
173
+ ctx.ui.notify(formatVerdictRejectedNotice(msg), "error");
173
174
  return;
174
175
  }
175
176
  checkpointWorkflowDatabase();
176
177
  const prevVerdict = current.verdict ?? "unknown";
177
178
  const effectiveVerdict = extractEffectiveVerdict(result.details, parsed.verdict);
178
179
  if (effectiveVerdict !== parsed.verdict) {
179
- ctx.ui.notify(`Milestone ${milestoneId} verdict requested: ${parsed.verdict}, effective: ${effectiveVerdict} (${existingValidation.source})`, "warning");
180
+ ctx.ui.notify(formatVerdictRecordedNotice(`Milestone ${milestoneId} verdict requested: ${parsed.verdict}, effective: ${effectiveVerdict} (${existingValidation.source})`), "warning");
180
181
  }
181
182
  else {
182
- ctx.ui.notify(`Milestone ${milestoneId} verdict: ${prevVerdict} -> ${effectiveVerdict} (${existingValidation.source})`, "success");
183
+ ctx.ui.notify(formatVerdictRecordedNotice(`Milestone ${milestoneId} verdict: ${prevVerdict} -> ${effectiveVerdict} (${existingValidation.source})`), "success");
183
184
  }
184
185
  if (effectiveVerdict === "needs-remediation") {
185
186
  ctx.ui.notify("Follow up with /gsd dispatch reassess to add remediation slices, then re-run /gsd auto.", "info");
@@ -5,8 +5,8 @@
5
5
  // distinguish gsd-pi's own writes (expected) from external edits made by gsd-core
6
6
  // (drift to import). gsd-core is oblivious to this file and ignores it.
7
7
  import { createHash } from "node:crypto";
8
- import { existsSync, readFileSync, renameSync, unlinkSync, writeFileSync, mkdirSync } from "node:fs";
9
- import { dirname, join } from "node:path";
8
+ import { existsSync, readFileSync, realpathSync, renameSync, unlinkSync, writeFileSync, mkdirSync } from "node:fs";
9
+ import { dirname, join, isAbsolute, normalize, relative, resolve } from "node:path";
10
10
  /** Current marker schema version. Bump on breaking format changes + migrate. */
11
11
  export const COMPAT_MARKER_SCHEMA = 2;
12
12
  /** Marker returned when no marker exists yet (fresh project, first gsd-pi run). */
@@ -32,6 +32,35 @@ export function normalizeForHash(content) {
32
32
  export function computeProjectionSha(content) {
33
33
  return createHash("sha256").update(normalizeForHash(content)).digest("hex").slice(0, 16);
34
34
  }
35
+ function normalizeRealPath(p) {
36
+ try {
37
+ return realpathSync.native(p);
38
+ }
39
+ catch {
40
+ return resolve(p);
41
+ }
42
+ }
43
+ function rootRelativeKey(rootPath, absPath) {
44
+ const root = normalizeRealPath(rootPath);
45
+ const abs = normalizeRealPath(absPath);
46
+ const rel = relative(root, abs);
47
+ if (!rel || rel === ".." || rel.startsWith(`..${sepForRelative(rel)}`) || isAbsolute(rel)) {
48
+ return null;
49
+ }
50
+ return rel.replace(/\\/g, "/");
51
+ }
52
+ function sepForRelative(rel) {
53
+ return rel.includes("\\") ? "\\" : "/";
54
+ }
55
+ export function deriveCompatProjectionKey(absPath, roots) {
56
+ for (const root of roots) {
57
+ const key = rootRelativeKey(root, absPath);
58
+ if (key)
59
+ return key;
60
+ }
61
+ const fallbackRoot = roots[roots.length - 1] ?? dirname(absPath);
62
+ return relative(fallbackRoot, absPath).replace(/\\/g, "/");
63
+ }
35
64
  /**
36
65
  * Read & validate the marker. A missing marker → EMPTY_MARKER (treat every
37
66
  * projection as external on next reconcile). A malformed marker is quarantined
@@ -39,7 +68,9 @@ export function computeProjectionSha(content) {
39
68
  * EMPTY_MARKER. A schema-mismatch returns EMPTY_MARKER (forward-compat: refuse
40
69
  * to act on a future format we don't understand).
41
70
  */
42
- export function readCompatMarker(basePath) {
71
+ export function readCompatMarker(basePath, options = {}) {
72
+ const healInvalidKeys = options.healInvalidKeys ?? true;
73
+ const quarantineInvalid = options.quarantineInvalid ?? true;
43
74
  const path = compatMarkerPath(basePath);
44
75
  if (!existsSync(path))
45
76
  return emptyMarker();
@@ -55,11 +86,16 @@ export function readCompatMarker(basePath) {
55
86
  parsed = JSON.parse(raw);
56
87
  }
57
88
  catch {
58
- quarantine(basePath, raw);
89
+ if (quarantineInvalid)
90
+ quarantine(basePath, raw);
59
91
  return emptyMarker();
60
92
  }
93
+ if (healInvalidKeys && healMarkerProjectionKeys(basePath, parsed) && isValidMarker(parsed)) {
94
+ writeCompatMarker(basePath, parsed);
95
+ }
61
96
  if (!isValidMarker(parsed)) {
62
- quarantine(basePath, raw);
97
+ if (quarantineInvalid)
98
+ quarantine(basePath, raw);
63
99
  return emptyMarker();
64
100
  }
65
101
  // Promote older markers by defaulting absent fields. Schema 1 → 2 only adds
@@ -170,15 +206,71 @@ function isValidProjectionEntry(x) {
170
206
  return false;
171
207
  return true;
172
208
  }
209
+ /**
210
+ * Projection-map keys are repo-relative paths under .gsd/ or .planning/.
211
+ * The marker is repo-controlled content, so a key must never escape its
212
+ * root: reject absolute paths, drive letters, backslashes, and any
213
+ * normalized form that starts with "..". Mirrors the write-side guard in
214
+ * db-writer.ts.
215
+ */
216
+ function isSafeProjectionKey(key) {
217
+ if (key.length === 0 || key.includes("\\") || key.includes("\0"))
218
+ return false;
219
+ if (isAbsolute(key) || /^[A-Za-z]:/.test(key))
220
+ return false;
221
+ const norm = normalize(key);
222
+ return norm !== ".." && !norm.startsWith("../") && !isAbsolute(norm);
223
+ }
173
224
  function isValidProjectionMap(x) {
174
225
  if (typeof x !== "object" || x === null)
175
226
  return false;
176
- for (const v of Object.values(x)) {
227
+ for (const [k, v] of Object.entries(x)) {
228
+ if (!isSafeProjectionKey(k))
229
+ return false;
177
230
  if (!isValidProjectionEntry(v))
178
231
  return false;
179
232
  }
180
233
  return true;
181
234
  }
235
+ function healMarkerProjectionKeys(basePath, marker) {
236
+ if (typeof marker !== "object" || marker === null)
237
+ return false;
238
+ const m = marker;
239
+ let changed = false;
240
+ if (typeof m.projections === "object" && m.projections !== null) {
241
+ changed = healProjectionMapKeys(basePath, ".gsd", m.projections) || changed;
242
+ }
243
+ const planning = m.planning;
244
+ if (typeof planning === "object" && planning !== null) {
245
+ const p = planning;
246
+ if (typeof p.projections === "object" && p.projections !== null) {
247
+ changed = healProjectionMapKeys(basePath, ".planning", p.projections) || changed;
248
+ }
249
+ if (typeof p.passthrough === "object" && p.passthrough !== null) {
250
+ changed = healProjectionMapKeys(basePath, ".planning", p.passthrough) || changed;
251
+ }
252
+ }
253
+ return changed;
254
+ }
255
+ function healProjectionMapKeys(basePath, rootName, map) {
256
+ let changed = false;
257
+ const root = join(basePath, rootName);
258
+ for (const key of Object.keys(map)) {
259
+ if (isSafeProjectionKey(key))
260
+ continue;
261
+ if (key.includes("\0") || isAbsolute(key) || /^[A-Za-z]:/.test(key))
262
+ continue;
263
+ const healedKey = rootRelativeKey(root, resolve(root, key));
264
+ if (!healedKey || !isSafeProjectionKey(healedKey))
265
+ continue;
266
+ if (!map[healedKey]) {
267
+ map[healedKey] = map[key];
268
+ }
269
+ delete map[key];
270
+ changed = true;
271
+ }
272
+ return changed;
273
+ }
182
274
  function isValidPlanningMarker(x) {
183
275
  if (typeof x !== "object" || x === null)
184
276
  return false;
@@ -24,36 +24,35 @@ export const CACHE_MAX = 50;
24
24
  * By scoping tools to this allowlist during discuss dispatches, the grammar
25
25
  * sent to the provider stays well under provider limits.
26
26
  *
27
- * Included tools and why:
27
+ * Included tools and why (canonical names only — aliases are no longer
28
+ * advertised to models by default, see plan 035):
28
29
  * - gsd_summary_save: writes CONTEXT.md artifacts (all discuss prompts)
29
- * - gsd_save_summary: alias for above
30
30
  * - gsd_decision_save: records decisions (discuss.md output phase)
31
- * - gsd_save_decision: alias for above
32
31
  * - gsd_plan_milestone: writes roadmap (discuss.md single/multi milestone)
33
- * - gsd_milestone_plan: alias for above
34
32
  * - gsd_milestone_generate_id: generates milestone IDs (discuss.md multi-milestone)
35
- * - gsd_generate_milestone_id: alias for above
36
33
  * - gsd_requirement_save: creates requirements during discuss
37
- * - gsd_save_requirement: alias for above
38
34
  * - gsd_requirement_update: updates requirements during discuss
39
- * - gsd_update_requirement: alias for above
40
35
  */
41
36
  export const DISCUSS_TOOLS_ALLOWLIST = [
42
37
  // Context / summary writing
43
38
  "gsd_summary_save",
44
- "gsd_save_summary",
45
39
  // Decision recording
46
40
  "gsd_decision_save",
47
- "gsd_save_decision",
48
41
  // Milestone planning (needed for discuss.md output phase)
49
42
  "gsd_plan_milestone",
50
- "gsd_milestone_plan",
51
43
  // Milestone ID generation (multi-milestone flow)
52
44
  "gsd_milestone_generate_id",
53
- "gsd_generate_milestone_id",
54
45
  // Requirement updates
55
46
  "gsd_requirement_save",
56
- "gsd_save_requirement",
57
47
  "gsd_requirement_update",
58
- "gsd_update_requirement",
59
48
  ];
49
+ // ─── Context Injection ────────────────────────────────────────────────────────
50
+ /**
51
+ * Leading marker stamped on every buildContextMessage() output
52
+ * (bootstrap/system-context.ts). Single source of truth for the producer and
53
+ * the consumer: the provider payload policy (filterSupersededContextInjections
54
+ * in context-masker.ts) matches this prefix to find and dedupe injected
55
+ * memory/guided/forensics messages after convertToLlm strips their customType.
56
+ * Both sides import it from here — do not inline the literal in either module.
57
+ */
58
+ export const GSD_CONTEXT_MESSAGE_SENTINEL = "[GSD Context Injection]";
@@ -1,22 +1,4 @@
1
- /**
2
- * Observation masking for GSD auto-mode sessions.
3
- *
4
- * Replaces tool result content older than N turns with a placeholder.
5
- * Reduces context bloat between compactions with zero LLM overhead.
6
- * Preserves message ordering, roles, and all assistant/user messages.
7
- *
8
- * Operates on provider payloads after convertToLlm:
9
- *
10
- * pi-ai Message[] payloads:
11
- * - toolResult messages: { role: "toolResult", content: TextContent[] }
12
- * - bash results are already converted to: { role: "user", content: [{type:"text",text:"..."}] }
13
- * and start with "Ran `" from bashExecutionToText.
14
- *
15
- * OpenAI/Codex Responses payloads:
16
- * - conversation items live in `input`, not `messages`
17
- * - tool results are { type: "function_call_output", output: string | content[] }
18
- * - bash results are user items with input_text content starting with "Ran `"
19
- */
1
+ import { GSD_CONTEXT_MESSAGE_SENTINEL } from "./constants.js";
20
2
  const MASK_PLACEHOLDER = "[result masked — within summarized history]";
21
3
  const MASK_CONTENT_BLOCK = [{ type: "text", text: MASK_PLACEHOLDER }];
22
4
  const RESPONSES_MASK_CONTENT_BLOCK = [{ type: "input_text", text: MASK_PLACEHOLDER }];
@@ -52,6 +34,26 @@ function findTurnBoundary(messages, keepRecentTurns) {
52
34
  }
53
35
  return 0;
54
36
  }
37
+ function countRealUserTurns(messages) {
38
+ let count = 0;
39
+ for (const m of messages) {
40
+ if (m.role === "user" && !isBashResultUserMessage(m))
41
+ count++;
42
+ }
43
+ return count;
44
+ }
45
+ /**
46
+ * Quantizes how many recent turns stay unmasked so the boundary only moves
47
+ * forward once per full block of `keepRecentTurns` new turns, instead of
48
+ * every turn. Keeps the masked prefix byte-stable within a block, which is
49
+ * what lets the LLM provider's prompt cache survive across turns.
50
+ */
51
+ function quantizedKeepTurns(totalTurns, keepRecentTurns) {
52
+ if (keepRecentTurns <= 0 || totalTurns < 2 * keepRecentTurns)
53
+ return totalTurns;
54
+ const maskedTurns = Math.floor((totalTurns - keepRecentTurns) / keepRecentTurns) * keepRecentTurns;
55
+ return totalTurns - maskedTurns;
56
+ }
55
57
  /**
56
58
  * Detect user messages that originated from bashExecution.
57
59
  * After convertToLlm, these are {role: "user", content: [{type:"text", text:"Ran `cmd`\n..."}]}.
@@ -73,7 +75,8 @@ function isMaskableMessage(m) {
73
75
  }
74
76
  export function createObservationMask(keepRecentTurns = 8) {
75
77
  return (messages) => {
76
- const boundary = findTurnBoundary(messages, keepRecentTurns);
78
+ const totalTurns = countRealUserTurns(messages);
79
+ const boundary = findTurnBoundary(messages, quantizedKeepTurns(totalTurns, keepRecentTurns));
77
80
  if (boundary === 0)
78
81
  return messages;
79
82
  return messages.map((m, i) => {
@@ -104,6 +107,14 @@ function findResponsesTurnBoundary(items, keepRecentTurns) {
104
107
  }
105
108
  return 0;
106
109
  }
110
+ function countResponsesRealUserTurns(items) {
111
+ let count = 0;
112
+ for (const item of items) {
113
+ if (item.role === "user" && !isResponsesBashResultUserItem(item))
114
+ count++;
115
+ }
116
+ return count;
117
+ }
107
118
  /**
108
119
  * Observation masking for OpenAI/Codex Responses API payloads.
109
120
  *
@@ -113,7 +124,8 @@ function findResponsesTurnBoundary(items, keepRecentTurns) {
113
124
  */
114
125
  export function createResponsesInputObservationMask(keepRecentTurns = 8) {
115
126
  return (items) => {
116
- const boundary = findResponsesTurnBoundary(items, keepRecentTurns);
127
+ const totalTurns = countResponsesRealUserTurns(items);
128
+ const boundary = findResponsesTurnBoundary(items, quantizedKeepTurns(totalTurns, keepRecentTurns));
117
129
  if (boundary === 0)
118
130
  return items;
119
131
  return items.map((item, i) => {
@@ -190,3 +202,67 @@ export function truncateResponsesInputResultItems(items, maxChars = 800) {
190
202
  return item;
191
203
  });
192
204
  }
205
+ // GSD injects at most one context message per turn (memory/guided/forensics —
206
+ // see buildContextMessage in bootstrap/system-context.ts), marked with
207
+ // GSD_CONTEXT_MESSAGE_SENTINEL. convertToLlm strips the distinguishing
208
+ // customType before the payload reaches this hook, so detection is by content
209
+ // prefix instead. Pre-sentinel session history lacks the sentinel, so we also
210
+ // match the stable *bracketed* GSD block labels those injections begin with,
211
+ // letting resumed sessions dedupe older memory/guided blocks.
212
+ //
213
+ // Only GSD-specific bracketed markers belong here — never generic prose. A
214
+ // message is dropped from the payload when it matches, so a natural-language
215
+ // prefix (e.g. the forensics prompt "Debug GSD itself.") could silently delete
216
+ // a real user message that happens to start the same way. Legacy forensics
217
+ // injections without memory are therefore left un-deduped by design; those
218
+ // with memory still match via the "[GSD Context Metadata]" wrapper.
219
+ const LEGACY_GSD_CONTEXT_INJECTION_PREFIXES = [
220
+ "[GSD Context Metadata]",
221
+ "[MEMORY — Critical and prompt-relevant memories from the GSD memory store]",
222
+ "[GSD Guided Execute Context]",
223
+ ];
224
+ function isGsdContextInjectionText(text) {
225
+ if (typeof text !== "string")
226
+ return false;
227
+ if (text.startsWith(GSD_CONTEXT_MESSAGE_SENTINEL))
228
+ return true;
229
+ return LEGACY_GSD_CONTEXT_INJECTION_PREFIXES.some((prefix) => text.startsWith(prefix));
230
+ }
231
+ function isGsdContextInjectionMessage(m) {
232
+ if (m.role !== "user")
233
+ return false;
234
+ return isGsdContextInjectionText(firstTextFromContent(m.content));
235
+ }
236
+ /**
237
+ * Removes every GSD context-injection user message except the latest one.
238
+ * Each turn re-injects a near-identical memory/guided/forensics block; left
239
+ * in place they duplicate verbatim across an N-turn session. Removal (not
240
+ * masking) — an empty placeholder still costs tokens and shifts message
241
+ * positions, breaking cache byte-stability. Pure function: stored history is
242
+ * never mutated, only the outgoing payload array.
243
+ */
244
+ export function filterSupersededContextInjections(messages) {
245
+ let lastIndex = -1;
246
+ for (let i = 0; i < messages.length; i++) {
247
+ if (isGsdContextInjectionMessage(messages[i]))
248
+ lastIndex = i;
249
+ }
250
+ if (lastIndex === -1)
251
+ return messages;
252
+ return messages.filter((m, i) => i === lastIndex || !isGsdContextInjectionMessage(m));
253
+ }
254
+ function isResponsesGsdContextInjectionItem(item) {
255
+ if (item.role !== "user")
256
+ return false;
257
+ return isGsdContextInjectionText(firstTextFromContent(item.content));
258
+ }
259
+ export function filterSupersededResponsesContextInjections(items) {
260
+ let lastIndex = -1;
261
+ for (let i = 0; i < items.length; i++) {
262
+ if (isResponsesGsdContextInjectionItem(items[i]))
263
+ lastIndex = i;
264
+ }
265
+ if (lastIndex === -1)
266
+ return items;
267
+ return items.filter((item, i) => i === lastIndex || !isResponsesGsdContextInjectionItem(item));
268
+ }