@opengsd/gsd-core 1.9.1 → 1.11.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 (426) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +2 -3
  3. package/.opencode/plugins/gsd-core.js +8 -1
  4. package/agents/gsd-code-fixer.md +27 -3
  5. package/agents/gsd-debug-session-manager.md +11 -0
  6. package/agents/gsd-debugger.md +12 -246
  7. package/agents/gsd-doc-synthesizer.md +2 -4
  8. package/agents/gsd-executor.md +12 -10
  9. package/agents/gsd-integration-checker.md +3 -0
  10. package/agents/gsd-mempalace-curator.md +5 -2
  11. package/agents/gsd-phase-researcher.md +20 -1
  12. package/agents/gsd-plan-checker.md +46 -0
  13. package/agents/gsd-planner.md +49 -54
  14. package/agents/gsd-roadmapper.md +21 -3
  15. package/agents/gsd-user-profiler.md +3 -0
  16. package/agents/gsd-verifier.md +26 -73
  17. package/bin/install.js +1272 -1238
  18. package/bin/lib/ui-safety-gate.cjs +2 -0
  19. package/commands/gsd/code-review.md +1 -1
  20. package/commands/gsd/execute-phase.md +1 -1
  21. package/commands/gsd/map-codebase.md +1 -1
  22. package/commands/gsd/mempalace-capture.md +2 -2
  23. package/commands/gsd/mempalace-recall.md +1 -1
  24. package/commands/gsd/new-milestone.md +2 -2
  25. package/commands/gsd/plan-phase.md +1 -1
  26. package/commands/gsd/quick.md +1 -1
  27. package/commands/gsd/review-backlog.md +2 -1
  28. package/commands/gsd/verify-work.md +1 -1
  29. package/gsd-core/bin/gsd-tools.cjs +1009 -115
  30. package/gsd-core/bin/lib/active-workstream-store.cjs +153 -12
  31. package/gsd-core/bin/lib/agent-install-check.cjs +268 -38
  32. package/gsd-core/bin/lib/api-coverage.cjs +123 -5
  33. package/gsd-core/bin/lib/artifacts.cjs +3 -0
  34. package/gsd-core/bin/lib/assumption-delta.cjs +2 -4
  35. package/gsd-core/bin/lib/audit-command-router.cjs +9 -2
  36. package/gsd-core/bin/lib/audit.cjs +926 -202
  37. package/gsd-core/bin/lib/broken-windows.cjs +36 -6
  38. package/gsd-core/bin/lib/capability-consent.cjs +149 -15
  39. package/gsd-core/bin/lib/capability-lifecycle.cjs +45 -0
  40. package/gsd-core/bin/lib/capability-registry.cjs +608 -148
  41. package/gsd-core/bin/lib/capability-source.cjs +92 -0
  42. package/gsd-core/bin/lib/capability-trust.cjs +444 -25
  43. package/gsd-core/bin/lib/capability-validator.cjs +507 -24
  44. package/gsd-core/bin/lib/capability-writer.cjs +3 -2
  45. package/gsd-core/bin/lib/check-command-router.cjs +114 -38
  46. package/gsd-core/bin/lib/claude-orchestration.cjs +56 -3
  47. package/gsd-core/bin/lib/codex-agent-toml.cjs +329 -0
  48. package/gsd-core/bin/lib/command-aliases.cjs +94 -0
  49. package/gsd-core/bin/lib/command-roster.cjs +44 -1
  50. package/gsd-core/bin/lib/commands.cjs +665 -99
  51. package/gsd-core/bin/lib/commonjs-marker.cjs +142 -0
  52. package/gsd-core/bin/lib/complexity-trigger.cjs +1172 -0
  53. package/gsd-core/bin/lib/config-loader.cjs +76 -0
  54. package/gsd-core/bin/lib/config.cjs +22 -2
  55. package/gsd-core/bin/lib/context-composer.cjs +278 -0
  56. package/gsd-core/bin/lib/context-predicates.cjs +506 -0
  57. package/gsd-core/bin/lib/core-utils.cjs +217 -40
  58. package/gsd-core/bin/lib/decisions.cjs +23 -0
  59. package/gsd-core/bin/lib/docs.cjs +3 -2
  60. package/gsd-core/bin/lib/external-job.cjs +19 -4
  61. package/gsd-core/bin/lib/fallow-runner.cjs +20 -44
  62. package/gsd-core/bin/lib/frontmatter.cjs +239 -32
  63. package/gsd-core/bin/lib/gap-checker.cjs +68 -7
  64. package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +57 -6
  65. package/gsd-core/bin/lib/git-base-branch.cjs +160 -15
  66. package/gsd-core/bin/lib/graphify.cjs +142 -27
  67. package/gsd-core/bin/lib/gsd2-import.cjs +37 -5
  68. package/gsd-core/bin/lib/health-diagnostic-rules/agent-install.cjs +101 -0
  69. package/gsd-core/bin/lib/health-diagnostic-rules/config-validation.cjs +348 -0
  70. package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +145 -0
  71. package/gsd-core/bin/lib/health-diagnostic-rules/install-surface-shadowing.cjs +98 -0
  72. package/gsd-core/bin/lib/health-diagnostic-rules/milestone-archive-hygiene.cjs +100 -0
  73. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +222 -0
  74. package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +265 -0
  75. package/gsd-core/bin/lib/health-diagnostic-rules/root-existence.cjs +161 -0
  76. package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +303 -0
  77. package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +173 -0
  78. package/gsd-core/bin/lib/health-diagnostic-types.cjs +68 -0
  79. package/gsd-core/bin/lib/health-diagnostic.cjs +431 -0
  80. package/gsd-core/bin/lib/host-integration.cjs +13 -1
  81. package/gsd-core/bin/lib/host-runtime-detection.cjs +134 -0
  82. package/gsd-core/bin/lib/init-command-router.cjs +83 -8
  83. package/gsd-core/bin/lib/init.cjs +1325 -169
  84. package/gsd-core/bin/lib/install-effort-resolver.cjs +73 -30
  85. package/gsd-core/bin/lib/install-engine.cjs +805 -264
  86. package/gsd-core/bin/lib/install-fs-adapter.cjs +262 -0
  87. package/gsd-core/bin/lib/install-model-override-resolver.cjs +203 -0
  88. package/gsd-core/bin/lib/install-profiles.cjs +160 -57
  89. package/gsd-core/bin/lib/install-scope.cjs +270 -0
  90. package/gsd-core/bin/lib/install-shadow-report.cjs +385 -0
  91. package/gsd-core/bin/lib/installed-surface-resolver.cjs +381 -0
  92. package/gsd-core/bin/lib/installer-migration-authoring.cjs +3 -1
  93. package/gsd-core/bin/lib/installer-migration-report.cjs +4 -0
  94. package/gsd-core/bin/lib/installer-migrations/007-retire-config-root-commonjs-marker.cjs +149 -0
  95. package/gsd-core/bin/lib/installer-migrations/008-cursor-retire-commands-surface.cjs +55 -0
  96. package/gsd-core/bin/lib/installer-migrations/009-pi-retire-reserved-hooks-dir.cjs +199 -0
  97. package/gsd-core/bin/lib/installer-migrations.cjs +206 -13
  98. package/gsd-core/bin/lib/io.cjs +38 -3
  99. package/gsd-core/bin/lib/markdown-sectionizer.cjs +8 -1
  100. package/gsd-core/bin/lib/markdown-table.cjs +133 -20
  101. package/gsd-core/bin/lib/mcp-catalog.cjs +518 -0
  102. package/gsd-core/bin/lib/mcp-server.cjs +135 -3
  103. package/gsd-core/bin/lib/milestone-lock.cjs +248 -0
  104. package/gsd-core/bin/lib/milestone.cjs +821 -109
  105. package/gsd-core/bin/lib/model-catalog.cjs +59 -1
  106. package/gsd-core/bin/lib/model-resolver.cjs +183 -40
  107. package/gsd-core/bin/lib/normalize-test-command.cjs +1 -1
  108. package/gsd-core/bin/lib/pattern.cjs +122 -0
  109. package/gsd-core/bin/lib/phase-estimation.cjs +1 -1
  110. package/gsd-core/bin/lib/phase-id.cjs +507 -36
  111. package/gsd-core/bin/lib/phase-lifecycle.cjs +28 -3
  112. package/gsd-core/bin/lib/phase-locator.cjs +258 -58
  113. package/gsd-core/bin/lib/phase.cjs +891 -156
  114. package/gsd-core/bin/lib/plan-dependency-graph.cjs +303 -0
  115. package/gsd-core/bin/lib/plan-drift-guard.cjs +120 -0
  116. package/gsd-core/bin/lib/plan-scan.cjs +86 -2
  117. package/gsd-core/bin/lib/planning-scope.cjs +31 -0
  118. package/gsd-core/bin/lib/planning-snapshot.cjs +890 -0
  119. package/gsd-core/bin/lib/planning-workspace.cjs +60 -6
  120. package/gsd-core/bin/lib/probe-core.cjs +1 -1
  121. package/gsd-core/bin/lib/profile-output.cjs +1 -1
  122. package/gsd-core/bin/lib/prompt-budget.cjs +128 -165
  123. package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +740 -0
  124. package/gsd-core/bin/lib/retired-artifact-cleanup.cjs +85 -0
  125. package/gsd-core/bin/lib/review-lane-descriptor.cjs +108 -0
  126. package/gsd-core/bin/lib/review-lane-invocation.cjs +30 -0
  127. package/gsd-core/bin/lib/review-lane-runner.cjs +447 -68
  128. package/gsd-core/bin/lib/review-reviewer-selection.cjs +13 -18
  129. package/gsd-core/bin/lib/roadmap-command-router.cjs +76 -9
  130. package/gsd-core/bin/lib/roadmap-parser.cjs +1035 -194
  131. package/gsd-core/bin/lib/roadmap-upgrade.cjs +37 -10
  132. package/gsd-core/bin/lib/roadmap.cjs +405 -84
  133. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +795 -100
  134. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +14 -2
  135. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +440 -57
  136. package/gsd-core/bin/lib/runtime-config-adapter-registry.cjs +3 -2
  137. package/gsd-core/bin/lib/runtime-homes.cjs +220 -41
  138. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +220 -44
  139. package/gsd-core/bin/lib/runtime-name-policy.cjs +3 -1
  140. package/gsd-core/bin/lib/runtime-slash.cjs +27 -9
  141. package/gsd-core/bin/lib/section-manifest.cjs +209 -0
  142. package/gsd-core/bin/lib/security.cjs +104 -5
  143. package/gsd-core/bin/lib/shell-command-projection.cjs +388 -30
  144. package/gsd-core/bin/lib/smart-entry.cjs +154 -22
  145. package/gsd-core/bin/lib/state-command-router.cjs +5 -1
  146. package/gsd-core/bin/lib/state-document.cjs +152 -8
  147. package/gsd-core/bin/lib/state-transition.cjs +424 -105
  148. package/gsd-core/bin/lib/state.cjs +1927 -401
  149. package/gsd-core/bin/lib/surface.cjs +35 -10
  150. package/gsd-core/bin/lib/text-lines.cjs +80 -0
  151. package/gsd-core/bin/lib/token-scanner.cjs +76 -0
  152. package/gsd-core/bin/lib/uat-predicate.cjs +20 -4
  153. package/gsd-core/bin/lib/uat.cjs +706 -64
  154. package/gsd-core/bin/lib/ui-frontend-evidence.cjs +157 -0
  155. package/gsd-core/bin/lib/ui-safety-gate.cjs +14 -5
  156. package/gsd-core/bin/lib/unusable-input.cjs +33 -0
  157. package/gsd-core/bin/lib/update-context.cjs +8 -2
  158. package/gsd-core/bin/lib/user-artifact-staging.cjs +705 -0
  159. package/gsd-core/bin/lib/validate.cjs +20 -6
  160. package/gsd-core/bin/lib/vendor/README.md +37 -0
  161. package/gsd-core/bin/lib/vendor/re2js.cjs +6480 -0
  162. package/gsd-core/bin/lib/vendor/re2js.d.cts +938 -0
  163. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  164. package/gsd-core/bin/lib/verification.cjs +287 -20
  165. package/gsd-core/bin/lib/verify.cjs +368 -880
  166. package/gsd-core/bin/lib/workflow-fragments.cjs +557 -0
  167. package/gsd-core/bin/lib/workstream-inventory-builder.cjs +203 -19
  168. package/gsd-core/bin/lib/workstream-inventory.cjs +576 -31
  169. package/gsd-core/bin/lib/workstream.cjs +8 -2
  170. package/gsd-core/bin/lib/worktree-base-ref.cjs +50 -6
  171. package/gsd-core/bin/lib/worktree-safety.cjs +450 -125
  172. package/gsd-core/bin/shared/config-defaults.manifest.json +1 -0
  173. package/gsd-core/bin/shared/config-schema.manifest.json +9 -1
  174. package/gsd-core/references/agent-contracts.md +43 -26
  175. package/gsd-core/references/artifact-types.md +10 -3
  176. package/gsd-core/references/autonomous-ui-design-contract.md +42 -0
  177. package/gsd-core/references/checkpoints.md +2 -2
  178. package/gsd-core/references/context-budget.md +1 -1
  179. package/gsd-core/references/debugger-techniques.md +255 -0
  180. package/gsd-core/references/dispatch-isolation-gate.md +138 -0
  181. package/gsd-core/references/doc-conflict-engine.md +1 -1
  182. package/gsd-core/references/execute-mvp-tdd.md +3 -3
  183. package/gsd-core/references/execute-phase-between-wave-reset.md +6 -2
  184. package/gsd-core/references/execute-phase-context-guard.md +1 -1
  185. package/gsd-core/references/execute-phase-response-language.md +1 -1
  186. package/gsd-core/references/execute-phase-wave-guard.md +6 -2
  187. package/gsd-core/references/gate-prompts.md +1 -1
  188. package/gsd-core/references/git-planning-commit.md +2 -1
  189. package/gsd-core/references/loop-hook-dispatch.md +39 -2
  190. package/gsd-core/references/model-profiles.md +12 -4
  191. package/gsd-core/references/mvp-concepts.md +9 -9
  192. package/gsd-core/references/planner-guidance.md +3 -9
  193. package/gsd-core/references/planner-preconditions.md +1 -1
  194. package/gsd-core/references/planner-reviews.md +1 -1
  195. package/gsd-core/references/planning-config.md +8 -6
  196. package/gsd-core/references/research-documentation-lookup.md +5 -3
  197. package/gsd-core/references/revision-loop.md +1 -1
  198. package/gsd-core/references/specless-probe-fallback.md +8 -7
  199. package/gsd-core/references/universal-anti-patterns.md +3 -3
  200. package/gsd-core/references/verifier-phase-gates.md +192 -0
  201. package/gsd-core/references/verifier-wiring-patterns.md +100 -0
  202. package/gsd-core/references/verify-mvp-mode.md +1 -1
  203. package/gsd-core/references/workstream-flag.md +22 -6
  204. package/gsd-core/references/worktree-branch-check.md +2 -2
  205. package/gsd-core/templates/discussion-log.md +1 -1
  206. package/gsd-core/templates/phase-prompt.md +2 -4
  207. package/gsd-core/templates/state.md +4 -4
  208. package/gsd-core/templates/summary-complex.md +2 -0
  209. package/gsd-core/templates/summary-minimal.md +2 -0
  210. package/gsd-core/templates/summary-standard.md +2 -0
  211. package/gsd-core/templates/summary.md +2 -0
  212. package/gsd-core/templates/verification-report.md +9 -1
  213. package/gsd-core/workflows/ai-integration-phase.md +9 -11
  214. package/gsd-core/workflows/audit-milestone.md +3 -0
  215. package/gsd-core/workflows/autonomous/steps/converge-banner.md +1 -0
  216. package/gsd-core/workflows/autonomous/steps/converge-dispatch-bg.md +11 -0
  217. package/gsd-core/workflows/autonomous/steps/converge-dispatch-inline.md +7 -0
  218. package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +21 -0
  219. package/gsd-core/workflows/autonomous/steps/converge-loop.md +7 -0
  220. package/gsd-core/workflows/autonomous.md +33 -70
  221. package/gsd-core/workflows/cleanup.md +62 -3
  222. package/gsd-core/workflows/code-review/steps/dispatch-fix.md +39 -0
  223. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +93 -0
  224. package/gsd-core/workflows/code-review-fix.md +37 -10
  225. package/gsd-core/workflows/code-review.md +74 -166
  226. package/gsd-core/workflows/complete-milestone/steps/git-tag.md +29 -0
  227. package/gsd-core/workflows/complete-milestone.md +160 -95
  228. package/gsd-core/workflows/debug.md +16 -17
  229. package/gsd-core/workflows/diagnose-issues.md +56 -8
  230. package/gsd-core/workflows/discuss-phase/modes/chain.md +2 -1
  231. package/gsd-core/workflows/discuss-phase/modes/default.md +1 -1
  232. package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +15 -0
  233. package/gsd-core/workflows/discuss-phase-assumptions.md +7 -17
  234. package/gsd-core/workflows/docs-update/steps/dispatch-monorepo-packages.md +51 -0
  235. package/gsd-core/workflows/docs-update.md +8 -51
  236. package/gsd-core/workflows/edit-phase.md +26 -1
  237. package/gsd-core/workflows/eval-review.md +3 -5
  238. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +64 -7
  239. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +50 -0
  240. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +31 -0
  241. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +77 -0
  242. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +21 -0
  243. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +42 -0
  244. package/gsd-core/workflows/execute-phase/steps/regression-gate.md +43 -37
  245. package/gsd-core/workflows/execute-phase.md +103 -187
  246. package/gsd-core/workflows/execute-plan.md +36 -4
  247. package/gsd-core/workflows/explore.md +131 -4
  248. package/gsd-core/workflows/fast.md +10 -2
  249. package/gsd-core/workflows/health.md +73 -4
  250. package/gsd-core/workflows/help/modes/full.md +6 -1
  251. package/gsd-core/workflows/import.md +4 -4
  252. package/gsd-core/workflows/ingest-docs.md +7 -6
  253. package/gsd-core/workflows/mvp-phase.md +6 -3
  254. package/gsd-core/workflows/new-milestone/steps/project-md-milestone-write.md +16 -0
  255. package/gsd-core/workflows/new-milestone/steps/reset-phase-safety.md +19 -0
  256. package/gsd-core/workflows/new-milestone.md +35 -47
  257. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +176 -0
  258. package/gsd-core/workflows/new-project/steps/auto-mode-detection.md +32 -0
  259. package/gsd-core/workflows/new-project/steps/codebase-map-offer.md +18 -0
  260. package/gsd-core/workflows/new-project.md +27 -240
  261. package/gsd-core/workflows/next.md +12 -0
  262. package/gsd-core/workflows/plan-phase/steps/adr-ingest-express-path.md +15 -0
  263. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +110 -0
  264. package/gsd-core/workflows/plan-phase/steps/prd-express-gate.md +8 -0
  265. package/gsd-core/workflows/plan-phase/steps/research-only-early-exit.md +17 -0
  266. package/gsd-core/workflows/plan-phase/steps/research-only-modifiers.md +16 -0
  267. package/gsd-core/workflows/plan-phase/steps/reviews-prerequisite.md +17 -0
  268. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +149 -0
  269. package/gsd-core/workflows/plan-phase.md +89 -209
  270. package/gsd-core/workflows/plan-review-convergence.md +50 -2
  271. package/gsd-core/workflows/progress/steps/forensic-audit.md +125 -0
  272. package/gsd-core/workflows/progress/steps/mvp-display.md +18 -0
  273. package/gsd-core/workflows/progress.md +45 -159
  274. package/gsd-core/workflows/quick/steps/discussion-phase.md +124 -0
  275. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +111 -0
  276. package/gsd-core/workflows/quick/steps/quick-verification.md +67 -0
  277. package/gsd-core/workflows/quick/steps/research-phase.md +72 -0
  278. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +37 -0
  279. package/gsd-core/workflows/quick.md +55 -405
  280. package/gsd-core/workflows/resume-project.md +3 -0
  281. package/gsd-core/workflows/review/steps/reviewer-instances-note-1.md +4 -0
  282. package/gsd-core/workflows/review/steps/reviewer-instances-note-2.md +3 -0
  283. package/gsd-core/workflows/review.md +41 -13
  284. package/gsd-core/workflows/section-manifest.json +219 -0
  285. package/gsd-core/workflows/secure-phase.md +1 -1
  286. package/gsd-core/workflows/session-report.md +2 -1
  287. package/gsd-core/workflows/settings.md +66 -2
  288. package/gsd-core/workflows/ship.md +104 -44
  289. package/gsd-core/workflows/sketch.md +1 -1
  290. package/gsd-core/workflows/spec-phase.md +41 -20
  291. package/gsd-core/workflows/spike-wrap-up.md +20 -5
  292. package/gsd-core/workflows/spike.md +50 -16
  293. package/gsd-core/workflows/sync-skills.md +106 -13
  294. package/gsd-core/workflows/transition/steps/workstream-collision-check.md +17 -0
  295. package/gsd-core/workflows/transition.md +53 -31
  296. package/gsd-core/workflows/ui-phase.md +13 -12
  297. package/gsd-core/workflows/ui-review.md +2 -2
  298. package/gsd-core/workflows/update/steps/channel-banner.md +7 -0
  299. package/gsd-core/workflows/update.md +19 -8
  300. package/gsd-core/workflows/validate-phase.md +1 -1
  301. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +36 -0
  302. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +21 -0
  303. package/gsd-core/workflows/verify-work.md +17 -65
  304. package/hooks/dist/gsd-agent-isolation-guard.js +517 -0
  305. package/hooks/dist/gsd-check-update-worker.js +64 -12
  306. package/hooks/dist/gsd-check-update.js +19 -1
  307. package/hooks/dist/gsd-cursor-pre-tool.js +0 -3
  308. package/hooks/dist/gsd-cursor-subagent-start.js +607 -26
  309. package/hooks/dist/gsd-cursor-subagent-stop.js +3 -2
  310. package/hooks/dist/gsd-prompt-guard.js +21 -20
  311. package/hooks/dist/gsd-read-injection-scanner.js +45 -24
  312. package/hooks/dist/gsd-statusline.js +90 -6
  313. package/hooks/dist/gsd-update-banner.js +22 -1
  314. package/hooks/dist/gsd-workflow-guard.js +134 -36
  315. package/hooks/dist/gsd-worktree-path-guard.js +2 -1
  316. package/hooks/dist/gsd-write-guard.js +359 -0
  317. package/hooks/dist/lib/git-cmd.js +92 -59
  318. package/hooks/dist/lib/injection-patterns.js +45 -0
  319. package/hooks/dist/lib/isolation-deny-reason.js +39 -0
  320. package/hooks/dist/lib/isolation-sentinel.js +277 -0
  321. package/hooks/dist/managed-hooks-registry.cjs +2 -0
  322. package/hooks/gsd-agent-isolation-guard.js +517 -0
  323. package/hooks/gsd-check-update-worker.js +64 -12
  324. package/hooks/gsd-check-update.js +19 -1
  325. package/hooks/gsd-cursor-pre-tool.js +0 -3
  326. package/hooks/gsd-cursor-subagent-start.js +607 -26
  327. package/hooks/gsd-cursor-subagent-stop.js +3 -2
  328. package/hooks/gsd-prompt-guard.js +21 -20
  329. package/hooks/gsd-read-injection-scanner.js +45 -24
  330. package/hooks/gsd-statusline.js +90 -6
  331. package/hooks/gsd-update-banner.js +22 -1
  332. package/hooks/gsd-workflow-guard.js +134 -36
  333. package/hooks/gsd-worktree-path-guard.js +2 -1
  334. package/hooks/gsd-write-guard.js +359 -0
  335. package/hooks/hooks.json +12 -0
  336. package/hooks/lib/git-cmd.js +92 -59
  337. package/hooks/lib/injection-patterns.js +45 -0
  338. package/hooks/lib/isolation-deny-reason.js +39 -0
  339. package/hooks/lib/isolation-sentinel.js +277 -0
  340. package/hooks/managed-hooks-registry.cjs +2 -0
  341. package/package.json +31 -10
  342. package/pi/gsd.cjs +71 -12
  343. package/scripts/baselines/planning-prompt-drift-baseline.json +4 -0
  344. package/scripts/baselines/planning-snapshot-bypass-baseline.json +12 -0
  345. package/scripts/baselines/unreachable-guard-drift-baseline.json +4 -0
  346. package/scripts/build-hooks.js +9 -0
  347. package/scripts/changeset/lint.cjs +68 -6
  348. package/scripts/changeset/serialize.cjs +5 -1
  349. package/scripts/check-alias-drift.cjs +7 -43
  350. package/scripts/check-contract-drift.cjs +297 -0
  351. package/scripts/ci-test-scope.cjs +19 -2
  352. package/scripts/command-contract-helpers.cjs +903 -1
  353. package/scripts/gen-adr-index.cjs +728 -38
  354. package/scripts/gen-capability-matrix.cjs +1 -1
  355. package/scripts/gen-capability-registry.cjs +3 -15
  356. package/scripts/gen-context-index.cjs +439 -0
  357. package/scripts/gen-health-docs.cjs +390 -0
  358. package/scripts/gen-inventory-manifest.cjs +150 -4
  359. package/scripts/gen-loop-host-contract.cjs +4 -24
  360. package/scripts/gen-prompt-budget-parity-corpus.cjs +645 -0
  361. package/scripts/gen-registry.cjs +3 -14
  362. package/scripts/gen-section-manifest.cjs +638 -0
  363. package/scripts/generate-package-identity.cjs +4 -2
  364. package/scripts/lib/alias-drift-families.cjs +46 -0
  365. package/scripts/lib/drift-scan.cjs +278 -0
  366. package/scripts/lint-allow-test-rule-refs.allowlist.json +15 -54
  367. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +4 -0
  368. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +3 -0
  369. package/scripts/lint-canary-version-leak.cjs +73 -0
  370. package/scripts/lint-command-contract.cjs +96 -13
  371. package/scripts/lint-compiled-artifact-sync.cjs +6 -1
  372. package/scripts/lint-completion-predicate-drift.cjs +933 -0
  373. package/scripts/lint-completion-ratio-drift.cjs +214 -0
  374. package/scripts/lint-default-flip-documentation.cjs +193 -0
  375. package/scripts/lint-docs-command-form.cjs +195 -0
  376. package/scripts/lint-docs-required.cjs +9 -1
  377. package/scripts/lint-emitted-drift-ack.cjs +215 -20
  378. package/scripts/lint-eslint-glob-coverage.allowlist.json +34 -0
  379. package/scripts/lint-eslint-glob-coverage.cjs +340 -0
  380. package/scripts/lint-example-parser-parity.cjs +395 -0
  381. package/scripts/lint-frontmatter-scalar-broad-grep.cjs +237 -0
  382. package/scripts/lint-health-diagnostic-rule-table.cjs +404 -0
  383. package/scripts/lint-hooks-runtime-build-seam.cjs +262 -0
  384. package/scripts/lint-milestone-window-drift.cjs +468 -0
  385. package/scripts/lint-phase-enumeration-drift.cjs +479 -0
  386. package/scripts/lint-plan-count-drift.cjs +318 -0
  387. package/scripts/lint-planning-artifact-writer-drift.cjs +398 -0
  388. package/scripts/lint-planning-prompt-drift.cjs +434 -0
  389. package/scripts/lint-planning-snapshot-bypass-drift.cjs +544 -0
  390. package/scripts/lint-regression-test-names.cjs +15 -13
  391. package/scripts/lint-removed-but-needed.cjs +320 -0
  392. package/scripts/lint-state-field-drift.cjs +805 -0
  393. package/scripts/lint-state-write-path-drift.cjs +1045 -0
  394. package/scripts/lint-test-file-count.allowlist.json +40 -3
  395. package/scripts/lint-unreachable-guard-drift.cjs +843 -0
  396. package/scripts/lint-vendored-deps.cjs +124 -0
  397. package/scripts/mutation-matrix.cjs +13 -0
  398. package/scripts/pr-changed-files.cjs +63 -0
  399. package/scripts/pr-template-policy.cjs +14 -4
  400. package/scripts/prompt-injection-scan.sh +52 -6
  401. package/scripts/require-issue-link-policy.cjs +192 -0
  402. package/scripts/state-write-path-drift-baseline.json +19 -0
  403. package/scripts/sync-runtime-launcher.cjs +2 -4
  404. package/skills/gsd-autonomous/SKILL.md +0 -1
  405. package/skills/gsd-code-review/SKILL.md +1 -1
  406. package/skills/gsd-execute-phase/SKILL.md +1 -2
  407. package/skills/gsd-map-codebase/SKILL.md +1 -1
  408. package/skills/gsd-mempalace-capture/SKILL.md +2 -2
  409. package/skills/gsd-mempalace-recall/SKILL.md +1 -1
  410. package/skills/gsd-new-milestone/SKILL.md +2 -2
  411. package/skills/gsd-next/SKILL.md +0 -1
  412. package/skills/gsd-plan-phase/SKILL.md +1 -2
  413. package/skills/gsd-progress/SKILL.md +0 -1
  414. package/skills/gsd-quick/SKILL.md +1 -1
  415. package/skills/gsd-review-backlog/SKILL.md +2 -1
  416. package/skills/gsd-stats/SKILL.md +0 -1
  417. package/skills/gsd-verify-work/SKILL.md +1 -1
  418. package/vscode/package.json +1 -1
  419. package/gsd-core/workflows/discovery-phase.md +0 -298
  420. package/gsd-core/workflows/plan-milestone-gaps.md +0 -281
  421. package/gsd-core/workflows/verify-phase.md +0 -577
  422. package/scripts/affected-tests-lib.cjs +0 -554
  423. package/scripts/gen-emitted-baseline.cjs +0 -145
  424. package/scripts/lint-allow-test-rule-refs.cjs +0 -162
  425. package/scripts/run-affected-tests.cjs +0 -7
  426. package/scripts/run-tests.cjs +0 -1050
@@ -13,13 +13,33 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
13
13
  const node_fs_1 = __importDefault(require("node:fs"));
14
14
  const node_path_1 = __importDefault(require("node:path"));
15
15
  const node_os_1 = __importDefault(require("node:os"));
16
+ // #2874 (ADR-58 cleanup phase): route the staging functions' fs calls
17
+ // through the installRuntimeArtifacts call tree's injectable seam — see
18
+ // install-fs-adapter.cts's module doc. Resolves to real `node:fs` unless the
19
+ // top-level installRuntimeArtifacts call injected a `deps.fs`. Only the
20
+ // staging functions reachable FROM that call tree are routed
21
+ // (stageSkillsForProfile / stageAgentsForProfile /
22
+ // stageAgentsForRuntimeWithConverter / stageSkillsForRuntimeAsSkills /
23
+ // stageCommandsForRuntimeFlat / buildNamespaceBundleMap) — the profile-marker
24
+ // and manifest-loading helpers below are not on that call tree and keep
25
+ // using real `fs` directly.
26
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
27
+ const installFsAdapter = require("./install-fs-adapter.cjs");
28
+ const { installFs, mkInstallTempDir } = installFsAdapter;
16
29
  const shell_command_projection_cjs_1 = require("./shell-command-projection.cjs");
17
30
  // #2322: reuse the existing pure path-containment seam (ADR-1239 Phase C-2)
18
31
  // instead of hand-rolling a new traversal check for capability skill stems.
19
32
  const external_descriptor_trust_cjs_1 = require("./external-descriptor-trust.cjs");
20
33
  // eslint-disable-next-line @typescript-eslint/no-require-imports
21
34
  const conversionModule = require("./runtime-artifact-conversion.cjs");
22
- const { applyAgentPathRewrites: _applyAgentPathRewrites, processAttribution: _processAttribution, normalizeAgentBodyForRuntime: _normalizeAgentBodyForRuntime, readGsdCommandNames: _readGsdCommandNames, } = conversionModule;
35
+ const { applyAgentPathRewrites: _applyAgentPathRewrites, processAttribution: _processAttribution, normalizeAgentBodyForRuntime: _normalizeAgentBodyForRuntime, readGsdCommandNames: _readGsdCommandNames, deriveAgentName: _deriveAgentName, applyAgentFrontmatterExtensions: _applyAgentFrontmatterExtensions, } = conversionModule;
36
+ // #2995 (epic #1671 Phase 6.4): agent bodies join the fragment model. Markers are
37
+ // stripped at emit BEFORE any path rewrite or converter runs, so a `.claude/` ->
38
+ // `.windsurf/` regex can never reach inside a marker attribute and corrupt it —
39
+ // the same ordering #2930 established for workflows.
40
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
41
+ const workflowFragmentsModule = require("./workflow-fragments.cjs");
42
+ const { composeWorkflow: _composeWorkflow } = workflowFragmentsModule;
23
43
  // ---------------------------------------------------------------------------
24
44
  // Profile definitions
25
45
  // ---------------------------------------------------------------------------
@@ -257,10 +277,41 @@ function resolveProfile({ modes, manifest, _profilesOverride, registry } = {}) {
257
277
  // site to track its own cleanup handle.
258
278
  const STAGED_DIRS = new Set();
259
279
  let exitHandlerRegistered = false;
280
+ // #2874 leak-fix: `cleanupStagedSkills` runs at process exit — AFTER
281
+ // `withInstallFs` has already restored `current` back to the real adapter
282
+ // (install-fs-adapter.cts's module doc, "SYNCHRONOUS-ONLY / RE-ENTRANCY
283
+ // ASSUMPTION" — extended there to reference this map). A dir staged during a
284
+ // fake-adapter call must be cleaned up with THAT SAME fake adapter, not with
285
+ // whatever is ambiently active later, or an exit handler would perform real
286
+ // filesystem IO on a path that only ever existed in the fake's in-memory
287
+ // store. Capturing the adapter OBJECT `installFs()` returns at registration
288
+ // time (not the ambient `current` variable, which changes) means cleanup
289
+ // always replays the exact adapter that created the path. Dirs added to
290
+ // STAGED_DIRS without going through `registerStagedDir` (the deprecated
291
+ // `stageSkillsForMode`, which creates its stage dir via raw `fs.mkdtempSync`
292
+ // and was never on the injectable seam) have no entry here and fall back to
293
+ // real `fs.rmSync` below — the same real fs it always used to create them.
294
+ const STAGED_DIR_ADAPTERS = new Map();
295
+ /**
296
+ * Register a dir just staged through the injectable seam (`installFs()`) for
297
+ * exit-time cleanup, capturing the adapter that staged it alongside the path.
298
+ * See `STAGED_DIR_ADAPTERS`'s comment for why the capture matters.
299
+ */
300
+ function registerStagedDir(dir) {
301
+ STAGED_DIRS.add(dir);
302
+ STAGED_DIR_ADAPTERS.set(dir, installFs());
303
+ ensureExitCleanup();
304
+ }
260
305
  function cleanupStagedSkills() {
261
306
  for (const dir of STAGED_DIRS) {
307
+ const adapter = STAGED_DIR_ADAPTERS.get(dir);
262
308
  try {
263
- node_fs_1.default.rmSync(dir, { recursive: true, force: true });
309
+ if (adapter) {
310
+ adapter.rmSync(dir, { recursive: true, force: true });
311
+ }
312
+ else {
313
+ node_fs_1.default.rmSync(dir, { recursive: true, force: true });
314
+ }
264
315
  }
265
316
  catch {
266
317
  // Best-effort: missing dir or permission error shouldn't crash a
@@ -268,6 +319,7 @@ function cleanupStagedSkills() {
268
319
  }
269
320
  }
270
321
  STAGED_DIRS.clear();
322
+ STAGED_DIR_ADAPTERS.clear();
271
323
  }
272
324
  // Signals we register a cleanup handler for in addition to the natural
273
325
  // 'exit' event. `process.on('exit')` does NOT fire on these — an installer
@@ -296,11 +348,11 @@ function ensureExitCleanup() {
296
348
  function stageSkillsForProfile(srcDir, resolvedProfile) {
297
349
  if (resolvedProfile.skills === '*')
298
350
  return srcDir;
299
- if (!node_fs_1.default.existsSync(srcDir))
351
+ if (!installFs().existsSync(srcDir))
300
352
  return srcDir;
301
- const stageDir = node_fs_1.default.mkdtempSync(node_path_1.default.join(node_os_1.default.tmpdir(), 'gsd-profile-skills-'));
353
+ const stageDir = mkInstallTempDir('gsd-profile-skills-');
302
354
  try {
303
- const entries = node_fs_1.default.readdirSync(srcDir, { withFileTypes: true });
355
+ const entries = installFs().readdirSync(srcDir, { withFileTypes: true });
304
356
  for (const entry of entries) {
305
357
  if (!entry.isFile())
306
358
  continue;
@@ -309,18 +361,17 @@ function stageSkillsForProfile(srcDir, resolvedProfile) {
309
361
  const stem = entry.name.slice(0, -3);
310
362
  if (!(resolvedProfile.skills).has(stem))
311
363
  continue;
312
- node_fs_1.default.copyFileSync(node_path_1.default.join(srcDir, entry.name), node_path_1.default.join(stageDir, entry.name));
364
+ installFs().copyFileSync(node_path_1.default.join(srcDir, entry.name), node_path_1.default.join(stageDir, entry.name));
313
365
  }
314
366
  }
315
367
  catch (err) {
316
368
  try {
317
- node_fs_1.default.rmSync(stageDir, { recursive: true, force: true });
369
+ installFs().rmSync(stageDir, { recursive: true, force: true });
318
370
  }
319
371
  catch { /* best-effort */ }
320
372
  throw err;
321
373
  }
322
- STAGED_DIRS.add(stageDir);
323
- ensureExitCleanup();
374
+ registerStagedDir(stageDir);
324
375
  return stageDir;
325
376
  }
326
377
  /**
@@ -329,16 +380,29 @@ function stageSkillsForProfile(srcDir, resolvedProfile) {
329
380
  * For tiered profiles, copies only agents whose full stem (e.g. 'gsd-planner')
330
381
  * is in resolvedProfile.agents — which is populated by resolveProfile() from
331
382
  * the _calls_agents_* entries in the manifest.
383
+ *
384
+ * ⚠️ RAW STAGER — ITS OUTPUT IS NOT EMISSION-READY (#2995). This stager performs a
385
+ * plain `fs.copyFileSync` and — under the default `full` profile — short-circuits
386
+ * and returns the real source directory unstaged. It does NOT strip `gsd:section`
387
+ * markers. It is still called, by `bin/install.js`'s `_stageAgents`, whose output
388
+ * feeds the inline agent loop and `installCodexConfig`; both of those compose the
389
+ * content themselves before writing, so the raw output never reaches disk. What
390
+ * changed in #2995 is that `agentsKind` and `kimiAgentsKind` no longer use it —
391
+ * they route through `stageAgentsForRuntimeWithConverter`, which composes.
392
+ *
393
+ * The invariant to preserve: anything that takes this function's output and WRITES
394
+ * it as a runtime artifact must call `composeWorkflow` on each file first, or it
395
+ * ships markers verbatim.
332
396
  */
333
397
  function stageAgentsForProfile(srcAgentsDir, resolvedProfile) {
334
398
  if (resolvedProfile.skills === '*')
335
399
  return srcAgentsDir;
336
- if (!node_fs_1.default.existsSync(srcAgentsDir))
400
+ if (!installFs().existsSync(srcAgentsDir))
337
401
  return srcAgentsDir;
338
- const stageDir = node_fs_1.default.mkdtempSync(node_path_1.default.join(node_os_1.default.tmpdir(), 'gsd-profile-agents-'));
402
+ const stageDir = mkInstallTempDir('gsd-profile-agents-');
339
403
  try {
340
404
  if (resolvedProfile.agents instanceof Set && resolvedProfile.agents.size > 0) {
341
- const entries = node_fs_1.default.readdirSync(srcAgentsDir, { withFileTypes: true });
405
+ const entries = installFs().readdirSync(srcAgentsDir, { withFileTypes: true });
342
406
  for (const entry of entries) {
343
407
  if (!entry.isFile())
344
408
  continue;
@@ -348,20 +412,19 @@ function stageAgentsForProfile(srcAgentsDir, resolvedProfile) {
348
412
  const stem = entry.name.slice(0, -3);
349
413
  if (!resolvedProfile.agents.has(stem))
350
414
  continue;
351
- node_fs_1.default.copyFileSync(node_path_1.default.join(srcAgentsDir, entry.name), node_path_1.default.join(stageDir, entry.name));
415
+ installFs().copyFileSync(node_path_1.default.join(srcAgentsDir, entry.name), node_path_1.default.join(stageDir, entry.name));
352
416
  }
353
417
  }
354
418
  // If agents is empty Set, we produce an empty stageDir (no agents for this profile)
355
419
  }
356
420
  catch (err) {
357
421
  try {
358
- node_fs_1.default.rmSync(stageDir, { recursive: true, force: true });
422
+ installFs().rmSync(stageDir, { recursive: true, force: true });
359
423
  }
360
424
  catch { /* best-effort */ }
361
425
  throw err;
362
426
  }
363
- STAGED_DIRS.add(stageDir);
364
- ensureExitCleanup();
427
+ registerStagedDir(stageDir);
365
428
  return stageDir;
366
429
  }
367
430
  /**
@@ -375,10 +438,10 @@ function buildNamespaceBundleMap(srcCommandsDir) {
375
438
  const routerStems = new Set();
376
439
  const routerChildren = new Map();
377
440
  const childToRouters = new Map();
378
- if (!node_fs_1.default.existsSync(srcCommandsDir)) {
441
+ if (!installFs().existsSync(srcCommandsDir)) {
379
442
  return { routerStems, routerChildren, childToRouters };
380
443
  }
381
- for (const entry of node_fs_1.default.readdirSync(srcCommandsDir, { withFileTypes: true })) {
444
+ for (const entry of installFs().readdirSync(srcCommandsDir, { withFileTypes: true })) {
382
445
  if (!entry.isFile() || !entry.name.endsWith('.md'))
383
446
  continue;
384
447
  if (!entry.name.startsWith('ns-'))
@@ -386,7 +449,7 @@ function buildNamespaceBundleMap(srcCommandsDir) {
386
449
  const stem = entry.name.slice(0, -3);
387
450
  let children = [];
388
451
  try {
389
- children = parseRequires(node_fs_1.default.readFileSync(node_path_1.default.join(srcCommandsDir, entry.name), 'utf8'));
452
+ children = parseRequires(installFs().readFileSync(node_path_1.default.join(srcCommandsDir, entry.name), 'utf8'));
390
453
  }
391
454
  catch {
392
455
  children = [];
@@ -617,7 +680,7 @@ function readInstalledCapabilitySkill(stem, registry) {
617
680
  * When absent, NOTHING third-party is staged (fail closed).
618
681
  */
619
682
  function stageSkillsForRuntimeAsSkills(srcCommandsDir, resolvedProfile, converter, prefix, nested = false, registry) {
620
- if (!node_fs_1.default.existsSync(srcCommandsDir))
683
+ if (!installFs().existsSync(srcCommandsDir))
621
684
  return srcCommandsDir;
622
685
  // Nesting applies to the `full` install AND to any surface whose skill set
623
686
  // still contains every namespace router (a full/reset surface). It must NOT
@@ -640,9 +703,9 @@ function stageSkillsForRuntimeAsSkills(srcCommandsDir, resolvedProfile, converte
640
703
  // this call, so the third-party fill-in pass below can enforce "first-party
641
704
  // ALWAYS wins on collision" without re-deriving membership.
642
705
  const firstPartyStems = new Set();
643
- const stageDir = node_fs_1.default.mkdtempSync(node_path_1.default.join(node_os_1.default.tmpdir(), 'gsd-profile-runtime-skills-'));
706
+ const stageDir = mkInstallTempDir('gsd-profile-runtime-skills-');
644
707
  try {
645
- const entries = node_fs_1.default.readdirSync(srcCommandsDir, { withFileTypes: true });
708
+ const entries = installFs().readdirSync(srcCommandsDir, { withFileTypes: true });
646
709
  for (const entry of entries) {
647
710
  if (!entry.isFile())
648
711
  continue;
@@ -652,15 +715,15 @@ function stageSkillsForRuntimeAsSkills(srcCommandsDir, resolvedProfile, converte
652
715
  if (resolvedProfile.skills !== '*' && !(resolvedProfile.skills).has(stem))
653
716
  continue;
654
717
  firstPartyStems.add(stem);
655
- const content = node_fs_1.default.readFileSync(node_path_1.default.join(srcCommandsDir, entry.name), 'utf8');
718
+ const content = installFs().readFileSync(node_path_1.default.join(srcCommandsDir, entry.name), 'utf8');
656
719
  const skillName = `${prefix}${stem}`;
657
720
  const converted = converter(content, skillName);
658
721
  if (doNest && bundles.routerStems.has(stem)) {
659
722
  // Router skill: rewrite its routing table to the nested Read pattern and
660
723
  // emit it as the single top-level bundle entry.
661
724
  const destDir = node_path_1.default.join(stageDir, skillName);
662
- node_fs_1.default.mkdirSync(destDir, { recursive: true });
663
- node_fs_1.default.writeFileSync(node_path_1.default.join(destDir, 'SKILL.md'), transformRouterBodyToNested(converted));
725
+ installFs().mkdirSync(destDir, { recursive: true });
726
+ installFs().writeFileSync(node_path_1.default.join(destDir, 'SKILL.md'), transformRouterBodyToNested(converted));
664
727
  continue;
665
728
  }
666
729
  if (doNest && bundles.childToRouters.has(stem)) {
@@ -669,16 +732,16 @@ function stageSkillsForRuntimeAsSkills(srcCommandsDir, resolvedProfile, converte
669
732
  // top-level eager listing while staying readable by file path (#69).
670
733
  for (const routerStem of bundles.childToRouters.get(stem)) {
671
734
  const destDir = node_path_1.default.join(stageDir, `${prefix}${routerStem}`, 'skills', stem);
672
- node_fs_1.default.mkdirSync(destDir, { recursive: true });
673
- node_fs_1.default.writeFileSync(node_path_1.default.join(destDir, 'SKILL.md'), converted);
735
+ installFs().mkdirSync(destDir, { recursive: true });
736
+ installFs().writeFileSync(node_path_1.default.join(destDir, 'SKILL.md'), converted);
674
737
  }
675
738
  continue;
676
739
  }
677
740
  // Flat top-level skill (default behaviour; also the unrouted fallback when
678
741
  // nesting is active).
679
742
  const destDir = node_path_1.default.join(stageDir, skillName);
680
- node_fs_1.default.mkdirSync(destDir, { recursive: true });
681
- node_fs_1.default.writeFileSync(node_path_1.default.join(destDir, 'SKILL.md'), converted);
743
+ installFs().mkdirSync(destDir, { recursive: true });
744
+ installFs().writeFileSync(node_path_1.default.join(destDir, 'SKILL.md'), converted);
682
745
  }
683
746
  // #2322: materialize installed THIRD-PARTY capability skills, bound to
684
747
  // their DECLARING capability via the registry's capabilityClusters view
@@ -720,25 +783,24 @@ function stageSkillsForRuntimeAsSkills(srcCommandsDir, resolvedProfile, converte
720
783
  if (!(0, external_descriptor_trust_cjs_1.isPathConfined)(skillName, stageDir))
721
784
  continue; // defense-in-depth
722
785
  const destDir = node_path_1.default.join(stageDir, skillName);
723
- node_fs_1.default.mkdirSync(destDir, { recursive: true });
724
- node_fs_1.default.writeFileSync(node_path_1.default.join(destDir, 'SKILL.md'), found.content);
786
+ installFs().mkdirSync(destDir, { recursive: true });
787
+ installFs().writeFileSync(node_path_1.default.join(destDir, 'SKILL.md'), found.content);
725
788
  // #2322 HIGH-3: persist the capability-owned marker so a later prune
726
789
  // pass (surface.cts pruneSkillDirs) can identify — and remove — this
727
790
  // directory even once the owning capability is uninstalled/unsurfaced
728
791
  // and no longer appears in any registry view.
729
- node_fs_1.default.writeFileSync(node_path_1.default.join(destDir, CAPABILITY_SKILL_MARKER), found.capId + '\n', 'utf8');
792
+ installFs().writeFileSync(node_path_1.default.join(destDir, CAPABILITY_SKILL_MARKER), found.capId + '\n', 'utf8');
730
793
  }
731
794
  }
732
795
  }
733
796
  catch (err) {
734
797
  try {
735
- node_fs_1.default.rmSync(stageDir, { recursive: true, force: true });
798
+ installFs().rmSync(stageDir, { recursive: true, force: true });
736
799
  }
737
800
  catch { /* best-effort */ }
738
801
  throw err;
739
802
  }
740
- STAGED_DIRS.add(stageDir);
741
- ensureExitCleanup();
803
+ registerStagedDir(stageDir);
742
804
  return stageDir;
743
805
  }
744
806
  /**
@@ -762,26 +824,57 @@ function stageSkillsForRuntimeAsSkills(srcCommandsDir, resolvedProfile, converte
762
824
  * 1. applyAgentPathRewrites (4 base ~/.claude/ regexes; skipped for copilot/antigravity)
763
825
  * 2. processAttribution (Co-Authored-By policy)
764
826
  * 3. converter (runtime-specific frontmatter/body transform)
765
- * 4. normalizeAgentBodyForRuntime (colon→hyphen refs; no-op for trivial group)
827
+ * 4. applyAgentFrontmatterExtensions (#2875 Part 2: effort/disallowedTools,
828
+ * gated by hostBehaviors.agentFrontmatterExtensions — no-op for a runtime
829
+ * that declares nothing, e.g. every non-Claude runtime today)
830
+ * 5. normalizeAgentBodyForRuntime (colon→hyphen refs; no-op for trivial group)
766
831
  * When `agentCtx` is absent, only the converter is applied (backward-compat for
767
832
  * the feat-1173 synthetic-descriptor tests and the copilot/antigravity paths
768
833
  * that handle cross-cutting inside their converters).
769
834
  *
770
835
  * @param srcAgentsDir source agents directory (e.g. agents/)
771
836
  * @param resolvedProfile profile filter from resolveProfile()
772
- * @param converter (content: string, isGlobal?: boolean) → string per-file
773
- * converter; scope-aware converters (copilot/antigravity)
774
- * read isGlobal, single-arg converters ignore it (#1173)
837
+ * @param converter (content: string, isGlobal?: boolean, meta?: {agentName: string}) → string
838
+ * per-file converter; scope-aware converters (copilot/antigravity)
839
+ * read isGlobal, single-arg converters ignore both extra args (#1173).
840
+ * `meta.agentName` (#2875 Part 2) is passed ONLY when `agentCtx` is
841
+ * present, letting a converter close over per-agent config
842
+ * (e.g. kilo/opencode model-override resolution in
843
+ * runtime-artifact-layout.cts's convertedAgentsKind) without widening
844
+ * every OTHER converter's contract — converters that don't declare a
845
+ * 3rd parameter simply never read it.
775
846
  * @param isGlobal install scope passed through to the converter
776
847
  * @param agentCtx optional cross-cutting context (ADR-1235 §1); when absent,
777
848
  * only the converter is applied (backward compat)
778
849
  */
779
850
  function stageAgentsForRuntimeWithConverter(srcAgentsDir, resolvedProfile, converter, isGlobal = false, agentCtx) {
780
- if (!node_fs_1.default.existsSync(srcAgentsDir))
851
+ if (!installFs().existsSync(srcAgentsDir))
781
852
  return srcAgentsDir;
782
- const stageDir = node_fs_1.default.mkdtempSync(node_path_1.default.join(node_os_1.default.tmpdir(), 'gsd-profile-runtime-agents-'));
853
+ const stageDir = mkInstallTempDir('gsd-profile-runtime-agents-');
854
+ let entries;
855
+ try {
856
+ // #2284/#2875: readdirSync-ing the shipped agents/ source is isolated in
857
+ // its own try/catch so an unreadable source directory (permissions, a
858
+ // corrupted install, or — as the #2284 test suite demonstrates — the
859
+ // fail-closed injection harness) produces the SAME "refusing to install"
860
+ // fail-closed wording every other agents-dir-unreadable path in this
861
+ // codebase uses (bin/install.js's `_resolveAvailableGsdRoles` /
862
+ // `_assertRoleResolvable`), instead of an unrelated raw fs error message
863
+ // escaping uncaught. Hermes's role-dispatch validation depends on the
864
+ // SAME shipped agents/ directory being readable; before this runtime also
865
+ // declared an `agents` kind, this function was never reached on a Hermes
866
+ // install, so an unreadable source here silently surfaced as a raw error
867
+ // rather than the deliberate fail-closed contract #2284 established.
868
+ entries = installFs().readdirSync(srcAgentsDir, { withFileTypes: true });
869
+ }
870
+ catch (err) {
871
+ try {
872
+ installFs().rmSync(stageDir, { recursive: true, force: true });
873
+ }
874
+ catch { /* best-effort */ }
875
+ throw new Error(`stageAgentsForRuntimeWithConverter: could not resolve the shipped agents/ directory "${srcAgentsDir}" to stage — refusing to install (fail-closed, #2284/#2875): ${err.message}`);
876
+ }
783
877
  try {
784
- const entries = node_fs_1.default.readdirSync(srcAgentsDir, { withFileTypes: true });
785
878
  // Resolve cmdNames once per staging call (not per file) for performance.
786
879
  const cmdNames = agentCtx ? _readGsdCommandNames() : [];
787
880
  for (const entry of entries) {
@@ -796,34 +889,45 @@ function stageAgentsForRuntimeWithConverter(srcAgentsDir, resolvedProfile, conve
796
889
  continue;
797
890
  }
798
891
  }
799
- let content = node_fs_1.default.readFileSync(node_path_1.default.join(srcAgentsDir, entry.name), 'utf8');
892
+ const agentSourcePath = node_path_1.default.join(srcAgentsDir, entry.name);
893
+ let content = installFs().readFileSync(agentSourcePath, 'utf8');
894
+ // #2995: strip gsd:section markers FIRST — before path rewrites, attribution,
895
+ // and the per-runtime converter. Byte-identical (no-op) for an unmarked agent;
896
+ // throws loudly naming the file for a malformed marker, never emitting a
897
+ // half-composed agent.
898
+ content = _composeWorkflow(content, { sourcePath: agentSourcePath });
800
899
  if (agentCtx) {
900
+ // #2875 Part 2 / row I3: derived exactly as the inline loop does —
901
+ // single-sourced via deriveAgentName (runtime-artifact-conversion.cts).
902
+ const agentName = _deriveAgentName(entry.name);
801
903
  // ADR-1235 §1: pre-converter cross-cutting (matches inline loop order exactly)
802
904
  // Step 1: path rewrites (4 base ~/.claude/ regexes; skipped for copilot/antigravity)
803
905
  content = _applyAgentPathRewrites(content, agentCtx.runtime, agentCtx.pathPrefix);
804
906
  // Step 2: attribution
805
907
  content = _processAttribution(content, agentCtx.attribution);
806
908
  // Step 3: converter (runtime-specific frontmatter/body transform)
807
- content = converter(content, isGlobal);
808
- // Step 4: normalize colon→hyphen refs (no-op for trivial group)
909
+ content = converter(content, isGlobal, { agentName });
910
+ // Step 4: frontmatter extensions (effort/disallowedTools; no-op unless
911
+ // the runtime declares hostBehaviors.agentFrontmatterExtensions)
912
+ content = _applyAgentFrontmatterExtensions(content, { runtime: agentCtx.runtime, agentName, targetDir: agentCtx.targetDir });
913
+ // Step 5: normalize colon→hyphen refs (no-op for trivial group)
809
914
  content = _normalizeAgentBodyForRuntime(content, agentCtx.runtime, cmdNames);
810
915
  }
811
916
  else {
812
917
  // Backward-compat: only apply the converter (no cross-cutting)
813
918
  content = converter(content, isGlobal);
814
919
  }
815
- node_fs_1.default.writeFileSync(node_path_1.default.join(stageDir, entry.name), content, 'utf8');
920
+ installFs().writeFileSync(node_path_1.default.join(stageDir, entry.name), content, 'utf8');
816
921
  }
817
922
  }
818
923
  catch (err) {
819
924
  try {
820
- node_fs_1.default.rmSync(stageDir, { recursive: true, force: true });
925
+ installFs().rmSync(stageDir, { recursive: true, force: true });
821
926
  }
822
927
  catch { /* best-effort */ }
823
928
  throw err;
824
929
  }
825
- STAGED_DIRS.add(stageDir);
826
- ensureExitCleanup();
930
+ registerStagedDir(stageDir);
827
931
  return stageDir;
828
932
  }
829
933
  /**
@@ -850,11 +954,11 @@ function stageAgentsForRuntimeWithConverter(srcAgentsDir, resolvedProfile, conve
850
954
  * @param prefix command name prefix (for converter arg), e.g. 'gsd-'
851
955
  */
852
956
  function stageCommandsForRuntimeFlat(srcCommandsDir, resolvedProfile, converter, prefix) {
853
- if (!node_fs_1.default.existsSync(srcCommandsDir))
957
+ if (!installFs().existsSync(srcCommandsDir))
854
958
  return srcCommandsDir;
855
- const stageDir = node_fs_1.default.mkdtempSync(node_path_1.default.join(node_os_1.default.tmpdir(), 'gsd-profile-runtime-commands-'));
959
+ const stageDir = mkInstallTempDir('gsd-profile-runtime-commands-');
856
960
  try {
857
- const entries = node_fs_1.default.readdirSync(srcCommandsDir, { withFileTypes: true });
961
+ const entries = installFs().readdirSync(srcCommandsDir, { withFileTypes: true });
858
962
  for (const entry of entries) {
859
963
  if (!entry.isFile())
860
964
  continue;
@@ -863,24 +967,23 @@ function stageCommandsForRuntimeFlat(srcCommandsDir, resolvedProfile, converter,
863
967
  const stem = entry.name.slice(0, -3);
864
968
  if (resolvedProfile.skills !== '*' && !(resolvedProfile.skills).has(stem))
865
969
  continue;
866
- const content = node_fs_1.default.readFileSync(node_path_1.default.join(srcCommandsDir, entry.name), 'utf8');
970
+ const content = installFs().readFileSync(node_path_1.default.join(srcCommandsDir, entry.name), 'utf8');
867
971
  // Pass the full command name (with prefix) to the converter so it can
868
972
  // reference the installed command name in the body (e.g. for descriptions).
869
973
  // The staged file itself is named without the prefix; _copyStaged adds it.
870
974
  const commandName = `${prefix}${stem}`;
871
975
  const converted = converter(content, commandName);
872
- node_fs_1.default.writeFileSync(node_path_1.default.join(stageDir, `${stem}.md`), converted);
976
+ installFs().writeFileSync(node_path_1.default.join(stageDir, `${stem}.md`), converted);
873
977
  }
874
978
  }
875
979
  catch (err) {
876
980
  try {
877
- node_fs_1.default.rmSync(stageDir, { recursive: true, force: true });
981
+ installFs().rmSync(stageDir, { recursive: true, force: true });
878
982
  }
879
983
  catch { /* best-effort */ }
880
984
  throw err;
881
985
  }
882
- STAGED_DIRS.add(stageDir);
883
- ensureExitCleanup();
986
+ registerStagedDir(stageDir);
884
987
  return stageDir;
885
988
  }
886
989
  // ---------------------------------------------------------------------------