@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
@@ -37,6 +37,7 @@ const { getDirName } = runtimeNamePolicy;
37
37
  const capabilityRegistry = require("./capability-registry.cjs");
38
38
  const hostIntegration = require("./host-integration.cjs");
39
39
  const shell_command_projection_cjs_1 = require("./shell-command-projection.cjs");
40
+ const frontmatterModule = require("./frontmatter.cjs");
40
41
  const pattern_cjs_1 = require("./pattern.cjs");
41
42
  const markdown_sectionizer_cjs_1 = require("./markdown-sectionizer.cjs");
42
43
  // #2870: install-scope.cts is a leaf-tier sibling (imports only
@@ -275,8 +276,22 @@ const kiloAgentPermissionOrder = [
275
276
  'codesearch',
276
277
  'lsp',
277
278
  ];
279
+ const kiloMcpPermissionPattern = /^mcp__([A-Za-z0-9_-]+)__((?:[A-Za-z0-9_-]+)|\*)$/;
280
+ /**
281
+ * Derive Kilo's native `{server}_{tool}` MCP permission key (kilo.ai/docs —
282
+ * external, fixed format we don't control). Not injective: both capture
283
+ * groups allow `_`, so e.g. `mcp__a_b__c` and `mcp__a__b_c` derive the same
284
+ * key. `buildKiloAgentPermissionBlock`'s `Set` resolves any such collision
285
+ * deterministically to first-seen-wins — see its regression test. Changing
286
+ * the derivation to avoid the collision isn't an option: Kilo's own runtime
287
+ * only recognizes this exact key shape.
288
+ */
278
289
  function convertClaudeToKiloPermissionTool(claudeTool) {
279
- return claudeToKiloAgentPermissions[claudeTool] || null;
290
+ const builtinPermission = claudeToKiloAgentPermissions[claudeTool];
291
+ if (builtinPermission)
292
+ return builtinPermission;
293
+ const mcpPermission = kiloMcpPermissionPattern.exec(claudeTool);
294
+ return mcpPermission ? `${mcpPermission[1]}_${mcpPermission[2]}` : null;
280
295
  }
281
296
  function buildKiloAgentPermissionBlock(claudeTools) {
282
297
  const allowedPermissions = new Set();
@@ -290,6 +305,11 @@ function buildKiloAgentPermissionBlock(claudeTools) {
290
305
  for (const permission of kiloAgentPermissionOrder) {
291
306
  lines.push(` ${permission}: ${allowedPermissions.has(permission) ? 'allow' : 'deny'}`);
292
307
  }
308
+ for (const permission of allowedPermissions) {
309
+ if (kiloAgentPermissionOrder.includes(permission))
310
+ continue;
311
+ lines.push(` ${permission}: allow`);
312
+ }
293
313
  return lines;
294
314
  }
295
315
  function replaceRelativePathReference(content, fromPath, toPath) {
@@ -644,6 +664,137 @@ function convertClaudeCommandToKimiCodeSkill(content, skillName, _runtime = null
644
664
  return convertClaudeCommandToKimiSkill(content, skillName, _runtime, cmdNames);
645
665
  }
646
666
  const KIMI_CANONICAL_GSD_AGENT_RE = /^gsd-[a-z0-9-]+$/;
667
+ /** Split a `tools:` comma list without tearing a quoted scalar that contains a literal comma. */
668
+ function splitToolScalars(text) {
669
+ const parts = [];
670
+ let current = '';
671
+ let quote = null;
672
+ for (const ch of text) {
673
+ if (quote) {
674
+ current += ch;
675
+ if (ch === quote)
676
+ quote = null;
677
+ }
678
+ else if (ch === '"' || ch === "'") {
679
+ quote = ch;
680
+ current += ch;
681
+ }
682
+ else if (ch === ',') {
683
+ parts.push(current);
684
+ current = '';
685
+ }
686
+ else {
687
+ current += ch;
688
+ }
689
+ }
690
+ parts.push(current);
691
+ return parts;
692
+ }
693
+ /** Normalize one complete frontmatter tool scalar through the shared YAML parser. */
694
+ function decodeToolScalar(raw) {
695
+ if (typeof raw !== 'string')
696
+ return null;
697
+ const value = raw.trim();
698
+ if (!value)
699
+ return null;
700
+ if (value.startsWith('"') || value.startsWith("'")) {
701
+ try {
702
+ const decoded = frontmatterModule.parseFrontmatter('---\ntool: ' + value + '\n---\n').tool;
703
+ return typeof decoded === 'string' && decoded.trim() ? decoded.trim() : null;
704
+ }
705
+ catch {
706
+ return null;
707
+ }
708
+ }
709
+ // A bare (unquoted) scalar may carry a trailing ` # comment` (YAML requires
710
+ // whitespace before `#` to start a comment) — every caller here passes a
711
+ // single already-comma-split token, never the whole `tools:` line, so this
712
+ // is safe to strip unconditionally rather than pushing the concern onto
713
+ // each call site. Strip BEFORE the malformed-quote check below: a comment
714
+ // may itself contain a `"`/`'` (e.g. `Bash # note: "internal"`), which is
715
+ // not a real YAML quote delimiter and must not cause a false rejection.
716
+ const commentIndex = value.search(/[ \t]#/);
717
+ const stripped = commentIndex === -1 ? value : value.slice(0, commentIndex).trimEnd();
718
+ if (!stripped)
719
+ return null;
720
+ if (stripped.endsWith('"') || stripped.endsWith("'"))
721
+ return null;
722
+ return stripped;
723
+ }
724
+ /** Append validated canonical grants without reserializing unrelated frontmatter. */
725
+ function appendAgentTools(content, grants) {
726
+ if (grants.length === 0)
727
+ return content;
728
+ const eol = content.includes('\r\n') ? '\r\n' : '\n';
729
+ const lines = content.split(eol);
730
+ if (lines[0] !== '---')
731
+ return content;
732
+ const frontmatterEnd = lines.indexOf('---', 1);
733
+ if (frontmatterEnd === -1)
734
+ return content;
735
+ const toolsIndex = lines.findIndex((line, index) => index < frontmatterEnd && /^tools:[ \t]*(.*)$/.test(line));
736
+ if (toolsIndex === -1)
737
+ return content;
738
+ const toolsMatch = /^tools:[ \t]*(.*)$/.exec(lines[toolsIndex]);
739
+ if (!toolsMatch)
740
+ return content;
741
+ // Plain (non-leading-quote) YAML scalars have no internal quoting — a `#`
742
+ // after whitespace is a real comment start regardless of nearby quote
743
+ // characters (verified: real YAML truncates `Read, "x #1"` at the space
744
+ // before `#` too), so this scan does not need to be quote-aware. The one
745
+ // case that DOES need protection — a value that IS a leading quoted scalar
746
+ // — is refused outright below rather than parsed past.
747
+ const commentIndex = toolsMatch[1].search(/[ \t]#/);
748
+ let inlineValue = commentIndex === -1 ? toolsMatch[1] : toolsMatch[1].slice(0, commentIndex);
749
+ let inlineComment = commentIndex === -1 ? '' : toolsMatch[1].slice(commentIndex);
750
+ // A header that is ONLY a comment (`tools: # note`) has no leading space in
751
+ // the captured group — the outer regex's `[ \t]*` already consumed it — so
752
+ // the `[ \t]#` scan above never fires. Reclassify as no inline value so the
753
+ // block-list scan below runs instead of swallowing the comment as content.
754
+ if (inlineValue.trim().startsWith('#')) {
755
+ inlineComment = toolsMatch[1];
756
+ inlineValue = '';
757
+ }
758
+ // A value that STARTS with a quote is a YAML quoted scalar occupying the
759
+ // whole node — nothing may follow it on the same line except a comment
760
+ // (`tools: "Bash"` is valid; `tools: "Bash", Read` is not, even before this
761
+ // function touches it). Appending in place would corrupt otherwise-valid
762
+ // frontmatter, so refuse rather than emit invalid YAML. A value that STARTS
763
+ // with `[` is a YAML flow sequence (`tools: [Bash, Read]`) — its own commas
764
+ // are node-internal, not scalar separators, and content cannot follow its
765
+ // closing `]` on the same line either, so the same refusal applies.
766
+ if (/^["'[]/.test(inlineValue.trim()))
767
+ return content;
768
+ const existing = [];
769
+ let insertAt = toolsIndex + 1;
770
+ if (inlineValue.trim()) {
771
+ existing.push(...splitToolScalars(inlineValue).map(decodeToolScalar).filter((value) => value !== null));
772
+ }
773
+ else {
774
+ while (insertAt < frontmatterEnd) {
775
+ const item = /^([ \t]+)-[ \t]*(\S.*)$/.exec(lines[insertAt]);
776
+ if (!item)
777
+ break;
778
+ const decoded = decodeToolScalar(item[2]);
779
+ if (decoded !== null)
780
+ existing.push(decoded);
781
+ insertAt += 1;
782
+ }
783
+ }
784
+ const present = new Set(existing);
785
+ const additions = grants.filter((grant) => !present.has(grant) && (present.add(grant), true));
786
+ if (additions.length === 0)
787
+ return content;
788
+ if (inlineValue.trim()) {
789
+ lines[toolsIndex] = `tools: ${inlineValue.trimEnd()}, ${additions.join(', ')}${inlineComment}`;
790
+ }
791
+ else {
792
+ const firstItem = /^([ \t]+)-/.exec(lines[toolsIndex + 1]);
793
+ const indent = firstItem ? firstItem[1] : ' ';
794
+ lines.splice(insertAt, 0, ...additions.map((grant) => `${indent}- ${JSON.stringify(grant)}`));
795
+ }
796
+ return lines.join(eol);
797
+ }
647
798
  function parseKimiAgentSource(source) {
648
799
  if (typeof source === 'string') {
649
800
  return {
@@ -671,7 +822,9 @@ function parseFrontmatterTools(frontmatter) {
671
822
  continue;
672
823
  if (collecting) {
673
824
  if (trimmed.startsWith('- ')) {
674
- tools.push(trimmed.slice(2).trim());
825
+ const tool = decodeToolScalar(trimmed.slice(2));
826
+ if (tool !== null)
827
+ tools.push(tool);
675
828
  continue;
676
829
  }
677
830
  collecting = false;
@@ -682,10 +835,13 @@ function parseFrontmatterTools(frontmatter) {
682
835
  }
683
836
  if (trimmed.startsWith('tools:') || trimmed.startsWith('allowed-tools:')) {
684
837
  const value = trimmed.slice(trimmed.indexOf(':') + 1).trim();
685
- if (value) {
686
- for (const tool of value.split(',')) {
687
- const name = tool.trim();
688
- if (name)
838
+ // A comment-only value (`tools: # note`) has no real inline content —
839
+ // fall through to the block-list scan below instead of decoding the
840
+ // comment text as a bogus tool name and silently dropping the list.
841
+ if (value && !value.startsWith('#')) {
842
+ for (const tool of splitToolScalars(value)) {
843
+ const name = decodeToolScalar(tool);
844
+ if (name !== null)
689
845
  tools.push(name);
690
846
  }
691
847
  }
@@ -847,7 +1003,8 @@ function buildKimiAgentArtifacts({ rootAgent = '', subagents = [], requestedSuba
847
1003
  /**
848
1004
  * Apply Antigravity-specific content conversion — path replacement + command name conversion.
849
1005
  * Path mappings depend on install mode:
850
- * Global: ~/.claude/ → ~/.gemini/antigravity/, ./.claude/ → ./.agents/
1006
+ * Global: ~/.claude/skills/ → ~/.gemini/config/skills/ (#3738),
1007
+ * ~/.claude/ → ~/.gemini/antigravity/, ./.claude/ → ./.agents/
851
1008
  * Local: ~/.claude/ → .agents/, ./.claude/ → ./.agents/
852
1009
  * Applied to ALL Antigravity content (skills, agents, engine files).
853
1010
  * @param {string} content - Source content to convert
@@ -856,6 +1013,18 @@ function buildKimiAgentArtifacts({ rootAgent = '', subagents = [], requestedSuba
856
1013
  function convertClaudeToAntigravityContent(content, isGlobal = false) {
857
1014
  let c = content;
858
1015
  if (isGlobal) {
1016
+ // #3738: global skills install under ~/.gemini/config/skills (the dir AGY
1017
+ // scans for global discovery), so skills-path references must divert there
1018
+ // — BEFORE the configHome rewrite below, which is correct for gsd-core
1019
+ // runtime-file references (settings, workflows, VERSION) but wrong for the
1020
+ // skills dir itself.
1021
+ c = c.replace(/\$HOME\/\.claude\/skills\//g, '$HOME/.gemini/config/skills/');
1022
+ c = c.replace(/~\/\.claude\/skills\//g, '~/.gemini/config/skills/');
1023
+ // Bare skills form (no trailing slash) — must also precede the generic
1024
+ // slash rule, which would otherwise divert it to the retired configHome
1025
+ // path ($HOME/.gemini/antigravity/skills).
1026
+ c = c.replace(/\$HOME\/\.claude\/skills\b/g, '$HOME/.gemini/config/skills');
1027
+ c = c.replace(/~\/\.claude\/skills\b/g, '~/.gemini/config/skills');
859
1028
  c = c.replace(/\$HOME\/\.claude\//g, '$HOME/.gemini/antigravity/');
860
1029
  c = c.replace(/~\/\.claude\//g, '~/.gemini/antigravity/');
861
1030
  // Bare form (no trailing slash) — must come after slash form to avoid double-replace
@@ -1609,26 +1778,37 @@ Execute mode fallback:
1609
1778
  ## C. Task() → spawn_agent Mapping
1610
1779
  GSD workflows use \`Task(...)\` (Claude Code syntax). Translate to Codex collaboration tools:
1611
1780
 
1612
- **Schema detection (required first step):** Codex exposes two \`spawn_agent\` schemas:
1613
- - **agent_type-capable schema** (e.g. \`multi_agent_v2\`): \`spawn_agent\` accepts \`agent_type\`, \`message\`, \`reasoning_effort\`, \`fork_context\`, etc. — typed GSD agent dispatch is available.
1614
- - **Generic schema** (\`multi_agent_v1\`): \`spawn_agent\` accepts only \`message\`, \`items\`, \`fork_context\` — there is **no \`agent_type\` field**. Typed GSD agent dispatch is unavailable in this session.
1781
+ **Schema detection (required first step):** Before spawning, inspect the \`spawn_agent\`
1782
+ tool's visible parameter schema (via \`tool_search\` or the tool list). Use the presence
1783
+ of \`agent_type\` only to choose typed dispatch versus the generic-agent workaround.
1784
+ Detect optional fields independently: \`model\`, \`reasoning_effort\`, \`task_name\`,
1785
+ \`fork_turns\`, and \`fork_context\` may be added or removed without \`agent_type\` changing.
1786
+ Never infer one field from a schema/version label or from the presence of another field.
1615
1787
 
1616
- Before spawning, inspect the \`spawn_agent\` tool's visible parameter schema (via \`tool_search\` or the tool list) to determine which form is active.
1788
+ - **agent_type-capable schema:** \`spawn_agent\` advertises \`agent_type\` — typed GSD agent dispatch is available.
1789
+ - **Generic schema:** \`spawn_agent\` does not advertise \`agent_type\` — typed GSD agent dispatch is unavailable in this session, even if other optional fields are present.
1617
1790
 
1618
1791
  Typed mapping (agent_type-capable schema only):
1619
1792
  - \`Task(subagent_type="X", prompt="Y")\` → \`spawn_agent(agent_type="X", message="Y")\`
1620
1793
  - \`Agent(subagent_type="X", prompt="Y")\` → \`spawn_agent(agent_type="X", message="Y")\`
1621
- - \`Task(model="...")\` → omit. \`spawn_agent\` has no inline \`model\` parameter;
1622
- GSD embeds the resolved per-agent model directly into each agent's \`.toml\`
1623
- at install time so \`model_overrides\` from \`.planning/config.json\` and
1624
- \`~/.gsd/defaults.json\` are honored automatically by Codex's agent router.
1625
- - Resolved \`reasoning_effort="low|medium|high|xhigh"\` (\`xhigh\` is a GSD/Codex tier, not a generic runtime enum) → pass \`reasoning_effort\`
1626
- to \`spawn_agent\` when the runtime/tool supports it. Omit missing, empty,
1627
- inherited, or unsupported values; do not invent one-off effort literals in
1628
- workflow prose.
1794
+ - \`Task(model="{resolved_model}")\` → pass \`model="{resolved_model}"\` when the
1795
+ visible \`spawn_agent\` schema advertises \`model\` and the resolved value is explicit.
1796
+ This is how \`model_profile\` tier routing, including \`adaptive\`, reaches the child agent.
1797
+ Omit \`model\` only when the schema does not advertise \`model\`, or when the value is
1798
+ missing, empty, or \`"inherit"\`; omission deliberately inherits the session/static agent
1799
+ configuration. Explicit \`model_overrides\` may also be embedded in agent \`.toml\` files,
1800
+ but ordinary profile-resolved models are not, so a TOML file is not a reason to discard
1801
+ an available inline value.
1802
+ - Before each typed spawn, obtain the paired effort for its role with
1803
+ \`gsd_run query resolve-model <subagent_type> --pick effort\` when the workflow has not
1804
+ already exposed it. The resolver's unified \`effort\` field maps to the Codex spawn argument
1805
+ \`reasoning_effort\`; do not look for a resolver field named \`reasoning_effort\`.
1806
+ Pass it when the visible \`spawn_agent\` schema advertises \`reasoning_effort\`. Omit the
1807
+ field when it is not advertised, or when the value is missing, empty, \`"inherit"\`, or
1808
+ unsupported; do not invent one-off effort literals in workflow prose.
1629
1809
  - \`fork_context: false\` by default — GSD agents load their own context via \`<required_reading>\` blocks
1630
- - \`task_name\` — required by the collaboration schema; provide a descriptive name for each spawned task
1631
- - \`fork_turns\` — optional parameter controlling turn-forking depth; coexists with \`fork_context\` (not a replacement)
1810
+ - \`task_name\` — when advertised, provide a descriptive name for each spawned task
1811
+ - \`fork_turns\` — when advertised, controls turn-forking depth; coexists with \`fork_context\` (not a replacement)
1632
1812
  - \`Task(isolation="worktree")\` / \`Agent(isolation="worktree")\` → no direct \`spawn_agent\` mapping,
1633
1813
  but Codex declares \`dispatch.isolation: orchestrator-worktree\` (#2584). Codex
1634
1814
  \`spawn_agent\` still does not create or bind a git worktree; instead GSD itself
@@ -1702,7 +1882,26 @@ function neutralizeAgentReferences(content, instructionFile) {
1702
1882
  c = c.replace(/Do NOT load full `AGENTS\.md` files[^\n]*/g, '');
1703
1883
  return c;
1704
1884
  }
1705
- function convertClaudeToOpencodeFrontmatter(content, { isAgent = false, modelOverride = null } = {}) {
1885
+ /**
1886
+ * Render one frontmatter `key: value` line whose value came from user config.
1887
+ *
1888
+ * #3706: both `model:` and `variant:` interpolate a value read from
1889
+ * `.planning/config.json` / `~/.gsd/defaults.json`. Raw interpolation lets a value
1890
+ * containing a newline inject additional TOP-LEVEL frontmatter keys into the
1891
+ * generated agent file — proven by execution during the #3705 security review
1892
+ * (`"sonnet\ntools: [\"*\"]\npermission: bypass"` produced two extra keys).
1893
+ *
1894
+ * That sink predates #3706, but this change adds a SECOND write to it, so it is
1895
+ * closed here rather than doubled. Both the decision and the escaping live in
1896
+ * frontmatter.cts so there is exactly one set of YAML scalar rules; a value that
1897
+ * round-trips bare is still emitted bare, so generated files do not churn.
1898
+ */
1899
+ function frontmatterScalar(key, value) {
1900
+ return frontmatterModule.agentScalarNeedsDoubleQuoting(value)
1901
+ ? `${key} "${frontmatterModule.escapeDoubleQuotedScalar(value)}"`
1902
+ : `${key} ${value}`;
1903
+ }
1904
+ function convertClaudeToOpencodeFrontmatter(content, { isAgent = false, modelOverride = null, variant = null } = {}) {
1706
1905
  // Replace tool name references in content (applies to all files)
1707
1906
  let convertedContent = content;
1708
1907
  convertedContent = convertedContent.replace(/\bAskUserQuestion\b/g, 'question');
@@ -1827,7 +2026,23 @@ function convertClaudeToOpencodeFrontmatter(content, { isAgent = false, modelOve
1827
2026
  // respected on OpenCode (which uses static agent frontmatter, not inline
1828
2027
  // Task() model parameters). See #2256.
1829
2028
  if (modelOverride) {
1830
- newLines.push(['model:', modelOverride].join(' '));
2029
+ newLines.push(frontmatterScalar('model:', modelOverride));
2030
+ }
2031
+ // #3706: deliver the RESOLVED reasoning effort to the spawned subagent.
2032
+ // `query resolve-model` reported an effort that never reached OpenCode, so
2033
+ // every subagent ran at whatever opencode.jsonc defaults the model to — for
2034
+ // a custom provider commonly the most expensive setting.
2035
+ //
2036
+ // OpenCode ONLY: `EFFORT_ARGV` declares surfaces for claude/opencode/codex
2037
+ // and NO kilo entry, so the Kilo converter below deliberately does not emit
2038
+ // this. Unlike the model side — where #2794 J8 requires kilo and opencode to
2039
+ // resolve identically — there is no kilo effort surface to render into, and
2040
+ // inventing one would emit a key that runtime never documented.
2041
+ //
2042
+ // Omitted entirely when absent, per #1156's rule for `model: inherit`:
2043
+ // never an empty or sentinel value, let the runtime use its own default.
2044
+ if (variant) {
2045
+ newLines.push(frontmatterScalar('variant:', variant));
1831
2046
  }
1832
2047
  }
1833
2048
  // For commands: add tools object if we had allowed-tools or tools
@@ -1899,7 +2114,9 @@ function convertClaudeToKiloFrontmatter(content, { isAgent = false, modelOverrid
1899
2114
  }
1900
2115
  if (isAgent && inAgentTools) {
1901
2116
  if (trimmed.startsWith('- ')) {
1902
- agentTools.push(trimmed.substring(2).trim());
2117
+ const tool = decodeToolScalar(trimmed.substring(2));
2118
+ if (tool !== null)
2119
+ agentTools.push(tool);
1903
2120
  continue;
1904
2121
  }
1905
2122
  if (trimmed && !trimmed.startsWith('-')) {
@@ -1910,8 +2127,11 @@ function convertClaudeToKiloFrontmatter(content, { isAgent = false, modelOverrid
1910
2127
  if (trimmed.startsWith('tools:')) {
1911
2128
  if (isAgent) {
1912
2129
  const toolsValue = trimmed.substring(6).trim();
1913
- if (toolsValue) {
1914
- const tools = toolsValue.split(',').map(t => t.trim()).filter(t => t);
2130
+ // A comment-only value (`tools: # note`) is not real inline content —
2131
+ // fall through to the block-list scan (`inAgentTools`) instead of
2132
+ // decoding the comment as a bogus tool name and dropping the list.
2133
+ if (toolsValue && !toolsValue.startsWith('#')) {
2134
+ const tools = splitToolScalars(toolsValue).map(decodeToolScalar).filter((tool) => tool !== null);
1915
2135
  agentTools.push(...tools);
1916
2136
  }
1917
2137
  else {
@@ -1973,7 +2193,9 @@ function convertClaudeToKiloFrontmatter(content, { isAgent = false, modelOverrid
1973
2193
  if (trimmed.startsWith('- ')) {
1974
2194
  const tool = trimmed.substring(2).trim();
1975
2195
  if (isAgent) {
1976
- agentTools.push(tool);
2196
+ const decoded = decodeToolScalar(tool);
2197
+ if (decoded !== null)
2198
+ agentTools.push(decoded);
1977
2199
  }
1978
2200
  else {
1979
2201
  allowedTools.push(tool);
@@ -1999,7 +2221,7 @@ function convertClaudeToKiloFrontmatter(content, { isAgent = false, modelOverrid
1999
2221
  // model emission exactly (#2093 UPGRADE 2 / ADR-1239; Kilo is an OpenCode
2000
2222
  // fork with the same static-frontmatter model constraint). See #2256.
2001
2223
  if (modelOverride) {
2002
- newLines.push(['model:', modelOverride].join(' '));
2224
+ newLines.push(frontmatterScalar('model:', modelOverride));
2003
2225
  }
2004
2226
  newLines.push(...buildKiloAgentPermissionBlock(agentTools));
2005
2227
  }
@@ -2306,11 +2528,16 @@ function convertClaudeAgentToQwenAgent(content) {
2306
2528
  * Byte-identical for an agent with no `mcp__*` grants (the common case) and
2307
2529
  * for an agent with no frontmatter at all.
2308
2530
  */
2531
+ /** Fail-closed: an undecodable scalar is dropped, never kept (ZCode's contract is "never emit mcp__*"). */
2532
+ function zcodeKeepsGrant(rawTool) {
2533
+ const decoded = decodeToolScalar(rawTool);
2534
+ return decoded !== null && !decoded.startsWith('mcp__');
2535
+ }
2309
2536
  function convertClaudeAgentToZcodeAgent(content) {
2310
- // Fast path: no MCP grant token anywhere means nothing to strip. (A body
2311
- // mention alone is not a grant — the line scan below finds no tools-line
2312
- // change and returns `content` unchanged anyway; this just skips the scan.)
2313
- if (!content.includes('mcp__'))
2537
+ // A double-quoted YAML scalar may encode the leading "m" in mcp__ as an
2538
+ // escape, so only skip the shared scalar-decoder scan when neither form is
2539
+ // present. The unchanged scan below still preserves byte-identical content.
2540
+ if (!content.includes('mcp__') && !content.includes('\\'))
2314
2541
  return content;
2315
2542
  const lines = content.split('\n');
2316
2543
  if (lines[0] !== '---')
@@ -2330,9 +2557,14 @@ function convertClaudeAgentToZcodeAgent(content) {
2330
2557
  while (i < fmEnd) {
2331
2558
  const line = lines[i];
2332
2559
  const inlineTools = /^tools:[ \t]*(.+)$/.exec(line);
2333
- if (inlineTools) {
2334
- const grants = inlineTools[1].split(',').map((tool) => tool.trim()).filter((tool) => tool !== '');
2335
- const kept = grants.filter((tool) => !tool.startsWith('mcp__'));
2560
+ // A header that is ONLY a comment (`tools: # note`) is not real inline
2561
+ // content — fall through to the block-list scan below instead of
2562
+ // matching here, or a following block list's mcp__* items never get
2563
+ // scanned and leak through unstripped.
2564
+ const commentOnlyHeader = inlineTools !== null && inlineTools[1].trim().startsWith('#');
2565
+ if (inlineTools && !commentOnlyHeader) {
2566
+ const grants = splitToolScalars(inlineTools[1]).map((tool) => tool.trim()).filter((tool) => tool !== '');
2567
+ const kept = grants.filter((tool) => zcodeKeepsGrant(tool));
2336
2568
  if (kept.length === grants.length) {
2337
2569
  out.push(line); // no mcp__* grants — keep the line byte-identical
2338
2570
  }
@@ -2346,7 +2578,7 @@ function convertClaudeAgentToZcodeAgent(content) {
2346
2578
  i++;
2347
2579
  continue;
2348
2580
  }
2349
- if (/^tools:[ \t]*$/.test(line)) {
2581
+ if (/^tools:[ \t]*$/.test(line) || commentOnlyHeader) {
2350
2582
  // Block-list form: collect the following `- item` lines.
2351
2583
  const items = [];
2352
2584
  let j = i + 1;
@@ -2356,7 +2588,7 @@ function convertClaudeAgentToZcodeAgent(content) {
2356
2588
  }
2357
2589
  const kept = items.filter((item) => {
2358
2590
  const name = /^([ \t]*)-[ \t]*(\S.*)$/.exec(item)[2].trim();
2359
- return !name.startsWith('mcp__');
2591
+ return zcodeKeepsGrant(name);
2360
2592
  });
2361
2593
  if (kept.length !== items.length) {
2362
2594
  changed = true;
@@ -2692,7 +2924,13 @@ function restoreClaudeGlobalAtRefTilde(content, pathPrefix) {
2692
2924
  return content;
2693
2925
  const tildeEquivalent = '~' + pathPrefix.slice('$HOME'.length);
2694
2926
  const atRefRe = new RegExp(`(?<!["'])@${(0, pattern_cjs_1.escapeRegex)(pathPrefix)}`, 'g');
2695
- return content.replace(atRefRe, `@${tildeEquivalent}`);
2927
+ // Function replacement, not a string. A string replacement treats `$&` and the
2928
+ // backtick-dollar form in the SUBSTITUTION as special patterns, so a --config-dir
2929
+ // containing either corrupts output: `$HOME/.cl$&ude/` yielded
2930
+ // `@~/.cl@$HOME/.cl$&ude/ude/x`, and the backtick form silently DROPPED text.
2931
+ // Pre-existing, and #3719 adds a THIRD call site to this sink — which is how the
2932
+ // previous two came to share the defect in the first place.
2933
+ return content.replace(atRefRe, () => `@${tildeEquivalent}`);
2696
2934
  }
2697
2935
  /**
2698
2936
  * Apply the per-runtime rewrite table to a single content string.
@@ -2885,6 +3123,20 @@ function _applyRuntimeRewrites(content, runtime, pathPrefix, isGlobal = false, a
2885
3123
  content = content.replace(/\.\/\.claude\b/g, `./${dirName}`);
2886
3124
  content = processAttribution(content, attribution);
2887
3125
  break;
3126
+ case 'zcode':
3127
+ // #4002: ZCode is a Claude-Code-shaped host (dot-home `.zcode`, `@~`-ref
3128
+ // expansion, `~/.zcode/...` documented paths) whose commands install with
3129
+ // `converter: null` — this pass is their only chance to receive
3130
+ // runtime-correct paths. Same shape as `claude`, including the tilde
3131
+ // restore: the tilde form is what ZCode expands and what its docs use.
3132
+ // `${_GSD_RUNTIME_ROOT}/.claude/…` matches none of these regexes and
3133
+ // survives as the project-local fallback, exactly as on every sibling.
3134
+ content = content.replace(/~\/\.claude\//g, pathPrefix);
3135
+ content = content.replace(/\$HOME\/\.claude\//g, pathPrefix);
3136
+ content = content.replace(/\.\/\.claude\//g, `./${dirName}/`);
3137
+ content = restoreClaudeGlobalAtRefTilde(content, pathPrefix);
3138
+ content = processAttribution(content, attribution);
3139
+ break;
2888
3140
  default:
2889
3141
  // Unknown runtime — no rewrites (OpenCode/Kilo handled by their own install path).
2890
3142
  break;
@@ -3124,8 +3376,34 @@ function applyAgentPathRewrites(content, runtime, pathPrefix) {
3124
3376
  const normalizedPathPrefix = pathPrefix.replace(/\/$/, '');
3125
3377
  content = content.replace(/~\/\.claude\//g, pathPrefix);
3126
3378
  content = content.replace(/\$HOME\/\.claude\//g, pathPrefix);
3127
- content = content.replace(/~\/\.claude\b/g, normalizedPathPrefix);
3128
- content = content.replace(/\$HOME\/\.claude\b/g, normalizedPathPrefix);
3379
+ // #3719 review (MAJOR): a bare `\b` is satisfied by ANY non-word character,
3380
+ // including '-' — for a --config-dir whose name EXTENDS '.claude' (e.g.
3381
+ // '.claude-work'), this re-matched the '.claude' PREFIX of the emitted
3382
+ // '.claude-work' path and corrupted it to '.claude-work-work'. Guard with
3383
+ // the SAME negative-lookahead convention already used at
3384
+ // copyWithPathReplacement's call site (bin/install.js:7729-7730).
3385
+ content = content.replace(/~\/\.claude(?![\w-])/g, normalizedPathPrefix);
3386
+ content = content.replace(/\$HOME\/\.claude(?![\w-])/g, normalizedPathPrefix);
3387
+ // #3719: the THIRD emit path that needed this restore. #3133 added it to the
3388
+ // skill/command pipeline (`_applyRuntimeRewrites` case 'claude') and #3544 to
3389
+ // bin/install.js's spec-tree copy; the agents pipeline never got it, so every
3390
+ // `@~/.claude/...` include in a global Claude install shipped as `@$HOME/...`
3391
+ // and resolved to NOTHING (27 of 34 emitted agents, 103 lines).
3392
+ //
3393
+ // Guarded on `claude` for the same reason the sibling call site lives inside
3394
+ // `case 'claude'`: the helper self-guards only on the `$HOME` PREFIX, and every
3395
+ // runtime's global prefix is a `$HOME` form (`$HOME/.cursor/`, ...), so an
3396
+ // unguarded call would rewrite `@`-refs for runtimes whose resolver has no
3397
+ // documented `~` expansion at all.
3398
+ //
3399
+ // Passed the NORMALIZED prefix, not `pathPrefix`. The two word-boundary
3400
+ // replaces above emit the trailing-slash-free form, and the helper's regex is
3401
+ // anchored to the exact prefix string it is handed — so `restore(pathPrefix)`
3402
+ // fixes `@$HOME/.claude/x` and leaves a bare `@$HOME/.claude` broken. The
3403
+ // normalized form is a PREFIX of both, so one call covers both.
3404
+ if (runtime === 'claude') {
3405
+ content = restoreClaudeGlobalAtRefTilde(content, normalizedPathPrefix);
3406
+ }
3129
3407
  return content;
3130
3408
  }
3131
3409
  // ── End rewrite engine ────────────────────────────────────────────────────────
@@ -3243,7 +3521,14 @@ function applyAgentFrontmatterExtensions(content, { runtime, agentName, targetDi
3243
3521
  // effort key, so skipping injection is the whole job.
3244
3522
  if (universalEffort !== 'inherit') {
3245
3523
  const renderedEffort = _getGsdEffortCatalog().renderEffortForRuntime(runtime, universalEffort).value;
3246
- result = injectEffortFrontmatter(result, renderedEffort);
3524
+ // #3007: `value` is `string | null` — a rejected/unrenderable level (e.g.
3525
+ // 'ultra', or a catalog with no advertised level at or above the request)
3526
+ // renders null. Same posture as the 'inherit' case above: omit the key
3527
+ // entirely rather than writing a literal `effort: null`, so the host
3528
+ // falls back to its own default instead of failing to parse.
3529
+ if (renderedEffort !== null) {
3530
+ result = injectEffortFrontmatter(result, renderedEffort);
3531
+ }
3247
3532
  }
3248
3533
  const disallowedTools = READONLY_AGENT_DISALLOWED_TOOLS[agentName];
3249
3534
  if (disallowedTools)
@@ -3276,6 +3561,7 @@ function processAttribution(content, attribution) {
3276
3561
  }
3277
3562
  module.exports = {
3278
3563
  processAttribution,
3564
+ appendAgentTools,
3279
3565
  // #2103: public accessor for hostBehaviors.agentFileExtension, exported so
3280
3566
  // surface.cts's _syncGsdDir can derive the .agent.md rename from the SAME
3281
3567
  // descriptor read as install-engine.cts (folds a duplicated hardcoded
@@ -3332,6 +3618,8 @@ module.exports = {
3332
3618
  // opencode/kilo command install through the engine instead of the bespoke path).
3333
3619
  convertClaudeToOpencodeFrontmatter,
3334
3620
  convertClaudeToKiloFrontmatter,
3621
+ _decodeToolScalar: decodeToolScalar,
3622
+ _splitToolScalars: splitToolScalars,
3335
3623
  readGsdCommandNames,
3336
3624
  transformContentToHyphen,
3337
3625
  // #1383: version resolver (exported for regression test of the Codex
@@ -51,7 +51,7 @@ function addCleanupDir(cleanupDirs, stagedDir, rewrittenDir) {
51
51
  return sourceDir;
52
52
  }
53
53
  function createRuntimeArtifactInstallPlan(args) {
54
- const { layout, resolvedProfile, homedir, platform, resolveAttribution, deps = {}, } = args;
54
+ const { layout, resolvedProfile, homedir, platform, resolveAttribution, projectDir, deps = {}, } = args;
55
55
  const conversionExports = _require('./runtime-artifact-conversion.cjs');
56
56
  const rewriteStagedSkillBodies = deps.rewriteStagedSkillBodies ?? conversionExports.rewriteStagedSkillBodies;
57
57
  const rewriteStagedCommandBodies = deps.rewriteStagedCommandBodies ?? conversionExports.rewriteStagedCommandBodies;
@@ -66,11 +66,10 @@ function createRuntimeArtifactInstallPlan(args) {
66
66
  platform,
67
67
  resolveAttribution,
68
68
  };
69
- // ADR-1235 §1: build agentCtx once per plan so agents kind entries can apply
70
- // the CORRECT pre-converter cross-cutting (path rewrites → attribution → converter
71
- // → normalize). This mirrors the exact per-file order in the inline agent loop
72
- // in bin/install.js (lines 9330-9415). agentCtx is passed as the second arg
73
- // to kind.stage() for agents kind entries with a converter (convertedAgentsKind).
69
+ // ADR-1235 §1: build the staging context once per plan. Agent kinds apply
70
+ // the CORRECT pre-converter cross-cutting (path rewrites → attribution →
71
+ // converter → normalize). This
72
+ // mirrors the exact per-file order in the former inline agent loop.
74
73
  // NO _stampNonClaudeRuntimeDefaults — agents are NOT stamped in the inline loop.
75
74
  const os = _require('node:os');
76
75
  const { posixNormalize } = _require('./shell-command-projection.cjs');
@@ -88,19 +87,19 @@ function createRuntimeArtifactInstallPlan(args) {
88
87
  const attribution = resolveAttribution ? resolveAttribution(layout.runtime) : undefined;
89
88
  // #2875 Part 2 (row I1): layout.configDir IS the install root the inline
90
89
  // agent loop called `targetDir` — same value, same resolution.
91
- const agentCtx = { runtime: layout.runtime, pathPrefix, attribution, targetDir: layout.configDir };
90
+ const agentCtx = {
91
+ runtime: layout.runtime,
92
+ pathPrefix,
93
+ attribution,
94
+ targetDir: layout.configDir,
95
+ projectDir: projectDir ?? layout.configDir,
96
+ };
92
97
  for (const kind of layout.kinds) {
93
98
  let stagedDir;
94
99
  try {
95
- if (kind.kind === 'agents') {
96
- // ADR-1235 §1: pass agentCtx so stageAgentsForRuntimeWithConverter applies
97
- // the full inline-loop order: pathRewrites → attribution → converter → normalize.
98
- // The cross-cutting is now PRE-converter (inside staging), not POST.
99
- stagedDir = kind.stage(resolvedProfile, agentCtx);
100
- }
101
- else {
102
- stagedDir = kind.stage(resolvedProfile);
103
- }
100
+ // Agent kinds use the context for their pre-converter cross-cutting
101
+ // sequence; other kinds ignore it.
102
+ stagedDir = kind.stage(resolvedProfile, agentCtx);
104
103
  }
105
104
  catch (err) {
106
105
  return { ok: false, kind: 'stage_failed', message: errorMessage(err), cleanupDirs, failedKind: kind.kind };
@@ -115,7 +114,7 @@ function createRuntimeArtifactInstallPlan(args) {
115
114
  const rewrittenDir = rewriteStagedSkillBodies(stagedDir, rewriteOpts);
116
115
  sourceDir = addCleanupDir(cleanupDirs, stagedDir, rewrittenDir);
117
116
  }
118
- // agents kind: cross-cutting already applied INSIDE kind.stage() via agentCtx.
117
+ // Agent kinds: cross-cutting already applied INSIDE kind.stage() via agentCtx.
119
118
  // No POST-step needed. sourceDir stays as stagedDir.
120
119
  }
121
120
  catch (err) {