@opengsd/gsd-pi 1.9.0 → 1.10.0-dev.a5e42e99

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 (502) hide show
  1. package/README.md +10 -9
  2. package/dist/headless.js +2 -1
  3. package/dist/resources/.managed-resources-content-hash +1 -1
  4. package/dist/resources/GSD-WORKFLOW.md +2 -2
  5. package/dist/resources/extensions/gsd/artifact-verification.js +3 -4
  6. package/dist/resources/extensions/gsd/auto/loop.js +24 -4
  7. package/dist/resources/extensions/gsd/auto/run-unit.js +19 -1
  8. package/dist/resources/extensions/gsd/auto/unit-phase.js +37 -5
  9. package/dist/resources/extensions/gsd/auto-artifact-paths.js +14 -8
  10. package/dist/resources/extensions/gsd/auto-dispatch.js +2 -0
  11. package/dist/resources/extensions/gsd/auto-model-selection.js +1 -0
  12. package/dist/resources/extensions/gsd/auto-prompts.js +102 -21
  13. package/dist/resources/extensions/gsd/auto-recovery.js +10 -5
  14. package/dist/resources/extensions/gsd/auto-runtime-state.js +5 -5
  15. package/dist/resources/extensions/gsd/auto-start.js +30 -10
  16. package/dist/resources/extensions/gsd/auto-tool-tracking.js +40 -0
  17. package/dist/resources/extensions/gsd/auto-verification.js +25 -12
  18. package/dist/resources/extensions/gsd/auto-worktree-cleanup.js +4 -0
  19. package/dist/resources/extensions/gsd/auto-worktree-sync.js +7 -3
  20. package/dist/resources/extensions/gsd/auto-worktree-teardown.js +1 -1
  21. package/dist/resources/extensions/gsd/auto.js +15 -5
  22. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +2 -0
  23. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +33 -7
  24. package/dist/resources/extensions/gsd/bootstrap/system-context.js +10 -3
  25. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +7 -26
  26. package/dist/resources/extensions/gsd/commands-verdict.js +10 -9
  27. package/dist/resources/extensions/gsd/compat/compat-marker.js +80 -5
  28. package/dist/resources/extensions/gsd/constants.js +12 -13
  29. package/dist/resources/extensions/gsd/context-masker.js +97 -21
  30. package/dist/resources/extensions/gsd/db/engine.js +5 -2
  31. package/dist/resources/extensions/gsd/docs/preferences-reference.md +33 -2
  32. package/dist/resources/extensions/gsd/doctor-engine-checks.js +40 -12
  33. package/dist/resources/extensions/gsd/error-classifier.js +12 -2
  34. package/dist/resources/extensions/gsd/exec-sandbox.js +1 -0
  35. package/dist/resources/extensions/gsd/flat-phase-migration.js +12 -0
  36. package/dist/resources/extensions/gsd/git-service.js +19 -7
  37. package/dist/resources/extensions/gsd/gsd-db.js +75 -31
  38. package/dist/resources/extensions/gsd/guided-flow.js +11 -5
  39. package/dist/resources/extensions/gsd/markdown-renderer.js +5 -21
  40. package/dist/resources/extensions/gsd/md-importer.js +5 -6
  41. package/dist/resources/extensions/gsd/model-cost-table.js +6 -1
  42. package/dist/resources/extensions/gsd/model-router.js +16 -0
  43. package/dist/resources/extensions/gsd/paths.js +66 -15
  44. package/dist/resources/extensions/gsd/planning-subagent-policy.js +37 -0
  45. package/dist/resources/extensions/gsd/planning-subagent-registry.js +33 -0
  46. package/dist/resources/extensions/gsd/preferences-models.js +50 -10
  47. package/dist/resources/extensions/gsd/preferences-types.js +6 -0
  48. package/dist/resources/extensions/gsd/preferences-validation.js +86 -4
  49. package/dist/resources/extensions/gsd/preferences.js +24 -0
  50. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +5 -5
  51. package/dist/resources/extensions/gsd/provider-payload-policy.js +16 -5
  52. package/dist/resources/extensions/gsd/safety/destructive-guard.js +1 -1
  53. package/dist/resources/extensions/gsd/skill-activation.js +17 -3
  54. package/dist/resources/extensions/gsd/state-reconciliation/drift/external-markdown-edit.js +98 -2
  55. package/dist/resources/extensions/gsd/state-reconciliation/drift/external-planning-edit.js +4 -1
  56. package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +5 -2
  57. package/dist/resources/extensions/gsd/stop-notice.js +9 -0
  58. package/dist/resources/extensions/gsd/templates/PREFERENCES.md +8 -0
  59. package/dist/resources/extensions/gsd/tools/complete-task.js +12 -5
  60. package/dist/resources/extensions/gsd/tools/plan-slice.js +5 -1
  61. package/dist/resources/extensions/gsd/tools/reopen-milestone.js +14 -5
  62. package/dist/resources/extensions/gsd/tools/reopen-slice.js +15 -5
  63. package/dist/resources/extensions/gsd/tools/reopen-task.js +16 -10
  64. package/dist/resources/extensions/gsd/unit-context-composer.js +28 -5
  65. package/dist/resources/extensions/gsd/verification-evidence.js +5 -3
  66. package/dist/resources/extensions/gsd/workflow-projections.js +2 -3
  67. package/dist/resources/extensions/gsd/workspace.js +2 -1
  68. package/dist/resources/extensions/gsd/worktree-state-projection.js +20 -18
  69. package/dist/resources/extensions/ollama/ollama-chat-provider.js +2 -2
  70. package/dist/resources/extensions/shared/interview-ui.js +43 -6
  71. package/dist/resources/extensions/subagent/index.js +1 -1
  72. package/dist/startup-model-validation.d.ts +1 -1
  73. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  74. package/dist/web/standalone/.next/BUILD_ID +1 -1
  75. package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
  76. package/dist/web/standalone/.next/build-manifest.json +3 -3
  77. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  78. package/dist/web/standalone/.next/required-server-files.json +3 -3
  79. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  80. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  81. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  82. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  90. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  91. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  92. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  93. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  94. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  96. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  100. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  101. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  105. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  106. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  110. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  118. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/mcp-connections/route_client-reference-manifest.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  140. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  150. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  156. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  166. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  172. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  175. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  176. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  181. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  182. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  183. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  184. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  185. package/dist/web/standalone/.next/server/app/index.html +1 -1
  186. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  187. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  188. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  189. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  190. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  191. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  192. package/dist/web/standalone/.next/server/app/page.js +2 -2
  193. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  194. package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
  195. package/dist/web/standalone/.next/server/chunks/1991.js +2 -2
  196. package/dist/web/standalone/.next/server/chunks/2842.js +4 -4
  197. package/dist/web/standalone/.next/server/chunks/5124.js +1 -1
  198. package/dist/web/standalone/.next/server/chunks/8357.js +3 -3
  199. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  200. package/dist/web/standalone/.next/server/middleware.js +3 -3
  201. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  202. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  203. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  204. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-a6fb1847f67f167c.js +1 -0
  205. package/dist/web/standalone/.next/static/chunks/app/{layout-b35cbfff38aaf4cf.js → layout-4ae2d68984392bbf.js} +1 -1
  206. package/dist/web/standalone/.next/static/chunks/app/page-72a856634ad14c10.js +1 -0
  207. package/dist/web/standalone/.next/static/chunks/{main-app-590a74400e35f685.js → main-app-90d1d8d5e5d2dc6b.js} +1 -1
  208. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-1115d46ac61b9823.js +1 -0
  209. package/dist/web/standalone/node_modules/@gsd/native/package.json +1 -1
  210. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  211. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  212. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  213. package/dist/web/standalone/server.js +1 -1
  214. package/integrations/hermes/open_gsd_hermes/gsd_client.py +1 -1
  215. package/integrations/hermes/pyproject.toml +1 -1
  216. package/package.json +8 -6
  217. package/packages/cloud-mcp-gateway/package.json +2 -2
  218. package/packages/contracts/dist/rpc.d.ts +1 -1
  219. package/packages/contracts/dist/rpc.d.ts.map +1 -1
  220. package/packages/contracts/dist/rpc.js +1 -1
  221. package/packages/contracts/dist/rpc.js.map +1 -1
  222. package/packages/contracts/dist/rpc.test.js +1 -1
  223. package/packages/contracts/dist/rpc.test.js.map +1 -1
  224. package/packages/contracts/package.json +1 -1
  225. package/packages/daemon/package.json +4 -4
  226. package/packages/gsd-agent-core/dist/compaction/compaction.d.ts.map +1 -1
  227. package/packages/gsd-agent-core/dist/compaction/compaction.js +36 -4
  228. package/packages/gsd-agent-core/dist/compaction/compaction.js.map +1 -1
  229. package/packages/gsd-agent-core/dist/sdk.d.ts.map +1 -1
  230. package/packages/gsd-agent-core/dist/sdk.js +1 -0
  231. package/packages/gsd-agent-core/dist/sdk.js.map +1 -1
  232. package/packages/gsd-agent-core/package.json +5 -5
  233. package/packages/gsd-agent-modes/dist/cli/args.js +2 -2
  234. package/packages/gsd-agent-modes/dist/cli/args.js.map +1 -1
  235. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  236. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js +1 -0
  237. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js.map +1 -1
  238. package/packages/gsd-agent-modes/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  239. package/packages/gsd-agent-modes/dist/modes/interactive/components/thinking-selector.js +1 -0
  240. package/packages/gsd-agent-modes/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  241. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-autocomplete.d.ts.map +1 -1
  242. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-autocomplete.js +1 -0
  243. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-autocomplete.js.map +1 -1
  244. package/packages/gsd-agent-modes/package.json +7 -7
  245. package/packages/gsd-cloud/README.md +21 -5
  246. package/packages/gsd-cloud/dist/background-cli.test.d.ts +2 -0
  247. package/packages/gsd-cloud/dist/background-cli.test.d.ts.map +1 -0
  248. package/packages/gsd-cloud/dist/background-cli.test.js +325 -0
  249. package/packages/gsd-cloud/dist/background-cli.test.js.map +1 -0
  250. package/packages/gsd-cloud/dist/cli.d.ts.map +1 -1
  251. package/packages/gsd-cloud/dist/cli.js +146 -16
  252. package/packages/gsd-cloud/dist/cli.js.map +1 -1
  253. package/packages/gsd-cloud/dist/cloud-config.d.ts +1 -1
  254. package/packages/gsd-cloud/dist/cloud-config.d.ts.map +1 -1
  255. package/packages/gsd-cloud/dist/cloud-config.js +7 -1
  256. package/packages/gsd-cloud/dist/cloud-config.js.map +1 -1
  257. package/packages/gsd-cloud/dist/cloud-runtime.d.ts +7 -4
  258. package/packages/gsd-cloud/dist/cloud-runtime.d.ts.map +1 -1
  259. package/packages/gsd-cloud/dist/cloud-runtime.js +115 -31
  260. package/packages/gsd-cloud/dist/cloud-runtime.js.map +1 -1
  261. package/packages/gsd-cloud/dist/cloud-runtime.test.js +224 -59
  262. package/packages/gsd-cloud/dist/cloud-runtime.test.js.map +1 -1
  263. package/packages/gsd-cloud/dist/runtime-artifacts.d.ts +3 -0
  264. package/packages/gsd-cloud/dist/runtime-artifacts.d.ts.map +1 -0
  265. package/packages/gsd-cloud/dist/runtime-artifacts.js +36 -0
  266. package/packages/gsd-cloud/dist/runtime-artifacts.js.map +1 -0
  267. package/packages/gsd-cloud/dist/runtime-process.d.ts +32 -0
  268. package/packages/gsd-cloud/dist/runtime-process.d.ts.map +1 -0
  269. package/packages/gsd-cloud/dist/runtime-process.js +640 -0
  270. package/packages/gsd-cloud/dist/runtime-process.js.map +1 -0
  271. package/packages/gsd-cloud/dist/runtime-process.test.d.ts +2 -0
  272. package/packages/gsd-cloud/dist/runtime-process.test.d.ts.map +1 -0
  273. package/packages/gsd-cloud/dist/runtime-process.test.js +543 -0
  274. package/packages/gsd-cloud/dist/runtime-process.test.js.map +1 -0
  275. package/packages/gsd-cloud/dist/runtime-telemetry.d.ts +117 -0
  276. package/packages/gsd-cloud/dist/runtime-telemetry.d.ts.map +1 -0
  277. package/packages/gsd-cloud/dist/runtime-telemetry.js +291 -0
  278. package/packages/gsd-cloud/dist/runtime-telemetry.js.map +1 -0
  279. package/packages/gsd-cloud/dist/runtime-telemetry.test.d.ts +2 -0
  280. package/packages/gsd-cloud/dist/runtime-telemetry.test.d.ts.map +1 -0
  281. package/packages/gsd-cloud/dist/runtime-telemetry.test.js +434 -0
  282. package/packages/gsd-cloud/dist/runtime-telemetry.test.js.map +1 -0
  283. package/packages/gsd-cloud/package.json +2 -2
  284. package/packages/mcp-server/README.md +7 -2
  285. package/packages/mcp-server/dist/cli-runner.d.ts +3 -0
  286. package/packages/mcp-server/dist/cli-runner.d.ts.map +1 -1
  287. package/packages/mcp-server/dist/cli-runner.js +119 -33
  288. package/packages/mcp-server/dist/cli-runner.js.map +1 -1
  289. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  290. package/packages/mcp-server/dist/server.js +5 -5
  291. package/packages/mcp-server/dist/server.js.map +1 -1
  292. package/packages/mcp-server/dist/workflow-tools.d.ts +4 -3
  293. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  294. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  295. package/packages/mcp-server/package.json +4 -4
  296. package/packages/native/package.json +1 -1
  297. package/packages/pi-agent-core/dist/agent.d.ts +5 -1
  298. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  299. package/packages/pi-agent-core/dist/agent.js +2 -0
  300. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  301. package/packages/pi-agent-core/dist/types.d.ts +2 -2
  302. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  303. package/packages/pi-agent-core/dist/types.js.map +1 -1
  304. package/packages/pi-agent-core/package.json +1 -1
  305. package/packages/pi-ai/dist/models.d.ts.map +1 -1
  306. package/packages/pi-ai/dist/models.generated.d.ts +187 -0
  307. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  308. package/packages/pi-ai/dist/models.generated.js +145 -0
  309. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  310. package/packages/pi-ai/dist/models.js +18 -6
  311. package/packages/pi-ai/dist/models.js.map +1 -1
  312. package/packages/pi-ai/dist/providers/amazon-bedrock.js +3 -2
  313. package/packages/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
  314. package/packages/pi-ai/dist/providers/anthropic.js +6 -1
  315. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  316. package/packages/pi-ai/dist/providers/azure-openai-responses.d.ts +1 -1
  317. package/packages/pi-ai/dist/providers/azure-openai-responses.d.ts.map +1 -1
  318. package/packages/pi-ai/dist/providers/azure-openai-responses.js.map +1 -1
  319. package/packages/pi-ai/dist/providers/google-vertex.js.map +1 -1
  320. package/packages/pi-ai/dist/providers/google.js.map +1 -1
  321. package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts +1 -1
  322. package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
  323. package/packages/pi-ai/dist/providers/openai-codex-responses.js +1 -1
  324. package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
  325. package/packages/pi-ai/dist/providers/openai-completions.d.ts +1 -1
  326. package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  327. package/packages/pi-ai/dist/providers/openai-completions.js +103 -0
  328. package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
  329. package/packages/pi-ai/dist/providers/openai-responses.d.ts +1 -1
  330. package/packages/pi-ai/dist/providers/openai-responses.d.ts.map +1 -1
  331. package/packages/pi-ai/dist/providers/openai-responses.js +1 -1
  332. package/packages/pi-ai/dist/providers/openai-responses.js.map +1 -1
  333. package/packages/pi-ai/dist/providers/simple-options.d.ts +1 -1
  334. package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  335. package/packages/pi-ai/dist/providers/simple-options.js +1 -1
  336. package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
  337. package/packages/pi-ai/dist/types.d.ts +9 -1
  338. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  339. package/packages/pi-ai/dist/types.js.map +1 -1
  340. package/packages/pi-ai/package.json +1 -1
  341. package/packages/pi-coding-agent/dist/core/capability-patches.js +1 -1
  342. package/packages/pi-coding-agent/dist/core/capability-patches.js.map +1 -1
  343. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  344. package/packages/pi-coding-agent/dist/core/model-registry.js +1 -0
  345. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  346. package/packages/pi-coding-agent/dist/core/model-resolver.js +2 -2
  347. package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
  348. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +14 -4
  349. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  350. package/packages/pi-coding-agent/dist/core/settings-manager.js +8 -0
  351. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  352. package/packages/pi-coding-agent/dist/core/skills.d.ts +5 -0
  353. package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
  354. package/packages/pi-coding-agent/dist/core/skills.js +54 -0
  355. package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
  356. package/packages/pi-coding-agent/dist/theme/theme.d.ts +1 -1
  357. package/packages/pi-coding-agent/dist/theme/theme.d.ts.map +1 -1
  358. package/packages/pi-coding-agent/dist/theme/theme.js +1 -0
  359. package/packages/pi-coding-agent/dist/theme/theme.js.map +1 -1
  360. package/packages/pi-coding-agent/package.json +7 -7
  361. package/packages/pi-tui/package.json +2 -2
  362. package/packages/rpc-client/package.json +2 -2
  363. package/pkg/dist/theme/theme.d.ts +1 -1
  364. package/pkg/dist/theme/theme.d.ts.map +1 -1
  365. package/pkg/dist/theme/theme.js +1 -0
  366. package/pkg/dist/theme/theme.js.map +1 -1
  367. package/pkg/package.json +1 -1
  368. package/src/resources/GSD-WORKFLOW.md +2 -2
  369. package/src/resources/extensions/gsd/artifact-verification.ts +3 -8
  370. package/src/resources/extensions/gsd/auto/loop.ts +48 -4
  371. package/src/resources/extensions/gsd/auto/run-unit.ts +20 -1
  372. package/src/resources/extensions/gsd/auto/unit-phase.ts +41 -5
  373. package/src/resources/extensions/gsd/auto-artifact-paths.ts +14 -7
  374. package/src/resources/extensions/gsd/auto-dispatch.ts +1 -0
  375. package/src/resources/extensions/gsd/auto-model-selection.ts +1 -0
  376. package/src/resources/extensions/gsd/auto-prompts.ts +118 -19
  377. package/src/resources/extensions/gsd/auto-recovery.ts +10 -8
  378. package/src/resources/extensions/gsd/auto-runtime-state.ts +12 -7
  379. package/src/resources/extensions/gsd/auto-start.ts +32 -9
  380. package/src/resources/extensions/gsd/auto-tool-tracking.ts +56 -0
  381. package/src/resources/extensions/gsd/auto-verification.ts +46 -12
  382. package/src/resources/extensions/gsd/auto-worktree-cleanup.ts +4 -0
  383. package/src/resources/extensions/gsd/auto-worktree-sync.ts +10 -3
  384. package/src/resources/extensions/gsd/auto-worktree-teardown.ts +1 -1
  385. package/src/resources/extensions/gsd/auto.ts +20 -7
  386. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +1 -0
  387. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +41 -12
  388. package/src/resources/extensions/gsd/bootstrap/system-context.ts +11 -3
  389. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +10 -31
  390. package/src/resources/extensions/gsd/commands-verdict.ts +16 -9
  391. package/src/resources/extensions/gsd/compat/compat-marker.ts +99 -5
  392. package/src/resources/extensions/gsd/constants.ts +14 -13
  393. package/src/resources/extensions/gsd/context-masker.ts +98 -2
  394. package/src/resources/extensions/gsd/db/engine.ts +5 -2
  395. package/src/resources/extensions/gsd/docs/preferences-reference.md +33 -2
  396. package/src/resources/extensions/gsd/doctor-engine-checks.ts +45 -11
  397. package/src/resources/extensions/gsd/error-classifier.ts +13 -2
  398. package/src/resources/extensions/gsd/exec-sandbox.ts +1 -0
  399. package/src/resources/extensions/gsd/flat-phase-migration.ts +14 -0
  400. package/src/resources/extensions/gsd/git-service.ts +19 -6
  401. package/src/resources/extensions/gsd/gsd-db.ts +85 -33
  402. package/src/resources/extensions/gsd/guided-flow.ts +11 -4
  403. package/src/resources/extensions/gsd/markdown-renderer.ts +5 -23
  404. package/src/resources/extensions/gsd/md-importer.ts +5 -5
  405. package/src/resources/extensions/gsd/model-cost-table.ts +14 -1
  406. package/src/resources/extensions/gsd/model-router.ts +17 -0
  407. package/src/resources/extensions/gsd/paths.ts +73 -15
  408. package/src/resources/extensions/gsd/planning-subagent-policy.ts +58 -0
  409. package/src/resources/extensions/gsd/planning-subagent-registry.ts +45 -0
  410. package/src/resources/extensions/gsd/preferences-models.ts +54 -10
  411. package/src/resources/extensions/gsd/preferences-types.ts +26 -2
  412. package/src/resources/extensions/gsd/preferences-validation.ts +108 -3
  413. package/src/resources/extensions/gsd/preferences.ts +38 -0
  414. package/src/resources/extensions/gsd/prompts/validate-milestone.md +5 -5
  415. package/src/resources/extensions/gsd/provider-payload-policy.ts +18 -4
  416. package/src/resources/extensions/gsd/safety/destructive-guard.ts +1 -1
  417. package/src/resources/extensions/gsd/skill-activation.ts +17 -3
  418. package/src/resources/extensions/gsd/state-reconciliation/drift/external-markdown-edit.ts +132 -2
  419. package/src/resources/extensions/gsd/state-reconciliation/drift/external-planning-edit.ts +4 -1
  420. package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +4 -2
  421. package/src/resources/extensions/gsd/stop-notice.ts +11 -0
  422. package/src/resources/extensions/gsd/templates/PREFERENCES.md +8 -0
  423. package/src/resources/extensions/gsd/tests/auto-artifact-paths.test.ts +7 -7
  424. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +264 -0
  425. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +39 -0
  426. package/src/resources/extensions/gsd/tests/auto-start-index-lock.test.ts +21 -1
  427. package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +74 -1
  428. package/src/resources/extensions/gsd/tests/before-provider-context-management.test.ts +55 -0
  429. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +10 -0
  430. package/src/resources/extensions/gsd/tests/compat-marker.test.ts +25 -0
  431. package/src/resources/extensions/gsd/tests/complete-task.test.ts +76 -1
  432. package/src/resources/extensions/gsd/tests/context-masker.test.ts +204 -8
  433. package/src/resources/extensions/gsd/tests/db-engine-cjs-compat.test.ts +12 -0
  434. package/src/resources/extensions/gsd/tests/db-tools-alias-suppression.test.ts +62 -0
  435. package/src/resources/extensions/gsd/tests/destructive-confirmation.test.ts +33 -0
  436. package/src/resources/extensions/gsd/tests/destructive-guard.test.ts +14 -0
  437. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +147 -0
  438. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +33 -1
  439. package/src/resources/extensions/gsd/tests/external-markdown-edit.test.ts +38 -1
  440. package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +8 -9
  441. package/src/resources/extensions/gsd/tests/flat-phase-validation-path.test.ts +20 -1
  442. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +32 -0
  443. package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +22 -0
  444. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +13 -0
  445. package/src/resources/extensions/gsd/tests/integration/paths.test.ts +22 -4
  446. package/src/resources/extensions/gsd/tests/integration-branch-meta-location.test.ts +62 -0
  447. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +5 -5
  448. package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +23 -0
  449. package/src/resources/extensions/gsd/tests/model-isolation.test.ts +55 -0
  450. package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
  451. package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +7 -5
  452. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +24 -0
  453. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +38 -1
  454. package/src/resources/extensions/gsd/tests/preferences.test.ts +151 -0
  455. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +7 -0
  456. package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +87 -0
  457. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +121 -1
  458. package/src/resources/extensions/gsd/tests/reactive-executor.test.ts +39 -0
  459. package/src/resources/extensions/gsd/tests/register-hooks-loop-guard-auto.test.ts +105 -0
  460. package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
  461. package/src/resources/extensions/gsd/tests/single-writer-v3-tool-surface.test.ts +33 -7
  462. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +20 -16
  463. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +52 -0
  464. package/src/resources/extensions/gsd/tests/stop-notice.test.ts +21 -1
  465. package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +13 -7
  466. package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +14 -0
  467. package/src/resources/extensions/gsd/tests/thinking-level-resolution.test.ts +1 -1
  468. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +19 -0
  469. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -0
  470. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +39 -0
  471. package/src/resources/extensions/gsd/tests/validate-milestone-prompt-verification-classes.test.ts +7 -0
  472. package/src/resources/extensions/gsd/tests/verification-evidence.test.ts +12 -0
  473. package/src/resources/extensions/gsd/tests/workflow-authority-faults.test.ts +238 -0
  474. package/src/resources/extensions/gsd/tests/workflow-authority-fixture.test.ts +48 -0
  475. package/src/resources/extensions/gsd/tests/workflow-authority-fixture.ts +141 -0
  476. package/src/resources/extensions/gsd/tests/workflow-authority-projection-conflict.test.ts +177 -0
  477. package/src/resources/extensions/gsd/tests/workflow-fault-harness.test.ts +39 -0
  478. package/src/resources/extensions/gsd/tests/workflow-fault-harness.ts +72 -0
  479. package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +4 -4
  480. package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +2 -2
  481. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +60 -0
  482. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +74 -0
  483. package/src/resources/extensions/gsd/tools/complete-task.ts +20 -5
  484. package/src/resources/extensions/gsd/tools/plan-slice.ts +5 -1
  485. package/src/resources/extensions/gsd/tools/reopen-milestone.ts +24 -5
  486. package/src/resources/extensions/gsd/tools/reopen-slice.ts +25 -5
  487. package/src/resources/extensions/gsd/tools/reopen-task.ts +23 -9
  488. package/src/resources/extensions/gsd/unit-context-composer.ts +34 -8
  489. package/src/resources/extensions/gsd/verification-evidence.ts +5 -2
  490. package/src/resources/extensions/gsd/workflow-projections.ts +2 -3
  491. package/src/resources/extensions/gsd/workspace.ts +2 -1
  492. package/src/resources/extensions/gsd/worktree-state-projection.ts +21 -24
  493. package/src/resources/extensions/ollama/ollama-chat-provider.ts +2 -2
  494. package/src/resources/extensions/ollama/tests/ollama-chat-provider-think.test.ts +4 -0
  495. package/src/resources/extensions/shared/interview-ui.ts +47 -8
  496. package/src/resources/extensions/shared/tests/interview-ui-border.test.ts +29 -0
  497. package/src/resources/extensions/subagent/index.ts +1 -1
  498. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-49f565245e1e4afe.js +0 -1
  499. package/dist/web/standalone/.next/static/chunks/app/page-bc4c723c6a19c6f0.js +0 -1
  500. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ec3eaffc9785ba48.js +0 -1
  501. /package/dist/web/standalone/.next/static/{BE5XoklToI6lZjRzpXih8 → xwUaOqui04jIIFVsIBLiL}/_buildManifest.js +0 -0
  502. /package/dist/web/standalone/.next/static/{BE5XoklToI6lZjRzpXih8 → xwUaOqui04jIIFVsIBLiL}/_ssgManifest.js +0 -0
@@ -67,6 +67,13 @@ export type { SliceRow, TaskRow } from "./db-task-slice-rows.js";
67
67
 
68
68
  import { TERMINAL_STATUS_SQL } from "./db/sql-constants.js";
69
69
  import { applyStatusTransition } from "./db/writers/status.js";
70
+ import {
71
+ LAYOUT_SEGMENTS,
72
+ derivePhaseSlug,
73
+ milestoneIdToPhaseNum,
74
+ milestoneIdUniqueSuffix,
75
+ phaseDirName,
76
+ } from "./layout-policy.js";
70
77
 
71
78
  export function insertDecision(d: Omit<Decision, "seq">): void {
72
79
  if (!getDbOrNull()!) throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
@@ -206,6 +213,47 @@ export function insertArtifact(a: {
206
213
  });
207
214
  }
208
215
 
216
+ function canonicalPhaseDirNameForDb(milestoneId: string, title: string): string {
217
+ const phaseNum = milestoneIdToPhaseNum(milestoneId);
218
+ const slug = derivePhaseSlug(title || milestoneId);
219
+ const suffix = milestoneIdUniqueSuffix(milestoneId);
220
+ return phaseDirName(phaseNum, suffix ? `${suffix}-${slug}` : slug);
221
+ }
222
+
223
+ function reconcileMilestonePhaseArtifactPaths(milestoneId: string, title: string): void {
224
+ const db = getDbOrNull()!;
225
+ const phaseNumPrefix = String(milestoneIdToPhaseNum(milestoneId)).padStart(2, "0");
226
+ const canonicalDir = canonicalPhaseDirNameForDb(milestoneId, title);
227
+ const staleRows = db.prepare(
228
+ `SELECT path
229
+ FROM artifacts
230
+ WHERE milestone_id = :milestone_id
231
+ AND path LIKE :phase_prefix`,
232
+ ).all({
233
+ ":milestone_id": milestoneId,
234
+ ":phase_prefix": `${LAYOUT_SEGMENTS.level1}/${phaseNumPrefix}-%/%`,
235
+ }) as Array<{ path: string }>;
236
+
237
+ const updatePath = db.prepare("UPDATE artifacts SET path = :new_path WHERE path = :old_path");
238
+ const deletePath = db.prepare("DELETE FROM artifacts WHERE path = :path");
239
+ const existingPath = db.prepare("SELECT 1 AS present FROM artifacts WHERE path = :path");
240
+
241
+ for (const row of staleRows) {
242
+ const parts = row.path.split("/");
243
+ if (parts.length < 3) continue;
244
+ if (parts[0] !== LAYOUT_SEGMENTS.level1) continue;
245
+ if (parts[1] === canonicalDir) continue;
246
+ if (!parts[1]?.startsWith(`${phaseNumPrefix}-`)) continue;
247
+
248
+ const newPath = [LAYOUT_SEGMENTS.level1, canonicalDir, ...parts.slice(2)].join("/");
249
+ if (existingPath.get({ ":path": newPath })) {
250
+ deletePath.run({ ":path": row.path });
251
+ continue;
252
+ }
253
+ updatePath.run({ ":new_path": newPath, ":old_path": row.path });
254
+ }
255
+ }
256
+
209
257
  export interface MilestonePlanningRecord {
210
258
  vision: string;
211
259
  successCriteria: string[];
@@ -287,39 +335,43 @@ export function insertMilestone(m: {
287
335
 
288
336
  export function upsertMilestonePlanning(milestoneId: string, planning: Partial<MilestonePlanningRecord> & { title?: string; status?: string; depends_on?: string[] }): void {
289
337
  if (!getDbOrNull()!) throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
290
- getDbOrNull()!.prepare(
291
- `UPDATE milestones SET
292
- title = COALESCE(NULLIF(:title, ''), title),
293
- status = COALESCE(NULLIF(:status, ''), status),
294
- depends_on = COALESCE(:depends_on, depends_on),
295
- vision = COALESCE(:vision, vision),
296
- success_criteria = COALESCE(:success_criteria, success_criteria),
297
- key_risks = COALESCE(:key_risks, key_risks),
298
- proof_strategy = COALESCE(:proof_strategy, proof_strategy),
299
- verification_contract = COALESCE(:verification_contract, verification_contract),
300
- verification_integration = COALESCE(:verification_integration, verification_integration),
301
- verification_operational = COALESCE(:verification_operational, verification_operational),
302
- verification_uat = COALESCE(:verification_uat, verification_uat),
303
- definition_of_done = COALESCE(:definition_of_done, definition_of_done),
304
- requirement_coverage = COALESCE(:requirement_coverage, requirement_coverage),
305
- boundary_map_markdown = COALESCE(:boundary_map_markdown, boundary_map_markdown)
306
- WHERE id = :id`,
307
- ).run({
308
- ":id": milestoneId,
309
- ":title": planning.title ?? "",
310
- ":status": planning.status ?? "",
311
- ":depends_on": planning.depends_on ? JSON.stringify(planning.depends_on) : null,
312
- ":vision": planning.vision ?? null,
313
- ":success_criteria": planning.successCriteria ? JSON.stringify(planning.successCriteria) : null,
314
- ":key_risks": planning.keyRisks ? JSON.stringify(planning.keyRisks) : null,
315
- ":proof_strategy": planning.proofStrategy ? JSON.stringify(planning.proofStrategy) : null,
316
- ":verification_contract": planning.verificationContract ?? null,
317
- ":verification_integration": planning.verificationIntegration ?? null,
318
- ":verification_operational": planning.verificationOperational ?? null,
319
- ":verification_uat": planning.verificationUat ?? null,
320
- ":definition_of_done": planning.definitionOfDone ? JSON.stringify(planning.definitionOfDone) : null,
321
- ":requirement_coverage": planning.requirementCoverage ?? null,
322
- ":boundary_map_markdown": planning.boundaryMapMarkdown ?? null,
338
+ transaction(() => {
339
+ getDbOrNull()!.prepare(
340
+ `UPDATE milestones SET
341
+ title = COALESCE(NULLIF(:title, ''), title),
342
+ status = COALESCE(NULLIF(:status, ''), status),
343
+ depends_on = COALESCE(:depends_on, depends_on),
344
+ vision = COALESCE(:vision, vision),
345
+ success_criteria = COALESCE(:success_criteria, success_criteria),
346
+ key_risks = COALESCE(:key_risks, key_risks),
347
+ proof_strategy = COALESCE(:proof_strategy, proof_strategy),
348
+ verification_contract = COALESCE(:verification_contract, verification_contract),
349
+ verification_integration = COALESCE(:verification_integration, verification_integration),
350
+ verification_operational = COALESCE(:verification_operational, verification_operational),
351
+ verification_uat = COALESCE(:verification_uat, verification_uat),
352
+ definition_of_done = COALESCE(:definition_of_done, definition_of_done),
353
+ requirement_coverage = COALESCE(:requirement_coverage, requirement_coverage),
354
+ boundary_map_markdown = COALESCE(:boundary_map_markdown, boundary_map_markdown)
355
+ WHERE id = :id`,
356
+ ).run({
357
+ ":id": milestoneId,
358
+ ":title": planning.title ?? "",
359
+ ":status": planning.status ?? "",
360
+ ":depends_on": planning.depends_on ? JSON.stringify(planning.depends_on) : null,
361
+ ":vision": planning.vision ?? null,
362
+ ":success_criteria": planning.successCriteria ? JSON.stringify(planning.successCriteria) : null,
363
+ ":key_risks": planning.keyRisks ? JSON.stringify(planning.keyRisks) : null,
364
+ ":proof_strategy": planning.proofStrategy ? JSON.stringify(planning.proofStrategy) : null,
365
+ ":verification_contract": planning.verificationContract ?? null,
366
+ ":verification_integration": planning.verificationIntegration ?? null,
367
+ ":verification_operational": planning.verificationOperational ?? null,
368
+ ":verification_uat": planning.verificationUat ?? null,
369
+ ":definition_of_done": planning.definitionOfDone ? JSON.stringify(planning.definitionOfDone) : null,
370
+ ":requirement_coverage": planning.requirementCoverage ?? null,
371
+ ":boundary_map_markdown": planning.boundaryMapMarkdown ?? null,
372
+ });
373
+ const finalTitle = planning.title?.trim();
374
+ if (finalTitle) reconcileMilestonePhaseArtifactPaths(milestoneId, finalTitle);
323
375
  });
324
376
  }
325
377
 
@@ -26,6 +26,7 @@ import {
26
26
  buildPlanMilestonePrompt,
27
27
  buildPlanSlicePrompt,
28
28
  buildSkillActivationBlock,
29
+ capPreamble,
29
30
  } from "./auto-prompts.js";
30
31
  import { deriveState, isGhostMilestone } from "./state.js";
31
32
  import { invalidateAllCaches } from "./cache.js";
@@ -1199,7 +1200,9 @@ function resolveDiscussSliceBasePath(basePath: string, milestoneId: string): str
1199
1200
  * slice summaries so the agent can ask grounded UX/behaviour questions
1200
1201
  * without wasting a turn reading files.
1201
1202
  */
1202
- async function buildDiscussSlicePrompt(
1203
+ // Exported for tests (`prompt-budget-enforcement.test.ts`) — verifies the
1204
+ // inlined-context cap. Not part of the public flow surface otherwise.
1205
+ export async function buildDiscussSlicePrompt(
1203
1206
  mid: string,
1204
1207
  sid: string,
1205
1208
  sTitle: string,
@@ -1262,8 +1265,12 @@ async function buildDiscussSlicePrompt(
1262
1265
  }
1263
1266
  }
1264
1267
 
1268
+ // Cap the inlined block: it grows unbounded with each completed slice's full
1269
+ // SUMMARY. `capPreamble` truncates at `### ` section boundaries — roadmap and
1270
+ // milestone context come first (survive), completed-slice summaries come last
1271
+ // (dropped first) when the executor's window can't hold everything.
1265
1272
  const inlinedContext = inlined.length > 0
1266
- ? `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`
1273
+ ? capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`)
1267
1274
  : `## Inlined Context\n\n_(no context files found yet — go in blind and ask broad questions)_`;
1268
1275
 
1269
1276
  const sliceDirPath = `.gsd/milestones/${mid}/slices/${sid}`;
@@ -1275,7 +1282,7 @@ async function buildDiscussSlicePrompt(
1275
1282
  : "";
1276
1283
 
1277
1284
  const inlinedTemplates = inlineTemplate("slice-context", "Slice Context");
1278
- return loadPrompt("guided-discuss-slice", {
1285
+ return prependLanguageDirective(base, loadPrompt("guided-discuss-slice", {
1279
1286
  milestoneId: mid,
1280
1287
  sliceId: sid,
1281
1288
  sliceTitle: sTitle,
@@ -1286,7 +1293,7 @@ async function buildDiscussSlicePrompt(
1286
1293
  inlinedTemplates,
1287
1294
  structuredQuestionsAvailable: options?.structuredQuestionsAvailable ?? "false",
1288
1295
  commitInstruction: buildDocsCommitInstruction(`docs(${mid}/${sid}): slice context from discuss`),
1289
- });
1296
+ }));
1290
1297
  }
1291
1298
 
1292
1299
  /**
@@ -12,7 +12,7 @@
12
12
  import { readFileSync, existsSync, mkdirSync, statSync, unlinkSync } from "node:fs";
13
13
  import { logWarning } from "./workflow-logger.js";
14
14
  import { isClosedStatus } from "./status-guards.js";
15
- import { dirname, join, relative } from "node:path";
15
+ import { dirname, join } from "node:path";
16
16
  import {
17
17
  getAllMilestones,
18
18
  getMilestone,
@@ -40,6 +40,7 @@ import {
40
40
  resolveTasksDir,
41
41
  targetMilestoneFile,
42
42
  targetSliceFile,
43
+ targetTaskFile,
43
44
  gsdProjectionRoot,
44
45
  gsdRoot,
45
46
  buildTaskFileName,
@@ -49,7 +50,7 @@ import { saveFile, clearParseCache, registerCacheClearCallback } from "./files.j
49
50
  import { parseRoadmap, parsePlan } from "./parsers-legacy.js";
50
51
  import { invalidateStateCache } from "./state.js";
51
52
  import { clearPathCache, milestonesDir, legacyMilestonesDir, isLegacyMilestonesLayout, resolveMilestonePath, relSliceFile, canonicalPhaseDirName } from "./paths.js";
52
- import { readCompatMarker, writeCompatMarker, computeProjectionSha } from "./compat/compat-marker.js";
53
+ import { readCompatMarker, writeCompatMarker, computeProjectionSha, deriveCompatProjectionKey } from "./compat/compat-marker.js";
53
54
  import type { RiskLevel } from "./types.js";
54
55
  import {
55
56
  phaseDirName,
@@ -108,13 +109,7 @@ function flushProjectionWritesToMarker(): void {
108
109
  */
109
110
  function toArtifactPath(absPath: string, basePath: string): string {
110
111
  const projectionRoot = gsdProjectionRoot(basePath);
111
- const projectionRel = relative(projectionRoot, absPath);
112
- const root = projectionRel && !projectionRel.startsWith("..") && !projectionRel.startsWith("/")
113
- ? projectionRoot
114
- : gsdRoot(basePath);
115
- const rel = relative(root, absPath);
116
- // Normalize to forward slashes for consistent DB keys
117
- return rel.replace(/\\/g, "/");
112
+ return deriveCompatProjectionKey(absPath, [projectionRoot, gsdRoot(basePath)]);
118
113
  }
119
114
 
120
115
  /**
@@ -756,20 +751,7 @@ export async function renderTaskSummary(
756
751
  return false; // No summary to render — skip silently
757
752
  }
758
753
 
759
- // Resolve the tasks directory, creating path if needed
760
- const slicePath = resolveSlicePath(basePath, milestoneId, sliceId);
761
- if (!slicePath) {
762
- process.stderr.write(
763
- `markdown-renderer: cannot resolve slice path for ${milestoneId}/${sliceId}\n`,
764
- );
765
- return false;
766
- }
767
-
768
- // Use the tasks/ subdir when it exists (legacy layout), otherwise use the
769
- // slice path directly (flat-phase: task summaries live alongside plan files).
770
- const tasksDir = resolveTasksDir(basePath, milestoneId, sliceId) ?? slicePath;
771
- const fileName = buildTaskFileName(taskId, "SUMMARY");
772
- const absPath = join(tasksDir, fileName);
754
+ const absPath = targetTaskFile(basePath, milestoneId, sliceId, taskId, "SUMMARY", getMilestone(milestoneId)?.title);
773
755
  const artifactPath = toArtifactPath(absPath, basePath);
774
756
 
775
757
  await writeAndStore(absPath, artifactPath, task.full_summary_md, {
@@ -31,6 +31,7 @@ import {
31
31
  legacyMilestonesDir,
32
32
  gsdRoot,
33
33
  resolveTaskFiles,
34
+ resolveTaskFile,
34
35
  resolveMilestonePath,
35
36
  } from './paths.js';
36
37
  import { findMilestoneIds } from './guided-flow.js';
@@ -925,8 +926,7 @@ export function migrateHierarchyToDb(
925
926
  legacyTasksDir = isLegacySlice
926
927
  ? resolveTasksDir(basePath, milestoneId, sliceEntry.id)
927
928
  : null;
928
- const summaryDir = legacyTasksDir ?? slicePath;
929
- taskSummaryFile = join(summaryDir, `${taskEntry.id}-SUMMARY.md`);
929
+ taskSummaryFile = resolveTaskFile(basePath, milestoneId, sliceEntry.id, taskEntry.id, 'SUMMARY');
930
930
  }
931
931
  const hasTaskSummary = taskSummaryFile !== null && existsSync(taskSummaryFile);
932
932
 
@@ -950,9 +950,9 @@ export function migrateHierarchyToDb(
950
950
  // first execute-task. The surviving SUMMARY wins over a stale checkbox.
951
951
  // reopen-task removes the SUMMARY, so this never re-completes an
952
952
  // intentionally reopened task.
953
- // Flat-phase summaries are phase-scoped (T01-SUMMARY.md); when a milestone
954
- // has multiple slices, require the summary parent frontmatter to match so
955
- // one slice's completion does not attest a sibling's same-named task.
953
+ // Flat-phase summaries are phase-scoped; when a milestone has multiple
954
+ // slices, require the summary parent frontmatter to match so one slice's
955
+ // completion does not attest a sibling's same-named task.
956
956
  let summaryAttestsCompletion = hasTaskSummary;
957
957
  if (summaryAttestsCompletion && !isLegacySlice && roadmap.slices.length > 1 && taskSummaryFile) {
958
958
  try {
@@ -12,6 +12,12 @@ export interface ModelCostEntry {
12
12
  inputPer1k: number;
13
13
  /** Approximate cost per 1K output tokens in USD */
14
14
  outputPer1k: number;
15
+ /** Input-token-based long-context pricing tiers, when published */
16
+ tiers?: Array<{
17
+ inputTokensAbove: number;
18
+ inputPer1k: number;
19
+ outputPer1k: number;
20
+ }>;
15
21
  /** Last updated date */
16
22
  updatedAt: string;
17
23
  }
@@ -62,6 +68,9 @@ export const BUNDLED_COST_TABLE: ModelCostEntry[] = [
62
68
  // GPT-5.5 API list price, also used for live Codex OAuth routing.
63
69
  // Source: https://openai.com/api/pricing/
64
70
  { id: "gpt-5.5", inputPer1k: 0.005, outputPer1k: 0.03, updatedAt: "2026-04-23" },
71
+ { id: "gpt-5.6-sol", inputPer1k: 0.005, outputPer1k: 0.03, tiers: [{ inputTokensAbove: 272000, inputPer1k: 0.01, outputPer1k: 0.045 }], updatedAt: "2026-07-11" },
72
+ { id: "gpt-5.6-terra", inputPer1k: 0.0025, outputPer1k: 0.015, tiers: [{ inputTokensAbove: 272000, inputPer1k: 0.005, outputPer1k: 0.0225 }], updatedAt: "2026-07-11" },
73
+ { id: "gpt-5.6-luna", inputPer1k: 0.001, outputPer1k: 0.006, tiers: [{ inputTokensAbove: 272000, inputPer1k: 0.002, outputPer1k: 0.009 }], updatedAt: "2026-07-11" },
65
74
 
66
75
  // Google
67
76
  { id: "gemini-2.0-flash", inputPer1k: 0.0001, outputPer1k: 0.0004, updatedAt: "2025-03-15" },
@@ -78,7 +87,11 @@ export const BUNDLED_COST_TABLE: ModelCostEntry[] = [
78
87
  export function lookupModelCost(modelId: string): ModelCostEntry | undefined {
79
88
  const bareId = modelId.includes("/") ? modelId.split("/").pop()! : modelId;
80
89
  return BUNDLED_COST_TABLE.find(e => e.id === bareId)
81
- ?? BUNDLED_COST_TABLE.find(e => bareId.includes(e.id) || e.id.includes(bareId));
90
+ ?? BUNDLED_COST_TABLE.find(e =>
91
+ bareId.startsWith(`${e.id}-`) ||
92
+ bareId.startsWith(`${e.id}:`) ||
93
+ bareId.startsWith(`${e.id}@`)
94
+ );
82
95
  }
83
96
 
84
97
  /**
@@ -111,10 +111,14 @@ export const MODEL_CAPABILITY_TIER: Record<string, ComplexityTier> = {
111
111
  "gpt-5.3-codex": "heavy",
112
112
  "gpt-5.4": "heavy",
113
113
  "gpt-5.5": "heavy",
114
+ "gpt-5.6-sol": "heavy",
115
+ "gpt-5.6-terra": "heavy",
116
+ "gpt-5.6-luna": "heavy",
114
117
  "o1": "heavy",
115
118
  "o3": "heavy",
116
119
  "o4-mini": "heavy",
117
120
  "o4-mini-deep-research": "heavy",
121
+ "grok-4.5": "heavy",
118
122
  };
119
123
 
120
124
  // ─── Cost Table (per 1K input tokens, approximate USD) ───────────────────────
@@ -149,11 +153,15 @@ const MODEL_COST_PER_1K_INPUT: Record<string, number> = {
149
153
  "gpt-5.3-codex-spark": 0.0003,
150
154
  "gpt-5.4": 0.005,
151
155
  "gpt-5.5": 0.005,
156
+ "gpt-5.6-sol": 0.005,
157
+ "gpt-5.6-terra": 0.0025,
158
+ "gpt-5.6-luna": 0.001,
152
159
  "o4-mini": 0.005,
153
160
  "o4-mini-deep-research": 0.005,
154
161
  "gemini-2.0-flash": 0.0001,
155
162
  "gemini-2.5-pro": 0.00125,
156
163
  "deepseek-chat": 0.00014,
164
+ "grok-4.5": 0.002,
157
165
  };
158
166
 
159
167
  // ─── Capability Profiles Data Table ──────────────────────────────────────────
@@ -198,6 +206,10 @@ export const MODEL_CAPABILITY_PROFILES: Record<string, ModelCapabilities> = {
198
206
  // OpenAI's 2026-04-23 published eval deltas across coding, tool use, and long context.
199
207
  // Source: https://openai.com/index/introducing-gpt-5-5/
200
208
  "gpt-5.5": { coding: 96, debugging: 93, research: 89, reasoning: 95, speed: 42, longContext: 90, instruction: 93 },
209
+ // GPT-5.6 profiles are provisional until official eval results are available.
210
+ "gpt-5.6-sol": { coding: 97, debugging: 94, research: 90, reasoning: 96, speed: 42, longContext: 91, instruction: 94 },
211
+ "gpt-5.6-terra": { coding: 96, debugging: 93, research: 89, reasoning: 95, speed: 48, longContext: 91, instruction: 93 },
212
+ "gpt-5.6-luna": { coding: 92, debugging: 88, research: 84, reasoning: 91, speed: 72, longContext: 91, instruction: 90 },
201
213
 
202
214
  // ── OpenAI o-series (reasoning-first) ──────────────────────────────────────
203
215
  "o1": { coding: 78, debugging: 82, research: 78, reasoning: 90, speed: 20, longContext: 65, instruction: 82 },
@@ -212,6 +224,11 @@ export const MODEL_CAPABILITY_PROFILES: Record<string, ModelCapabilities> = {
212
224
 
213
225
  // ── DeepSeek ───────────────────────────────────────────────────────────────
214
226
  "deepseek-chat": { coding: 75, debugging: 65, research: 55, reasoning: 70, speed: 70, longContext: 55, instruction: 65 },
227
+
228
+ // ── xAI ────────────────────────────────────────────────────────────────────
229
+ // Grok 4.5 (2026-07): Opus-class frontier model tuned for coding and agentic
230
+ // work; notably faster and more token-efficient than peer heavy models.
231
+ "grok-4.5": { coding: 95, debugging: 90, research: 82, reasoning: 93, speed: 55, longContext: 80, instruction: 90 },
215
232
  };
216
233
 
217
234
  // ─── Base Task Requirements Data Table ───────────────────────────────────────
@@ -136,6 +136,14 @@ function cachedReaddir(dirPath: string): string[] {
136
136
  return entries;
137
137
  }
138
138
 
139
+ function isExistingFile(path: string): boolean {
140
+ try {
141
+ return statSync(path).isFile();
142
+ } catch {
143
+ return false;
144
+ }
145
+ }
146
+
139
147
  /**
140
148
  * Clear the volatile directory listing caches.
141
149
  * Call after milestone transitions, file creation in planning directories,
@@ -223,6 +231,26 @@ export function buildTaskFileName(taskId: string, suffix: string): string {
223
231
  return `${taskId}-${suffix}.md`;
224
232
  }
225
233
 
234
+ /**
235
+ * Build a flat-phase task artifact file name.
236
+ * ("S06", "T03", "SUMMARY") → "S06-T03-SUMMARY.md"
237
+ */
238
+ export function buildFlatTaskFileName(sliceId: string, taskId: string, suffix: string): string {
239
+ return `${sliceId}-${taskId}-${suffix}.md`;
240
+ }
241
+
242
+ /**
243
+ * Extract the task ID from a task artifact filename.
244
+ * Supports flat-phase S##-T##-SUFFIX.md plus legacy T##-SUFFIX.md and
245
+ * T##-DESCRIPTOR-SUFFIX.md names.
246
+ */
247
+ export function taskIdFromTaskFileName(fileName: string, suffix: string): string | null {
248
+ const flat = new RegExp(`^S\\d+-(T\\d+)-${suffix}\\.md$`, "i").exec(fileName);
249
+ if (flat?.[1]) return flat[1].toUpperCase();
250
+ const legacy = new RegExp(`^(T\\d+)(?:-.*)?-${suffix}\\.md$`, "i").exec(fileName);
251
+ return legacy?.[1]?.toUpperCase() ?? null;
252
+ }
253
+
226
254
  // ─── Resolvers ─────────────────────────────────────────────────────────────
227
255
 
228
256
  /**
@@ -264,7 +292,7 @@ export function resolveFile(dir: string, idPrefix: string, suffix: string): stri
264
292
  if (!existsSync(dir)) return null;
265
293
  const target = `${idPrefix}-${suffix}.md`.toUpperCase();
266
294
  try {
267
- const entries = cachedReaddir(dir);
295
+ const entries = cachedReaddirWithTypes(dir).filter(e => e.isFile()).map(e => e.name);
268
296
  // Direct match: ID-SUFFIX.md
269
297
  const direct = entries.find(e => e.toUpperCase() === target);
270
298
  if (direct) return direct;
@@ -284,18 +312,17 @@ export function resolveFile(dir: string, idPrefix: string, suffix: string): stri
284
312
  }
285
313
 
286
314
  /**
287
- * Find all task files matching a pattern in a tasks directory.
288
- * Returns sorted file names matching T##-SUFFIX.md or legacy T##-*-SUFFIX.md
315
+ * Find all task files matching a pattern in a tasks directory or flat phase dir.
316
+ * Returns sorted file names matching S##-T##-SUFFIX.md, T##-SUFFIX.md,
317
+ * or legacy T##-*-SUFFIX.md.
289
318
  */
290
319
  export function resolveTaskFiles(tasksDir: string, suffix: string): string[] {
291
320
  if (!existsSync(tasksDir)) return [];
292
321
  try {
293
- // Current convention: T01-PLAN.md
294
- const currentPattern = new RegExp(`^T\\d+-${suffix}\\.md$`, "i");
295
- // Legacy convention: T01-INSTALL-PACKAGES-PLAN.md
296
- const legacyPattern = new RegExp(`^T\\d+-.*-${suffix}\\.md$`, "i");
297
- return cachedReaddir(tasksDir)
298
- .filter(f => currentPattern.test(f) || legacyPattern.test(f))
322
+ return cachedReaddirWithTypes(tasksDir)
323
+ .filter(e => e.isFile())
324
+ .map(e => e.name)
325
+ .filter(f => taskIdFromTaskFileName(f, suffix) !== null)
299
326
  .sort();
300
327
  } catch {
301
328
  return [];
@@ -843,7 +870,7 @@ export function resolveMilestoneFile(
843
870
  const prefix = `${String(phaseNum).padStart(2, "0")}`;
844
871
  const flatName = `${prefix}-${suffix}.md`;
845
872
  const flatPath = join(mDir, flatName);
846
- if (existsSync(flatPath)) return flatPath;
873
+ if (isExistingFile(flatPath)) return flatPath;
847
874
  // Legacy fallback: M001-SUFFIX.md
848
875
  const file = resolveFile(mDir, milestoneId, suffix);
849
876
  return file ? join(mDir, file) : null;
@@ -878,11 +905,11 @@ export function resolveSliceFile(
878
905
  const planNum = sliceIdToPlanNum(sliceId);
879
906
  const flatName = planFileName(phaseNum, planNum, suffix);
880
907
  const flatPath = join(phaseDir, flatName);
881
- if (existsSync(flatPath)) return flatPath;
908
+ if (isExistingFile(flatPath)) return flatPath;
882
909
  // Also check plan-number-only format MM-SUFFIX.md (written by buildSliceFileName)
883
910
  const planOnlyName = `${String(planNum).padStart(2, "0")}-${suffix}.md`;
884
911
  const planOnlyPath = join(phaseDir, planOnlyName);
885
- if (existsSync(planOnlyPath)) return planOnlyPath;
912
+ if (isExistingFile(planOnlyPath)) return planOnlyPath;
886
913
  // Try prefix match for the phase+plan number (handles suffix variations)
887
914
  const planPrefix = `${String(phaseNum).padStart(2, "0")}-${String(planNum).padStart(2, "0")}-`;
888
915
  try {
@@ -931,8 +958,10 @@ export function resolveTaskFile(
931
958
  const isLegacy = phaseDir.startsWith(legacyBase + "/") || phaseDir.startsWith(legacyBase + "\\");
932
959
 
933
960
  if (suffix !== "PLAN" && !isLegacy) {
934
- const flatPath = join(phaseDir, buildTaskFileName(taskId, suffix));
935
- return existsSync(flatPath) ? flatPath : null;
961
+ const flatPath = join(phaseDir, buildFlatTaskFileName(sliceId, taskId, suffix));
962
+ if (isExistingFile(flatPath)) return flatPath;
963
+ const legacyFlatPath = join(phaseDir, buildTaskFileName(taskId, suffix));
964
+ return isExistingFile(legacyFlatPath) ? legacyFlatPath : null;
936
965
  }
937
966
 
938
967
  const tDir = resolveTasksDir(basePath, milestoneId, sliceId);
@@ -1066,6 +1095,35 @@ export function targetSliceFile(
1066
1095
  return join(dir, fileName);
1067
1096
  }
1068
1097
 
1098
+ /**
1099
+ * Build the canonical absolute write target for a task file.
1100
+ * Readers that need legacy flat-phase fallback should call resolveTaskFile.
1101
+ */
1102
+ export function targetTaskFile(
1103
+ basePath: string, milestoneId: string, sliceId: string,
1104
+ taskId: string, suffix: string, milestoneTitle?: string
1105
+ ): string {
1106
+ if (suffix === "PLAN") {
1107
+ return targetSliceFile(basePath, milestoneId, sliceId, "PLAN", milestoneTitle);
1108
+ }
1109
+
1110
+ const mDir = resolveMilestonePath(basePath, milestoneId);
1111
+ const legacyBase = legacyMilestonesDir(basePath);
1112
+ const isLegacy = mDir
1113
+ ? mDir.startsWith(legacyBase + "/") || mDir.startsWith(legacyBase + "\\")
1114
+ : isLegacyMilestonesLayout(basePath);
1115
+ const milestoneDir = mDir
1116
+ ?? dirname(targetMilestoneFile(basePath, milestoneId, "ROADMAP", milestoneTitle));
1117
+
1118
+ if (isLegacy) {
1119
+ const slicesDir = join(milestoneDir, "slices");
1120
+ const sliceDir = join(slicesDir, resolveDir(slicesDir, sliceId) ?? sliceId);
1121
+ return join(sliceDir, "tasks", buildTaskFileName(taskId, suffix));
1122
+ }
1123
+
1124
+ return join(milestoneDir, buildFlatTaskFileName(sliceId, taskId, suffix));
1125
+ }
1126
+
1069
1127
  /**
1070
1128
  * Build relative .gsd/ path to a slice file.
1071
1129
  * Preserves an existing compatibility filename when present; otherwise falls
@@ -1105,5 +1163,5 @@ export function relTaskFile(
1105
1163
  return relSliceFile(basePath, milestoneId, sliceId, "PLAN");
1106
1164
  }
1107
1165
  const relS = relSlicePath(basePath, milestoneId, sliceId, milestoneTitle);
1108
- return `${relS}/${buildTaskFileName(taskId, suffix)}`;
1166
+ return `${relS}/${buildFlatTaskFileName(sliceId, taskId, suffix)}`;
1109
1167
  }
@@ -0,0 +1,58 @@
1
+ import { CONFIGURABLE_PLANNING_SUBAGENT_UNITS, type GSDPreferences } from "./preferences-types.js";
2
+ import { loadEffectiveGSDPreferences } from "./preferences.js";
3
+ import type { ToolsPolicy } from "./unit-context-manifest.js";
4
+
5
+ const CONFIGURABLE_UNITS = new Set<string>(CONFIGURABLE_PLANNING_SUBAGENT_UNITS);
6
+
7
+ function configuredAllowedSubagents(
8
+ unitType: string,
9
+ preferences: GSDPreferences | null | undefined,
10
+ ): readonly string[] {
11
+ if (!CONFIGURABLE_UNITS.has(unitType)) return [];
12
+ return preferences?.planning_subagents?.[
13
+ unitType as keyof NonNullable<GSDPreferences["planning_subagents"]>
14
+ ]?.allowed ?? [];
15
+ }
16
+
17
+ function mergeAllowedSubagents(
18
+ current: readonly string[],
19
+ configured: readonly string[],
20
+ ): readonly string[] {
21
+ return Array.from(new Set([...current, ...configured]));
22
+ }
23
+
24
+ export function applyPlanningSubagentPreferences(
25
+ unitType: string,
26
+ policy: ToolsPolicy | null | undefined,
27
+ preferences: GSDPreferences | null | undefined,
28
+ ): ToolsPolicy | null | undefined {
29
+ if (!policy) return policy;
30
+ const configured = configuredAllowedSubagents(unitType, preferences);
31
+ if (configured.length === 0) return policy;
32
+
33
+ if (policy.mode === "planning") {
34
+ return {
35
+ mode: "planning-dispatch",
36
+ allowedSubagents: mergeAllowedSubagents([], configured),
37
+ };
38
+ }
39
+
40
+ if (policy.mode === "planning-dispatch") {
41
+ return {
42
+ ...policy,
43
+ allowedSubagents: mergeAllowedSubagents(policy.allowedSubagents, configured),
44
+ };
45
+ }
46
+
47
+ return policy;
48
+ }
49
+
50
+ export function resolveEffectivePlanningToolsPolicy(
51
+ unitType: string,
52
+ policy: ToolsPolicy | null | undefined,
53
+ basePath?: string,
54
+ ): ToolsPolicy | null | undefined {
55
+ if (!basePath) return policy;
56
+ const preferences = loadEffectiveGSDPreferences(basePath)?.preferences;
57
+ return applyPlanningSubagentPreferences(unitType, policy, preferences);
58
+ }
@@ -0,0 +1,45 @@
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
+ import type { PlanningSubagentRegistryConfig } from "./preferences-types.js";
10
+
11
+ const PLANNING_DISPATCH_AGENT_REGISTRY = {
12
+ mnemo: { readOnlySpecialist: true },
13
+ scout: { readOnlySpecialist: true },
14
+ planner: { readOnlySpecialist: true },
15
+ reviewer: { readOnlySpecialist: true },
16
+ security: { readOnlySpecialist: true },
17
+ tester: { readOnlySpecialist: true },
18
+ } as const satisfies Record<string, { readonly readOnlySpecialist: boolean }>;
19
+
20
+ export const ALLOWED_PLANNING_DISPATCH_AGENTS = new Set<string>(
21
+ Object.entries(PLANNING_DISPATCH_AGENT_REGISTRY)
22
+ .filter(([, metadata]) => metadata.readOnlySpecialist)
23
+ .map(([agentId]) => agentId),
24
+ );
25
+
26
+ function configuredPlanningDispatchAgents(registry?: PlanningSubagentRegistryConfig): string[] {
27
+ return Object.entries(registry ?? {})
28
+ .filter(([, metadata]) => metadata.read_only_specialist === true)
29
+ .map(([agentId]) => agentId);
30
+ }
31
+
32
+ export function isReadOnlyPlanningDispatchAgent(
33
+ agentId: string,
34
+ registry?: PlanningSubagentRegistryConfig,
35
+ ): boolean {
36
+ const metadata = PLANNING_DISPATCH_AGENT_REGISTRY[agentId as keyof typeof PLANNING_DISPATCH_AGENT_REGISTRY];
37
+ return metadata?.readOnlySpecialist === true || registry?.[agentId]?.read_only_specialist === true;
38
+ }
39
+
40
+ export function allowedPlanningDispatchAgentsList(registry?: PlanningSubagentRegistryConfig): string {
41
+ return Array.from(new Set([
42
+ ...ALLOWED_PLANNING_DISPATCH_AGENTS,
43
+ ...configuredPlanningDispatchAgents(registry),
44
+ ])).join(", ");
45
+ }