@opengsd/gsd-pi 1.9.0 → 1.10.0

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 (300) hide show
  1. package/README.md +10 -10
  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-prompts.js +102 -21
  12. package/dist/resources/extensions/gsd/auto-recovery.js +10 -5
  13. package/dist/resources/extensions/gsd/auto-runtime-state.js +5 -5
  14. package/dist/resources/extensions/gsd/auto-start.js +29 -9
  15. package/dist/resources/extensions/gsd/auto-tool-tracking.js +40 -0
  16. package/dist/resources/extensions/gsd/auto-worktree-cleanup.js +4 -0
  17. package/dist/resources/extensions/gsd/auto-worktree-sync.js +7 -3
  18. package/dist/resources/extensions/gsd/auto-worktree-teardown.js +1 -1
  19. package/dist/resources/extensions/gsd/auto.js +15 -5
  20. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +2 -0
  21. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +33 -7
  22. package/dist/resources/extensions/gsd/bootstrap/system-context.js +10 -3
  23. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +4 -24
  24. package/dist/resources/extensions/gsd/commands-verdict.js +10 -9
  25. package/dist/resources/extensions/gsd/compat/compat-marker.js +80 -5
  26. package/dist/resources/extensions/gsd/constants.js +12 -13
  27. package/dist/resources/extensions/gsd/context-masker.js +97 -21
  28. package/dist/resources/extensions/gsd/db/engine.js +5 -2
  29. package/dist/resources/extensions/gsd/docs/preferences-reference.md +22 -0
  30. package/dist/resources/extensions/gsd/doctor-engine-checks.js +24 -8
  31. package/dist/resources/extensions/gsd/error-classifier.js +12 -2
  32. package/dist/resources/extensions/gsd/exec-sandbox.js +1 -0
  33. package/dist/resources/extensions/gsd/flat-phase-migration.js +12 -0
  34. package/dist/resources/extensions/gsd/git-service.js +19 -7
  35. package/dist/resources/extensions/gsd/gsd-db.js +75 -31
  36. package/dist/resources/extensions/gsd/guided-flow.js +11 -5
  37. package/dist/resources/extensions/gsd/markdown-renderer.js +5 -21
  38. package/dist/resources/extensions/gsd/md-importer.js +5 -6
  39. package/dist/resources/extensions/gsd/model-cost-table.js +2 -0
  40. package/dist/resources/extensions/gsd/model-router.js +11 -0
  41. package/dist/resources/extensions/gsd/paths.js +66 -15
  42. package/dist/resources/extensions/gsd/planning-subagent-policy.js +37 -0
  43. package/dist/resources/extensions/gsd/planning-subagent-registry.js +25 -0
  44. package/dist/resources/extensions/gsd/preferences-types.js +5 -0
  45. package/dist/resources/extensions/gsd/preferences-validation.js +48 -1
  46. package/dist/resources/extensions/gsd/preferences.js +17 -0
  47. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +5 -5
  48. package/dist/resources/extensions/gsd/provider-payload-policy.js +16 -5
  49. package/dist/resources/extensions/gsd/safety/destructive-guard.js +1 -1
  50. package/dist/resources/extensions/gsd/skill-activation.js +17 -3
  51. package/dist/resources/extensions/gsd/state-reconciliation/drift/external-markdown-edit.js +98 -2
  52. package/dist/resources/extensions/gsd/state-reconciliation/drift/external-planning-edit.js +4 -1
  53. package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +5 -2
  54. package/dist/resources/extensions/gsd/stop-notice.js +9 -0
  55. package/dist/resources/extensions/gsd/templates/PREFERENCES.md +5 -0
  56. package/dist/resources/extensions/gsd/tools/complete-task.js +12 -5
  57. package/dist/resources/extensions/gsd/tools/reopen-milestone.js +14 -5
  58. package/dist/resources/extensions/gsd/tools/reopen-slice.js +15 -5
  59. package/dist/resources/extensions/gsd/tools/reopen-task.js +16 -10
  60. package/dist/resources/extensions/gsd/unit-context-composer.js +28 -5
  61. package/dist/resources/extensions/gsd/workflow-projections.js +2 -3
  62. package/dist/resources/extensions/gsd/workspace.js +2 -1
  63. package/dist/resources/extensions/gsd/worktree-state-projection.js +20 -18
  64. package/dist/resources/extensions/shared/interview-ui.js +43 -6
  65. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  66. package/dist/web/standalone/.next/BUILD_ID +1 -1
  67. package/dist/web/standalone/.next/app-path-routes-manifest.json +8 -8
  68. package/dist/web/standalone/.next/build-manifest.json +2 -2
  69. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  70. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  77. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  78. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/index.html +1 -1
  86. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app-paths-manifest.json +8 -8
  93. package/dist/web/standalone/.next/server/chunks/1991.js +2 -2
  94. package/dist/web/standalone/.next/server/chunks/5124.js +1 -1
  95. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  96. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  97. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  98. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  99. package/dist/web/standalone/node_modules/@gsd/native/package.json +1 -1
  100. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  101. package/integrations/hermes/open_gsd_hermes/gsd_client.py +1 -1
  102. package/integrations/hermes/pyproject.toml +1 -1
  103. package/package.json +7 -6
  104. package/packages/cloud-mcp-gateway/package.json +2 -2
  105. package/packages/contracts/package.json +1 -1
  106. package/packages/daemon/package.json +4 -4
  107. package/packages/gsd-agent-core/dist/compaction/compaction.d.ts.map +1 -1
  108. package/packages/gsd-agent-core/dist/compaction/compaction.js +36 -4
  109. package/packages/gsd-agent-core/dist/compaction/compaction.js.map +1 -1
  110. package/packages/gsd-agent-core/dist/sdk.d.ts.map +1 -1
  111. package/packages/gsd-agent-core/dist/sdk.js +1 -0
  112. package/packages/gsd-agent-core/dist/sdk.js.map +1 -1
  113. package/packages/gsd-agent-core/package.json +5 -5
  114. package/packages/gsd-agent-modes/package.json +7 -7
  115. package/packages/gsd-cloud/README.md +9 -3
  116. package/packages/gsd-cloud/dist/background-cli.test.d.ts +2 -0
  117. package/packages/gsd-cloud/dist/background-cli.test.d.ts.map +1 -0
  118. package/packages/gsd-cloud/dist/background-cli.test.js +248 -0
  119. package/packages/gsd-cloud/dist/background-cli.test.js.map +1 -0
  120. package/packages/gsd-cloud/dist/cli.d.ts.map +1 -1
  121. package/packages/gsd-cloud/dist/cli.js +121 -15
  122. package/packages/gsd-cloud/dist/cli.js.map +1 -1
  123. package/packages/gsd-cloud/dist/cloud-config.d.ts +1 -1
  124. package/packages/gsd-cloud/dist/cloud-config.d.ts.map +1 -1
  125. package/packages/gsd-cloud/dist/cloud-config.js +7 -1
  126. package/packages/gsd-cloud/dist/cloud-config.js.map +1 -1
  127. package/packages/gsd-cloud/dist/cloud-runtime.d.ts +1 -3
  128. package/packages/gsd-cloud/dist/cloud-runtime.d.ts.map +1 -1
  129. package/packages/gsd-cloud/dist/cloud-runtime.js +9 -7
  130. package/packages/gsd-cloud/dist/cloud-runtime.js.map +1 -1
  131. package/packages/gsd-cloud/dist/runtime-process.d.ts +27 -0
  132. package/packages/gsd-cloud/dist/runtime-process.d.ts.map +1 -0
  133. package/packages/gsd-cloud/dist/runtime-process.js +272 -0
  134. package/packages/gsd-cloud/dist/runtime-process.js.map +1 -0
  135. package/packages/gsd-cloud/dist/runtime-process.test.d.ts +2 -0
  136. package/packages/gsd-cloud/dist/runtime-process.test.d.ts.map +1 -0
  137. package/packages/gsd-cloud/dist/runtime-process.test.js +97 -0
  138. package/packages/gsd-cloud/dist/runtime-process.test.js.map +1 -0
  139. package/packages/gsd-cloud/package.json +2 -2
  140. package/packages/mcp-server/README.md +7 -2
  141. package/packages/mcp-server/dist/cli-runner.d.ts +3 -0
  142. package/packages/mcp-server/dist/cli-runner.d.ts.map +1 -1
  143. package/packages/mcp-server/dist/cli-runner.js +119 -33
  144. package/packages/mcp-server/dist/cli-runner.js.map +1 -1
  145. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  146. package/packages/mcp-server/dist/server.js +5 -5
  147. package/packages/mcp-server/dist/server.js.map +1 -1
  148. package/packages/mcp-server/dist/workflow-tools.d.ts +4 -3
  149. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  150. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  151. package/packages/mcp-server/package.json +4 -4
  152. package/packages/native/package.json +1 -1
  153. package/packages/pi-agent-core/dist/agent.d.ts +5 -1
  154. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  155. package/packages/pi-agent-core/dist/agent.js +2 -0
  156. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  157. package/packages/pi-agent-core/package.json +1 -1
  158. package/packages/pi-ai/dist/models.generated.d.ts +76 -0
  159. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  160. package/packages/pi-ai/dist/models.generated.js +70 -0
  161. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  162. package/packages/pi-ai/dist/providers/anthropic.js +6 -1
  163. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  164. package/packages/pi-ai/dist/providers/openai-codex-responses.js +1 -1
  165. package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
  166. package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  167. package/packages/pi-ai/dist/providers/openai-completions.js +103 -0
  168. package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
  169. package/packages/pi-ai/dist/providers/openai-responses.js +1 -1
  170. package/packages/pi-ai/dist/providers/openai-responses.js.map +1 -1
  171. package/packages/pi-ai/package.json +1 -1
  172. package/packages/pi-coding-agent/dist/core/capability-patches.js +1 -1
  173. package/packages/pi-coding-agent/dist/core/capability-patches.js.map +1 -1
  174. package/packages/pi-coding-agent/dist/core/model-resolver.js +1 -1
  175. package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
  176. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +11 -1
  177. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  178. package/packages/pi-coding-agent/dist/core/settings-manager.js +8 -0
  179. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  180. package/packages/pi-coding-agent/dist/core/skills.d.ts +5 -0
  181. package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
  182. package/packages/pi-coding-agent/dist/core/skills.js +54 -0
  183. package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
  184. package/packages/pi-coding-agent/package.json +7 -7
  185. package/packages/pi-tui/package.json +2 -2
  186. package/packages/rpc-client/package.json +2 -2
  187. package/pkg/package.json +1 -1
  188. package/src/resources/GSD-WORKFLOW.md +2 -2
  189. package/src/resources/extensions/gsd/artifact-verification.ts +3 -8
  190. package/src/resources/extensions/gsd/auto/loop.ts +48 -4
  191. package/src/resources/extensions/gsd/auto/run-unit.ts +20 -1
  192. package/src/resources/extensions/gsd/auto/unit-phase.ts +41 -5
  193. package/src/resources/extensions/gsd/auto-artifact-paths.ts +14 -7
  194. package/src/resources/extensions/gsd/auto-dispatch.ts +1 -0
  195. package/src/resources/extensions/gsd/auto-prompts.ts +118 -19
  196. package/src/resources/extensions/gsd/auto-recovery.ts +10 -8
  197. package/src/resources/extensions/gsd/auto-runtime-state.ts +12 -7
  198. package/src/resources/extensions/gsd/auto-start.ts +31 -8
  199. package/src/resources/extensions/gsd/auto-tool-tracking.ts +56 -0
  200. package/src/resources/extensions/gsd/auto-worktree-cleanup.ts +4 -0
  201. package/src/resources/extensions/gsd/auto-worktree-sync.ts +10 -3
  202. package/src/resources/extensions/gsd/auto-worktree-teardown.ts +1 -1
  203. package/src/resources/extensions/gsd/auto.ts +20 -7
  204. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +1 -0
  205. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +41 -12
  206. package/src/resources/extensions/gsd/bootstrap/system-context.ts +11 -3
  207. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +7 -29
  208. package/src/resources/extensions/gsd/commands-verdict.ts +16 -9
  209. package/src/resources/extensions/gsd/compat/compat-marker.ts +99 -5
  210. package/src/resources/extensions/gsd/constants.ts +14 -13
  211. package/src/resources/extensions/gsd/context-masker.ts +98 -2
  212. package/src/resources/extensions/gsd/db/engine.ts +5 -2
  213. package/src/resources/extensions/gsd/docs/preferences-reference.md +22 -0
  214. package/src/resources/extensions/gsd/doctor-engine-checks.ts +30 -7
  215. package/src/resources/extensions/gsd/error-classifier.ts +13 -2
  216. package/src/resources/extensions/gsd/exec-sandbox.ts +1 -0
  217. package/src/resources/extensions/gsd/flat-phase-migration.ts +14 -0
  218. package/src/resources/extensions/gsd/git-service.ts +19 -6
  219. package/src/resources/extensions/gsd/gsd-db.ts +85 -33
  220. package/src/resources/extensions/gsd/guided-flow.ts +11 -4
  221. package/src/resources/extensions/gsd/markdown-renderer.ts +5 -23
  222. package/src/resources/extensions/gsd/md-importer.ts +5 -5
  223. package/src/resources/extensions/gsd/model-cost-table.ts +2 -0
  224. package/src/resources/extensions/gsd/model-router.ts +12 -0
  225. package/src/resources/extensions/gsd/paths.ts +73 -15
  226. package/src/resources/extensions/gsd/planning-subagent-policy.ts +58 -0
  227. package/src/resources/extensions/gsd/planning-subagent-registry.ts +31 -0
  228. package/src/resources/extensions/gsd/preferences-types.ts +16 -0
  229. package/src/resources/extensions/gsd/preferences-validation.ts +62 -0
  230. package/src/resources/extensions/gsd/preferences.ts +25 -0
  231. package/src/resources/extensions/gsd/prompts/validate-milestone.md +5 -5
  232. package/src/resources/extensions/gsd/provider-payload-policy.ts +18 -4
  233. package/src/resources/extensions/gsd/safety/destructive-guard.ts +1 -1
  234. package/src/resources/extensions/gsd/skill-activation.ts +17 -3
  235. package/src/resources/extensions/gsd/state-reconciliation/drift/external-markdown-edit.ts +132 -2
  236. package/src/resources/extensions/gsd/state-reconciliation/drift/external-planning-edit.ts +4 -1
  237. package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +4 -2
  238. package/src/resources/extensions/gsd/stop-notice.ts +11 -0
  239. package/src/resources/extensions/gsd/templates/PREFERENCES.md +5 -0
  240. package/src/resources/extensions/gsd/tests/auto-artifact-paths.test.ts +7 -7
  241. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +264 -0
  242. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +39 -0
  243. package/src/resources/extensions/gsd/tests/auto-start-index-lock.test.ts +21 -1
  244. package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +74 -1
  245. package/src/resources/extensions/gsd/tests/before-provider-context-management.test.ts +55 -0
  246. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +10 -0
  247. package/src/resources/extensions/gsd/tests/compat-marker.test.ts +25 -0
  248. package/src/resources/extensions/gsd/tests/complete-task.test.ts +76 -1
  249. package/src/resources/extensions/gsd/tests/context-masker.test.ts +204 -8
  250. package/src/resources/extensions/gsd/tests/db-engine-cjs-compat.test.ts +12 -0
  251. package/src/resources/extensions/gsd/tests/db-tools-alias-suppression.test.ts +62 -0
  252. package/src/resources/extensions/gsd/tests/destructive-confirmation.test.ts +33 -0
  253. package/src/resources/extensions/gsd/tests/destructive-guard.test.ts +14 -0
  254. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +83 -0
  255. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +33 -1
  256. package/src/resources/extensions/gsd/tests/external-markdown-edit.test.ts +38 -1
  257. package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +8 -9
  258. package/src/resources/extensions/gsd/tests/flat-phase-validation-path.test.ts +20 -1
  259. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +32 -0
  260. package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +22 -0
  261. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +13 -0
  262. package/src/resources/extensions/gsd/tests/integration/paths.test.ts +22 -4
  263. package/src/resources/extensions/gsd/tests/integration-branch-meta-location.test.ts +62 -0
  264. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +5 -5
  265. package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
  266. package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
  267. package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +7 -5
  268. package/src/resources/extensions/gsd/tests/preferences.test.ts +84 -0
  269. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +4 -0
  270. package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +87 -0
  271. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +121 -1
  272. package/src/resources/extensions/gsd/tests/reactive-executor.test.ts +39 -0
  273. package/src/resources/extensions/gsd/tests/register-hooks-loop-guard-auto.test.ts +105 -0
  274. package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
  275. package/src/resources/extensions/gsd/tests/single-writer-v3-tool-surface.test.ts +33 -7
  276. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +20 -16
  277. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +52 -0
  278. package/src/resources/extensions/gsd/tests/stop-notice.test.ts +21 -1
  279. package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +13 -7
  280. package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +14 -0
  281. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +19 -0
  282. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -0
  283. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +39 -0
  284. package/src/resources/extensions/gsd/tests/validate-milestone-prompt-verification-classes.test.ts +7 -0
  285. package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +4 -4
  286. package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +2 -2
  287. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +60 -0
  288. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +34 -0
  289. package/src/resources/extensions/gsd/tools/complete-task.ts +20 -5
  290. package/src/resources/extensions/gsd/tools/reopen-milestone.ts +24 -5
  291. package/src/resources/extensions/gsd/tools/reopen-slice.ts +25 -5
  292. package/src/resources/extensions/gsd/tools/reopen-task.ts +23 -9
  293. package/src/resources/extensions/gsd/unit-context-composer.ts +34 -8
  294. package/src/resources/extensions/gsd/workflow-projections.ts +2 -3
  295. package/src/resources/extensions/gsd/workspace.ts +2 -1
  296. package/src/resources/extensions/gsd/worktree-state-projection.ts +21 -24
  297. package/src/resources/extensions/shared/interview-ui.ts +47 -8
  298. package/src/resources/extensions/shared/tests/interview-ui-border.test.ts +29 -0
  299. /package/dist/web/standalone/.next/static/{BE5XoklToI6lZjRzpXih8 → EAhnhYMt5UVOiG9-iPDjc}/_buildManifest.js +0 -0
  300. /package/dist/web/standalone/.next/static/{BE5XoklToI6lZjRzpXih8 → EAhnhYMt5UVOiG9-iPDjc}/_ssgManifest.js +0 -0
@@ -46,9 +46,10 @@ import { classifyMilestoneSummaryContent } from "./milestone-summary-classifier.
46
46
  import { extractVerdict } from "./verdict-parser.js";
47
47
  import { auditOrphanedPreflightStashes } from "./orphan-stash-audit.js";
48
48
  import { parseProject } from "./schemas/parsers.js";
49
+ import { LAYOUT_SEGMENTS } from "./layout-policy.js";
49
50
  import { debugLog, enableDebug, isDebugEnabled, getDebugLogPath, } from "./debug-logger.js";
50
51
  import { logWarning, logError } from "./workflow-logger.js";
51
- import { existsSync, mkdirSync, readFileSync, rmSync, } from "node:fs";
52
+ import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, } from "node:fs";
52
53
  import { join } from "node:path";
53
54
  import { validateDirectory } from "./validate-directory.js";
54
55
  import { isCustomProvider, resolveDefaultSessionModel, resolveDynamicRoutingConfig, } from "./preferences-models.js";
@@ -73,6 +74,30 @@ const MAX_CONSECUTIVE_COMPLETE_BOOTSTRAPS = 2;
73
74
  export function hasGitIndexLockForTest(basePath) {
74
75
  return existsSync(join(basePath, ".git", "index.lock"));
75
76
  }
77
+ function isEmptyDirectory(dirPath) {
78
+ try {
79
+ return existsSync(dirPath) && readdirSync(dirPath).length === 0;
80
+ }
81
+ catch {
82
+ return false;
83
+ }
84
+ }
85
+ export function reconcileFlatPhaseBootstrapLayout(basePath) {
86
+ const gsdDir = join(basePath, ".gsd");
87
+ const phasesPath = join(gsdDir, LAYOUT_SEGMENTS.level1);
88
+ const milestonesPath = join(gsdDir, "milestones");
89
+ if (isEmptyDirectory(milestonesPath)) {
90
+ if (!existsSync(phasesPath))
91
+ mkdirSync(phasesPath, { recursive: true });
92
+ rmSync(milestonesPath, { recursive: true, force: true });
93
+ return true;
94
+ }
95
+ if (!existsSync(phasesPath) && !existsSync(milestonesPath)) {
96
+ mkdirSync(phasesPath, { recursive: true });
97
+ return true;
98
+ }
99
+ return false;
100
+ }
76
101
  export function _shouldAbortBootstrapForUnavailableDbForTest(gsdDbPath, dbAvailable, pathExists = existsSync) {
77
102
  return pathExists(gsdDbPath) && !dbAvailable;
78
103
  }
@@ -868,20 +893,15 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
868
893
  ensureGitignore(base, { manageGitignore });
869
894
  if (manageGitignore !== false)
870
895
  untrackRuntimeFiles(base);
871
- // Bootstrap milestones/ if it doesn't exist.
872
- // Check milestones/ directly — ensureGsdSymlink above already created .gsd/,
873
- // so checking .gsd/ existence would be dead code (#2942).
874
- const gsdDir = join(base, ".gsd");
875
- const milestonesPath = join(gsdDir, "milestones");
876
- if (!existsSync(milestonesPath)) {
877
- mkdirSync(milestonesPath, { recursive: true });
896
+ // Bootstrap the flat-phase projection root and clean empty legacy scaffolds.
897
+ if (reconcileFlatPhaseBootstrapLayout(base)) {
878
898
  try {
879
899
  nativeAddAll(base);
880
900
  nativeCommit(base, "chore: init gsd");
881
901
  }
882
902
  catch (err) {
883
903
  /* nothing to commit */
884
- logWarning("engine", `mkdir failed: ${err instanceof Error ? err.message : String(err)}`);
904
+ logWarning("engine", `layout bootstrap commit failed: ${err instanceof Error ? err.message : String(err)}`);
885
905
  }
886
906
  }
887
907
  {
@@ -118,6 +118,8 @@ export function clearInFlightTools() {
118
118
  */
119
119
  const TOOL_INVOCATION_ERROR_RE = /Validation failed for tool|Input validation error|Invalid arguments for tool|MCP error -32602|No such tool available|Expected ',' or '\}'(?: after property value)?(?: in JSON)?|Unexpected end of JSON|Unexpected token.*in JSON|does not provide an export named|Named export .* not found|Cannot find module|ERR_MODULE_NOT_FOUND|ERR_MODULE_NOT_EXPORTED|ERR_PACKAGE_PATH_NOT_EXPORTED/i;
120
120
  const DETERMINISTIC_POLICY_ERROR_RE = /(?:^|\b)(?:HARD BLOCK:|Blocked: \/gsd queue is a planning tool|Direct writes to \.gsd\/STATE\.md and \.gsd\/gsd\.db are blocked|This is a mechanical gate)/i;
121
+ const SCHEDULE_WAKEUP_TOOL_NAME = "ScheduleWakeup";
122
+ const SCHEDULE_WAKEUP_CONTINUATION_ERROR = "`prompt` is required when `stop` is not true";
121
123
  /**
122
124
  * Matches the runtime's "tool not registered" error. Unlike the deterministic
123
125
  * invocation failures above, this one is usually transient: the workflow MCP
@@ -135,6 +137,44 @@ export function isToolInvocationError(errorMsg) {
135
137
  return false;
136
138
  return TOOL_INVOCATION_ERROR_RE.test(errorMsg) || isDeterministicPolicyError(errorMsg);
137
139
  }
140
+ /**
141
+ * Claude Code validates its native ScheduleWakeup tool outside GSD's schema.
142
+ * Keep this exact and tool-scoped so similarly worded business validation from
143
+ * unrelated tools does not pause auto-mode.
144
+ */
145
+ export function isScheduleWakeupContinuationError(toolName, errorMsg) {
146
+ return stripMcpToolPrefix(toolName) === SCHEDULE_WAKEUP_TOOL_NAME
147
+ && errorMsg.trim() === SCHEDULE_WAKEUP_CONTINUATION_ERROR;
148
+ }
149
+ function shouldRecordToolInvocationError(toolName, errorMsg) {
150
+ return isScheduleWakeupContinuationError(toolName, errorMsg)
151
+ || isToolInvocationError(errorMsg)
152
+ || isQueuedUserMessageSkip(errorMsg);
153
+ }
154
+ function isRecordedScheduleWakeupContinuationError(recordedError) {
155
+ if (!recordedError)
156
+ return false;
157
+ const separator = recordedError.indexOf(": ");
158
+ return separator >= 0 && isScheduleWakeupContinuationError(recordedError.slice(0, separator), recordedError.slice(separator + 2));
159
+ }
160
+ export function updateToolInvocationError(recordedError, toolName, errorMsg) {
161
+ if (!shouldRecordToolInvocationError(toolName, errorMsg))
162
+ return recordedError;
163
+ if (isRecordedScheduleWakeupContinuationError(recordedError)
164
+ && !isScheduleWakeupContinuationError(toolName, errorMsg))
165
+ return recordedError;
166
+ return `${toolName}: ${errorMsg}`;
167
+ }
168
+ /**
169
+ * A failed continuation must survive successful diagnostic/read calls in the
170
+ * same turn. Only a later successful ScheduleWakeup proves the continuation
171
+ * was armed; all other invocation errors retain their existing clear-on-success
172
+ * behavior.
173
+ */
174
+ export function shouldClearToolInvocationErrorAfterSuccess(recordedError, successfulToolName) {
175
+ return !isRecordedScheduleWakeupContinuationError(recordedError)
176
+ || stripMcpToolPrefix(successfulToolName ?? "") === SCHEDULE_WAKEUP_TOOL_NAME;
177
+ }
138
178
  /**
139
179
  * Returns true if the error message indicates the called tool was not on the
140
180
  * session's tool surface (MCP startup race — see TOOL_UNAVAILABLE_ERROR_RE).
@@ -8,6 +8,7 @@ import { execFileSync } from "node:child_process";
8
8
  import { existsSync, realpathSync, unlinkSync } from "node:fs";
9
9
  import { isAbsolute, join, relative } from "node:path";
10
10
  import { gsdRoot } from "./paths.js";
11
+ import { milestoneMetaPath } from "./git-service.js";
11
12
  import { logWarning } from "./workflow-logger.js";
12
13
  function isSamePath(a, b) {
13
14
  try {
@@ -73,6 +74,9 @@ export function clearProjectRootStateFiles(basePath, milestoneId) {
73
74
  // worth removing on teardown.
74
75
  const transientFiles = [
75
76
  join(gsdDir, "STATE.md"),
77
+ // Integration-branch META now lives flat at .gsd/<MID>-META.json (ADR-045).
78
+ milestoneMetaPath(basePath, milestoneId),
79
+ // Legacy location — still cleaned for pre-migration trees.
76
80
  join(gsdDir, "milestones", milestoneId, `${milestoneId}-META.json`),
77
81
  ];
78
82
  for (const file of transientFiles) {
@@ -5,7 +5,7 @@
5
5
  import { cpSync, existsSync, lstatSync as lstatSyncFn, mkdirSync, readdirSync, } from "node:fs";
6
6
  import { join } from "node:path";
7
7
  import { _isSamePath as isSamePath, } from "./auto-worktree-cleanup.js";
8
- import { resolveGsdPathContract } from "./paths.js";
8
+ import { dirIsContentBearingLegacyMilestone, resolveGsdPathContract } from "./paths.js";
9
9
  import { WorktreeStateProjection } from "./worktree-state-projection.js";
10
10
  import { logWarning } from "./workflow-logger.js";
11
11
  const PROJECT_PREFERENCES_FILE = "PREFERENCES.md";
@@ -143,10 +143,14 @@ function syncMilestoneLayout(mainGsd, wtGsd, layoutSegment, synced) {
143
143
  if (!existsSync(mainMilestonesDir))
144
144
  return;
145
145
  try {
146
- mkdirSync(wtMilestonesDir, { recursive: true });
147
146
  const mainMilestones = readdirSync(mainMilestonesDir, { withFileTypes: true })
148
147
  .filter((entry) => entry.isDirectory())
149
- .map((entry) => entry.name);
148
+ .map((entry) => entry.name)
149
+ .filter((name) => layoutSegment !== "milestones" ||
150
+ dirIsContentBearingLegacyMilestone(join(mainMilestonesDir, name)));
151
+ if (mainMilestones.length === 0)
152
+ return;
153
+ mkdirSync(wtMilestonesDir, { recursive: true });
150
154
  for (const milestoneId of mainMilestones) {
151
155
  syncMilestoneDirectory(mainMilestonesDir, wtMilestonesDir, milestoneId, synced);
152
156
  }
@@ -45,7 +45,7 @@ export function teardownAutoWorktree(originalBasePath, milestoneId, opts = {}) {
45
45
  throw new GSDError(GSD_IO_ERROR, `Failed to chdir back to ${originalBasePath} during teardown: ${err instanceof Error ? err.message : String(err)}`);
46
46
  }
47
47
  // Mirror cleanup steps from mergeMilestoneToMain abort path:
48
- // 1. Remove transient state files (STATE.md, auto.lock, {MID}-META.json).
48
+ // 1. Remove transient state files (STATE.md, auto.lock, .gsd/{MID}-META.json).
49
49
  // Non-fatal — must not block teardown.
50
50
  try {
51
51
  clearProjectRootStateFiles(originalBasePath, milestoneId);
@@ -28,7 +28,7 @@ import { acquireSessionLock, getSessionLockStatus, releaseSessionLock, updateSes
28
28
  import { resolveAutoSupervisorConfig, loadEffectiveGSDPreferences, loadEffectiveGSDPreferencesWithRegistry, resolveProfileAnchorProvider, getIsolationMode, resolveEffectiveUnitIsolationMode, } from "./preferences.js";
29
29
  import { playNotificationBell, sendDesktopNotification } from "./notifications.js";
30
30
  import { getBudgetAlertLevel, getNewBudgetAlertLevel, getBudgetEnforcementAction, HARD_CONTEXT_REROOT_THRESHOLD_PERCENT, resolveCompactionThresholdPercent, shouldRerootStepSessionForContext, shouldWarnStepSessionForContext, } from "./auto-budget.js";
31
- import { markToolStart as _markToolStart, markToolEnd as _markToolEnd, getOldestInFlightToolAgeMs as _getOldestInFlightToolAgeMs, clearInFlightTools, isToolInvocationError, isQueuedUserMessageSkip, isDeterministicPolicyError, } from "./auto-tool-tracking.js";
31
+ import { markToolStart as _markToolStart, markToolEnd as _markToolEnd, getOldestInFlightToolAgeMs as _getOldestInFlightToolAgeMs, clearInFlightTools, updateToolInvocationError, } from "./auto-tool-tracking.js";
32
32
  import { closeoutUnit } from "./auto-unit-closeout.js";
33
33
  import { selectAndApplyModel, resolveModelId, clearToolBaseline, isModelUnavailable, applyThinkingLevelForModel } from "./auto-model-selection.js";
34
34
  import { resolveModelWithFallbacksForUnit } from "./preferences-models.js";
@@ -617,15 +617,14 @@ export function markToolEnd(toolCallId) {
617
617
  * Called from tool_execution_end when a GSD tool fails with isError.
618
618
  * Stores the error if it matches:
619
619
  * - tool-invocation-error pattern (malformed/truncated JSON)
620
+ * - failed ScheduleWakeup continuation validation (#1379)
620
621
  * - queued-user-message skip pattern
621
622
  * - deterministic policy rejection (#4973, e.g. context_write_blocked)
622
623
  */
623
624
  export function recordToolInvocationError(toolName, errorMsg) {
624
625
  if (!s.active)
625
626
  return;
626
- if (isToolInvocationError(errorMsg) || isQueuedUserMessageSkip(errorMsg) || isDeterministicPolicyError(errorMsg)) {
627
- s.lastToolInvocationError = `${toolName}: ${errorMsg}`;
628
- }
627
+ s.lastToolInvocationError = updateToolInvocationError(s.lastToolInvocationError, toolName, errorMsg);
629
628
  }
630
629
  export function getOldestInFlightToolAgeMs() {
631
630
  return _getOldestInFlightToolAgeMs();
@@ -2441,7 +2440,18 @@ export async function dispatchHookUnit(ctx, pi, hookName, triggerUnitType, trigg
2441
2440
  startedAt: hookStartedAt,
2442
2441
  workspaceRoot: s.basePath,
2443
2442
  });
2444
- const result = await s.cmdCtx.newSession({ workspaceRoot: s.basePath });
2443
+ const cmdCtx = s.cmdCtx;
2444
+ if (typeof cmdCtx?.newSession !== "function") {
2445
+ const message = "Auto-mode has no command context for dispatch.";
2446
+ ctx.ui.notify(message, "error");
2447
+ const unitToCommit = previousCurrentUnit ?? s.currentUnit;
2448
+ if (unitToCommit) {
2449
+ await autoCommitUnit(s.basePath, unitToCommit.type, unitToCommit.id, ctx);
2450
+ }
2451
+ await stopAuto(ctx, pi, message, { preserveWorktree: true });
2452
+ return false;
2453
+ }
2454
+ const result = await cmdCtx.newSession({ workspaceRoot: s.basePath });
2445
2455
  if (result.cancelled) {
2446
2456
  await stopAuto(ctx, pi);
2447
2457
  return false;
@@ -46,6 +46,8 @@ function registerAlias(pi, toolDef, aliasName, canonicalName) {
46
46
  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- toolDef shape matches ToolDefinition but varies by schema
47
47
  function registerWorkflowTool(pi, toolDef) {
48
48
  pi.registerTool(toolDef);
49
+ if (process.env.GSD_ADVERTISE_TOOL_ALIASES !== "1")
50
+ return; // canonical-only model surface (see plan 035)
49
51
  for (const alias of aliasesForWorkflowTool(toolDef.name)) {
50
52
  registerAlias(pi, toolDef, alias, toolDef.name);
51
53
  }
@@ -22,13 +22,14 @@ import { saveActivityLog } from "../activity-log.js";
22
22
  import { recordToolCall as safetyRecordToolCall, recordToolResult as safetyRecordToolResult, saveEvidenceToDisk } from "../safety/evidence-collector.js";
23
23
  import { parseUnitId } from "../unit-id.js";
24
24
  import { classifyCommand } from "../safety/destructive-guard.js";
25
- import { confirmDestructiveCommand, consumeDestructiveConfirmation, isDestructiveConfirmGateId, requestDestructiveConfirmation, } from "../safety/destructive-confirmation.js";
25
+ import { confirmDestructiveCommand, consumeDestructiveConfirmation, isDestructiveConfirmGateId, peekPendingDestructiveCommand, requestDestructiveConfirmation, resetDestructiveConfirmation, } from "../safety/destructive-confirmation.js";
26
26
  import { logWarning as safetyLogWarning, setStderrLoggingEnabled } from "../workflow-logger.js";
27
27
  import { isUnitCloseoutTool, runInteractiveUnitCloseout } from "../unit-closeout.js";
28
28
  import { installNotifyInterceptor } from "./notify-interceptor.js";
29
29
  import { initNotificationStore } from "../notification-store.js";
30
30
  import { initNotificationWidget } from "../notification-widget.js";
31
31
  import { notifyPreferenceDiagnostics } from "../preferences-diagnostics.js";
32
+ import { resolveEffectivePlanningToolsPolicy } from "../planning-subagent-policy.js";
32
33
  import { resolveWorktreeProjectRoot } from "../worktree-root.js";
33
34
  import { extractSubagentAgentClasses } from "./subagent-input.js";
34
35
  import { approvalGateIdForUnit, evaluateAskUserQuestionsRound, formatUnansweredConsentQuestionMessage, isExplicitApprovalResponse, messageHasPendingAskUserQuestionsTool, shouldPauseForQuestion, } from "../consent-question.js";
@@ -136,6 +137,7 @@ function suppressWelcomeHeader(ctx) {
136
137
  * are bounded — cleared on activation, session boundaries, and verification.
137
138
  */
138
139
  const deferredApprovalGates = new Map();
140
+ const deferredDestructiveConfirmationPauses = new Set();
139
141
  export const MINIMAL_GSD_TOOL_NAMES = [
140
142
  "gsd_exec",
141
143
  "gsd_exec_search",
@@ -456,6 +458,21 @@ function clearDeferredApprovalGate(basePath) {
456
458
  deferredApprovalGates.delete(basePath);
457
459
  }
458
460
  }
461
+ function deferDestructiveConfirmationPause(basePath) {
462
+ deferredDestructiveConfirmationPauses.add(basePath);
463
+ }
464
+ function clearDeferredDestructiveConfirmationPause(basePath) {
465
+ if (!basePath) {
466
+ deferredDestructiveConfirmationPauses.clear();
467
+ }
468
+ else {
469
+ deferredDestructiveConfirmationPauses.delete(basePath);
470
+ }
471
+ }
472
+ function isDestructiveConfirmationBlocking(basePath) {
473
+ return deferredDestructiveConfirmationPauses.has(basePath)
474
+ && Boolean(peekPendingDestructiveCommand(basePath));
475
+ }
459
476
  function deferApprovalGate(gateId, basePath) {
460
477
  // Verified-on-disk wins (same adapter policy as activation/re-arm): if the
461
478
  // workflow MCP child already verified this gate, deferring would block
@@ -798,6 +815,7 @@ export function registerHooks(pi, ecosystemHandlers) {
798
815
  await applyToolCallLoopGuardConfig(basePath);
799
816
  approvalQuestionAbortInFlight = false;
800
817
  clearDeferredApprovalGate();
818
+ clearDeferredDestructiveConfirmationPause();
801
819
  await resetAskUserQuestionsTurnCache();
802
820
  await syncServiceTierStatus(ctx);
803
821
  await applyDisabledModelProviderPolicy(ctx);
@@ -883,6 +901,7 @@ export function registerHooks(pi, ecosystemHandlers) {
883
901
  resetToolCallLoopGuard();
884
902
  await applyToolCallLoopGuardConfig(basePath);
885
903
  clearDeferredApprovalGate();
904
+ clearDeferredDestructiveConfirmationPause();
886
905
  await resetAskUserQuestionsTurnCache();
887
906
  clearDiscussionFlowState(basePath);
888
907
  // /clear or /new destroys the conversation holding a discuss interview, so
@@ -933,6 +952,7 @@ export function registerHooks(pi, ecosystemHandlers) {
933
952
  }
934
953
  }
935
954
  clearDeferredApprovalGate(beforeAgentBasePath);
955
+ clearDeferredDestructiveConfirmationPause(beforeAgentBasePath);
936
956
  // session_start can fire before the active provider has settled. By
937
957
  // before_agent_start, Claude Code CLI sessions should get the same
938
958
  // project MCP config that /gsd mcp init would write.
@@ -1010,7 +1030,10 @@ export function registerHooks(pi, ecosystemHandlers) {
1010
1030
  }
1011
1031
  finally {
1012
1032
  activateDeferredApprovalGate(agentEndBasePath);
1033
+ const destructiveConfirmationBlocking = isDestructiveConfirmationBlocking(agentEndBasePath);
1034
+ clearDeferredDestructiveConfirmationPause(agentEndBasePath);
1013
1035
  await maybePauseAutoForApprovalGate(ctx, pi, isApprovalGateBlocking(agentEndBasePath), "Depth confirmation is waiting for your answer — pausing auto-mode.");
1036
+ await maybePauseAutoForApprovalGate(ctx, pi, destructiveConfirmationBlocking, "Destructive-command confirmation is waiting for your answer — pausing auto-mode.");
1014
1037
  }
1015
1038
  });
1016
1039
  pi.on("message_end", async (event) => {
@@ -1276,6 +1299,7 @@ export function registerHooks(pi, ecosystemHandlers) {
1276
1299
  const activeUnitType = dash.currentUnit?.type ?? guidedUnit?.unitType;
1277
1300
  if (activeUnitType) {
1278
1301
  const manifest = resolveManifest(activeUnitType);
1302
+ const planningBasePath = dash.basePath || guidedUnit?.basePath || discussionBasePath;
1279
1303
  let planningInput = "";
1280
1304
  let agentClasses;
1281
1305
  if (isToolCallEventType("write", event)) {
@@ -1291,7 +1315,7 @@ export function registerHooks(pi, ecosystemHandlers) {
1291
1315
  // Subagent inputs use { agent }, { tasks: [{ agent }] }, or { chain: [{ agent }] }.
1292
1316
  agentClasses = extractSubagentAgentClasses(event.input);
1293
1317
  }
1294
- const planningGuard = shouldBlockPlanningUnit(event.toolName, planningInput, dash.basePath || guidedUnit?.basePath || discussionBasePath, activeUnitType, manifest?.tools, agentClasses, event.input, dash.currentUnit?.id);
1318
+ const planningGuard = shouldBlockPlanningUnit(event.toolName, planningInput, planningBasePath, activeUnitType, resolveEffectivePlanningToolsPolicy(activeUnitType, manifest?.tools, planningBasePath), agentClasses, event.input, dash.currentUnit?.id);
1295
1319
  if (planningGuard.block)
1296
1320
  return planningGuard;
1297
1321
  }
@@ -1373,6 +1397,7 @@ export function registerHooks(pi, ecosystemHandlers) {
1373
1397
  // Record the command as pending so an affirmative answer to a
1374
1398
  // destructive_confirm gate (handled in tool_result) can confirm it.
1375
1399
  requestDestructiveConfirmation(command, guardBasePath);
1400
+ deferDestructiveConfirmationPause(guardBasePath);
1376
1401
  const reason = [
1377
1402
  "HARD BLOCK: destructive Bash command requires explicit human confirmation.",
1378
1403
  `Detected: ${classification.labels.join(", ")}`,
@@ -1383,9 +1408,6 @@ export function registerHooks(pi, ecosystemHandlers) {
1383
1408
  safetyLogWarning("safety", `destructive command: ${classification.labels.join(", ")}`, {
1384
1409
  command: String(command).slice(0, 200),
1385
1410
  });
1386
- if (ctx) {
1387
- await maybePauseAutoForApprovalGate(ctx, pi, isAutoActive(), "Destructive-command confirmation is waiting for your answer — pausing auto-mode.");
1388
- }
1389
1411
  return { block: true, reason };
1390
1412
  }
1391
1413
  }
@@ -1426,7 +1448,7 @@ export function registerHooks(pi, ecosystemHandlers) {
1426
1448
  recordRetryableHarnessToolError(toolName, resultPayload, errorText);
1427
1449
  }
1428
1450
  else if (isAutoActive()) {
1429
- clearToolInvocationError();
1451
+ clearToolInvocationError(event.toolName);
1430
1452
  }
1431
1453
  // Interactive Closeout adapter (ADR-032): auto-mode owns closeout for its
1432
1454
  // own units; interactive completions get the durable git subset (commit +
@@ -1541,6 +1563,10 @@ export function registerHooks(pi, ecosystemHandlers) {
1541
1563
  if (isDepthConfirmationAnswer(answer?.selected, question.options)) {
1542
1564
  confirmDestructiveCommand(basePath);
1543
1565
  }
1566
+ else {
1567
+ resetDestructiveConfirmation(basePath);
1568
+ }
1569
+ clearDeferredDestructiveConfirmationPause(basePath);
1544
1570
  break;
1545
1571
  }
1546
1572
  }
@@ -1605,7 +1631,7 @@ export function registerHooks(pi, ecosystemHandlers) {
1605
1631
  recordRetryableHarnessToolError(toolName, event.result, errorText);
1606
1632
  }
1607
1633
  else if (isAutoActive()) {
1608
- clearToolInvocationError();
1634
+ clearToolInvocationError(event.toolName);
1609
1635
  }
1610
1636
  // Safety harness: record tool execution results for evidence cross-referencing
1611
1637
  if (isAutoActive()) {
@@ -18,6 +18,13 @@ import { formatOverridesSection, formatShortcut, loadActiveOverrides, loadFile,
18
18
  import { toPosixPath } from "../../shared/mod.js";
19
19
  import { autoEnableCmuxPreferences } from "../commands-cmux.js";
20
20
  import { gsdHome } from "../gsd-home.js";
21
+ import { GSD_CONTEXT_MESSAGE_SENTINEL } from "../constants.js";
22
+ // Single source of truth lives in ../constants.js; re-exported here because
23
+ // buildContextMessage() stamps this marker on every context injection and the
24
+ // provider payload policy (filterSupersededContextInjections in
25
+ // context-masker.ts) matches it to dedupe. Adding a new context customType?
26
+ // Ensure buildContextMessage still prepends this sentinel.
27
+ export { GSD_CONTEXT_MESSAGE_SENTINEL };
21
28
  const DEFAULT_CONTEXT_MESSAGE_MAX_CHARS = 4_000;
22
29
  const DEFAULT_KNOWLEDGE_MAX_CHARS = 12_000;
23
30
  const DEFAULT_CODEBASE_MAX_CHARS = 8_000;
@@ -385,17 +392,17 @@ export function buildContextMessage(opts) {
385
392
  const contextCharLimit = getContextMessageCharLimit();
386
393
  const memoryContent = markMemoryContextSupplied(opts.memoryBlock.trim());
387
394
  if (opts.injection) {
388
- const content = limitContextMessageContent(memoryContent ? `${memoryContent}\n\n${opts.injection}` : opts.injection, contextCharLimit);
395
+ const content = limitContextMessageContent(`${GSD_CONTEXT_MESSAGE_SENTINEL}\n${memoryContent ? `${memoryContent}\n\n${opts.injection}` : opts.injection}`, contextCharLimit);
389
396
  return { customType: "gsd-guided-context", content, display: false };
390
397
  }
391
398
  if (opts.forensicsInjection) {
392
- const content = limitContextMessageContent(memoryContent ? `${memoryContent}\n\n${opts.forensicsInjection}` : opts.forensicsInjection, contextCharLimit);
399
+ const content = limitContextMessageContent(`${GSD_CONTEXT_MESSAGE_SENTINEL}\n${memoryContent ? `${memoryContent}\n\n${opts.forensicsInjection}` : opts.forensicsInjection}`, contextCharLimit);
393
400
  return { customType: "gsd-forensics", content, display: false };
394
401
  }
395
402
  if (memoryContent) {
396
403
  return {
397
404
  customType: "gsd-memory",
398
- content: limitContextMessageContent(memoryContent, contextCharLimit),
405
+ content: limitContextMessageContent(`${GSD_CONTEXT_MESSAGE_SENTINEL}\n${memoryContent}`, contextCharLimit),
399
406
  display: false,
400
407
  };
401
408
  }
@@ -7,6 +7,7 @@ import { canonicalToolName } from "../engine-hook-contract.js";
7
7
  import { loadJsonFileOrNull } from "../json-persistence.js";
8
8
  import { getIsolationMode } from "../preferences.js";
9
9
  import { compileSubagentPermissionContract } from "../unit-context-manifest.js";
10
+ import { allowedPlanningDispatchAgentsList, isReadOnlyPlanningDispatchAgent, } from "../planning-subagent-registry.js";
10
11
  import { logWarning } from "../workflow-logger.js";
11
12
  import { acquireSyncLock, releaseSyncLock } from "../sync-lock.js";
12
13
  import { isGsdWorktreePath, resolveWorktreeProjectRoot } from "../worktree-root.js";
@@ -981,29 +982,8 @@ export function shouldBlockQueueExecutionInSnapshot(snapshot, toolName, input, q
981
982
  // guards.
982
983
  const PLANNING_WRITE_TOOLS = new Set(["write", "edit", "multi_edit", "notebook_edit"]);
983
984
  const PLANNING_SUBAGENT_TOOLS = new Set(["subagent", "task"]);
984
- /**
985
- * Canonical registry for agents that planning-dispatch may consider. Unit
986
- * manifests still declare per-unit subsets via ToolsPolicy.allowedSubagents.
987
- */
988
- const PLANNING_DISPATCH_AGENT_REGISTRY = {
989
- mnemo: { readOnlySpecialist: true },
990
- scout: { readOnlySpecialist: true },
991
- planner: { readOnlySpecialist: true },
992
- reviewer: { readOnlySpecialist: true },
993
- security: { readOnlySpecialist: true },
994
- tester: { readOnlySpecialist: true },
995
- };
996
- export const ALLOWED_PLANNING_DISPATCH_AGENTS = new Set(Object.entries(PLANNING_DISPATCH_AGENT_REGISTRY)
997
- .filter(([, metadata]) => metadata.readOnlySpecialist)
998
- .map(([agentId]) => agentId));
985
+ export { ALLOWED_PLANNING_DISPATCH_AGENTS } from "../planning-subagent-registry.js";
999
986
  let warnedMissingControlledDispatchAgentClasses = false;
1000
- function isReadOnlySpecialist(agentId) {
1001
- const metadata = PLANNING_DISPATCH_AGENT_REGISTRY[agentId];
1002
- return metadata?.readOnlySpecialist === true;
1003
- }
1004
- function allowedPlanningDispatchAgentsList() {
1005
- return [...ALLOWED_PLANNING_DISPATCH_AGENTS].join(", ");
1006
- }
1007
987
  function allowsControlledSubagentDispatch(policy) {
1008
988
  return ((policy.mode === "planning-dispatch" || policy.mode === "verification" || policy.mode === "workflow-only") &&
1009
989
  Array.isArray(policy.allowedSubagents));
@@ -1151,13 +1131,13 @@ export function shouldBlockPlanningUnit(toolName, pathOrCommand, basePath, unitT
1151
1131
  if (requested.length === 0) {
1152
1132
  return { block: false };
1153
1133
  }
1154
- const globallyDisallowed = requested.find(a => !isReadOnlySpecialist(a));
1134
+ const globallyDisallowed = requested.find(a => !isReadOnlyPlanningDispatchAgent(a));
1155
1135
  if (globallyDisallowed) {
1156
1136
  return planningBlock(unitType, policy.mode, `subagent dispatch of "${globallyDisallowed}" not permitted; only read-only specialists (${allowedPlanningDispatchAgentsList()}) may be dispatched from ${policy.mode} units`);
1157
1137
  }
1158
1138
  const disallowedByPolicy = requested.find(a => !allowed.has(a));
1159
1139
  if (disallowedByPolicy) {
1160
- return planningBlock(unitType, policy.mode, `subagent dispatch of "${disallowedByPolicy}" not permitted by ToolsPolicy.allowedSubagents; permitted agents for this unit: ${allowedSubagents.join(", ")}`);
1140
+ return planningBlock(unitType, policy.mode, `subagent dispatch of "${disallowedByPolicy}" not permitted by unit allowlist (ToolsPolicy.allowedSubagents/planning_subagents); permitted agents for this unit: ${allowedSubagents.join(", ")}`);
1161
1141
  }
1162
1142
  return { block: false };
1163
1143
  }
@@ -8,6 +8,7 @@ import { executeValidateMilestone } from "./tools/workflow-tool-executors.js";
8
8
  import { ensureDbOpen } from "./bootstrap/dynamic-tools.js";
9
9
  import { getLatestAssessmentByScope } from "./gsd-db.js";
10
10
  import { checkpointWorkflowDatabase } from "./db-workspace.js";
11
+ import { formatVerdictRecordedNotice, formatVerdictRejectedNotice } from "./stop-notice.js";
11
12
  import { VALIDATION_VERDICTS, extractVerdict, isValidMilestoneVerdict, } from "./verdict-parser.js";
12
13
  const USAGE = 'Usage: /gsd verdict <pass|needs-attention|needs-remediation> [--milestone Mxxx] [--rationale "..."]';
13
14
  function tokenize(raw) {
@@ -123,35 +124,35 @@ async function loadExistingValidation(basePath, milestoneId) {
123
124
  }
124
125
  export async function handleVerdict(rawArgs, ctx, basePath) {
125
126
  if (!rawArgs.trim()) {
126
- ctx.ui.notify(USAGE, "warning");
127
+ ctx.ui.notify(formatVerdictRejectedNotice(USAGE), "warning");
127
128
  return;
128
129
  }
129
130
  const parsed = parseArgs(rawArgs);
130
131
  if ("error" in parsed) {
131
- ctx.ui.notify(`${parsed.error}\n${USAGE}`, "warning");
132
+ ctx.ui.notify(formatVerdictRejectedNotice(`${parsed.error}\n${USAGE}`), "warning");
132
133
  return;
133
134
  }
134
135
  if (!parsed.verdict) {
135
- ctx.ui.notify(USAGE, "warning");
136
+ ctx.ui.notify(formatVerdictRejectedNotice(USAGE), "warning");
136
137
  return;
137
138
  }
138
139
  let milestoneId = parsed.milestoneId;
139
140
  if (!milestoneId) {
140
141
  const state = await deriveState(basePath);
141
142
  if (!state.activeMilestone) {
142
- ctx.ui.notify("No active milestone — pass --milestone Mxxx to target a specific milestone.", "warning");
143
+ ctx.ui.notify(formatVerdictRejectedNotice("No active milestone — pass --milestone Mxxx to target a specific milestone."), "warning");
143
144
  return;
144
145
  }
145
146
  milestoneId = state.activeMilestone.id;
146
147
  }
147
148
  const existingValidation = await loadExistingValidation(basePath, milestoneId);
148
149
  if (!existingValidation) {
149
- ctx.ui.notify(`No milestone validation found for ${milestoneId}. Run /gsd auto to validate first, then retry /gsd verdict.`, "warning");
150
+ ctx.ui.notify(formatVerdictRejectedNotice(`No milestone validation found for ${milestoneId}. Run /gsd auto to validate first, then retry /gsd verdict.`), "warning");
150
151
  return;
151
152
  }
152
153
  const current = parseValidationFile(existingValidation.content);
153
154
  if (parsed.verdict !== "pass" && !parsed.rationale) {
154
- ctx.ui.notify(`--rationale is required when overriding to ${parsed.verdict}.`, "warning");
155
+ ctx.ui.notify(formatVerdictRejectedNotice(`--rationale is required when overriding to ${parsed.verdict}.`), "warning");
155
156
  return;
156
157
  }
157
158
  const verdictRationale = parsed.rationale ?? "Manually overridden via /gsd verdict";
@@ -169,17 +170,17 @@ export async function handleVerdict(rawArgs, ctx, basePath) {
169
170
  }, basePath, parsed.verdict === "pass" ? { skipBrowserEvidenceGate: true } : undefined);
170
171
  if (result.isError) {
171
172
  const msg = result.content[0]?.type === "text" ? result.content[0].text : "Unknown error";
172
- ctx.ui.notify(msg, "error");
173
+ ctx.ui.notify(formatVerdictRejectedNotice(msg), "error");
173
174
  return;
174
175
  }
175
176
  checkpointWorkflowDatabase();
176
177
  const prevVerdict = current.verdict ?? "unknown";
177
178
  const effectiveVerdict = extractEffectiveVerdict(result.details, parsed.verdict);
178
179
  if (effectiveVerdict !== parsed.verdict) {
179
- ctx.ui.notify(`Milestone ${milestoneId} verdict requested: ${parsed.verdict}, effective: ${effectiveVerdict} (${existingValidation.source})`, "warning");
180
+ ctx.ui.notify(formatVerdictRecordedNotice(`Milestone ${milestoneId} verdict requested: ${parsed.verdict}, effective: ${effectiveVerdict} (${existingValidation.source})`), "warning");
180
181
  }
181
182
  else {
182
- ctx.ui.notify(`Milestone ${milestoneId} verdict: ${prevVerdict} -> ${effectiveVerdict} (${existingValidation.source})`, "success");
183
+ ctx.ui.notify(formatVerdictRecordedNotice(`Milestone ${milestoneId} verdict: ${prevVerdict} -> ${effectiveVerdict} (${existingValidation.source})`), "success");
183
184
  }
184
185
  if (effectiveVerdict === "needs-remediation") {
185
186
  ctx.ui.notify("Follow up with /gsd dispatch reassess to add remediation slices, then re-run /gsd auto.", "info");