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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (546) hide show
  1. package/README.md +10 -8
  2. package/dist/cli.js +5 -1
  3. package/dist/headless-events.d.ts +2 -1
  4. package/dist/headless-events.js +11 -3
  5. package/dist/headless-milestone-readiness.d.ts +29 -0
  6. package/dist/headless-milestone-readiness.js +161 -0
  7. package/dist/headless.js +25 -2
  8. package/dist/print-mode-exit.d.ts +12 -0
  9. package/dist/print-mode-exit.js +14 -0
  10. package/dist/resources/.managed-resources-content-hash +1 -1
  11. package/dist/resources/GSD-WORKFLOW.md +18 -49
  12. package/dist/resources/extensions/browser-tools/capture.js +2 -77
  13. package/dist/resources/extensions/browser-tools/screenshot-constraints.js +83 -0
  14. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +17 -2
  15. package/dist/resources/extensions/claude-code-cli/turn-assembler.js +30 -2
  16. package/dist/resources/extensions/gsd/artifact-verification.js +3 -4
  17. package/dist/resources/extensions/gsd/auto-artifact-paths.js +16 -10
  18. package/dist/resources/extensions/gsd/auto-dispatch.js +74 -19
  19. package/dist/resources/extensions/gsd/auto-post-unit.js +4 -0
  20. package/dist/resources/extensions/gsd/auto-prompts.js +125 -18
  21. package/dist/resources/extensions/gsd/auto-recovery.js +10 -5
  22. package/dist/resources/extensions/gsd/auto-worktree-cleanup.js +4 -0
  23. package/dist/resources/extensions/gsd/auto-worktree-teardown.js +1 -1
  24. package/dist/resources/extensions/gsd/auto.js +5 -1
  25. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +80 -4
  26. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +31 -5
  27. package/dist/resources/extensions/gsd/bootstrap/system-context.js +10 -3
  28. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +88 -50
  29. package/dist/resources/extensions/gsd/command-feedback.js +16 -12
  30. package/dist/resources/extensions/gsd/compat/compat-marker.js +19 -2
  31. package/dist/resources/extensions/gsd/constants.js +12 -13
  32. package/dist/resources/extensions/gsd/context-masker.js +97 -21
  33. package/dist/resources/extensions/gsd/db/command-queue.js +7 -2
  34. package/dist/resources/extensions/gsd/db/engine.js +51 -16
  35. package/dist/resources/extensions/gsd/db/writers/cascades.js +5 -1
  36. package/dist/resources/extensions/gsd/db/writers/status.js +13 -3
  37. package/dist/resources/extensions/gsd/db-base-schema.js +28 -0
  38. package/dist/resources/extensions/gsd/db-migration-steps.js +30 -0
  39. package/dist/resources/extensions/gsd/db-schema-metadata.js +4 -1
  40. package/dist/resources/extensions/gsd/docs/preferences-reference.md +26 -4
  41. package/dist/resources/extensions/gsd/doctor-engine-checks.js +3 -6
  42. package/dist/resources/extensions/gsd/flat-phase-migration.js +156 -21
  43. package/dist/resources/extensions/gsd/git-service.js +19 -7
  44. package/dist/resources/extensions/gsd/gsd-db.js +187 -45
  45. package/dist/resources/extensions/gsd/guided-flow.js +38 -13
  46. package/dist/resources/extensions/gsd/markdown-renderer.js +17 -13
  47. package/dist/resources/extensions/gsd/md-importer.js +107 -20
  48. package/dist/resources/extensions/gsd/migrate/command.js +19 -162
  49. package/dist/resources/extensions/gsd/migrate/execution.js +98 -0
  50. package/dist/resources/extensions/gsd/migrate/plan.js +49 -0
  51. package/dist/resources/extensions/gsd/migrate/planning-writer.js +12 -17
  52. package/dist/resources/extensions/gsd/migrate/presentation.js +64 -0
  53. package/dist/resources/extensions/gsd/model-cost-table.js +2 -0
  54. package/dist/resources/extensions/gsd/model-router.js +11 -0
  55. package/dist/resources/extensions/gsd/parallel-eligibility.js +5 -4
  56. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +28 -43
  57. package/dist/resources/extensions/gsd/paths.js +55 -11
  58. package/dist/resources/extensions/gsd/phase-anchor.js +7 -2
  59. package/dist/resources/extensions/gsd/planning-subagent-policy.js +37 -0
  60. package/dist/resources/extensions/gsd/planning-subagent-registry.js +25 -0
  61. package/dist/resources/extensions/gsd/post-execution-checks.js +4 -4
  62. package/dist/resources/extensions/gsd/preferences-types.js +5 -0
  63. package/dist/resources/extensions/gsd/preferences-validation.js +48 -1
  64. package/dist/resources/extensions/gsd/preferences.js +17 -0
  65. package/dist/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  66. package/dist/resources/extensions/gsd/provider-payload-policy.js +16 -5
  67. package/dist/resources/extensions/gsd/safety/destructive-guard.js +1 -1
  68. package/dist/resources/extensions/gsd/safety/evidence-collector.js +26 -1
  69. package/dist/resources/extensions/gsd/safety/evidence-cross-ref.js +30 -5
  70. package/dist/resources/extensions/gsd/skill-activation.js +17 -3
  71. package/dist/resources/extensions/gsd/state-reconciliation/drift/external-markdown-edit.js +27 -13
  72. package/dist/resources/extensions/gsd/state-reconciliation/drift/external-planning-edit.js +13 -3
  73. package/dist/resources/extensions/gsd/stop-notice.js +15 -1
  74. package/dist/resources/extensions/gsd/sync-lock.js +13 -7
  75. package/dist/resources/extensions/gsd/templates/PREFERENCES.md +5 -0
  76. package/dist/resources/extensions/gsd/tools/complete-task.js +94 -6
  77. package/dist/resources/extensions/gsd/tools/plan-task.js +13 -15
  78. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +18 -15
  79. package/dist/resources/extensions/gsd/tools/reopen-milestone.js +14 -5
  80. package/dist/resources/extensions/gsd/tools/reopen-slice.js +15 -5
  81. package/dist/resources/extensions/gsd/tools/reopen-task.js +16 -10
  82. package/dist/resources/extensions/gsd/tools/replan-task.js +128 -0
  83. package/dist/resources/extensions/gsd/tools/rework-brief.js +74 -0
  84. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +81 -0
  85. package/dist/resources/extensions/gsd/unit-context-composer.js +28 -5
  86. package/dist/resources/extensions/gsd/unit-registry.js +4 -0
  87. package/dist/resources/extensions/gsd/uok/plan-v2.js +19 -3
  88. package/dist/resources/extensions/gsd/workflow-projections.js +2 -3
  89. package/dist/resources/extensions/gsd/workspace.js +2 -1
  90. package/dist/resources/extensions/gsd/worktree-state-projection.js +6 -0
  91. package/dist/resources/extensions/mac-tools/index.js +31 -9
  92. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  93. package/dist/web/standalone/.next/BUILD_ID +1 -1
  94. package/dist/web/standalone/.next/app-path-routes-manifest.json +8 -8
  95. package/dist/web/standalone/.next/build-manifest.json +3 -3
  96. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  97. package/dist/web/standalone/.next/required-server-files.json +3 -3
  98. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  99. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  100. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  101. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  105. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  108. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  109. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  110. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  111. package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -4
  112. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -4
  113. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  114. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -4
  115. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  116. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  117. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  118. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  125. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  137. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/mcp-connections/route_client-reference-manifest.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  159. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  166. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  169. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  172. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  175. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  181. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  182. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  183. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  184. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  185. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  186. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  187. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  188. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  189. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  190. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  191. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  192. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  193. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  194. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  195. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  196. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  197. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  198. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  199. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  200. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  201. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  202. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  203. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  204. package/dist/web/standalone/.next/server/app/index.html +1 -1
  205. package/dist/web/standalone/.next/server/app/index.rsc +5 -5
  206. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  207. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +5 -5
  208. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  209. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -4
  210. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  211. package/dist/web/standalone/.next/server/app/page.js +2 -2
  212. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  213. package/dist/web/standalone/.next/server/app-paths-manifest.json +8 -8
  214. package/dist/web/standalone/.next/server/chunks/2842.js +4 -4
  215. package/dist/web/standalone/.next/server/chunks/8357.js +3 -3
  216. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  217. package/dist/web/standalone/.next/server/middleware.js +3 -3
  218. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  219. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  220. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  221. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-a6fb1847f67f167c.js +1 -0
  222. package/dist/web/standalone/.next/static/chunks/app/{layout-b35cbfff38aaf4cf.js → layout-4ae2d68984392bbf.js} +1 -1
  223. package/dist/web/standalone/.next/static/chunks/app/page-72a856634ad14c10.js +1 -0
  224. package/dist/web/standalone/.next/static/chunks/{main-app-590a74400e35f685.js → main-app-90d1d8d5e5d2dc6b.js} +1 -1
  225. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-1115d46ac61b9823.js +1 -0
  226. package/dist/web/standalone/.next/static/css/3b1ceb7abfb9a230.css +1 -0
  227. package/dist/web/standalone/node_modules/@gsd/native/package.json +1 -1
  228. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  229. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  230. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  231. package/dist/web/standalone/package.json +0 -1
  232. package/dist/web/standalone/server.js +1 -1
  233. package/dist/web-mode.js +31 -3
  234. package/integrations/hermes/open_gsd_hermes/gsd_client.py +1 -1
  235. package/integrations/hermes/pyproject.toml +1 -1
  236. package/package.json +12 -10
  237. package/packages/cloud-mcp-gateway/package.json +2 -2
  238. package/packages/contracts/dist/workflow.d.ts +14 -0
  239. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  240. package/packages/contracts/dist/workflow.js +16 -0
  241. package/packages/contracts/dist/workflow.js.map +1 -1
  242. package/packages/contracts/package.json +1 -1
  243. package/packages/daemon/dist/cloud-config.d.ts +1 -1
  244. package/packages/daemon/dist/cloud-config.d.ts.map +1 -1
  245. package/packages/daemon/dist/cloud-config.js +5 -1
  246. package/packages/daemon/dist/cloud-config.js.map +1 -1
  247. package/packages/daemon/dist/cloud-config.test.js +51 -1
  248. package/packages/daemon/dist/cloud-config.test.js.map +1 -1
  249. package/packages/daemon/dist/local-tool-executor.d.ts.map +1 -1
  250. package/packages/daemon/dist/local-tool-executor.js +2 -0
  251. package/packages/daemon/dist/local-tool-executor.js.map +1 -1
  252. package/packages/daemon/package.json +6 -6
  253. package/packages/gsd-agent-core/dist/compaction/compaction.d.ts.map +1 -1
  254. package/packages/gsd-agent-core/dist/compaction/compaction.js +36 -4
  255. package/packages/gsd-agent-core/dist/compaction/compaction.js.map +1 -1
  256. package/packages/gsd-agent-core/dist/sdk.d.ts.map +1 -1
  257. package/packages/gsd-agent-core/dist/sdk.js +1 -0
  258. package/packages/gsd-agent-core/dist/sdk.js.map +1 -1
  259. package/packages/gsd-agent-core/package.json +5 -5
  260. package/packages/gsd-agent-modes/package.json +7 -7
  261. package/packages/gsd-cloud/dist/cli.d.ts +5 -0
  262. package/packages/gsd-cloud/dist/cli.d.ts.map +1 -0
  263. package/packages/gsd-cloud/dist/cli.js +160 -0
  264. package/packages/gsd-cloud/dist/cli.js.map +1 -0
  265. package/packages/gsd-cloud/dist/cloud-config.d.ts +19 -0
  266. package/packages/gsd-cloud/dist/cloud-config.d.ts.map +1 -0
  267. package/packages/gsd-cloud/dist/cloud-config.js +231 -0
  268. package/packages/gsd-cloud/dist/cloud-config.js.map +1 -0
  269. package/packages/gsd-cloud/dist/cloud-config.test.d.ts +2 -0
  270. package/packages/gsd-cloud/dist/cloud-config.test.d.ts.map +1 -0
  271. package/packages/gsd-cloud/dist/cloud-config.test.js +118 -0
  272. package/packages/gsd-cloud/dist/cloud-config.test.js.map +1 -0
  273. package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.d.ts +2 -0
  274. package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.d.ts.map +1 -0
  275. package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.js +37 -0
  276. package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.js.map +1 -0
  277. package/packages/gsd-cloud/dist/cloud-runtime.d.ts +35 -0
  278. package/packages/gsd-cloud/dist/cloud-runtime.d.ts.map +1 -0
  279. package/packages/gsd-cloud/dist/cloud-runtime.js +258 -0
  280. package/packages/gsd-cloud/dist/cloud-runtime.js.map +1 -0
  281. package/packages/gsd-cloud/dist/cloud-runtime.test.d.ts +2 -0
  282. package/packages/gsd-cloud/dist/cloud-runtime.test.d.ts.map +1 -0
  283. package/packages/gsd-cloud/dist/cloud-runtime.test.js +88 -0
  284. package/packages/gsd-cloud/dist/cloud-runtime.test.js.map +1 -0
  285. package/packages/gsd-cloud/dist/cloud-token.d.ts +3 -0
  286. package/packages/gsd-cloud/dist/cloud-token.d.ts.map +1 -0
  287. package/packages/gsd-cloud/dist/cloud-token.js +37 -0
  288. package/packages/gsd-cloud/dist/cloud-token.js.map +1 -0
  289. package/packages/gsd-cloud/dist/config.d.ts +17 -0
  290. package/packages/gsd-cloud/dist/config.d.ts.map +1 -0
  291. package/packages/gsd-cloud/dist/config.js +146 -0
  292. package/packages/gsd-cloud/dist/config.js.map +1 -0
  293. package/packages/gsd-cloud/dist/device-flow.d.ts +24 -0
  294. package/packages/gsd-cloud/dist/device-flow.d.ts.map +1 -0
  295. package/packages/gsd-cloud/dist/device-flow.js +128 -0
  296. package/packages/gsd-cloud/dist/device-flow.js.map +1 -0
  297. package/packages/gsd-cloud/dist/device-flow.test.d.ts +2 -0
  298. package/packages/gsd-cloud/dist/device-flow.test.d.ts.map +1 -0
  299. package/packages/gsd-cloud/dist/device-flow.test.js +155 -0
  300. package/packages/gsd-cloud/dist/device-flow.test.js.map +1 -0
  301. package/packages/gsd-cloud/dist/executors/claude-executor.d.ts +6 -0
  302. package/packages/gsd-cloud/dist/executors/claude-executor.d.ts.map +1 -0
  303. package/packages/gsd-cloud/dist/executors/claude-executor.js +15 -0
  304. package/packages/gsd-cloud/dist/executors/claude-executor.js.map +1 -0
  305. package/packages/gsd-cloud/dist/executors/codex-executor.d.ts +6 -0
  306. package/packages/gsd-cloud/dist/executors/codex-executor.d.ts.map +1 -0
  307. package/packages/gsd-cloud/dist/executors/codex-executor.js +15 -0
  308. package/packages/gsd-cloud/dist/executors/codex-executor.js.map +1 -0
  309. package/packages/gsd-cloud/dist/executors/executor.d.ts +28 -0
  310. package/packages/gsd-cloud/dist/executors/executor.d.ts.map +1 -0
  311. package/packages/gsd-cloud/dist/executors/executor.js +11 -0
  312. package/packages/gsd-cloud/dist/executors/executor.js.map +1 -0
  313. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.d.ts +34 -0
  314. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.d.ts.map +1 -0
  315. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.js +179 -0
  316. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.js.map +1 -0
  317. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.d.ts +2 -0
  318. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.d.ts.map +1 -0
  319. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.js +44 -0
  320. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.js.map +1 -0
  321. package/packages/gsd-cloud/dist/executors/index.d.ts +17 -0
  322. package/packages/gsd-cloud/dist/executors/index.d.ts.map +1 -0
  323. package/packages/gsd-cloud/dist/executors/index.js +29 -0
  324. package/packages/gsd-cloud/dist/executors/index.js.map +1 -0
  325. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.d.ts +36 -0
  326. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.d.ts.map +1 -0
  327. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.js +176 -0
  328. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.js.map +1 -0
  329. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.d.ts +2 -0
  330. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.d.ts.map +1 -0
  331. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.js +34 -0
  332. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.js.map +1 -0
  333. package/packages/gsd-cloud/dist/index.d.ts +7 -0
  334. package/packages/gsd-cloud/dist/index.d.ts.map +1 -0
  335. package/packages/gsd-cloud/dist/index.js +8 -0
  336. package/packages/gsd-cloud/dist/index.js.map +1 -0
  337. package/packages/gsd-cloud/dist/inject-gateway.d.ts +16 -0
  338. package/packages/gsd-cloud/dist/inject-gateway.d.ts.map +1 -0
  339. package/packages/gsd-cloud/dist/inject-gateway.js +29 -0
  340. package/packages/gsd-cloud/dist/inject-gateway.js.map +1 -0
  341. package/packages/gsd-cloud/dist/inject-gateway.test.d.ts +2 -0
  342. package/packages/gsd-cloud/dist/inject-gateway.test.d.ts.map +1 -0
  343. package/packages/gsd-cloud/dist/inject-gateway.test.js +41 -0
  344. package/packages/gsd-cloud/dist/inject-gateway.test.js.map +1 -0
  345. package/packages/gsd-cloud/dist/logger.d.ts +25 -0
  346. package/packages/gsd-cloud/dist/logger.d.ts.map +1 -0
  347. package/packages/gsd-cloud/dist/logger.js +72 -0
  348. package/packages/gsd-cloud/dist/logger.js.map +1 -0
  349. package/packages/gsd-cloud/dist/types.d.ts +51 -0
  350. package/packages/gsd-cloud/dist/types.d.ts.map +1 -0
  351. package/packages/gsd-cloud/dist/types.js +9 -0
  352. package/packages/gsd-cloud/dist/types.js.map +1 -0
  353. package/packages/gsd-cloud/package.json +3 -3
  354. package/packages/mcp-server/README.md +15 -2
  355. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  356. package/packages/mcp-server/dist/server.js +5 -5
  357. package/packages/mcp-server/dist/server.js.map +1 -1
  358. package/packages/mcp-server/dist/workflow-tools.d.ts +4 -3
  359. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  360. package/packages/mcp-server/dist/workflow-tools.js +64 -2
  361. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  362. package/packages/mcp-server/package.json +4 -4
  363. package/packages/native/package.json +1 -1
  364. package/packages/pi-agent-core/dist/agent.d.ts +5 -1
  365. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  366. package/packages/pi-agent-core/dist/agent.js +2 -0
  367. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  368. package/packages/pi-agent-core/package.json +1 -1
  369. package/packages/pi-ai/dist/models.generated.d.ts +119 -0
  370. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  371. package/packages/pi-ai/dist/models.generated.js +107 -0
  372. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  373. package/packages/pi-ai/dist/providers/amazon-bedrock.js +1 -0
  374. package/packages/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
  375. package/packages/pi-ai/dist/providers/anthropic.js +25 -1
  376. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  377. package/packages/pi-ai/dist/providers/openai-codex-responses.js +1 -1
  378. package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
  379. package/packages/pi-ai/dist/providers/openai-responses.js +1 -1
  380. package/packages/pi-ai/dist/providers/openai-responses.js.map +1 -1
  381. package/packages/pi-ai/package.json +1 -1
  382. package/packages/pi-coding-agent/dist/core/capability-patches.js +1 -1
  383. package/packages/pi-coding-agent/dist/core/capability-patches.js.map +1 -1
  384. package/packages/pi-coding-agent/dist/core/model-resolver.js +1 -1
  385. package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
  386. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +11 -1
  387. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  388. package/packages/pi-coding-agent/dist/core/settings-manager.js +8 -0
  389. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  390. package/packages/pi-coding-agent/package.json +7 -7
  391. package/packages/pi-tui/package.json +2 -2
  392. package/packages/rpc-client/package.json +2 -2
  393. package/pkg/package.json +1 -1
  394. package/src/resources/GSD-WORKFLOW.md +18 -49
  395. package/src/resources/extensions/browser-tools/capture.ts +2 -86
  396. package/src/resources/extensions/browser-tools/screenshot-constraints.ts +94 -0
  397. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +18 -1
  398. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +108 -0
  399. package/src/resources/extensions/claude-code-cli/turn-assembler.ts +30 -2
  400. package/src/resources/extensions/gsd/artifact-verification.ts +3 -8
  401. package/src/resources/extensions/gsd/auto-artifact-paths.ts +16 -9
  402. package/src/resources/extensions/gsd/auto-dispatch.ts +86 -19
  403. package/src/resources/extensions/gsd/auto-post-unit.ts +4 -0
  404. package/src/resources/extensions/gsd/auto-prompts.ts +142 -16
  405. package/src/resources/extensions/gsd/auto-recovery.ts +10 -8
  406. package/src/resources/extensions/gsd/auto-worktree-cleanup.ts +4 -0
  407. package/src/resources/extensions/gsd/auto-worktree-teardown.ts +1 -1
  408. package/src/resources/extensions/gsd/auto.ts +5 -1
  409. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +92 -4
  410. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +39 -10
  411. package/src/resources/extensions/gsd/bootstrap/system-context.ts +11 -3
  412. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +87 -53
  413. package/src/resources/extensions/gsd/command-feedback.ts +19 -12
  414. package/src/resources/extensions/gsd/compat/compat-marker.ts +21 -4
  415. package/src/resources/extensions/gsd/constants.ts +14 -13
  416. package/src/resources/extensions/gsd/context-masker.ts +98 -2
  417. package/src/resources/extensions/gsd/db/command-queue.ts +7 -1
  418. package/src/resources/extensions/gsd/db/engine.ts +53 -17
  419. package/src/resources/extensions/gsd/db/writers/cascades.ts +5 -1
  420. package/src/resources/extensions/gsd/db/writers/status.ts +25 -8
  421. package/src/resources/extensions/gsd/db-base-schema.ts +30 -0
  422. package/src/resources/extensions/gsd/db-migration-steps.ts +32 -0
  423. package/src/resources/extensions/gsd/db-schema-metadata.ts +4 -1
  424. package/src/resources/extensions/gsd/docs/preferences-reference.md +26 -4
  425. package/src/resources/extensions/gsd/doctor-engine-checks.ts +3 -5
  426. package/src/resources/extensions/gsd/flat-phase-migration.ts +160 -19
  427. package/src/resources/extensions/gsd/git-service.ts +19 -6
  428. package/src/resources/extensions/gsd/gsd-db.ts +255 -52
  429. package/src/resources/extensions/gsd/guided-flow.ts +48 -12
  430. package/src/resources/extensions/gsd/markdown-renderer.ts +25 -21
  431. package/src/resources/extensions/gsd/md-importer.ts +114 -16
  432. package/src/resources/extensions/gsd/migrate/command.ts +21 -227
  433. package/src/resources/extensions/gsd/migrate/execution.ts +136 -0
  434. package/src/resources/extensions/gsd/migrate/plan.ts +101 -0
  435. package/src/resources/extensions/gsd/migrate/planning-writer.ts +12 -20
  436. package/src/resources/extensions/gsd/migrate/presentation.ts +83 -0
  437. package/src/resources/extensions/gsd/model-cost-table.ts +2 -0
  438. package/src/resources/extensions/gsd/model-router.ts +12 -0
  439. package/src/resources/extensions/gsd/parallel-eligibility.ts +5 -4
  440. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +37 -40
  441. package/src/resources/extensions/gsd/paths.ts +62 -11
  442. package/src/resources/extensions/gsd/phase-anchor.ts +8 -2
  443. package/src/resources/extensions/gsd/planning-subagent-policy.ts +58 -0
  444. package/src/resources/extensions/gsd/planning-subagent-registry.ts +31 -0
  445. package/src/resources/extensions/gsd/post-execution-checks.ts +4 -4
  446. package/src/resources/extensions/gsd/preferences-types.ts +16 -0
  447. package/src/resources/extensions/gsd/preferences-validation.ts +62 -0
  448. package/src/resources/extensions/gsd/preferences.ts +25 -0
  449. package/src/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  450. package/src/resources/extensions/gsd/provider-payload-policy.ts +18 -4
  451. package/src/resources/extensions/gsd/safety/destructive-guard.ts +1 -1
  452. package/src/resources/extensions/gsd/safety/evidence-collector.ts +28 -1
  453. package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +31 -5
  454. package/src/resources/extensions/gsd/skill-activation.ts +17 -3
  455. package/src/resources/extensions/gsd/state-reconciliation/drift/external-markdown-edit.ts +30 -13
  456. package/src/resources/extensions/gsd/state-reconciliation/drift/external-planning-edit.ts +16 -3
  457. package/src/resources/extensions/gsd/state-reconciliation/types.ts +2 -2
  458. package/src/resources/extensions/gsd/stop-notice.ts +18 -1
  459. package/src/resources/extensions/gsd/sync-lock.ts +14 -6
  460. package/src/resources/extensions/gsd/templates/PREFERENCES.md +5 -0
  461. package/src/resources/extensions/gsd/tests/auto-artifact-paths.test.ts +7 -7
  462. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +39 -0
  463. package/src/resources/extensions/gsd/tests/before-provider-context-management.test.ts +55 -0
  464. package/src/resources/extensions/gsd/tests/closeout-git-deferral.test.ts +96 -1
  465. package/src/resources/extensions/gsd/tests/command-feedback.test.ts +12 -0
  466. package/src/resources/extensions/gsd/tests/compat-marker.test.ts +104 -0
  467. package/src/resources/extensions/gsd/tests/complete-task.test.ts +362 -1
  468. package/src/resources/extensions/gsd/tests/context-masker.test.ts +204 -8
  469. package/src/resources/extensions/gsd/tests/db-engine-migrate-guards.test.ts +186 -0
  470. package/src/resources/extensions/gsd/tests/db-tools-alias-suppression.test.ts +62 -0
  471. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +29 -0
  472. package/src/resources/extensions/gsd/tests/destructive-confirmation.test.ts +33 -0
  473. package/src/resources/extensions/gsd/tests/destructive-guard.test.ts +14 -0
  474. package/src/resources/extensions/gsd/tests/discuss-routing-fixes.test.ts +123 -0
  475. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +50 -0
  476. package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +49 -0
  477. package/src/resources/extensions/gsd/tests/evidence-cross-ref.test.ts +81 -0
  478. package/src/resources/extensions/gsd/tests/evidence-xref-gsd-exec.test.ts +22 -0
  479. package/src/resources/extensions/gsd/tests/external-edit-scoped-import.test.ts +262 -0
  480. package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +202 -0
  481. package/src/resources/extensions/gsd/tests/gate-storage.test.ts +29 -0
  482. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +25 -0
  483. package/src/resources/extensions/gsd/tests/import-slice-milestone-completion-preserve.test.ts +116 -0
  484. package/src/resources/extensions/gsd/tests/integration/paths.test.ts +22 -4
  485. package/src/resources/extensions/gsd/tests/integration-branch-meta-location.test.ts +62 -0
  486. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +5 -5
  487. package/src/resources/extensions/gsd/tests/migrate-plan.test.ts +68 -0
  488. package/src/resources/extensions/gsd/tests/migrate-presentation.test.ts +98 -0
  489. package/src/resources/extensions/gsd/tests/migrate-safety-audit.test.ts +1 -1
  490. package/src/resources/extensions/gsd/tests/milestone-leases.test.ts +55 -0
  491. package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
  492. package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
  493. package/src/resources/extensions/gsd/tests/parallel-eligibility-file-overlap.test.ts +146 -0
  494. package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +59 -0
  495. package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +7 -5
  496. package/src/resources/extensions/gsd/tests/phase-anchor.test.ts +32 -4
  497. package/src/resources/extensions/gsd/tests/plan-task.test.ts +26 -23
  498. package/src/resources/extensions/gsd/tests/planning-writer.test.ts +29 -0
  499. package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +22 -0
  500. package/src/resources/extensions/gsd/tests/preferences.test.ts +84 -0
  501. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +4 -0
  502. package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +66 -0
  503. package/src/resources/extensions/gsd/tests/reactive-executor.test.ts +39 -0
  504. package/src/resources/extensions/gsd/tests/reassess-handler.test.ts +50 -0
  505. package/src/resources/extensions/gsd/tests/replan-task-handler.test.ts +103 -0
  506. package/src/resources/extensions/gsd/tests/rework-brief.test.ts +197 -0
  507. package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
  508. package/src/resources/extensions/gsd/tests/single-writer-v3-tool-surface.test.ts +33 -7
  509. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +20 -16
  510. package/src/resources/extensions/gsd/tests/skip-slice-cascades-tasks.test.ts +21 -0
  511. package/src/resources/extensions/gsd/tests/stop-notice.test.ts +17 -0
  512. package/src/resources/extensions/gsd/tests/sync-lock.test.ts +19 -0
  513. package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +13 -7
  514. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -0
  515. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +73 -0
  516. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +93 -1
  517. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +2 -0
  518. package/src/resources/extensions/gsd/tests/workflow-migration-gates.test.ts +139 -0
  519. package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +4 -4
  520. package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +36 -0
  521. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +34 -0
  522. package/src/resources/extensions/gsd/tests/write-gate-seam.test.ts +52 -0
  523. package/src/resources/extensions/gsd/tools/complete-task.ts +140 -5
  524. package/src/resources/extensions/gsd/tools/plan-task.ts +14 -16
  525. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +18 -17
  526. package/src/resources/extensions/gsd/tools/reopen-milestone.ts +24 -5
  527. package/src/resources/extensions/gsd/tools/reopen-slice.ts +25 -5
  528. package/src/resources/extensions/gsd/tools/reopen-task.ts +23 -9
  529. package/src/resources/extensions/gsd/tools/replan-task.ts +160 -0
  530. package/src/resources/extensions/gsd/tools/rework-brief.ts +91 -0
  531. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +92 -0
  532. package/src/resources/extensions/gsd/types.ts +11 -0
  533. package/src/resources/extensions/gsd/unit-context-composer.ts +34 -8
  534. package/src/resources/extensions/gsd/unit-registry.ts +4 -0
  535. package/src/resources/extensions/gsd/uok/plan-v2.ts +20 -3
  536. package/src/resources/extensions/gsd/workflow-projections.ts +2 -3
  537. package/src/resources/extensions/gsd/workspace.ts +2 -1
  538. package/src/resources/extensions/gsd/worktree-state-projection.ts +12 -0
  539. package/src/resources/extensions/mac-tools/index.ts +52 -9
  540. package/src/resources/extensions/mac-tools/tests/mac-screenshot-payload.test.cjs +70 -0
  541. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-49f565245e1e4afe.js +0 -1
  542. package/dist/web/standalone/.next/static/chunks/app/page-bc4c723c6a19c6f0.js +0 -1
  543. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ec3eaffc9785ba48.js +0 -1
  544. package/dist/web/standalone/.next/static/css/18c2fdf261bfc1b7.css +0 -1
  545. /package/dist/web/standalone/.next/static/{UaXRrOYxBpG9QBINKhZkg → 6YWV7VAPg-jqjfPswrKZb}/_buildManifest.js +0 -0
  546. /package/dist/web/standalone/.next/static/{UaXRrOYxBpG9QBINKhZkg → 6YWV7VAPg-jqjfPswrKZb}/_ssgManifest.js +0 -0
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Read-only planning specialists that controlled planning dispatch may use.
3
+ *
4
+ * Unit manifests and project preferences still declare per-unit subsets. This
5
+ * registry is the global safety classification checked by the write gate and
6
+ * preference validation before any configured planning allowlist takes effect.
7
+ */
8
+
9
+ const PLANNING_DISPATCH_AGENT_REGISTRY = {
10
+ mnemo: { readOnlySpecialist: true },
11
+ scout: { readOnlySpecialist: true },
12
+ planner: { readOnlySpecialist: true },
13
+ reviewer: { readOnlySpecialist: true },
14
+ security: { readOnlySpecialist: true },
15
+ tester: { readOnlySpecialist: true },
16
+ } as const satisfies Record<string, { readonly readOnlySpecialist: boolean }>;
17
+
18
+ export const ALLOWED_PLANNING_DISPATCH_AGENTS = new Set<string>(
19
+ Object.entries(PLANNING_DISPATCH_AGENT_REGISTRY)
20
+ .filter(([, metadata]) => metadata.readOnlySpecialist)
21
+ .map(([agentId]) => agentId),
22
+ );
23
+
24
+ export function isReadOnlyPlanningDispatchAgent(agentId: string): boolean {
25
+ const metadata = PLANNING_DISPATCH_AGENT_REGISTRY[agentId as keyof typeof PLANNING_DISPATCH_AGENT_REGISTRY];
26
+ return metadata?.readOnlySpecialist === true;
27
+ }
28
+
29
+ export function allowedPlanningDispatchAgentsList(): string {
30
+ return [...ALLOWED_PLANNING_DISPATCH_AGENTS].join(", ");
31
+ }
@@ -318,12 +318,12 @@ export function checkImportResolution(
318
318
  const imports = extractRelativeImports(source);
319
319
 
320
320
  for (const { importPath, lineNum } of imports) {
321
- // Framework-generated type modules may not exist on disk during post-exec
322
- // checks (typically generated during framework builds/typegen). Don't
323
- // block task completion on these imports.
321
+ // Framework/codegen-generated modules may not exist on disk during
322
+ // post-exec checks. Don't block task completion on these imports.
324
323
  if (
325
324
  /^\.{1,2}\/\+types\//.test(importPath) ||
326
- /^(?:\.{1,2}\/)+(?:[^/]+\/)*\$types(?:$|\/)/.test(importPath)
325
+ /^(?:\.{1,2}\/)+(?:[^/]+\/)*\$types(?:$|\/)/.test(importPath) ||
326
+ /^(?:\.{1,2}\/)+(?:[^/]+\/)*_generated(?:$|\/)/.test(importPath)
327
327
  ) {
328
328
  continue;
329
329
  }
@@ -141,6 +141,7 @@ export const KNOWN_PREFERENCE_KEYS = new Set<string>([
141
141
  "git",
142
142
  "post_unit_hooks",
143
143
  "pre_dispatch_hooks",
144
+ "planning_subagents",
144
145
  "dynamic_routing",
145
146
  "disabled_model_providers",
146
147
  "uok",
@@ -217,6 +218,20 @@ export const KNOWN_UNIT_LABELS = [
217
218
  ] as const;
218
219
  export type UnitLabel = (typeof KNOWN_UNIT_LABELS)[number];
219
220
 
221
+ export const CONFIGURABLE_PLANNING_SUBAGENT_UNITS = [
222
+ "plan-milestone",
223
+ "plan-slice",
224
+ ] as const;
225
+ export type ConfigurablePlanningSubagentUnit = (typeof CONFIGURABLE_PLANNING_SUBAGENT_UNITS)[number];
226
+
227
+ export interface PlanningSubagentUnitConfig {
228
+ allowed?: string[];
229
+ }
230
+
231
+ export type PlanningSubagentsConfig = Partial<
232
+ Record<ConfigurablePlanningSubagentUnit, PlanningSubagentUnitConfig>
233
+ >;
234
+
220
235
 
221
236
  export const SKILL_ACTIONS = new Set(["use", "prefer", "avoid"]);
222
237
 
@@ -476,6 +491,7 @@ export interface GSDPreferences {
476
491
  git?: GitPreferences;
477
492
  post_unit_hooks?: PostUnitHookConfig[];
478
493
  pre_dispatch_hooks?: PreDispatchHookConfig[];
494
+ planning_subagents?: PlanningSubagentsConfig;
479
495
  dynamic_routing?: DynamicRoutingConfig;
480
496
  /** Provider IDs to exclude from /model and automatic model routing while leaving tool auth intact. */
481
497
  disabled_model_providers?: string[];
@@ -17,6 +17,7 @@ import { getGateIdsForTurn } from "./gate-registry.js";
17
17
  import {
18
18
  KNOWN_PREFERENCE_KEYS,
19
19
  KNOWN_UNIT_LABELS,
20
+ CONFIGURABLE_PLANNING_SUBAGENT_UNITS,
20
21
  GSD_MODEL_PHASE_KEYS,
21
22
 
22
23
  SKILL_ACTIONS,
@@ -26,6 +27,10 @@ import {
26
27
  type GSDSkillRule,
27
28
  type GSDThinkingLevel,
28
29
  } from "./preferences-types.js";
30
+ import {
31
+ ALLOWED_PLANNING_DISPATCH_AGENTS,
32
+ allowedPlanningDispatchAgentsList,
33
+ } from "./planning-subagent-registry.js";
29
34
 
30
35
  const VALID_TOKEN_PROFILES = new Set<TokenProfile>(["budget", "balanced", "quality", "burn-max"]);
31
36
  const VALID_THINKING_LEVELS = new Set<GSDThinkingLevel>([
@@ -747,6 +752,63 @@ export function validatePreferences(preferences: GSDPreferences): {
747
752
  }
748
753
  }
749
754
 
755
+ // ─── Planning Subagents ─────────────────────────────────────────────────
756
+ if (preferences.planning_subagents !== undefined) {
757
+ if (
758
+ !preferences.planning_subagents ||
759
+ typeof preferences.planning_subagents !== "object" ||
760
+ Array.isArray(preferences.planning_subagents)
761
+ ) {
762
+ errors.push("planning_subagents must be an object keyed by planning unit type");
763
+ } else {
764
+ const validUnits = new Set<string>(CONFIGURABLE_PLANNING_SUBAGENT_UNITS);
765
+ const validPlanningSubagents: NonNullable<GSDPreferences["planning_subagents"]> = {};
766
+
767
+ for (const [unitType, rawConfig] of Object.entries(preferences.planning_subagents as Record<string, unknown>)) {
768
+ if (!validUnits.has(unitType)) {
769
+ errors.push(
770
+ `planning_subagents unknown or unsupported unit "${unitType}" — supported units: ` +
771
+ `${CONFIGURABLE_PLANNING_SUBAGENT_UNITS.join(", ")}`,
772
+ );
773
+ continue;
774
+ }
775
+ if (!rawConfig || typeof rawConfig !== "object" || Array.isArray(rawConfig)) {
776
+ errors.push(`planning_subagents.${unitType} must be an object with an allowed array`);
777
+ continue;
778
+ }
779
+
780
+ const allowed = normalizeStringArray((rawConfig as Record<string, unknown>).allowed);
781
+ if (allowed.length === 0) {
782
+ errors.push(`planning_subagents.${unitType}.allowed must include at least one read-only planning specialist`);
783
+ continue;
784
+ }
785
+
786
+ const sanitizedAllowed: string[] = [];
787
+ for (const agentId of allowed) {
788
+ if (!ALLOWED_PLANNING_DISPATCH_AGENTS.has(agentId)) {
789
+ errors.push(
790
+ `planning_subagents.${unitType}.allowed includes "${agentId}", which is not classified as a ` +
791
+ `read-only planning specialist. Allowed agents: ${allowedPlanningDispatchAgentsList()}`,
792
+ );
793
+ continue;
794
+ }
795
+ sanitizedAllowed.push(agentId);
796
+ }
797
+
798
+ const dedupedAllowed = Array.from(new Set(sanitizedAllowed));
799
+ if (dedupedAllowed.length > 0) {
800
+ validPlanningSubagents[unitType as keyof NonNullable<GSDPreferences["planning_subagents"]>] = {
801
+ allowed: dedupedAllowed,
802
+ };
803
+ }
804
+ }
805
+
806
+ if (Object.keys(validPlanningSubagents).length > 0) {
807
+ validated.planning_subagents = validPlanningSubagents;
808
+ }
809
+ }
810
+ }
811
+
750
812
  // ─── Dynamic Routing ─────────────────────────────────────────────────
751
813
  if (preferences.dynamic_routing !== undefined) {
752
814
  if (typeof preferences.dynamic_routing === "object" && preferences.dynamic_routing !== null) {
@@ -817,6 +817,7 @@ function mergePreferences(base: GSDPreferences, override: GSDPreferences): GSDPr
817
817
  : undefined,
818
818
  post_unit_hooks: mergePostUnitHooks(base.post_unit_hooks, override.post_unit_hooks),
819
819
  pre_dispatch_hooks: mergePreDispatchHooks(base.pre_dispatch_hooks, override.pre_dispatch_hooks),
820
+ planning_subagents: mergePlanningSubagents(base.planning_subagents, override.planning_subagents),
820
821
  dynamic_routing: (base.dynamic_routing || override.dynamic_routing)
821
822
  ? { ...(base.dynamic_routing ?? {}), ...(override.dynamic_routing ?? {}) } as DynamicRoutingConfig
822
823
  : undefined,
@@ -943,6 +944,30 @@ function mergePreDispatchHooks(
943
944
  return merged.length > 0 ? merged : undefined;
944
945
  }
945
946
 
947
+ function mergePlanningSubagents(
948
+ base?: GSDPreferences["planning_subagents"],
949
+ override?: GSDPreferences["planning_subagents"],
950
+ ): GSDPreferences["planning_subagents"] | undefined {
951
+ if (!base && !override) return undefined;
952
+ const merged: NonNullable<GSDPreferences["planning_subagents"]> = {};
953
+ const unitTypes = new Set([
954
+ ...Object.keys(base ?? {}),
955
+ ...Object.keys(override ?? {}),
956
+ ]);
957
+
958
+ for (const unitType of unitTypes) {
959
+ const allowed = mergeStringLists(
960
+ base?.[unitType as keyof NonNullable<GSDPreferences["planning_subagents"]>]?.allowed,
961
+ override?.[unitType as keyof NonNullable<GSDPreferences["planning_subagents"]>]?.allowed,
962
+ );
963
+ if (allowed?.length) {
964
+ merged[unitType as keyof NonNullable<GSDPreferences["planning_subagents"]>] = { allowed };
965
+ }
966
+ }
967
+
968
+ return Object.keys(merged).length > 0 ? merged : undefined;
969
+ }
970
+
946
971
  // ─── System Prompt Rendering ──────────────────────────────────────────────────
947
972
 
948
973
  export function renderPreferencesForSystemPrompt(
@@ -66,12 +66,12 @@ Then:
66
66
  **Web apps:** when inlined Web App UAT guidance is present, follow it for Playwright scaffolding and browser-capable verification commands.
67
67
  4. For non-trivial slices, plan observability / proof level / integration closure, threat surface, and requirement impact. Omit entirely for simple slices.
68
68
  5. Decompose the slice into tasks that fit one context window each. Every task passed to `gsd_plan_slice` must use the exact keys `taskId`, `title`, `description`, `estimate`, `files`, `verify`, `inputs`, `expectedOutput`, and optional `observabilityImpact`. Put Why / Do / Done-when detail in `description`. `files`, `inputs`, and `expectedOutput` must be JSON arrays of strings, even for one path (for example, `"expectedOutput": ["src/index.ts"]`, never `"expectedOutput": "src/index.ts"`). `expectedOutput` is path-only: list only files the task creates or overwrites, and use `[]` for pure verification tasks. Never list GSD planning artifacts — anything under `.gsd/`, `.planning/`, or `.audits/`, or artifact names like `M001-CONTEXT.md` / `S01-PLAN.md` — in `inputs`, `files`, or `expectedOutput`: their content is preloaded as context, and they are written by workflow tools, not by tasks.
69
- 6. **Persist planning state through `gsd_plan_slice`.** Call it with the full payload. The tool writes to the DB and renders `{{outputPath}}` and `{{slicePath}}/tasks/T##-PLAN.md` automatically. Do NOT rely on direct `PLAN.md` writes.
69
+ 6. **Persist planning state through `gsd_plan_slice`.** Call it with the full payload. The tool writes to the DB and renders `{{outputPath}}` with embedded task planning automatically. Do NOT rely on direct `PLAN.md` writes.
70
70
  7. **Self-audit the plan.** If every task were completed exactly as written, the slice goal/demo should be true. Every must-have maps to a task. Inputs and Expected Output are backtick-wrapped file paths.
71
71
  8. If refinement produced structural decisions that diverge from the sketch, call `gsd_decision_save` for each; the tool persists the decision and regenerates `.gsd/DECISIONS.md`.
72
72
  9. {{commitInstruction}}
73
73
 
74
- The slice directory and tasks/ subdirectory already exist. Do NOT mkdir.
74
+ The slice plan path already exists. Do NOT mkdir.
75
75
 
76
76
  **Autonomous execution:** Do not call `ask_user_questions` or `secure_env_collect`. Document assumptions in the plan.
77
77
 
@@ -2,10 +2,12 @@
2
2
  * Provider Payload Policy - ordered shaping of provider request payloads.
3
3
  *
4
4
  * The order is intentional:
5
- * 1. observation budgeting masks old tool results in auto-mode,
6
- * 2. display truncation caps tool-result text for every mode,
7
- * 3. the protected Source Context Block is appended after truncation,
8
- * 4. supported models receive the configured service tier.
5
+ * 1. superseded GSD context injections (memory/guided/forensics) are removed,
6
+ * keeping only the latest, for every mode,
7
+ * 2. observation budgeting masks old tool results in auto-mode,
8
+ * 3. display truncation caps tool-result text for every mode,
9
+ * 4. the protected Source Context Block is appended after truncation,
10
+ * 5. supported models receive the configured service tier.
9
11
  */
10
12
 
11
13
  import type { ContextManagementConfig } from "./preferences-types.js";
@@ -14,6 +16,8 @@ import type { ServiceTierSetting } from "./service-tier.js";
14
16
  import {
15
17
  createObservationMask,
16
18
  createResponsesInputObservationMask,
19
+ filterSupersededContextInjections,
20
+ filterSupersededResponsesContextInjections,
17
21
  truncateContextResultMessages,
18
22
  truncateResponsesInputResultItems,
19
23
  } from "./context-masker.js";
@@ -80,10 +84,20 @@ function applyContextManagement(
80
84
  deps: ProviderPayloadPolicyDeps,
81
85
  ): void {
82
86
  const config = deps.loadContextManagementConfig();
87
+ applyContextInjectionFilter(payload);
83
88
  applyObservationBudget(payload, config, deps.isAutoActive());
84
89
  applyDisplayTruncation(payload, config);
85
90
  }
86
91
 
92
+ function applyContextInjectionFilter(payload: Record<string, unknown>): void {
93
+ if (Array.isArray(payload.messages)) {
94
+ payload.messages = filterSupersededContextInjections(payload.messages as MessagePayload);
95
+ }
96
+ if (Array.isArray(payload.input)) {
97
+ payload.input = filterSupersededResponsesContextInjections(payload.input as ResponsesInputPayload);
98
+ }
99
+ }
100
+
87
101
  function applyObservationBudget(
88
102
  payload: Record<string, unknown>,
89
103
  config: ContextManagementConfig | undefined,
@@ -14,7 +14,7 @@ interface DestructivePattern {
14
14
  }
15
15
 
16
16
  const DESTRUCTIVE_PATTERNS: readonly DestructivePattern[] = [
17
- { pattern: /\brm\s+(-[^\s]*[rfRF][^\s]*\s+|.*\s+-[^\s]*[rfRF])/, label: "recursive delete" },
17
+ { pattern: /\brm\s+((?:-(?!-)[^\s]*[rR][^\s]*|--recursive)\s+|.*\s+(?:-(?!-)[^\s]*[rR][^\s]*|--recursive)(?:\s|$))/, label: "recursive delete" },
18
18
  { pattern: /\bgit\s+push\s+.*--force/, label: "force push" },
19
19
  { pattern: /\bgit\s+push\s+-f\b/, label: "force push" },
20
20
  { pattern: /\bgit\s+reset\s+--hard/, label: "hard reset" },
@@ -232,7 +232,7 @@ export function recordToolCall(toolCallId: string, toolName: string, input: Reco
232
232
  toolCallId,
233
233
  // gsd_exec / gsd_uat_exec carry the script body in `script` (or `code`);
234
234
  // bash-style tools use `command`/`cmd`; gsd_exec_search uses `query`.
235
- command: String(input.command ?? input.script ?? input.cmd ?? input.code ?? input.query ?? ""),
235
+ command: formatExecutionEvidenceCommand(toolName, input),
236
236
  exitCode: -1,
237
237
  outputSnippet: "",
238
238
  timestamp: Date.now(),
@@ -254,6 +254,33 @@ export function recordToolCall(toolCallId: string, toolName: string, input: Reco
254
254
  }
255
255
  }
256
256
 
257
+ function pickString(input: Record<string, unknown>, ...keys: string[]): string {
258
+ for (const key of keys) {
259
+ const value = input[key];
260
+ if (typeof value === "string" && value.trim().length > 0) return value.trim();
261
+ }
262
+ return "";
263
+ }
264
+
265
+ function canonicalExecutionToolLabel(toolName: string): string {
266
+ const normalized = toolName.trim().toLowerCase();
267
+ const mcpMatch = normalized.match(/^mcp__.+__(gsd_(?:uat_)?exec(?:_search)?)$/);
268
+ return mcpMatch?.[1] ?? normalized;
269
+ }
270
+
271
+ function formatExecutionEvidenceCommand(toolName: string, input: Record<string, unknown>): string {
272
+ const body = pickString(input, "command", "script", "cmd", "code", "query");
273
+ const tool = canonicalExecutionToolLabel(toolName);
274
+ const purpose = pickString(input, "purpose");
275
+ const runtime = pickString(input, "runtime").toLowerCase();
276
+ const label = purpose && (tool === "gsd_exec" || tool === "gsd_uat_exec")
277
+ ? `${tool}${runtime ? ` ${runtime}` : ""}: ${purpose}`
278
+ : "";
279
+
280
+ if (label && body) return `${label}\n${body}`;
281
+ return body || label;
282
+ }
283
+
257
284
  /**
258
285
  * Record a tool execution result. Matches the entry by toolCallId (assigned
259
286
  * at dispatch time) and fills in exit code + output. Prior versions matched
@@ -161,9 +161,18 @@ function findMatches(
161
161
  ): BashEvidence[] {
162
162
  const normalized = claimedCommand.trim();
163
163
 
164
- // Exact matches first
165
- const exact = bashCalls.filter(b => b.command.trim() === normalized);
166
- if (exact.length > 0) return exact;
164
+ const exact = bashCalls.filter((b) => b.command.trim() === normalized);
165
+
166
+ // When an exact run exists, also consider wrapper-equivalent reruns (e.g.
167
+ // `cd ... && <command>`) so a newer pass is not shadowed by a stale exact
168
+ // failure. Do not merge arbitrary containing scripts: their exit code may
169
+ // belong to later work, not to the claimed verification command.
170
+ const scriptWrapped = bashCalls.filter((b) => {
171
+ const command = b.command.trim();
172
+ if (command.length === 0 || command === normalized) return false;
173
+ return isWrapperEquivalentCommand(command, normalized);
174
+ });
175
+ if (exact.length > 0) return [...exact, ...scriptWrapped];
167
176
 
168
177
  // Substring match: claimed is contained in actual or actual in claimed.
169
178
  // A claimed verification command typically appears verbatim inside a
@@ -171,7 +180,7 @@ function findMatches(
171
180
  // script-containing-claim is the common direction. Blank-command entries
172
181
  // must be excluded — `"x".includes("")` is true, so they'd match anything.
173
182
  const substring = bashCalls.filter(
174
- b => b.command.trim().length > 0 &&
183
+ (b) => b.command.trim().length > 0 &&
175
184
  (b.command.includes(normalized) || normalized.includes(b.command)),
176
185
  );
177
186
  if (substring.length > 0) return substring;
@@ -199,6 +208,23 @@ function findMatches(
199
208
 
200
209
  function latestMatch(matches: readonly BashEvidence[]): BashEvidence {
201
210
  return matches.reduce((latest, match) => (
202
- match.timestamp > latest.timestamp ? match : latest
211
+ match.timestamp >= latest.timestamp ? match : latest
203
212
  ));
204
213
  }
214
+
215
+ /** True when `actual` is the same command with only shell wrapper noise. */
216
+ function isWrapperEquivalentCommand(actual: string, claimed: string): boolean {
217
+ const claimIndex = actual.lastIndexOf(claimed);
218
+ if (claimIndex < 0) return false;
219
+
220
+ const prefix = actual.slice(0, claimIndex).trim();
221
+ if (prefix.length > 0 && !/^cd\s+.+\s+&&$/.test(prefix)) return false;
222
+
223
+ const suffix = actual.slice(claimIndex + claimed.length).trim();
224
+ return suffix.length === 0 || isBenignWrapperSuffix(suffix);
225
+ }
226
+
227
+ function isBenignWrapperSuffix(suffix: string): boolean {
228
+ if (/^;\s*echo\s+["']?[A-Z_]*EXIT=\$\?["']?$/.test(suffix)) return true;
229
+ return /^(?:(?:\d?>>?|&>)\s*\S+|\d?>&\d)(?:\s+(?:(?:\d?>>?|&>)\s*\S+|\d?>&\d))*$/.test(suffix);
230
+ }
@@ -131,10 +131,23 @@ function resolvePreferredSkillNames(
131
131
  * to prevent prompt injection via crafted directory names. */
132
132
  const SAFE_SKILL_NAME = /^[a-z0-9][a-z0-9-]*$/;
133
133
 
134
- function formatSkillActivationBlock(skillNames: string[]): string {
134
+ function escapeXml(str: string): string {
135
+ return str
136
+ .replace(/&/g, "&amp;")
137
+ .replace(/</g, "&lt;")
138
+ .replace(/>/g, "&gt;")
139
+ .replace(/"/g, "&quot;")
140
+ .replace(/'/g, "&apos;");
141
+ }
142
+
143
+ function formatSkillActivationBlock(skillNames: string[], skillPaths: Map<string, string>): string {
135
144
  const safe = skillNames.filter(name => SAFE_SKILL_NAME.test(name));
136
145
  if (safe.length === 0) return "";
137
- const reads = safe.map(name => `Read the installed '${name}' skill file from <available_skills>`).join(". ");
146
+ const reads = safe.map(name => {
147
+ const path = skillPaths.get(name);
148
+ if (path) return `Read the skill file at \`${escapeXml(path)}\``;
149
+ return `Find '${name}' in <available_skills>, copy its <location> value, and pass that exact path to read`;
150
+ }).join(". ");
138
151
  return `<skill_activation>${reads}.</skill_activation>`;
139
152
  }
140
153
 
@@ -203,6 +216,7 @@ export function buildSkillActivationBlock(params: {
203
216
  const visibleSkills = loaded;
204
217
  const manifestScopedSkills = filterSkillsByManifest(visibleSkills, params.unitType);
205
218
  const installedNames = new Set(visibleSkills.map(skill => normalizeSkillReference(skill.name)));
219
+ const installedSkillPaths = new Map(visibleSkills.map(skill => [normalizeSkillReference(skill.name), skill.filePath]));
206
220
  warnIfManifestHasMissingSkills(params.unitType, installedNames);
207
221
  const avoided = new Set(resolvePreferenceSkillNames(prefs?.avoid_skills ?? [], params.base));
208
222
  const matched = new Set<string>();
@@ -252,7 +266,7 @@ export function buildSkillActivationBlock(params: {
252
266
  const ordered = [...matched]
253
267
  .filter(name => installedNames.has(name) && !avoided.has(name))
254
268
  .sort();
255
- const activationBlock = formatSkillActivationBlock(ordered);
269
+ const activationBlock = formatSkillActivationBlock(ordered, installedSkillPaths);
256
270
 
257
271
  // Omit recommendations when the system catalog is manifest-scoped for this
258
272
  // unit — skill names are already listed in <available_skills>.
@@ -3,9 +3,10 @@
3
3
  //
4
4
  // gsd-pi's DB is canonical, but .gsd/*.md is the inter-tool contract. When
5
5
  // gsd-core edits a projection file, this handler detects the sha drift vs the
6
- // recorded baseline in .gsd/.compat.json and re-imports the affected entities
7
- // into the DB. The next renderAllFromDb pass re-projects; the write-time
8
- // invalidation hook then refreshes the marker entry, closing the loop.
6
+ // recorded baseline in .gsd/.compat.json and re-imports from markdown with
7
+ // status authority scoped to the affected milestone ids. The next
8
+ // renderAllFromDb pass re-projects; the write-time invalidation hook then
9
+ // refreshes the marker entry, closing the loop.
9
10
 
10
11
  import { existsSync, readFileSync } from "node:fs";
11
12
  import { join } from "node:path";
@@ -59,10 +60,11 @@ function detectExternalMarkdownEdit(
59
60
  }
60
61
 
61
62
  /**
62
- * Idempotent repair: re-import hierarchy for the affected entities from
63
- * markdown into the DB, then update the marker entry so the next detect pass
64
- * sees the file as expected. migrateHierarchyToDb is itself idempotent
65
- * (upsert), so re-running this repair after a successful one is a no-op.
63
+ * Idempotent repair: re-import the hierarchy from markdown while allowing
64
+ * markdown status authority only for milestones named by the drifted file's
65
+ * marker entities, then update the marker entry so the next detect pass sees
66
+ * the file as expected. migrateHierarchyToDb is itself idempotent (upsert), so
67
+ * re-running this repair after a successful one is a no-op.
66
68
  */
67
69
  async function repairExternalMarkdownEdit(
68
70
  record: ExternalMarkdownEditDrift,
@@ -72,13 +74,28 @@ async function repairExternalMarkdownEdit(
72
74
  // Dynamic imports break a module-init cycle: this handler ← registry ←
73
75
  // state.ts ← guided-flow.ts ← md-importer.ts ← (this handler's old static
74
76
  // import). Deferring to repair time keeps module load cycle-free.
75
- const { migrateHierarchyToDb } = await import("../../md-importer.js");
77
+ const { migrateHierarchyToDb, milestoneIdsFromEntities } = await import("../../md-importer.js");
76
78
  const { invalidateStateCache } = await import("../../state.js");
77
- // Scoped re-import. migrateHierarchyToDb walks the whole tree but is a
78
- // cheap upsert; per-entity scoping would require decomposing it, which is
79
- // out of scope for v1. The cost is bounded by tree size and runs at most
80
- // once per reconcile pass (MAX_PASSES=2).
81
- migrateHierarchyToDb(ctx.basePath);
79
+ // #027: migrateHierarchyToDb walks the whole tree (a cheap upsert), so
80
+ // without scoping every projection rides along with markdown *status*
81
+ // authority. That lets an unrelated file that is stale from gsd-pi's own
82
+ // miss silently revert a reopened slice/milestone. Scope status authority to
83
+ // exactly the milestone(s) this drifted file projects.
84
+ //
85
+ // Step 1: the marker's `entities` are DB ids (`M001`, `M001/S01`,
86
+ // `M001/S01/T01`), so the milestone id is always the first `/`-segment —
87
+ // layout-independent (legacy `milestones/<MID>/…` and flat `phases/NN-slug/…`
88
+ // both resolve the same way), no projectionPath parsing needed. An empty set
89
+ // (no resolvable entities) preserves DB status everywhere: fail toward
90
+ // protecting the DB, not toward markdown authority.
91
+ const statusAuthoritativeMilestones = milestoneIdsFromEntities(record.entities);
92
+ if (statusAuthoritativeMilestones.size === 0) {
93
+ logWarning(
94
+ "reconcile",
95
+ `external-markdown-edit: no milestone scope resolved for ${record.projectionPath}; preserving DB status for all milestones`,
96
+ );
97
+ }
98
+ migrateHierarchyToDb(ctx.basePath, { statusAuthoritativeMilestones });
82
99
  invalidateStateCache();
83
100
  } catch (err) {
84
101
  logWarning(
@@ -3,7 +3,8 @@
3
3
  // Parallel to external-markdown-edit.ts. Detects sha drift between the compat
4
4
  // marker's planning.projections/passthrough and current .planning/ files.
5
5
  //
6
- // Modeled files (projections): re-imported via parsePlanningDirectory → DB.
6
+ // Modeled files (projections): re-imported via parsePlanningDirectory → DB,
7
+ // with markdown status authority scoped to their marker entity milestone ids.
7
8
  // Passthrough files (un-modeled docs): sha refreshed, content untouched.
8
9
 
9
10
  import { existsSync, readFileSync } from "node:fs";
@@ -148,13 +149,25 @@ async function repairExternalPlanningEdit(
148
149
  const { parsePlanningDirectory } = await import("../../migrate/parser.js");
149
150
  const { transformToGSD } = await import("../../migrate/transformer.js");
150
151
  const { writeGSDDirectory } = await import("../../migrate/writer.js");
151
- const { migrateHierarchyToDb } = await import("../../md-importer.js");
152
+ const { migrateHierarchyToDb, milestoneIdsFromEntities } = await import("../../md-importer.js");
152
153
  const { invalidateStateCache } = await import("../../state.js");
153
154
 
154
155
  const parsed = await parsePlanningDirectory(join(ctx.basePath, ".planning"));
155
156
  const gsdProject = transformToGSD(parsed);
156
157
  await writeGSDDirectory(gsdProject, ctx.basePath);
157
- migrateHierarchyToDb(ctx.basePath);
158
+ // #027: scope status authority to the milestone(s) this drifted .planning/
159
+ // file projects (first `/`-segment of its DB entity ids), so a stale
160
+ // checkbox in an unrelated projection can't revert a reopened slice/milestone
161
+ // in the DB. Unseeded files carry no entities → empty set → preserve DB
162
+ // status everywhere (fail toward the DB, log the breadcrumb).
163
+ const statusAuthoritativeMilestones = milestoneIdsFromEntities(record.entities);
164
+ if (statusAuthoritativeMilestones.size === 0) {
165
+ logWarning(
166
+ "reconcile",
167
+ `external-planning-edit: no milestone scope resolved for ${record.projectionPath}; preserving DB status for all milestones`,
168
+ );
169
+ }
170
+ migrateHierarchyToDb(ctx.basePath, { statusAuthoritativeMilestones });
158
171
  invalidateStateCache();
159
172
  } catch (err) {
160
173
  logWarning(
@@ -49,14 +49,14 @@ export type DriftRecord =
49
49
  projectionPath: string; // relative to basePath, e.g. "m1/plan.md"
50
50
  expectedSha: string; // sha recorded in .compat.json
51
51
  actualSha: string; // freshly computed from disk
52
- entities: string[]; // DB entity ids to re-import
52
+ entities: string[]; // DB entity ids used to scope status authority
53
53
  }
54
54
  | {
55
55
  kind: "external-planning-edit";
56
56
  projectionPath: string; // relative to .planning/, e.g. "phases/01-foo/01-01-PLAN.md"
57
57
  expectedSha: string;
58
58
  actualSha: string;
59
- entities: string[];
59
+ entities: string[]; // DB entity ids used to scope status authority
60
60
  passthrough: boolean; // true = content-only, no re-import, just refresh sha
61
61
  };
62
62
 
@@ -66,10 +66,27 @@ export function isNonBlockingPauseNotice(message: string): boolean {
66
66
  return message.includes("idempotent advance: unit already active");
67
67
  }
68
68
 
69
+ /**
70
+ * A picker / next-action menu that could not render in a non-interactive
71
+ * (headless / RPC) session. Both wordings originate from the menu-unavailable
72
+ * helpers (`notifyCommandMenuUnavailable` and `notifyPickerCommandNeedsInteractiveMenu`
73
+ * in next-action-ui.ts / command-feedback.ts). Headless `auto`/`next` cannot
74
+ * answer such a menu, so the run has dead-ended and needs operator intervention.
75
+ * Classify it as blocked so the headless host exits 10 instead of idling
76
+ * forever waiting for a completion signal that never comes. (#1294)
77
+ */
78
+ export function isInteractiveMenuUnavailableNotice(message: string): boolean {
79
+ return (
80
+ message.includes("menu could not be shown in this session") ||
81
+ message.includes("did not start:")
82
+ );
83
+ }
84
+
69
85
  export function isBlockedNoticeMessage(message: string): boolean {
70
86
  return (
71
87
  message.includes("blocked:") ||
72
88
  (isPauseNotice(message) && !isNonBlockingPauseNotice(message)) ||
73
- isManualResolutionNotice(message)
89
+ isManualResolutionNotice(message) ||
90
+ isInteractiveMenuUnavailableNotice(message)
74
91
  );
75
92
  }
@@ -9,8 +9,10 @@ import { dirname, join } from "node:path";
9
9
  const STALE_THRESHOLD_MS = 60_000; // 60 seconds
10
10
  const DEFAULT_TIMEOUT_MS = 0; // fail fast; sync waits block the JS event loop
11
11
 
12
- function lockFilePath(basePath: string): string {
13
- return join(basePath, ".gsd", "sync.lock");
12
+ const DEFAULT_LOCK_NAME = "sync.lock";
13
+
14
+ function lockFilePath(basePath: string, lockName: string = DEFAULT_LOCK_NAME): string {
15
+ return join(basePath, ".gsd", lockName);
14
16
  }
15
17
 
16
18
  /** True if the given PID is alive in the current process namespace. */
@@ -74,8 +76,9 @@ function tryCreateLockFile(lp: string, payload: string): boolean {
74
76
  export function acquireSyncLock(
75
77
  basePath: string,
76
78
  _timeoutMs: number = DEFAULT_TIMEOUT_MS,
79
+ lockName: string = DEFAULT_LOCK_NAME,
77
80
  ): { acquired: boolean } {
78
- const lp = lockFilePath(basePath);
81
+ const lp = lockFilePath(basePath, lockName);
79
82
  const lockData = JSON.stringify(
80
83
  { pid: process.pid, acquired_at: new Date().toISOString() },
81
84
  null,
@@ -89,7 +92,12 @@ export function acquireSyncLock(
89
92
  return { acquired: true };
90
93
  }
91
94
  } catch {
92
- /* unexpected fall through to retry */
95
+ // tryCreateLockFile only throws for non-EEXIST errors — a persistently
96
+ // uncreatable lock path (dangling-symlink parent, ENOTDIR, read-only FS).
97
+ // Retrying would spin the loop forever with no progress condition,
98
+ // blocking the JS event loop. Fail open like a contended lock so callers
99
+ // proceed (racy but functional) instead of hanging.
100
+ return { acquired: false };
93
101
  }
94
102
 
95
103
  // File exists. Decide whether to steal (stale + owner dead) or skip.
@@ -131,8 +139,8 @@ export function acquireSyncLock(
131
139
  /**
132
140
  * Release the advisory sync lock. No-op if lock file does not exist.
133
141
  */
134
- export function releaseSyncLock(basePath: string): void {
135
- const lp = lockFilePath(basePath);
142
+ export function releaseSyncLock(basePath: string, lockName: string = DEFAULT_LOCK_NAME): void {
143
+ const lp = lockFilePath(basePath, lockName);
136
144
  try {
137
145
  if (existsSync(lp)) {
138
146
  unlinkSync(lp);
@@ -92,6 +92,11 @@ remote_questions:
92
92
  uat_dispatch:
93
93
  post_unit_hooks: []
94
94
  pre_dispatch_hooks: []
95
+ # planning_subagents:
96
+ # plan-milestone:
97
+ # allowed: [scout, planner, security]
98
+ # plan-slice:
99
+ # allowed: [scout, planner, reviewer, security]
95
100
  # language:
96
101
  # experimental:
97
102
  # rtk: false