@opengsd/gsd-core 1.11.0 → 1.13.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 (498) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.opencode/plugins/gsd-core.js +12 -0
  4. package/agents/gsd-code-fixer.md +1 -1
  5. package/agents/gsd-debug-session-manager.md +1 -1
  6. package/agents/gsd-debugger.md +1 -1
  7. package/agents/gsd-dom-verifier.md +169 -0
  8. package/agents/gsd-eval-auditor.md +1 -1
  9. package/agents/gsd-executor.md +78 -42
  10. package/agents/gsd-framework-selector.md +1 -3
  11. package/agents/gsd-intel-updater.md +1 -1
  12. package/agents/gsd-mempalace-curator.md +0 -1
  13. package/agents/gsd-pattern-mapper.md +11 -0
  14. package/agents/gsd-phase-researcher.md +3 -1
  15. package/agents/gsd-plan-checker.md +91 -112
  16. package/agents/gsd-planner.md +20 -4
  17. package/agents/gsd-project-researcher.md +1 -1
  18. package/agents/gsd-research-synthesizer.md +2 -2
  19. package/agents/gsd-roadmapper.md +15 -11
  20. package/agents/gsd-ui-checker.md +82 -7
  21. package/agents/gsd-ui-researcher.md +70 -3
  22. package/agents/gsd-verifier.md +24 -2
  23. package/bin/install.js +847 -200
  24. package/commands/gsd/discuss-phase.md +1 -1
  25. package/commands/gsd/execute-phase.md +1 -1
  26. package/commands/gsd/import.md +1 -1
  27. package/commands/gsd/ns-workflow.md +2 -1
  28. package/commands/gsd/phase.md +1 -1
  29. package/commands/gsd/quick-batch.md +105 -0
  30. package/commands/gsd/quick.md +8 -4
  31. package/commands/gsd/surface.md +18 -8
  32. package/gsd-core/bin/gsd-tools.cjs +761 -100
  33. package/gsd-core/bin/lib/active-workstream-store.cjs +8 -0
  34. package/gsd-core/bin/lib/adr-parser.cjs +13 -7
  35. package/gsd-core/bin/lib/agent-install-check.cjs +162 -0
  36. package/gsd-core/bin/lib/api-coverage.cjs +30 -9
  37. package/gsd-core/bin/lib/artifacts.cjs +2 -0
  38. package/gsd-core/bin/lib/assumption-delta.cjs +30 -11
  39. package/gsd-core/bin/lib/audit.cjs +163 -41
  40. package/gsd-core/bin/lib/broken-windows.cjs +306 -28
  41. package/gsd-core/bin/lib/capability-activation.cjs +27 -0
  42. package/gsd-core/bin/lib/capability-lock.cjs +10 -4
  43. package/gsd-core/bin/lib/capability-registry.cjs +785 -144
  44. package/gsd-core/bin/lib/capability-state.cjs +25 -4
  45. package/gsd-core/bin/lib/capability-validator.cjs +321 -18
  46. package/gsd-core/bin/lib/capability-writer.cjs +14 -4
  47. package/gsd-core/bin/lib/check-command-router.cjs +229 -6
  48. package/gsd-core/bin/lib/claude-orchestration.cjs +10 -25
  49. package/gsd-core/bin/lib/cli-exit.cjs +496 -10
  50. package/gsd-core/bin/lib/clusters.cjs +1 -0
  51. package/gsd-core/bin/lib/code-review-depth.cjs +288 -0
  52. package/gsd-core/bin/lib/codex-agent-toml.cjs +410 -4
  53. package/gsd-core/bin/lib/command-aliases.cjs +16 -0
  54. package/gsd-core/bin/lib/command-arg-projection.cjs +144 -14
  55. package/gsd-core/bin/lib/command-routing-hub.cjs +31 -2
  56. package/gsd-core/bin/lib/commands.cjs +877 -54
  57. package/gsd-core/bin/lib/complexity-trigger.cjs +26 -6
  58. package/gsd-core/bin/lib/config-loader.cjs +121 -29
  59. package/gsd-core/bin/lib/config.cjs +92 -2
  60. package/gsd-core/bin/lib/configuration.cjs +129 -37
  61. package/gsd-core/bin/lib/core-utils.cjs +118 -14
  62. package/gsd-core/bin/lib/decisions.cjs +213 -1
  63. package/gsd-core/bin/lib/edge-probe.cjs +23 -2
  64. package/gsd-core/bin/lib/estimate-cli.cjs +55 -11
  65. package/gsd-core/bin/lib/exit-code-registry.cjs +98 -0
  66. package/gsd-core/bin/lib/file-overlap-partitioner.cjs +74 -0
  67. package/gsd-core/bin/lib/frontmatter.cjs +975 -326
  68. package/gsd-core/bin/lib/gap-checker.cjs +41 -8
  69. package/gsd-core/bin/lib/git-base-branch.cjs +182 -39
  70. package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +7 -3
  71. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +8 -2
  72. package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +60 -14
  73. package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +75 -22
  74. package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +22 -8
  75. package/gsd-core/bin/lib/health-diagnostic.cjs +23 -3
  76. package/gsd-core/bin/lib/host-integration.cjs +96 -11
  77. package/gsd-core/bin/lib/init-command-router.cjs +132 -21
  78. package/gsd-core/bin/lib/init.cjs +252 -56
  79. package/gsd-core/bin/lib/install-engine.cjs +252 -15
  80. package/gsd-core/bin/lib/install-model-override-resolver.cjs +78 -1
  81. package/gsd-core/bin/lib/install-profiles.cjs +100 -18
  82. package/gsd-core/bin/lib/installer-migration-report.cjs +4 -0
  83. package/gsd-core/bin/lib/installer-migrations/010-antigravity-retire-confighome-artifacts.cjs +169 -0
  84. package/gsd-core/bin/lib/installer-migrations.cjs +10 -7
  85. package/gsd-core/bin/lib/intel.cjs +101 -26
  86. package/gsd-core/bin/lib/io.cjs +195 -15
  87. package/gsd-core/bin/lib/learnings.cjs +85 -14
  88. package/gsd-core/bin/lib/legacy-cleanup.cjs +8 -2
  89. package/gsd-core/bin/lib/loop-resolver.cjs +14 -8
  90. package/gsd-core/bin/lib/markdown-table.cjs +175 -4
  91. package/gsd-core/bin/lib/milestone.cjs +112 -7
  92. package/gsd-core/bin/lib/model-catalog.cjs +177 -19
  93. package/gsd-core/bin/lib/model-resolver.cjs +10 -28
  94. package/gsd-core/bin/lib/onboard-projection.cjs +5 -1
  95. package/gsd-core/bin/lib/phase-command-router.cjs +13 -6
  96. package/gsd-core/bin/lib/phase-estimation.cjs +17 -8
  97. package/gsd-core/bin/lib/phase-id.cjs +321 -13
  98. package/gsd-core/bin/lib/phase-lifecycle.cjs +24 -16
  99. package/gsd-core/bin/lib/phase-locator.cjs +138 -17
  100. package/gsd-core/bin/lib/phase.cjs +1175 -115
  101. package/gsd-core/bin/lib/plan-document.cjs +273 -0
  102. package/gsd-core/bin/lib/plan-scan.cjs +13 -2
  103. package/gsd-core/bin/lib/planning-command-router.cjs +61 -0
  104. package/gsd-core/bin/lib/planning-inspect.cjs +1168 -0
  105. package/gsd-core/bin/lib/planning-snapshot.cjs +165 -34
  106. package/gsd-core/bin/lib/planning-workspace.cjs +159 -28
  107. package/gsd-core/bin/lib/probe-core.cjs +4 -1
  108. package/gsd-core/bin/lib/profile-pipeline-command-router.cjs +50 -7
  109. package/gsd-core/bin/lib/profile-pipeline.cjs +6 -3
  110. package/gsd-core/bin/lib/quick-batch-command-router.cjs +285 -0
  111. package/gsd-core/bin/lib/quick-batch-dispatch.cjs +250 -0
  112. package/gsd-core/bin/lib/quick-batch.cjs +840 -0
  113. package/gsd-core/bin/lib/real-home-guard.cjs +419 -0
  114. package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +71 -45
  115. package/gsd-core/bin/lib/review-lane-descriptor.cjs +62 -14
  116. package/gsd-core/bin/lib/review-lane-invocation.cjs +73 -1
  117. package/gsd-core/bin/lib/review-lane-runner.cjs +136 -10
  118. package/gsd-core/bin/lib/roadmap-command-router.cjs +45 -31
  119. package/gsd-core/bin/lib/roadmap-parser.cjs +577 -41
  120. package/gsd-core/bin/lib/roadmap.cjs +248 -64
  121. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +329 -41
  122. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +16 -17
  123. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +320 -109
  124. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +487 -83
  125. package/gsd-core/bin/lib/runtime-identity.cjs +234 -0
  126. package/gsd-core/bin/lib/runtime-slash.cjs +72 -2
  127. package/gsd-core/bin/lib/shell-command-projection.cjs +75 -8
  128. package/gsd-core/bin/lib/smart-entry.cjs +19 -31
  129. package/gsd-core/bin/lib/spec-section.cjs +12 -7
  130. package/gsd-core/bin/lib/state-command-router.cjs +47 -18
  131. package/gsd-core/bin/lib/state-contract.cjs +359 -0
  132. package/gsd-core/bin/lib/state-document.cjs +216 -5
  133. package/gsd-core/bin/lib/state-md-schema.cjs +231 -0
  134. package/gsd-core/bin/lib/state-transition.cjs +850 -145
  135. package/gsd-core/bin/lib/state.cjs +1629 -287
  136. package/gsd-core/bin/lib/surface.cjs +33 -10
  137. package/gsd-core/bin/lib/task-command-router.cjs +111 -1
  138. package/gsd-core/bin/lib/task-content-resolution.cjs +368 -0
  139. package/gsd-core/bin/lib/tdd-red-evidence.cjs +133 -0
  140. package/gsd-core/bin/lib/teams-status.cjs +4 -1
  141. package/gsd-core/bin/lib/uat-predicate.cjs +58 -20
  142. package/gsd-core/bin/lib/uat.cjs +2542 -387
  143. package/gsd-core/bin/lib/ui-consideration-probe.cjs +9 -1
  144. package/gsd-core/bin/lib/ui-safety-gate.cjs +37 -7
  145. package/gsd-core/bin/lib/unusable-input.cjs +13 -0
  146. package/gsd-core/bin/lib/update-context.cjs +6 -2
  147. package/gsd-core/bin/lib/validate-command-router.cjs +2 -2
  148. package/gsd-core/bin/lib/validate.cjs +230 -12
  149. package/gsd-core/bin/lib/vendor/README.md +43 -5
  150. package/gsd-core/bin/lib/vendor/js-yaml.cjs +3014 -0
  151. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  152. package/gsd-core/bin/lib/verification.cjs +287 -13
  153. package/gsd-core/bin/lib/verify-command-grounding.cjs +846 -0
  154. package/gsd-core/bin/lib/verify-command-router.cjs +1 -0
  155. package/gsd-core/bin/lib/verify.cjs +441 -56
  156. package/gsd-core/bin/lib/workstream-inventory.cjs +20 -2
  157. package/gsd-core/bin/lib/workstream-name-policy.cjs +25 -4
  158. package/gsd-core/bin/lib/worktree-base-ref.cjs +66 -12
  159. package/gsd-core/bin/lib/worktree-safety.cjs +185 -21
  160. package/gsd-core/bin/shared/config-defaults.manifest.json +7 -1
  161. package/gsd-core/bin/shared/config-schema.manifest.json +13 -0
  162. package/gsd-core/bin/shared/exit-codes.json +8 -0
  163. package/gsd-core/bin/shared/exit-codes.sh +20 -0
  164. package/gsd-core/bin/shared/model-catalog.json +8 -1
  165. package/gsd-core/bin/verify-reapply-patches.cjs +70 -3
  166. package/gsd-core/references/agent-contracts.md +6 -5
  167. package/gsd-core/references/api-coverage.md +24 -2
  168. package/gsd-core/references/autonomous-smart-discuss.md +3 -3
  169. package/gsd-core/references/checkpoints.md +37 -19
  170. package/gsd-core/references/decimal-phase-calculation.md +5 -5
  171. package/gsd-core/references/edge-probe.md +17 -5
  172. package/gsd-core/references/execute-mvp-tdd.md +18 -18
  173. package/gsd-core/references/execute-phase-between-wave-reset.md +9 -12
  174. package/gsd-core/references/execute-phase-response-language.md +6 -0
  175. package/gsd-core/references/execute-phase-wave-guard.md +11 -9
  176. package/gsd-core/references/executor-examples.md +42 -0
  177. package/gsd-core/references/failing-direction.md +78 -0
  178. package/gsd-core/references/few-shot-examples/plan-checker.md +15 -15
  179. package/gsd-core/references/gate-prompts.md +1 -1
  180. package/gsd-core/references/git-integration.md +5 -5
  181. package/gsd-core/references/git-planning-commit.md +3 -3
  182. package/gsd-core/references/gsd-run-resolver.md +1 -1
  183. package/gsd-core/references/loop-hook-dispatch.md +22 -0
  184. package/gsd-core/references/model-profiles.md +1 -1
  185. package/gsd-core/references/mvp-concepts.md +2 -2
  186. package/gsd-core/references/nyquist-compliance.md +74 -0
  187. package/gsd-core/references/offer-next.md +3 -5
  188. package/gsd-core/references/phase-argument-parsing.md +3 -3
  189. package/gsd-core/references/plan-checker-examples.md +41 -0
  190. package/gsd-core/references/planner-antipatterns.md +25 -0
  191. package/gsd-core/references/planner-chunked.md +5 -1
  192. package/gsd-core/references/planner-coupling.md +42 -0
  193. package/gsd-core/references/planner-failing-direction.md +53 -0
  194. package/gsd-core/references/planner-human-verify-mode.md +15 -1
  195. package/gsd-core/references/planner-quick-batch.md +71 -0
  196. package/gsd-core/references/planner-reviews.md +47 -0
  197. package/gsd-core/references/planner-revision.md +76 -3
  198. package/gsd-core/references/planner-verify-command-grounding.md +17 -0
  199. package/gsd-core/references/planning-config.md +39 -9
  200. package/gsd-core/references/response-language-directive.md +9 -0
  201. package/gsd-core/references/reviewer-instances.md +31 -0
  202. package/gsd-core/references/revision-loop.md +118 -11
  203. package/gsd-core/references/runtime-aware-dispatch.md +1 -1
  204. package/gsd-core/references/tdd.md +15 -12
  205. package/gsd-core/references/ui-brand.md +65 -21
  206. package/gsd-core/references/ui-consideration-probe.md +1 -1
  207. package/gsd-core/references/universal-anti-patterns.md +2 -2
  208. package/gsd-core/references/verifier-evidence-gate.md +160 -0
  209. package/gsd-core/references/verify-command-path-resolvability.md +42 -0
  210. package/gsd-core/references/verify-mvp-mode.md +1 -1
  211. package/gsd-core/references/workstream-flag.md +11 -11
  212. package/gsd-core/templates/README.md +1 -1
  213. package/gsd-core/templates/SECURITY.md +3 -3
  214. package/gsd-core/templates/UI-SPEC.md +25 -3
  215. package/gsd-core/templates/VALIDATION.md +3 -3
  216. package/gsd-core/templates/phase-prompt.md +7 -0
  217. package/gsd-core/templates/state.md +7 -0
  218. package/gsd-core/templates/verification-report.md +5 -0
  219. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
  220. package/gsd-core/workflows/add-backlog.md +3 -1
  221. package/gsd-core/workflows/add-phase.md +5 -3
  222. package/gsd-core/workflows/add-tests.md +4 -9
  223. package/gsd-core/workflows/add-todo.md +2 -2
  224. package/gsd-core/workflows/ai-integration-phase.md +5 -10
  225. package/gsd-core/workflows/analyze-dependencies.md +2 -0
  226. package/gsd-core/workflows/audit-fix.md +14 -3
  227. package/gsd-core/workflows/audit-milestone.md +11 -9
  228. package/gsd-core/workflows/audit-uat.md +19 -2
  229. package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +2 -2
  230. package/gsd-core/workflows/autonomous.md +12 -26
  231. package/gsd-core/workflows/check-todos.md +2 -2
  232. package/gsd-core/workflows/cleanup.md +3 -3
  233. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +16 -14
  234. package/gsd-core/workflows/code-review-fix.md +3 -1
  235. package/gsd-core/workflows/code-review.md +192 -69
  236. package/gsd-core/workflows/complete-milestone.md +28 -14
  237. package/gsd-core/workflows/debug.md +6 -4
  238. package/gsd-core/workflows/diagnose-issues.md +17 -7
  239. package/gsd-core/workflows/discuss-phase/modes/advisor.md +3 -1
  240. package/gsd-core/workflows/discuss-phase/modes/all.md +2 -0
  241. package/gsd-core/workflows/discuss-phase/modes/analyze.md +2 -0
  242. package/gsd-core/workflows/discuss-phase/modes/auto.md +2 -0
  243. package/gsd-core/workflows/discuss-phase/modes/batch.md +2 -0
  244. package/gsd-core/workflows/discuss-phase/modes/chain.md +5 -7
  245. package/gsd-core/workflows/discuss-phase/modes/default.md +2 -0
  246. package/gsd-core/workflows/discuss-phase/modes/power.md +2 -0
  247. package/gsd-core/workflows/discuss-phase/modes/text.md +3 -1
  248. package/gsd-core/workflows/discuss-phase/templates/context.md +2 -0
  249. package/gsd-core/workflows/discuss-phase/templates/discussion-log.md +2 -0
  250. package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +1 -3
  251. package/gsd-core/workflows/discuss-phase-assumptions.md +3 -3
  252. package/gsd-core/workflows/discuss-phase-power.md +2 -0
  253. package/gsd-core/workflows/discuss-phase.md +2 -2
  254. package/gsd-core/workflows/do.md +46 -19
  255. package/gsd-core/workflows/docs-update.md +6 -5
  256. package/gsd-core/workflows/edit-phase.md +3 -1
  257. package/gsd-core/workflows/eval-review.md +5 -10
  258. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +3 -1
  259. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +129 -11
  260. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +1 -1
  261. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +1 -1
  262. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
  263. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +29 -5
  264. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +2 -2
  265. package/gsd-core/workflows/execute-phase/steps/protected-branch.md +21 -0
  266. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +4 -2
  267. package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +25 -0
  268. package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +39 -0
  269. package/gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md +2 -0
  270. package/gsd-core/workflows/execute-phase.md +68 -66
  271. package/gsd-core/workflows/execute-plan.md +25 -20
  272. package/gsd-core/workflows/explore.md +3 -1
  273. package/gsd-core/workflows/extract-learnings.md +3 -1
  274. package/gsd-core/workflows/fast.md +8 -2
  275. package/gsd-core/workflows/forensics.md +3 -1
  276. package/gsd-core/workflows/graduation.md +6 -6
  277. package/gsd-core/workflows/health.md +4 -7
  278. package/gsd-core/workflows/help/modes/brief.md +2 -0
  279. package/gsd-core/workflows/help/modes/default.md +2 -0
  280. package/gsd-core/workflows/help/modes/full.md +12 -0
  281. package/gsd-core/workflows/help/modes/topic.md +2 -0
  282. package/gsd-core/workflows/help.md +2 -0
  283. package/gsd-core/workflows/import.md +17 -14
  284. package/gsd-core/workflows/inbox.md +5 -6
  285. package/gsd-core/workflows/ingest-docs.md +45 -12
  286. package/gsd-core/workflows/insert-phase.md +7 -5
  287. package/gsd-core/workflows/list-phase-assumptions.md +2 -0
  288. package/gsd-core/workflows/list-seeds.md +7 -3
  289. package/gsd-core/workflows/list-workspaces.md +3 -1
  290. package/gsd-core/workflows/manager.md +15 -26
  291. package/gsd-core/workflows/map-codebase.md +3 -1
  292. package/gsd-core/workflows/milestone-summary.md +3 -1
  293. package/gsd-core/workflows/mvp-phase.md +3 -3
  294. package/gsd-core/workflows/new-milestone.md +10 -22
  295. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
  296. package/gsd-core/workflows/new-project.md +17 -29
  297. package/gsd-core/workflows/new-workspace.md +2 -2
  298. package/gsd-core/workflows/next.md +4 -2
  299. package/gsd-core/workflows/node-repair.md +2 -0
  300. package/gsd-core/workflows/note.md +2 -0
  301. package/gsd-core/workflows/onboard.md +1 -1
  302. package/gsd-core/workflows/pause-work.md +20 -5
  303. package/gsd-core/workflows/plan-phase/steps/adr-ingest-express-path.md +1 -1
  304. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +100 -18
  305. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +4 -4
  306. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +12 -3
  307. package/gsd-core/workflows/plan-phase.md +251 -54
  308. package/gsd-core/workflows/plan-review-convergence.md +148 -19
  309. package/gsd-core/workflows/plant-seed.md +3 -3
  310. package/gsd-core/workflows/pr-branch.md +195 -51
  311. package/gsd-core/workflows/profile-user.md +17 -15
  312. package/gsd-core/workflows/progress/steps/forensic-audit.md +1 -1
  313. package/gsd-core/workflows/progress.md +52 -15
  314. package/gsd-core/workflows/quick/steps/discussion-phase.md +1 -3
  315. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +38 -5
  316. package/gsd-core/workflows/quick/steps/quick-verification.md +2 -4
  317. package/gsd-core/workflows/quick/steps/research-phase.md +5 -7
  318. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +3 -3
  319. package/gsd-core/workflows/quick-batch/steps/batch-init.md +55 -0
  320. package/gsd-core/workflows/quick-batch/steps/completion.md +65 -0
  321. package/gsd-core/workflows/quick-batch/steps/merge-wave.md +100 -0
  322. package/gsd-core/workflows/quick-batch/steps/plan-checker-loop.md +147 -0
  323. package/gsd-core/workflows/quick-batch/steps/planner-wave.md +158 -0
  324. package/gsd-core/workflows/quick-batch/steps/research-phase.md +95 -0
  325. package/gsd-core/workflows/quick-batch/steps/resume-mode.md +49 -0
  326. package/gsd-core/workflows/quick-batch/steps/verification-wave.md +73 -0
  327. package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +169 -0
  328. package/gsd-core/workflows/quick-batch.md +203 -0
  329. package/gsd-core/workflows/quick.md +33 -32
  330. package/gsd-core/workflows/reapply-patches.md +2 -0
  331. package/gsd-core/workflows/remove-phase.md +6 -4
  332. package/gsd-core/workflows/remove-workspace.md +3 -3
  333. package/gsd-core/workflows/resume-project.md +14 -14
  334. package/gsd-core/workflows/review.md +404 -21
  335. package/gsd-core/workflows/scan.md +3 -1
  336. package/gsd-core/workflows/section-manifest.json +12 -0
  337. package/gsd-core/workflows/secure-phase.md +3 -3
  338. package/gsd-core/workflows/session-report.md +2 -0
  339. package/gsd-core/workflows/settings-advanced.md +9 -9
  340. package/gsd-core/workflows/settings-integrations.md +66 -32
  341. package/gsd-core/workflows/settings.md +4 -6
  342. package/gsd-core/workflows/ship.md +22 -16
  343. package/gsd-core/workflows/sketch-wrap-up.md +13 -17
  344. package/gsd-core/workflows/sketch.md +13 -19
  345. package/gsd-core/workflows/smart-entry.md +4 -6
  346. package/gsd-core/workflows/spec-phase.md +31 -4
  347. package/gsd-core/workflows/spike-wrap-up.md +9 -11
  348. package/gsd-core/workflows/spike.md +21 -32
  349. package/gsd-core/workflows/stats.md +4 -2
  350. package/gsd-core/workflows/sync-skills.md +13 -5
  351. package/gsd-core/workflows/thread.md +13 -7
  352. package/gsd-core/workflows/transition.md +7 -5
  353. package/gsd-core/workflows/ui-phase.md +36 -21
  354. package/gsd-core/workflows/ui-review.md +7 -11
  355. package/gsd-core/workflows/ultraplan-phase.md +7 -13
  356. package/gsd-core/workflows/undo.md +9 -17
  357. package/gsd-core/workflows/update.md +47 -48
  358. package/gsd-core/workflows/validate-phase.md +3 -3
  359. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +25 -1
  360. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
  361. package/gsd-core/workflows/verify-work.md +106 -21
  362. package/hooks/dist/gsd-agent-isolation-guard.js +77 -38
  363. package/hooks/dist/gsd-check-update-worker.js +19 -2
  364. package/hooks/dist/gsd-config-reload.js +18 -12
  365. package/hooks/dist/gsd-context-monitor.js +302 -22
  366. package/hooks/dist/gsd-cursor-post-tool.js +3 -1
  367. package/hooks/dist/gsd-cursor-pre-tool.js +3 -1
  368. package/hooks/dist/gsd-cursor-session-start.js +2 -1
  369. package/hooks/dist/gsd-cursor-stop.js +2 -1
  370. package/hooks/dist/gsd-cursor-subagent-start.js +28 -23
  371. package/hooks/dist/gsd-cursor-subagent-stop.js +3 -1
  372. package/hooks/dist/gsd-ensure-canonical-path.js +2 -1
  373. package/hooks/dist/gsd-graphify-update.sh +22 -18
  374. package/hooks/dist/gsd-node-runner.sh +77 -0
  375. package/hooks/dist/gsd-phase-boundary.sh +1 -0
  376. package/hooks/dist/gsd-prompt-guard.js +46 -12
  377. package/hooks/dist/gsd-read-guard.js +18 -7
  378. package/hooks/dist/gsd-read-injection-scanner.js +22 -13
  379. package/hooks/dist/gsd-secret-read-guard.js +1079 -0
  380. package/hooks/dist/gsd-session-state.sh +1 -0
  381. package/hooks/dist/gsd-statusline.js +222 -29
  382. package/hooks/dist/gsd-validate-commit.sh +523 -12
  383. package/hooks/dist/gsd-windsurf-pre-command.js +16 -11
  384. package/hooks/dist/gsd-windsurf-pre-write.js +22 -13
  385. package/hooks/dist/gsd-workflow-guard.js +36 -17
  386. package/hooks/dist/gsd-worktree-path-guard.js +36 -21
  387. package/hooks/dist/gsd-write-guard.js +35 -25
  388. package/hooks/dist/lib/cli-exit.js +560 -0
  389. package/hooks/dist/lib/exit-code-registry.js +98 -0
  390. package/hooks/dist/lib/git-cmd.js +210 -1
  391. package/hooks/dist/lib/git-probe.js +84 -0
  392. package/hooks/dist/lib/hook-exit.js +81 -0
  393. package/hooks/dist/lib/injection-patterns.js +36 -6
  394. package/hooks/dist/managed-hooks-registry.cjs +4 -0
  395. package/hooks/gsd-agent-isolation-guard.js +77 -38
  396. package/hooks/gsd-check-update-worker.js +19 -2
  397. package/hooks/gsd-config-reload.js +18 -12
  398. package/hooks/gsd-context-monitor.js +302 -22
  399. package/hooks/gsd-cursor-post-tool.js +3 -1
  400. package/hooks/gsd-cursor-pre-tool.js +3 -1
  401. package/hooks/gsd-cursor-session-start.js +2 -1
  402. package/hooks/gsd-cursor-stop.js +2 -1
  403. package/hooks/gsd-cursor-subagent-start.js +28 -23
  404. package/hooks/gsd-cursor-subagent-stop.js +3 -1
  405. package/hooks/gsd-ensure-canonical-path.js +2 -1
  406. package/hooks/gsd-graphify-update.sh +22 -18
  407. package/hooks/gsd-node-runner.sh +77 -0
  408. package/hooks/gsd-phase-boundary.sh +1 -0
  409. package/hooks/gsd-prompt-guard.js +46 -12
  410. package/hooks/gsd-read-guard.js +18 -7
  411. package/hooks/gsd-read-injection-scanner.js +22 -13
  412. package/hooks/gsd-secret-read-guard.js +1079 -0
  413. package/hooks/gsd-session-state.sh +1 -0
  414. package/hooks/gsd-statusline.js +222 -29
  415. package/hooks/gsd-validate-commit.sh +523 -12
  416. package/hooks/gsd-windsurf-pre-command.js +16 -11
  417. package/hooks/gsd-windsurf-pre-write.js +22 -13
  418. package/hooks/gsd-workflow-guard.js +36 -17
  419. package/hooks/gsd-worktree-path-guard.js +36 -21
  420. package/hooks/gsd-write-guard.js +35 -25
  421. package/hooks/hooks.json +6 -0
  422. package/hooks/lib/cli-exit.js +560 -0
  423. package/hooks/lib/exit-code-registry.js +98 -0
  424. package/hooks/lib/git-cmd.js +210 -1
  425. package/hooks/lib/git-probe.js +84 -0
  426. package/hooks/lib/hook-exit.js +81 -0
  427. package/hooks/lib/injection-patterns.js +36 -6
  428. package/hooks/managed-hooks-registry.cjs +4 -0
  429. package/package.json +14 -9
  430. package/scripts/base64-scan.sh +74 -12
  431. package/scripts/build-hooks.js +12 -0
  432. package/scripts/check-glossary-refs.cjs +77 -15
  433. package/scripts/check-mutation-score-ratchet.cjs +156 -0
  434. package/scripts/ci-check-job-near-cap.cjs +49 -0
  435. package/scripts/ci-pr-mergeability.cjs +262 -0
  436. package/scripts/ci-test-scope.cjs +52 -12
  437. package/scripts/ci-timeout-report.cjs +230 -0
  438. package/scripts/docs-guard-registry.cjs +406 -0
  439. package/scripts/gen-capability-registry.cjs +8 -6
  440. package/scripts/gen-exit-code-docs.cjs +318 -0
  441. package/scripts/gen-exit-code-registry.cjs +891 -0
  442. package/scripts/gen-features.cjs +836 -0
  443. package/scripts/gen-hooks-cli-exit.cjs +239 -0
  444. package/scripts/gen-install-tree-fixtures.cjs +2 -2
  445. package/scripts/gen-loop-host-contract.cjs +189 -4
  446. package/scripts/gen-scripts-cli-exit.cjs +185 -0
  447. package/scripts/gen-state-md-docs.cjs +727 -0
  448. package/scripts/{test-failure-reasons.cjs → gsd-test-gate-reasons.cjs} +6 -0
  449. package/scripts/lib/ci-job-timing.cjs +72 -0
  450. package/scripts/lib/cli-exit.cjs +546 -44
  451. package/scripts/lib/drift-scan.cjs +32 -2
  452. package/scripts/lib/exit-code-registry.cjs +98 -0
  453. package/scripts/lib/ndjson-reporter.cjs +119 -0
  454. package/scripts/lib/shellcheck-fetch.cjs +247 -0
  455. package/scripts/lint-allow-test-rule-refs.allowlist.json +0 -6
  456. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +1 -1
  457. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
  458. package/scripts/lint-docs-guard-registration.cjs +495 -0
  459. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +198 -0
  460. package/scripts/lint-eslint-glob-coverage.allowlist.json +4 -0
  461. package/scripts/{lint-fix-has-regression-test.cjs → lint-fix-has-regression-tests.cjs} +12 -6
  462. package/scripts/lint-health-diagnostic-rule-table.cjs +65 -8
  463. package/scripts/lint-mutation-test-derivation-drift.cjs +86 -0
  464. package/scripts/lint-phase-enumeration-drift.cjs +45 -14
  465. package/scripts/lint-phase-id-drift.cjs +133 -8
  466. package/scripts/lint-planning-prompt-drift.cjs +38 -1
  467. package/scripts/lint-portable-grep.cjs +176 -0
  468. package/scripts/lint-removed-but-needed.cjs +184 -16
  469. package/scripts/lint-response-language-coverage.cjs +524 -0
  470. package/scripts/lint-seam-enforcement.cjs +182 -0
  471. package/scripts/lint-slug-derivation-drift.cjs +921 -0
  472. package/scripts/lint-source-test-name-collision.cjs +241 -0
  473. package/scripts/lint-state-write-path-drift.cjs +337 -432
  474. package/scripts/lint-test-file-count.allowlist.json +124 -4
  475. package/scripts/lint-test-file-count.cjs +25 -3
  476. package/scripts/lint-unreachable-guard-drift.cjs +51 -64
  477. package/scripts/lint-vendored-deps.cjs +208 -35
  478. package/scripts/lint-workflow-shellcheck-baseline.json +1027 -0
  479. package/scripts/lint-workflow-shellcheck.cjs +614 -0
  480. package/scripts/mutation-matrix.cjs +599 -50
  481. package/scripts/npm-audit-baseline.cjs +376 -0
  482. package/scripts/prompt-injection-scan.sh +83 -14
  483. package/scripts/require-issue-link-policy.cjs +16 -1
  484. package/scripts/secret-scan.sh +75 -13
  485. package/scripts/select-docs-guards.cjs +56 -0
  486. package/scripts/sync-runtime-launcher.cjs +22 -3
  487. package/skills/gsd-discuss-phase/SKILL.md +1 -1
  488. package/skills/gsd-execute-phase/SKILL.md +1 -1
  489. package/skills/gsd-import/SKILL.md +1 -1
  490. package/skills/gsd-ns-workflow/SKILL.md +1 -0
  491. package/skills/gsd-phase/SKILL.md +1 -1
  492. package/skills/gsd-quick/SKILL.md +8 -4
  493. package/skills/gsd-quick-batch/SKILL.md +105 -0
  494. package/skills/gsd-surface/SKILL.md +18 -8
  495. package/vscode/package.json +1 -1
  496. package/bin/lib/ui-safety-gate.cjs +0 -109
  497. package/scripts/lint-emitted-drift-ack.cjs +0 -344
  498. package/scripts/state-write-path-drift-baseline.json +0 -19
@@ -32,7 +32,7 @@ const shell_command_projection_cjs_1 = require("./shell-command-projection.cjs")
32
32
  const external_descriptor_trust_cjs_1 = require("./external-descriptor-trust.cjs");
33
33
  // eslint-disable-next-line @typescript-eslint/no-require-imports
34
34
  const conversionModule = require("./runtime-artifact-conversion.cjs");
35
- const { applyAgentPathRewrites: _applyAgentPathRewrites, processAttribution: _processAttribution, normalizeAgentBodyForRuntime: _normalizeAgentBodyForRuntime, readGsdCommandNames: _readGsdCommandNames, deriveAgentName: _deriveAgentName, applyAgentFrontmatterExtensions: _applyAgentFrontmatterExtensions, } = conversionModule;
35
+ const { applyAgentPathRewrites: _applyAgentPathRewrites, processAttribution: _processAttribution, normalizeAgentBodyForRuntime: _normalizeAgentBodyForRuntime, readGsdCommandNames: _readGsdCommandNames, deriveAgentName: _deriveAgentName, applyAgentFrontmatterExtensions: _applyAgentFrontmatterExtensions, appendAgentTools: _appendAgentTools, } = conversionModule;
36
36
  // #2995 (epic #1671 Phase 6.4): agent bodies join the fragment model. Markers are
37
37
  // stripped at emit BEFORE any path rewrite or converter runs, so a `.claude/` ->
38
38
  // `.windsurf/` regex can never reach inside a marker attribute and corrupt it —
@@ -40,6 +40,8 @@ const { applyAgentPathRewrites: _applyAgentPathRewrites, processAttribution: _pr
40
40
  // eslint-disable-next-line @typescript-eslint/no-require-imports
41
41
  const workflowFragmentsModule = require("./workflow-fragments.cjs");
42
42
  const { composeWorkflow: _composeWorkflow } = workflowFragmentsModule;
43
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
44
+ const installModelOverrideResolver = require("./install-model-override-resolver.cjs");
43
45
  // ---------------------------------------------------------------------------
44
46
  // Profile definitions
45
47
  // ---------------------------------------------------------------------------
@@ -137,9 +139,79 @@ function parseCallsAgents(content) {
137
139
  * Also derives calls_agents for each skill by scanning the body text for
138
140
  * `gsd-*` agent name references. Agent stems are stored under the special
139
141
  * key `_calls_agents_<stem>` so they don't conflict with skill stems.
142
+ *
143
+ * #3798: command bodies are thin delegators — the actual `subagent_type=`
144
+ * spawns live in the workflow files each command references
145
+ * (`@…/workflows/<name>.md`). The agent derivation therefore ALSO reads every
146
+ * workflow file the command references (plus the workflow's steps/ fragments
147
+ * when it is split per the progressive-disclosure pattern) and unions their
148
+ * `gsd-*` tokens into the same `_calls_agents_<stem>` set. Without this,
149
+ * tiered profiles omitted agents their own installed skills spawn
150
+ * (gsd-verifier at execute-phase's verify_phase_goal was the filed repro).
151
+ * Over-inclusion fails safe: a tiered profile installing one extra agent
152
+ * costs bytes, never a broken spawn.
140
153
  */
141
154
  const DEFAULT_COMMANDS_DIR = node_path_1.default.resolve(__dirname, '..', '..', '..', 'commands', 'gsd');
142
- function loadSkillsManifest(commandsDir = DEFAULT_COMMANDS_DIR) {
155
+ const DEFAULT_WORKFLOWS_DIR = node_path_1.default.resolve(__dirname, '..', '..', 'workflows');
156
+ /**
157
+ * Collect the `gsd-*` agent tokens from every workflow file a command body
158
+ * references. References are the `workflows/<name>.md` path suffixes the
159
+ * delegating commands embed (`@…/gsd-core/workflows/<name>.md`). A
160
+ * split workflow (workflows/<name>/steps/*.md) contributes its fragments as
161
+ * well, because the parent dispatches into them and the spawns live there.
162
+ */
163
+ function workflowAgentRefs(content, workflowsDir) {
164
+ const refs = content.match(/workflows\/([a-z0-9][a-z0-9-]*)\.md/g) || [];
165
+ const names = [...new Set(refs.map((r) => r.slice('workflows/'.length)))];
166
+ const tokens = new Set();
167
+ for (const name of names) {
168
+ const direct = node_path_1.default.join(workflowsDir, name);
169
+ let body = null;
170
+ try {
171
+ body = node_fs_1.default.readFileSync(direct, 'utf8');
172
+ }
173
+ catch {
174
+ body = null;
175
+ }
176
+ if (body === null)
177
+ continue;
178
+ for (const tok of parseCallsAgents(body))
179
+ tokens.add(tok);
180
+ // Split workflow: union EVERY fragment under the workflow's directory
181
+ // (steps/, modes/, templates/…) — the parent dispatches into these per
182
+ // the progressive-disclosure pattern, and spawns live in all of them
183
+ // (#3798 review: modes/ carried gsd-advisor-researcher's spawn while the
184
+ // parent only named it incidentally in prose).
185
+ const fragDir = node_path_1.default.join(workflowsDir, name.slice(0, -3));
186
+ const walk = (dir) => {
187
+ let frags;
188
+ try {
189
+ frags = node_fs_1.default.readdirSync(dir, { withFileTypes: true });
190
+ }
191
+ catch {
192
+ return;
193
+ }
194
+ for (const frag of frags) {
195
+ const full = node_path_1.default.join(dir, frag.name);
196
+ if (frag.isDirectory()) {
197
+ walk(full);
198
+ continue;
199
+ }
200
+ if (!frag.isFile() || !frag.name.endsWith('.md'))
201
+ continue;
202
+ try {
203
+ const fragBody = node_fs_1.default.readFileSync(full, 'utf8');
204
+ for (const tok of parseCallsAgents(fragBody))
205
+ tokens.add(tok);
206
+ }
207
+ catch { /* unreadable fragment — skip */ }
208
+ }
209
+ };
210
+ walk(fragDir);
211
+ }
212
+ return [...tokens];
213
+ }
214
+ function loadSkillsManifest(commandsDir = DEFAULT_COMMANDS_DIR, workflowsDir = DEFAULT_WORKFLOWS_DIR) {
143
215
  const manifest = new Map();
144
216
  if (!node_fs_1.default.existsSync(commandsDir))
145
217
  return manifest;
@@ -153,9 +225,12 @@ function loadSkillsManifest(commandsDir = DEFAULT_COMMANDS_DIR) {
153
225
  try {
154
226
  const content = node_fs_1.default.readFileSync(node_path_1.default.join(commandsDir, entry.name), 'utf8');
155
227
  manifest.set(stem, parseRequires(content));
156
- // Derive agent references from body text
157
- const agentRefs = parseCallsAgents(content);
158
- manifest.set(`_calls_agents_${stem}`, agentRefs);
228
+ // Derive agent references from body text + the workflows it delegates to
229
+ const agentRefs = [
230
+ ...parseCallsAgents(content),
231
+ ...workflowAgentRefs(content, workflowsDir),
232
+ ];
233
+ manifest.set(`_calls_agents_${stem}`, [...new Set(agentRefs)]);
159
234
  }
160
235
  catch {
161
236
  manifest.set(stem, []);
@@ -823,14 +898,14 @@ function stageSkillsForRuntimeAsSkills(srcCommandsDir, resolvedProfile, converte
823
898
  * agent loop in bin/install.js exactly:
824
899
  * 1. applyAgentPathRewrites (4 base ~/.claude/ regexes; skipped for copilot/antigravity)
825
900
  * 2. processAttribution (Co-Authored-By policy)
826
- * 3. converter (runtime-specific frontmatter/body transform)
827
- * 4. applyAgentFrontmatterExtensions (#2875 Part 2: effort/disallowedTools,
901
+ * 3. appendAgentTools (#4032: validated agent_tools grants, before host conversion)
902
+ * 4. converter (runtime-specific frontmatter/body transform)
903
+ * 5. applyAgentFrontmatterExtensions (#2875 Part 2: effort/disallowedTools,
828
904
  * gated by hostBehaviors.agentFrontmatterExtensions — no-op for a runtime
829
905
  * that declares nothing, e.g. every non-Claude runtime today)
830
- * 5. normalizeAgentBodyForRuntime (colon→hyphen refs; no-op for trivial group)
831
- * When `agentCtx` is absent, only the converter is applied (backward-compat for
832
- * the feat-1173 synthetic-descriptor tests and the copilot/antigravity paths
833
- * that handle cross-cutting inside their converters).
906
+ * 6. normalizeAgentBodyForRuntime (colon→hyphen refs; no-op for trivial group)
907
+ * When `agentCtx` is absent, only global `agent_tools` augmentation and the
908
+ * converter run; other cross-cutting remains absent for backward compatibility.
834
909
  *
835
910
  * @param srcAgentsDir source agents directory (e.g. agents/)
836
911
  * @param resolvedProfile profile filter from resolveProfile()
@@ -844,8 +919,7 @@ function stageSkillsForRuntimeAsSkills(srcCommandsDir, resolvedProfile, converte
844
919
  * every OTHER converter's contract — converters that don't declare a
845
920
  * 3rd parameter simply never read it.
846
921
  * @param isGlobal install scope passed through to the converter
847
- * @param agentCtx optional cross-cutting context (ADR-1235 §1); when absent,
848
- * only the converter is applied (backward compat)
922
+ * @param agentCtx optional cross-cutting context (ADR-1235 §1)
849
923
  */
850
924
  function stageAgentsForRuntimeWithConverter(srcAgentsDir, resolvedProfile, converter, isGlobal = false, agentCtx) {
851
925
  if (!installFs().existsSync(srcAgentsDir))
@@ -877,6 +951,7 @@ function stageAgentsForRuntimeWithConverter(srcAgentsDir, resolvedProfile, conve
877
951
  try {
878
952
  // Resolve cmdNames once per staging call (not per file) for performance.
879
953
  const cmdNames = agentCtx ? _readGsdCommandNames() : [];
954
+ const agentTools = installModelOverrideResolver.readGsdEffectiveAgentTools(agentCtx?.projectDir ?? agentCtx?.targetDir ?? null);
880
955
  for (const entry of entries) {
881
956
  if (!entry.isFile())
882
957
  continue;
@@ -896,25 +971,31 @@ function stageAgentsForRuntimeWithConverter(srcAgentsDir, resolvedProfile, conve
896
971
  // throws loudly naming the file for a malformed marker, never emitting a
897
972
  // half-composed agent.
898
973
  content = _composeWorkflow(content, { sourcePath: agentSourcePath });
974
+ const agentName = _deriveAgentName(entry.name);
975
+ const grants = [
976
+ ...(agentTools?.['*'] || []),
977
+ ...(agentTools?.[agentName] || []),
978
+ ];
899
979
  if (agentCtx) {
900
980
  // #2875 Part 2 / row I3: derived exactly as the inline loop does —
901
981
  // single-sourced via deriveAgentName (runtime-artifact-conversion.cts).
902
- const agentName = _deriveAgentName(entry.name);
903
982
  // ADR-1235 §1: pre-converter cross-cutting (matches inline loop order exactly)
904
983
  // Step 1: path rewrites (4 base ~/.claude/ regexes; skipped for copilot/antigravity)
905
984
  content = _applyAgentPathRewrites(content, agentCtx.runtime, agentCtx.pathPrefix);
906
985
  // Step 2: attribution
907
986
  content = _processAttribution(content, agentCtx.attribution);
908
- // Step 3: converter (runtime-specific frontmatter/body transform)
987
+ // Step 3: validated canonical grants, before host conversion.
988
+ content = _appendAgentTools(content, grants);
989
+ // Step 4: converter (runtime-specific frontmatter/body transform)
909
990
  content = converter(content, isGlobal, { agentName });
910
- // Step 4: frontmatter extensions (effort/disallowedTools; no-op unless
991
+ // Step 5: frontmatter extensions (effort/disallowedTools; no-op unless
911
992
  // the runtime declares hostBehaviors.agentFrontmatterExtensions)
912
993
  content = _applyAgentFrontmatterExtensions(content, { runtime: agentCtx.runtime, agentName, targetDir: agentCtx.targetDir });
913
- // Step 5: normalize colon→hyphen refs (no-op for trivial group)
994
+ // Step 6: normalize colon→hyphen refs (no-op for trivial group)
914
995
  content = _normalizeAgentBodyForRuntime(content, agentCtx.runtime, cmdNames);
915
996
  }
916
997
  else {
917
- // Backward-compat: only apply the converter (no cross-cutting)
998
+ content = _appendAgentTools(content, grants);
918
999
  content = converter(content, isGlobal);
919
1000
  }
920
1001
  installFs().writeFileSync(node_path_1.default.join(stageDir, entry.name), content, 'utf8');
@@ -1156,6 +1237,7 @@ module.exports = {
1156
1237
  // Shared internals
1157
1238
  parseRequires,
1158
1239
  parseCallsAgents,
1240
+ workflowAgentRefs,
1159
1241
  cleanupStagedSkills,
1160
1242
  // #2322: capability-skill security seams — exported for direct unit-testing
1161
1243
  // and for surface.cts's prune pass (CAPABILITY_SKILL_MARKER parity).
@@ -48,10 +48,14 @@ exports.BUNDLED_GSD_HOOK_FILES = Object.freeze(new Set([
48
48
  'hooks/gsd-windsurf-pre-command.js',
49
49
  'hooks/gsd-ensure-canonical-path.js',
50
50
  'hooks/gsd-graphify-update.sh',
51
+ // #3662: portable node resolver staged into hooks/ (not itself a lifecycle
52
+ // hook — managed JS hook commands route through it under --portable-hooks).
53
+ 'hooks/gsd-node-runner.sh',
51
54
  'hooks/gsd-phase-boundary.sh',
52
55
  'hooks/gsd-prompt-guard.js',
53
56
  'hooks/gsd-read-guard.js',
54
57
  'hooks/gsd-read-injection-scanner.js',
58
+ 'hooks/gsd-secret-read-guard.js',
55
59
  'hooks/gsd-session-state.sh',
56
60
  'hooks/gsd-statusline.js',
57
61
  'hooks/gsd-update-banner.js',
@@ -0,0 +1,169 @@
1
+ "use strict";
2
+ /**
3
+ * Installer migration: retire Antigravity's configHome skills/agents surfaces (#3738).
4
+ *
5
+ * Antigravity's machine-local discovery scans ~/.gemini/config/{skills,agents}
6
+ * (antigravity.google/docs/skills, /docs/subagents); the configHome
7
+ * (~/.gemini/antigravity{,-ide,-cli}) is not scanned for global artifacts, so
8
+ * skills installed there are silently ignored. Since #3738 the global layout
9
+ * declares a `home: ".gemini/config"` override for both kinds, and new
10
+ * installs land in the scanned dir. This migration converges an existing
11
+ * installation: manifest-managed files under the configHome's skills/ and
12
+ * agents/ subtrees are removed (modified ones backed up first), unmanifested
13
+ * files are preserved, and now-empty container directories are retired.
14
+ *
15
+ * Scope is GLOBAL only: the local workspace layout (.agents/skills,
16
+ * .agents/agents) is the documented, still-live surface and is never touched.
17
+ *
18
+ * Is the action safe in non-interactive install?
19
+ * Yes. Every emitted action type (`remove-managed`, `backup-and-remove`,
20
+ * `remove-empty-dir`) is non-interactive and journaled; none requires a
21
+ * user choice, and unknown files never produce an action.
22
+ *
23
+ * See docs/installer-migrations.md#shipped-migrations and the antigravity row
24
+ * of docs/installer-migrations.md#runtime-configuration-contract-registry.
25
+ */
26
+ var __importDefault = (this && this.__importDefault) || function (mod) {
27
+ return (mod && mod.__esModule) ? mod : { "default": mod };
28
+ };
29
+ const node_fs_1 = __importDefault(require("node:fs"));
30
+ const node_path_1 = __importDefault(require("node:path"));
31
+ /** The two retired configHome-relative artifact subpaths. */
32
+ const RETIRED_SUBPATHS = ['skills', 'agents'];
33
+ /** Only GSD-owned top-level entries are retirement candidates. */
34
+ const GSD_PREFIX = 'gsd-';
35
+ const FILE_REASON = 'Antigravity scans ~/.gemini/config/{skills,agents} for global discovery and does not scan the ' +
36
+ 'configHome, so these artifacts are invisible to the runtime (#3738); the same artifacts reinstall ' +
37
+ "under the global layout's .gemini/config home override";
38
+ const FILE_OWNERSHIP_EVIDENCE = 'pre-#3738 antigravity installs record skills/gsd-*/** and agents/gsd-*.md keys in ' +
39
+ 'gsd-file-manifest.json at the configHome root; the migration only walks gsd--prefixed entries ' +
40
+ 'under the two retired subpaths';
41
+ const DIR_REASON = 'the retired container directory is removed only once every GSD-owned entry inside it is gone; a ' +
42
+ 'directory that still holds an unmanifested user file — or any file-level action that failed to ' +
43
+ 'apply — is left in place by the emptiness re-check';
44
+ const DIR_OWNERSHIP_EVIDENCE = 'skills/ and agents/ at the antigravity configHome root are GSD-installed container directories ' +
45
+ 'from the pre-#3738 layout; removal is gated on emptiness by the shared remove-empty-dir action';
46
+ /**
47
+ * Recursively collect files and directories under `root/relDir`, never
48
+ * following a symlink (whether it names a file or a directory) and never
49
+ * emitting a path that resolves outside `baseResolved`. Mirrors the traversal
50
+ * guard in migration 009 (`walkPiHooksTree`).
51
+ */
52
+ function walkTree(root, relDir, baseResolved, files, dirs) {
53
+ const dir = node_path_1.default.join(root, relDir);
54
+ const entries = node_fs_1.default.readdirSync(dir, { withFileTypes: true });
55
+ for (const entry of entries) {
56
+ // Never follow a symlink into or through: it must not be traversed,
57
+ // hashed, or removed, regardless of what it points at.
58
+ if (entry.isSymbolicLink())
59
+ continue;
60
+ const relPath = node_path_1.default.posix.join(relDir, entry.name);
61
+ const resolved = node_path_1.default.resolve(root, relPath);
62
+ if (resolved !== baseResolved && !resolved.startsWith(baseResolved + node_path_1.default.sep))
63
+ continue;
64
+ if (entry.isDirectory()) {
65
+ dirs.push(relPath);
66
+ walkTree(root, relPath, baseResolved, files, dirs);
67
+ }
68
+ else if (entry.isFile()) {
69
+ files.push(relPath);
70
+ }
71
+ }
72
+ }
73
+ const migration = {
74
+ id: '2026-08-26-antigravity-retire-confighome-artifacts',
75
+ title: "Retire Antigravity's configHome skills/agents surfaces",
76
+ description: 'Remove manifest-managed skills/gsd-*/ and agents/gsd-*.md under the Antigravity configHome ' +
77
+ '(~/.gemini/antigravity{,-ide,-cli}) — a location Antigravity does not scan for global discovery — ' +
78
+ 'and retire the now-empty container directories, now that the global layout installs both kinds ' +
79
+ 'under the ~/.gemini/config home override (#3738). Global scope only; the local .agents workspace ' +
80
+ 'surface is untouched.',
81
+ introducedIn: '1.11.0',
82
+ runtimes: ['antigravity'],
83
+ scopes: ['global'],
84
+ destructive: true,
85
+ plan: (ctx) => {
86
+ // Defense in depth ahead of the framework's own runtimes/scope filters:
87
+ // a claude/kimi/etc. skills/ or agents/ directory is a live install
88
+ // surface, never a retirement target, and so is antigravity's LOCAL
89
+ // .agents/skills layout.
90
+ if (ctx.runtime !== 'antigravity')
91
+ return [];
92
+ if (ctx.scope !== 'global')
93
+ return [];
94
+ const actions = [];
95
+ for (const subpath of RETIRED_SUBPATHS) {
96
+ const surfaceRoot = node_path_1.default.join(ctx.configDir, subpath);
97
+ let rootLstat;
98
+ try {
99
+ rootLstat = node_fs_1.default.lstatSync(surfaceRoot);
100
+ }
101
+ catch {
102
+ continue; // absent -> nothing to retire for this surface, idempotent
103
+ }
104
+ // Never follow a symlinked surface root: walking through it could plan
105
+ // actions against paths outside the config directory entirely.
106
+ if (rootLstat.isSymbolicLink() || !rootLstat.isDirectory())
107
+ continue;
108
+ const baseResolved = node_path_1.default.resolve(ctx.configDir);
109
+ const files = [];
110
+ const dirs = [];
111
+ try {
112
+ const entries = node_fs_1.default.readdirSync(surfaceRoot, { withFileTypes: true });
113
+ for (const entry of entries) {
114
+ if (entry.isSymbolicLink() || !entry.name.startsWith(GSD_PREFIX))
115
+ continue;
116
+ const relPath = node_path_1.default.posix.join(subpath, entry.name);
117
+ if (entry.isDirectory()) {
118
+ dirs.push(relPath);
119
+ walkTree(ctx.configDir, relPath, baseResolved, files, dirs);
120
+ }
121
+ else if (entry.isFile()) {
122
+ files.push(relPath);
123
+ }
124
+ }
125
+ }
126
+ catch {
127
+ // Unreadable directory: nothing safe to plan for this surface.
128
+ continue;
129
+ }
130
+ for (const relPath of files) {
131
+ const { classification } = ctx.classifyArtifact(relPath);
132
+ if (classification === 'managed-pristine') {
133
+ actions.push({ type: 'remove-managed', relPath, reason: FILE_REASON, ownershipEvidence: FILE_OWNERSHIP_EVIDENCE });
134
+ }
135
+ else if (classification === 'managed-modified') {
136
+ actions.push({ type: 'backup-and-remove', relPath, reason: FILE_REASON, ownershipEvidence: FILE_OWNERSHIP_EVIDENCE });
137
+ }
138
+ // 'unknown' (user-added, not manifest-recorded): no action, preserved.
139
+ // 'missing' / 'managed-missing': impossible here — relPath was just
140
+ // discovered by walking the live filesystem, so it currently exists.
141
+ }
142
+ // Deepest directories first, so a child has already been evaluated
143
+ // (and possibly removed) before its parent's own emptiness is
144
+ // re-checked by the executor. The surface root itself is appended
145
+ // last, unconditionally: the executor's own emptiness re-check is what
146
+ // actually decides whether it goes, not this ordering.
147
+ const orderedDirs = [...dirs].sort((a, b) => b.split('/').length - a.split('/').length);
148
+ orderedDirs.push(subpath);
149
+ for (const relPath of orderedDirs) {
150
+ actions.push({
151
+ type: 'remove-empty-dir',
152
+ relPath,
153
+ reason: DIR_REASON,
154
+ ownershipEvidence: DIR_OWNERSHIP_EVIDENCE,
155
+ // Declared, not derived: classifyArtifact() hashes file contents
156
+ // via sha256File(), which throws EISDIR against a directory path.
157
+ // These relPaths name directories, so classification is stated
158
+ // directly (never 'unknown', so the planner's
159
+ // unknown-classification block never fires for them).
160
+ classification: 'managed-pristine',
161
+ originalHash: null,
162
+ currentHash: null,
163
+ });
164
+ }
165
+ }
166
+ return actions;
167
+ },
168
+ };
169
+ module.exports = migration;
@@ -505,17 +505,20 @@ function acquireInstallMigrationLock(configDir, { timeoutMs = DEFAULT_LOCK_TIMEO
505
505
  let lockCreatedByUs = false;
506
506
  try {
507
507
  fd = node_fs_1.default.openSync(lockPath, 'wx');
508
- // Close the open descriptor before writing so the file handle is
509
- // released on Windows before the release closure unlinks it.
510
- // Write payload via writeFileSync with the path (not the fd) so we
511
- // don't hold an open fd across the lifetime of the lock.
512
- node_fs_1.default.closeSync(fd);
513
- fd = null;
514
508
  lockCreatedByUs = true; // we own the file; clean it up on any subsequent error
515
- node_fs_1.default.writeFileSync(lockPath, JSON.stringify({
509
+ // Write the payload through the exclusively-created descriptor: a
510
+ // second open-by-path here would be a TOCTOU window (CWE-367) where a
511
+ // co-writer of the directory could symlink-swap the just-created empty
512
+ // lock file before the payload lands.
513
+ node_fs_1.default.writeFileSync(fd, JSON.stringify({
516
514
  pid: process.pid,
517
515
  acquiredAt: new Date().toISOString(),
518
516
  }) + '\n');
517
+ // Close before returning so no handle stays open across the lock's
518
+ // lifetime — Windows cannot unlink a file with an open handle when the
519
+ // release closure runs.
520
+ node_fs_1.default.closeSync(fd);
521
+ fd = null;
519
522
  lockCreatedByUs = false; // release closure owns cleanup from here
520
523
  return () => {
521
524
  const failures = [];
@@ -23,6 +23,9 @@ const shell_command_projection_cjs_1 = require("./shell-command-projection.cjs")
23
23
  // eslint-disable-next-line @typescript-eslint/no-require-imports
24
24
  const capabilityStateMod = require("./capability-state.cjs");
25
25
  const { isCapabilityActive } = capabilityStateMod;
26
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
27
+ const ioMod = require("./io.cjs");
28
+ const { formatDiagnosticToken } = ioMod;
26
29
  // ─── Constants ───────────────────────────────────────────────────────────────
27
30
  const INTEL_DIR = '.planning/intel';
28
31
  const INTEL_FILES = {
@@ -32,6 +35,16 @@ const INTEL_FILES = {
32
35
  arch: 'arch-decisions.json',
33
36
  stack: 'stack.json',
34
37
  };
38
+ /**
39
+ * ADR-3473 §8.5 / #3885: recursion bound for the intel JSON search walk.
40
+ * Restored from the retired SDK lineage (`sdk/src/query/intel.ts` at `11918dcc3^`),
41
+ * lost in the ADR-0174 consolidation. Unlike the original, hitting the ceiling is
42
+ * NOT reported as a silent "no match" — the walk that stops early sets a
43
+ * `truncated` flag threaded back up to `intelQuery`'s result (Decision 4: a
44
+ * routine that discards an input says so). The bound is on DEPTH only; breadth
45
+ * (sibling count at any given depth) is unaffected.
46
+ */
47
+ const MAX_JSON_SEARCH_DEPTH = 48;
35
48
  // ─── Internal helpers ────────────────────────────────────────────────────────
36
49
  /**
37
50
  * Ensure the intel directory exists under the given planning dir.
@@ -71,16 +84,42 @@ function intelFilePath(planningDir, filename) {
71
84
  }
72
85
  /**
73
86
  * Safely read and parse a JSON intel file.
74
- * Returns null if file doesn't exist or can't be parsed.
87
+ *
88
+ * Returns null for THREE distinct on-disk states, only one of which is a
89
+ * "quiet" case (#3885, ADR-3473 §8.5):
90
+ * - ABSENT (ENOENT, via platformReadSync returning null): silent — not
91
+ * every project has every intel file, and callers already loop over
92
+ * the full INTEL_FILES set expecting misses. Never pushed to `errors`.
93
+ * - UNREADABLE (EACCES/EIO/... — platformReadSync rethrows anything that
94
+ * isn't ENOENT): surfaced, naming the file, when `errors` is supplied.
95
+ * - MALFORMED (JSON.parse throws on a file that WAS read successfully):
96
+ * also surfaced, naming the file — a corrupt intel file used to read
97
+ * identically to "no matches", which is the same defect one layer down.
98
+ *
99
+ * `errors` is an optional accumulator so callers that want to thread the
100
+ * outcome into their own result shape can pass an array and read it back
101
+ * after the call; callers that omit it keep the prior fold-to-null shape.
75
102
  */
76
- function safeReadJson(filePath) {
103
+ function safeReadJson(filePath, errors) {
104
+ let raw;
105
+ try {
106
+ raw = (0, shell_command_projection_cjs_1.platformReadSync)(filePath);
107
+ }
108
+ catch (err) {
109
+ if (errors) {
110
+ errors.push(`Could not read ${formatDiagnosticToken(filePath)}: ${formatDiagnosticToken(err?.message ?? String(err))}`);
111
+ }
112
+ return null;
113
+ }
114
+ if (raw === null)
115
+ return null; // ENOENT — genuinely absent, not an error.
77
116
  try {
78
- const raw = (0, shell_command_projection_cjs_1.platformReadSync)(filePath);
79
- if (raw === null)
80
- return null;
81
117
  return JSON.parse(raw);
82
118
  }
83
- catch {
119
+ catch (err) {
120
+ if (errors) {
121
+ errors.push(`Could not parse ${formatDiagnosticToken(filePath)}: ${formatDiagnosticToken(err?.message ?? String(err))}`);
122
+ }
84
123
  return null;
85
124
  }
86
125
  }
@@ -101,16 +140,17 @@ function hashFile(filePath) {
101
140
  }
102
141
  /**
103
142
  * Search for a term (case-insensitive) in a JSON object's keys and string values.
104
- * Returns an array of matching entries.
143
+ * Returns matching entries plus whether the walk hit MAX_JSON_SEARCH_DEPTH.
105
144
  */
106
145
  function searchJsonEntries(data, term) {
107
146
  if (!data || typeof data !== 'object')
108
- return [];
147
+ return { matches: [], truncated: false };
109
148
  const entries = data.entries || data;
110
149
  if (!entries || typeof entries !== 'object')
111
- return [];
150
+ return { matches: [], truncated: false };
112
151
  const lowerTerm = term.toLowerCase();
113
152
  const matches = [];
153
+ const state = { truncated: false };
114
154
  for (const [key, value] of Object.entries(entries)) {
115
155
  if (key === '_meta')
116
156
  continue;
@@ -119,25 +159,40 @@ function searchJsonEntries(data, term) {
119
159
  matches.push({ key, value });
120
160
  continue;
121
161
  }
122
- // Check string value match (recursive for objects)
123
- if (matchesInValue(value, lowerTerm)) {
162
+ // Check string value match (recursive for objects/arrays, bounded by depth)
163
+ if (matchesInValue(value, lowerTerm, 0, state)) {
124
164
  matches.push({ key, value });
125
165
  }
126
166
  }
127
- return matches;
167
+ return { matches, truncated: state.truncated };
128
168
  }
129
169
  /**
130
170
  * Recursively check if a term appears in any string value.
171
+ *
172
+ * `depth` counts container unwraps already performed (starts at 0 for the
173
+ * entry's own value). Strings never fail the ceiling check themselves — only
174
+ * a container (object/array) refuses to recurse one level deeper once
175
+ * `depth > MAX_JSON_SEARCH_DEPTH`, at which point `state.truncated` is set so
176
+ * the caller can report "I stopped looking" rather than a bare "no match".
177
+ * The bound is on nesting depth only, never on sibling breadth.
131
178
  */
132
- function matchesInValue(value, lowerTerm) {
179
+ function matchesInValue(value, lowerTerm, depth, state) {
133
180
  if (typeof value === 'string') {
134
181
  return value.toLowerCase().includes(lowerTerm);
135
182
  }
136
183
  if (Array.isArray(value)) {
137
- return value.some(v => matchesInValue(v, lowerTerm));
184
+ if (depth > MAX_JSON_SEARCH_DEPTH) {
185
+ state.truncated = true;
186
+ return false;
187
+ }
188
+ return value.some(v => matchesInValue(v, lowerTerm, depth + 1, state));
138
189
  }
139
190
  if (value && typeof value === 'object') {
140
- return Object.values(value).some(v => matchesInValue(v, lowerTerm));
191
+ if (depth > MAX_JSON_SEARCH_DEPTH) {
192
+ state.truncated = true;
193
+ return false;
194
+ }
195
+ return Object.values(value).some(v => matchesInValue(v, lowerTerm, depth + 1, state));
141
196
  }
142
197
  return false;
143
198
  }
@@ -150,19 +205,23 @@ function intelQuery(term, planningDir) {
150
205
  return disabledResponse();
151
206
  const matches = [];
152
207
  let total = 0;
208
+ let truncated = false;
209
+ const readErrors = [];
153
210
  // Search all JSON intel files
154
211
  for (const [_key, filename] of Object.entries(INTEL_FILES)) {
155
212
  const filePath = intelFilePath(planningDir, filename);
156
- const data = safeReadJson(filePath);
213
+ const data = safeReadJson(filePath, readErrors);
157
214
  if (!data)
158
215
  continue;
159
- const found = searchJsonEntries(data, term);
216
+ const { matches: found, truncated: fileTruncated } = searchJsonEntries(data, term);
217
+ if (fileTruncated)
218
+ truncated = true;
160
219
  if (found.length > 0) {
161
220
  matches.push({ source: filename, entries: found });
162
221
  total += found.length;
163
222
  }
164
223
  }
165
- return { matches, term, total };
224
+ return { matches, term, total, truncated, read_errors: readErrors };
166
225
  }
167
226
  /**
168
227
  * Report status and staleness of each intel file.
@@ -179,13 +238,14 @@ function intelStatus(planningDir) {
179
238
  const filePath = intelFilePath(planningDir, filename);
180
239
  const exists = node_fs_1.default.existsSync(filePath);
181
240
  if (!exists) {
182
- files[filename] = { exists: false, updated_at: null, stale: true };
241
+ files[filename] = { exists: false, updated_at: null, stale: true, read_error: null };
183
242
  overallStale = true;
184
243
  continue;
185
244
  }
186
245
  let updatedAt = null;
187
246
  // All intel files are JSON — read _meta.updated_at
188
- const data = safeReadJson(filePath);
247
+ const readErrors = [];
248
+ const data = safeReadJson(filePath, readErrors);
189
249
  if (data && data._meta && data._meta.updated_at) {
190
250
  updatedAt = data._meta.updated_at;
191
251
  }
@@ -196,7 +256,7 @@ function intelStatus(planningDir) {
196
256
  }
197
257
  if (stale)
198
258
  overallStale = true;
199
- files[filename] = { exists: true, updated_at: updatedAt, stale };
259
+ files[filename] = { exists: true, updated_at: updatedAt, stale, read_error: readErrors[0] ?? null };
200
260
  }
201
261
  return { files, overall_stale: overallStale };
202
262
  }
@@ -207,9 +267,15 @@ function intelDiff(planningDir) {
207
267
  if (!isIntelCapabilityActive(planningDir))
208
268
  return disabledResponse();
209
269
  const snapshotPath = intelFilePath(planningDir, '.last-refresh.json');
210
- const snapshot = safeReadJson(snapshotPath);
270
+ const readErrors = [];
271
+ const snapshot = safeReadJson(snapshotPath, readErrors);
211
272
  if (!snapshot) {
212
- return { no_baseline: true };
273
+ // #3885 (ADR-3473 §8.5): `no_baseline: true` stays true for BOTH a
274
+ // genuinely-never-snapshotted project (ENOENT, read_error stays null)
275
+ // AND a present-but-unreadable/malformed snapshot — collapsing those
276
+ // two into a bare `no_baseline: true` would manufacture "you've never
277
+ // run a refresh" out of a read failure. `read_error` names which one.
278
+ return { no_baseline: true, read_error: readErrors[0] ?? null };
213
279
  }
214
280
  const prevHashes = snapshot.hashes || {};
215
281
  const changed = [];
@@ -374,7 +440,9 @@ function intelApiSurface(planningDir) {
374
440
  const intelPath = ensureIntelDir(planningDir);
375
441
  const apiMapPath = node_path_1.default.join(intelPath, INTEL_FILES.apis);
376
442
  const outputPath = node_path_1.default.join(intelPath, 'API-SURFACE.md');
377
- const data = safeReadJson(apiMapPath);
443
+ const readErrors = [];
444
+ const data = safeReadJson(apiMapPath, readErrors);
445
+ const readError = readErrors[0] ?? null;
378
446
  const entries = (data && data.entries && typeof data.entries === 'object')
379
447
  ? Object.entries(data.entries)
380
448
  : [];
@@ -392,7 +460,14 @@ function intelApiSurface(planningDir) {
392
460
  lines.push('> Generated from `.planning/intel/api-map.json`. Do not edit by hand.');
393
461
  lines.push('');
394
462
  if (symbolCount === 0) {
395
- lines.push('> **Incomplete:** api-map.json has no entries (intel extraction is regex/JS-only or not yet populated).');
463
+ if (readError) {
464
+ // #3885: a read/parse failure is NOT "not yet populated" — say so,
465
+ // rather than manufacturing the wrong reason for the empty surface.
466
+ lines.push(`> **Incomplete:** ${readError}`);
467
+ }
468
+ else {
469
+ lines.push('> **Incomplete:** api-map.json has no entries (intel extraction is regex/JS-only or not yet populated).');
470
+ }
396
471
  lines.push('> Treat absence here as "unknown", not "does not exist".');
397
472
  lines.push('');
398
473
  }
@@ -414,7 +489,7 @@ function intelApiSurface(planningDir) {
414
489
  }
415
490
  }
416
491
  (0, shell_command_projection_cjs_1.platformWriteSync)(outputPath, lines.join('\n'));
417
- return { written: outputPath, symbolCount, stale };
492
+ return { written: outputPath, symbolCount, stale, read_error: readError };
418
493
  }
419
494
  /**
420
495
  * Patch _meta.updated_at in a JSON intel file to the current timestamp.