@opengsd/gsd-core 1.12.0 → 1.14.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 (455) 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-advisor-researcher.compact.md +85 -0
  5. package/agents/gsd-ai-researcher.compact.md +96 -0
  6. package/agents/gsd-assumptions-analyzer.compact.md +81 -0
  7. package/agents/gsd-code-fixer.compact.md +458 -0
  8. package/agents/gsd-code-fixer.md +5 -5
  9. package/agents/gsd-code-reviewer.compact.md +269 -0
  10. package/agents/gsd-code-reviewer.md +15 -3
  11. package/agents/gsd-codebase-mapper.compact.md +760 -0
  12. package/agents/gsd-debug-session-manager.compact.md +345 -0
  13. package/agents/gsd-doc-classifier.compact.md +192 -0
  14. package/agents/gsd-doc-synthesizer.compact.md +200 -0
  15. package/agents/gsd-doc-verifier.compact.md +143 -0
  16. package/agents/gsd-doc-writer.compact.md +440 -0
  17. package/agents/gsd-dom-verifier.compact.md +138 -0
  18. package/agents/gsd-domain-researcher.compact.md +141 -0
  19. package/agents/gsd-eval-auditor.compact.md +160 -0
  20. package/agents/gsd-eval-planner.compact.md +137 -0
  21. package/agents/gsd-executor.md +63 -35
  22. package/agents/gsd-framework-selector.compact.md +82 -0
  23. package/agents/gsd-integration-checker.compact.md +245 -0
  24. package/agents/gsd-intel-updater.compact.md +226 -0
  25. package/agents/gsd-mempalace-curator.compact.md +45 -0
  26. package/agents/gsd-nyquist-auditor.compact.md +179 -0
  27. package/agents/gsd-pattern-mapper.compact.md +275 -0
  28. package/agents/gsd-plan-checker.md +76 -57
  29. package/agents/gsd-planner.md +14 -0
  30. package/agents/gsd-project-researcher.compact.md +587 -0
  31. package/agents/gsd-research-synthesizer.compact.md +212 -0
  32. package/agents/gsd-roadmapper.compact.md +454 -0
  33. package/agents/gsd-roadmapper.md +13 -0
  34. package/agents/gsd-security-auditor.compact.md +162 -0
  35. package/agents/gsd-ui-auditor.compact.md +404 -0
  36. package/agents/gsd-ui-checker.compact.md +277 -0
  37. package/agents/gsd-ui-checker.md +19 -3
  38. package/agents/gsd-ui-researcher.compact.md +282 -0
  39. package/agents/gsd-ui-researcher.md +29 -0
  40. package/agents/gsd-user-profiler.compact.md +108 -0
  41. package/agents/gsd-verifier.md +23 -1
  42. package/bin/install.js +444 -134
  43. package/commands/gsd/cleanup.md +1 -0
  44. package/commands/gsd/code-review.md +2 -1
  45. package/commands/gsd/complete-milestone.md +1 -0
  46. package/commands/gsd/config.md +1 -0
  47. package/commands/gsd/debug.md +1 -0
  48. package/commands/gsd/execute-phase.md +1 -1
  49. package/commands/gsd/graphify.md +1 -0
  50. package/commands/gsd/health.md +1 -0
  51. package/commands/gsd/mempalace-capture.md +1 -0
  52. package/commands/gsd/mempalace-recall.md +1 -0
  53. package/commands/gsd/new-milestone.md +1 -0
  54. package/commands/gsd/new-project.md +1 -0
  55. package/commands/gsd/next.md +1 -0
  56. package/commands/gsd/ns-workflow.md +2 -1
  57. package/commands/gsd/pause-work.md +1 -0
  58. package/commands/gsd/phase.md +2 -1
  59. package/commands/gsd/pr-branch.md +1 -0
  60. package/commands/gsd/quick-batch.md +105 -0
  61. package/commands/gsd/resume-work.md +1 -0
  62. package/commands/gsd/review-backlog.md +1 -0
  63. package/commands/gsd/settings.md +2 -1
  64. package/commands/gsd/stats.md +1 -0
  65. package/commands/gsd/surface.md +18 -8
  66. package/commands/gsd/thread.md +1 -0
  67. package/commands/gsd/workspace.md +1 -0
  68. package/commands/gsd/workstreams.md +1 -0
  69. package/gsd-core/bin/check-latest-version.cjs +8 -3
  70. package/gsd-core/bin/gsd-tools.cjs +532 -174
  71. package/gsd-core/bin/lib/adr-parser.cjs +1 -1
  72. package/gsd-core/bin/lib/artifacts.cjs +2 -1
  73. package/gsd-core/bin/lib/audit.cjs +39 -22
  74. package/gsd-core/bin/lib/broken-windows.cjs +168 -49
  75. package/gsd-core/bin/lib/capability-activation.cjs +27 -0
  76. package/gsd-core/bin/lib/capability-lifecycle.cjs +10 -6
  77. package/gsd-core/bin/lib/capability-loader.cjs +135 -1
  78. package/gsd-core/bin/lib/capability-registry.cjs +528 -116
  79. package/gsd-core/bin/lib/capability-source.cjs +19 -2
  80. package/gsd-core/bin/lib/capability-state.cjs +7 -1
  81. package/gsd-core/bin/lib/capability-validator.cjs +134 -5
  82. package/gsd-core/bin/lib/capability-writer.cjs +14 -4
  83. package/gsd-core/bin/lib/check-command-router.cjs +198 -38
  84. package/gsd-core/bin/lib/claude-orchestration.cjs +10 -25
  85. package/gsd-core/bin/lib/clusters.cjs +1 -0
  86. package/gsd-core/bin/lib/code-review-depth.cjs +2 -2
  87. package/gsd-core/bin/lib/command-aliases.cjs +16 -0
  88. package/gsd-core/bin/lib/commands.cjs +981 -79
  89. package/gsd-core/bin/lib/config-loader.cjs +4 -0
  90. package/gsd-core/bin/lib/config.cjs +153 -38
  91. package/gsd-core/bin/lib/core-utils.cjs +34 -7
  92. package/gsd-core/bin/lib/coverage.cjs +1 -1
  93. package/gsd-core/bin/lib/decisions.cjs +343 -28
  94. package/gsd-core/bin/lib/edge-probe.cjs +14 -1
  95. package/gsd-core/bin/lib/external-descriptor-trust.cjs +29 -14
  96. package/gsd-core/bin/lib/file-overlap-partitioner.cjs +74 -0
  97. package/gsd-core/bin/lib/frontmatter.cjs +137 -23
  98. package/gsd-core/bin/lib/gap-checker.cjs +22 -13
  99. package/gsd-core/bin/lib/git-base-branch.cjs +10 -2
  100. package/gsd-core/bin/lib/gsd2-import.cjs +1 -2
  101. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +8 -2
  102. package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +54 -11
  103. package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +87 -23
  104. package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +1 -1
  105. package/gsd-core/bin/lib/host-integration.cjs +57 -5
  106. package/gsd-core/bin/lib/init-command-router.cjs +14 -0
  107. package/gsd-core/bin/lib/init.cjs +539 -60
  108. package/gsd-core/bin/lib/install-engine.cjs +199 -14
  109. package/gsd-core/bin/lib/install-model-override-resolver.cjs +45 -0
  110. package/gsd-core/bin/lib/install-profiles.cjs +36 -14
  111. package/gsd-core/bin/lib/installer-migration-report.cjs +1 -0
  112. package/gsd-core/bin/lib/installer-migrations.cjs +33 -4
  113. package/gsd-core/bin/lib/io.cjs +35 -0
  114. package/gsd-core/bin/lib/loop-resolver.cjs +64 -39
  115. package/gsd-core/bin/lib/markdown-table.cjs +123 -0
  116. package/gsd-core/bin/lib/mcp-catalog.cjs +2 -2
  117. package/gsd-core/bin/lib/milestone.cjs +41 -10
  118. package/gsd-core/bin/lib/model-resolver.cjs +101 -10
  119. package/gsd-core/bin/lib/phase-command-router.cjs +20 -7
  120. package/gsd-core/bin/lib/phase-id.cjs +412 -31
  121. package/gsd-core/bin/lib/phase-lifecycle.cjs +61 -0
  122. package/gsd-core/bin/lib/phase.cjs +941 -98
  123. package/gsd-core/bin/lib/plan-document.cjs +10 -0
  124. package/gsd-core/bin/lib/planning-inspect.cjs +34 -18
  125. package/gsd-core/bin/lib/planning-snapshot.cjs +206 -30
  126. package/gsd-core/bin/lib/planning-workspace.cjs +153 -29
  127. package/gsd-core/bin/lib/pristine-baseline.cjs +182 -0
  128. package/gsd-core/bin/lib/prohibition-enforcement.cjs +91 -4
  129. package/gsd-core/bin/lib/quick-batch-command-router.cjs +285 -0
  130. package/gsd-core/bin/lib/quick-batch-dispatch.cjs +250 -0
  131. package/gsd-core/bin/lib/quick-batch.cjs +840 -0
  132. package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +61 -2
  133. package/gsd-core/bin/lib/research-store.cjs +11 -12
  134. package/gsd-core/bin/lib/review-lane-descriptor.cjs +53 -5
  135. package/gsd-core/bin/lib/review-lane-invocation.cjs +96 -1
  136. package/gsd-core/bin/lib/review-lane-runner.cjs +136 -10
  137. package/gsd-core/bin/lib/reviewer-step-dispatch.cjs +337 -0
  138. package/gsd-core/bin/lib/roadmap-parser.cjs +555 -41
  139. package/gsd-core/bin/lib/roadmap.cjs +292 -69
  140. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +260 -43
  141. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +28 -20
  142. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +294 -108
  143. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +408 -47
  144. package/gsd-core/bin/lib/security.cjs +126 -7
  145. package/gsd-core/bin/lib/shell-command-projection.cjs +4 -0
  146. package/gsd-core/bin/lib/smart-entry.cjs +7 -9
  147. package/gsd-core/bin/lib/state-document.cjs +159 -32
  148. package/gsd-core/bin/lib/state-md-schema.cjs +44 -27
  149. package/gsd-core/bin/lib/state-transition.cjs +465 -62
  150. package/gsd-core/bin/lib/state.cjs +906 -151
  151. package/gsd-core/bin/lib/surface.cjs +83 -10
  152. package/gsd-core/bin/lib/task-command-router.cjs +12 -6
  153. package/gsd-core/bin/lib/tdd-red-evidence.cjs +133 -0
  154. package/gsd-core/bin/lib/uat.cjs +1420 -516
  155. package/gsd-core/bin/lib/update-context.cjs +36 -26
  156. package/gsd-core/bin/lib/validate.cjs +230 -12
  157. package/gsd-core/bin/lib/vendor/js-yaml.cjs +11 -3
  158. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  159. package/gsd-core/bin/lib/verification.cjs +316 -23
  160. package/gsd-core/bin/lib/verify-command-grounding.cjs +1 -1
  161. package/gsd-core/bin/lib/verify-command-router.cjs +1 -0
  162. package/gsd-core/bin/lib/verify.cjs +531 -36
  163. package/gsd-core/bin/lib/workstream-inventory.cjs +21 -2
  164. package/gsd-core/bin/lib/worktree-safety.cjs +21 -7
  165. package/gsd-core/bin/shared/config-defaults.manifest.json +1 -0
  166. package/gsd-core/bin/shared/config-schema.manifest.json +13 -0
  167. package/gsd-core/bin/verify-reapply-patches.cjs +507 -81
  168. package/gsd-core/references/agent-contracts.md +3 -3
  169. package/gsd-core/references/compact-content-gate.md +66 -0
  170. package/gsd-core/references/edge-probe.md +17 -13
  171. package/gsd-core/references/execute-mvp-tdd.md +18 -16
  172. package/gsd-core/references/execute-phase-response-language.md +6 -0
  173. package/gsd-core/references/executor-examples.md +42 -0
  174. package/gsd-core/references/few-shot-examples/plan-checker.md +15 -15
  175. package/gsd-core/references/loop-hook-dispatch.md +18 -0
  176. package/gsd-core/references/model-profiles.md +12 -3
  177. package/gsd-core/references/mvp-concepts.md +2 -2
  178. package/gsd-core/references/plan-checker-examples.md +41 -0
  179. package/gsd-core/references/planner-antipatterns.md +25 -0
  180. package/gsd-core/references/planner-chunked.md +5 -1
  181. package/gsd-core/references/planner-coupling.md +42 -0
  182. package/gsd-core/references/planner-quick-batch.md +71 -0
  183. package/gsd-core/references/planner-reviews.md +47 -0
  184. package/gsd-core/references/planner-revision.md +75 -2
  185. package/gsd-core/references/planning-config.md +5 -1
  186. package/gsd-core/references/response-language-directive.md +9 -0
  187. package/gsd-core/references/revision-loop.md +118 -11
  188. package/gsd-core/references/tdd.md +17 -9
  189. package/gsd-core/references/thinking-models-planning.md +18 -2
  190. package/gsd-core/references/verification-patterns.md +17 -4
  191. package/gsd-core/references/verifier-evidence-gate.md +160 -0
  192. package/gsd-core/references/worktree-path-safety.md +112 -2
  193. package/gsd-core/templates/README.md +7 -1
  194. package/gsd-core/templates/phase-prompt.md +4 -0
  195. package/gsd-core/templates/state.md +6 -3
  196. package/gsd-core/templates/summary.compact.md +212 -0
  197. package/gsd-core/templates/user-setup.compact.md +199 -0
  198. package/gsd-core/templates/user-setup.md +0 -9
  199. package/gsd-core/templates/verification-report.md +5 -0
  200. package/gsd-core/workflows/add-backlog.md +2 -0
  201. package/gsd-core/workflows/add-phase.md +2 -0
  202. package/gsd-core/workflows/add-tests.md +1 -1
  203. package/gsd-core/workflows/add-todo.md +4 -3
  204. package/gsd-core/workflows/ai-integration-phase.md +1 -1
  205. package/gsd-core/workflows/analyze-dependencies.md +2 -0
  206. package/gsd-core/workflows/audit-fix.md +2 -0
  207. package/gsd-core/workflows/audit-milestone.md +2 -0
  208. package/gsd-core/workflows/audit-uat.md +2 -0
  209. package/gsd-core/workflows/autonomous.md +15 -10
  210. package/gsd-core/workflows/check-todos.md +5 -3
  211. package/gsd-core/workflows/cleanup.md +4 -2
  212. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +22 -13
  213. package/gsd-core/workflows/code-review-fix.md +5 -3
  214. package/gsd-core/workflows/code-review.md +211 -43
  215. package/gsd-core/workflows/complete-milestone/detail/elaboration.md +274 -0
  216. package/gsd-core/workflows/complete-milestone.md +40 -254
  217. package/gsd-core/workflows/debug.md +1 -1
  218. package/gsd-core/workflows/diagnose-issues.md +5 -1
  219. package/gsd-core/workflows/discuss-phase/modes/advisor.md +2 -0
  220. package/gsd-core/workflows/discuss-phase/modes/all.md +2 -0
  221. package/gsd-core/workflows/discuss-phase/modes/analyze.md +2 -0
  222. package/gsd-core/workflows/discuss-phase/modes/auto.md +2 -0
  223. package/gsd-core/workflows/discuss-phase/modes/batch.md +2 -0
  224. package/gsd-core/workflows/discuss-phase/modes/chain.md +2 -0
  225. package/gsd-core/workflows/discuss-phase/modes/default.md +2 -0
  226. package/gsd-core/workflows/discuss-phase/modes/power.md +2 -0
  227. package/gsd-core/workflows/discuss-phase/modes/text.md +2 -0
  228. package/gsd-core/workflows/discuss-phase/templates/context.md +2 -0
  229. package/gsd-core/workflows/discuss-phase/templates/discussion-log.md +2 -0
  230. package/gsd-core/workflows/discuss-phase-assumptions.md +1 -1
  231. package/gsd-core/workflows/discuss-phase-power.md +2 -0
  232. package/gsd-core/workflows/discuss-phase.md +1 -1
  233. package/gsd-core/workflows/do.md +43 -13
  234. package/gsd-core/workflows/docs-update/detail/elaboration.md +179 -0
  235. package/gsd-core/workflows/docs-update.md +15 -156
  236. package/gsd-core/workflows/edit-phase.md +2 -0
  237. package/gsd-core/workflows/eval-review.md +1 -1
  238. package/gsd-core/workflows/execute-phase/detail/elaboration.md +124 -0
  239. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +20 -3
  240. package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +56 -0
  241. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +24 -3
  242. package/gsd-core/workflows/execute-phase/steps/executor-progress-policy.md +43 -0
  243. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +8 -2
  244. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +2 -0
  245. package/gsd-core/workflows/execute-phase/steps/sequential-root-pin.md +35 -0
  246. package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +25 -0
  247. package/gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md +2 -0
  248. package/gsd-core/workflows/execute-phase.md +78 -159
  249. package/gsd-core/workflows/execute-plan.md +28 -15
  250. package/gsd-core/workflows/explore.md +2 -0
  251. package/gsd-core/workflows/extract-learnings.md +2 -0
  252. package/gsd-core/workflows/fast.md +6 -0
  253. package/gsd-core/workflows/forensics.md +2 -0
  254. package/gsd-core/workflows/graduation.md +1 -1
  255. package/gsd-core/workflows/health.md +1 -1
  256. package/gsd-core/workflows/help/modes/brief.md +2 -0
  257. package/gsd-core/workflows/help/modes/default.md +2 -0
  258. package/gsd-core/workflows/help/modes/full.compact.md +398 -0
  259. package/gsd-core/workflows/help/modes/full.md +12 -0
  260. package/gsd-core/workflows/help/modes/topic.md +2 -0
  261. package/gsd-core/workflows/help.md +3 -1
  262. package/gsd-core/workflows/import.md +3 -3
  263. package/gsd-core/workflows/inbox.md +1 -1
  264. package/gsd-core/workflows/ingest-docs.md +1 -1
  265. package/gsd-core/workflows/insert-phase.md +2 -0
  266. package/gsd-core/workflows/list-phase-assumptions.md +2 -0
  267. package/gsd-core/workflows/list-seeds.md +2 -0
  268. package/gsd-core/workflows/list-workspaces.md +2 -0
  269. package/gsd-core/workflows/manager.md +3 -3
  270. package/gsd-core/workflows/map-codebase.md +52 -3
  271. package/gsd-core/workflows/milestone-summary.md +2 -0
  272. package/gsd-core/workflows/mvp-phase.md +1 -1
  273. package/gsd-core/workflows/new-milestone.md +55 -13
  274. package/gsd-core/workflows/new-project/detail/elaboration.md +216 -0
  275. package/gsd-core/workflows/new-project.md +37 -205
  276. package/gsd-core/workflows/new-workspace.md +1 -1
  277. package/gsd-core/workflows/next.md +2 -0
  278. package/gsd-core/workflows/node-repair.md +2 -0
  279. package/gsd-core/workflows/note.md +2 -0
  280. package/gsd-core/workflows/onboard.md +1 -1
  281. package/gsd-core/workflows/pause-work.md +19 -4
  282. package/gsd-core/workflows/plan-phase/detail/elaboration.md +209 -0
  283. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +100 -18
  284. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +2 -0
  285. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +9 -0
  286. package/gsd-core/workflows/plan-phase.md +144 -185
  287. package/gsd-core/workflows/plan-review-convergence.md +102 -10
  288. package/gsd-core/workflows/plant-seed.md +1 -1
  289. package/gsd-core/workflows/pr-branch.md +30 -10
  290. package/gsd-core/workflows/profile-user.md +1 -1
  291. package/gsd-core/workflows/progress/steps/forensic-audit.md +1 -1
  292. package/gsd-core/workflows/progress.md +25 -3
  293. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +37 -2
  294. package/gsd-core/workflows/quick/steps/research-phase.md +3 -3
  295. package/gsd-core/workflows/quick-batch/steps/batch-init.md +55 -0
  296. package/gsd-core/workflows/quick-batch/steps/completion.md +65 -0
  297. package/gsd-core/workflows/quick-batch/steps/merge-wave.md +100 -0
  298. package/gsd-core/workflows/quick-batch/steps/plan-checker-loop.md +147 -0
  299. package/gsd-core/workflows/quick-batch/steps/planner-wave.md +158 -0
  300. package/gsd-core/workflows/quick-batch/steps/research-phase.md +95 -0
  301. package/gsd-core/workflows/quick-batch/steps/resume-mode.md +49 -0
  302. package/gsd-core/workflows/quick-batch/steps/verification-wave.md +73 -0
  303. package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +169 -0
  304. package/gsd-core/workflows/quick-batch.md +203 -0
  305. package/gsd-core/workflows/quick.md +21 -4
  306. package/gsd-core/workflows/reapply-patches.md +79 -3
  307. package/gsd-core/workflows/remove-phase.md +2 -0
  308. package/gsd-core/workflows/remove-workspace.md +1 -1
  309. package/gsd-core/workflows/resume-project.md +6 -2
  310. package/gsd-core/workflows/review.md +215 -10
  311. package/gsd-core/workflows/scan.md +2 -0
  312. package/gsd-core/workflows/section-manifest.json +12 -0
  313. package/gsd-core/workflows/secure-phase.md +1 -1
  314. package/gsd-core/workflows/session-report.md +2 -0
  315. package/gsd-core/workflows/settings-advanced.md +2 -0
  316. package/gsd-core/workflows/settings-integrations.md +9 -8
  317. package/gsd-core/workflows/settings.md +19 -6
  318. package/gsd-core/workflows/ship.md +10 -10
  319. package/gsd-core/workflows/sketch-wrap-up.md +2 -0
  320. package/gsd-core/workflows/sketch.md +1 -1
  321. package/gsd-core/workflows/smart-entry.md +1 -1
  322. package/gsd-core/workflows/spec-phase.md +24 -19
  323. package/gsd-core/workflows/spike-wrap-up.md +2 -0
  324. package/gsd-core/workflows/spike.md +1 -1
  325. package/gsd-core/workflows/stats.md +2 -0
  326. package/gsd-core/workflows/sync-skills.md +12 -4
  327. package/gsd-core/workflows/thread.md +2 -0
  328. package/gsd-core/workflows/transition.md +2 -0
  329. package/gsd-core/workflows/ui-phase.md +26 -5
  330. package/gsd-core/workflows/ui-review.md +1 -1
  331. package/gsd-core/workflows/ultraplan-phase.md +2 -0
  332. package/gsd-core/workflows/undo.md +1 -1
  333. package/gsd-core/workflows/update.md +48 -43
  334. package/gsd-core/workflows/validate-phase.md +1 -1
  335. package/gsd-core/workflows/verify-work/detail/elaboration.md +230 -0
  336. package/gsd-core/workflows/verify-work.md +68 -182
  337. package/hooks/dist/gsd-agent-isolation-guard.js +42 -16
  338. package/hooks/dist/gsd-check-update-worker.js +19 -2
  339. package/hooks/dist/gsd-context-monitor.js +371 -27
  340. package/hooks/dist/gsd-cursor-subagent-start.js +34 -14
  341. package/hooks/dist/gsd-node-runner.sh +1 -0
  342. package/hooks/dist/gsd-prompt-guard.js +30 -5
  343. package/hooks/dist/gsd-read-guard.js +2 -0
  344. package/hooks/dist/gsd-read-injection-scanner.js +5 -5
  345. package/hooks/dist/gsd-secret-read-guard.js +1105 -0
  346. package/hooks/dist/gsd-statusline.js +18 -10
  347. package/hooks/dist/gsd-validate-commit.sh +474 -7
  348. package/hooks/dist/gsd-workflow-guard.js +2 -1
  349. package/hooks/dist/gsd-worktree-path-guard.js +25 -14
  350. package/hooks/dist/gsd-write-guard.js +46 -1
  351. package/hooks/dist/lib/dispatch-identity.js +187 -0
  352. package/hooks/dist/lib/filename-classification.js +64 -0
  353. package/hooks/dist/lib/git-cmd.js +210 -1
  354. package/hooks/dist/lib/injection-patterns.js +36 -6
  355. package/hooks/dist/lib/isolation-deny-reason.js +53 -1
  356. package/hooks/dist/lib/isolation-sentinel.js +58 -19
  357. package/hooks/dist/managed-hooks-registry.cjs +1 -0
  358. package/hooks/gsd-agent-isolation-guard.js +42 -16
  359. package/hooks/gsd-check-update-worker.js +19 -2
  360. package/hooks/gsd-context-monitor.js +371 -27
  361. package/hooks/gsd-cursor-subagent-start.js +34 -14
  362. package/hooks/gsd-node-runner.sh +1 -0
  363. package/hooks/gsd-prompt-guard.js +30 -5
  364. package/hooks/gsd-read-guard.js +2 -0
  365. package/hooks/gsd-read-injection-scanner.js +5 -5
  366. package/hooks/gsd-secret-read-guard.js +1105 -0
  367. package/hooks/gsd-statusline.js +18 -10
  368. package/hooks/gsd-validate-commit.sh +474 -7
  369. package/hooks/gsd-workflow-guard.js +2 -1
  370. package/hooks/gsd-worktree-path-guard.js +25 -14
  371. package/hooks/gsd-write-guard.js +46 -1
  372. package/hooks/hooks.json +6 -0
  373. package/hooks/lib/dispatch-identity.js +187 -0
  374. package/hooks/lib/filename-classification.js +64 -0
  375. package/hooks/lib/git-cmd.js +210 -1
  376. package/hooks/lib/injection-patterns.js +36 -6
  377. package/hooks/lib/isolation-deny-reason.js +53 -1
  378. package/hooks/lib/isolation-sentinel.js +58 -19
  379. package/hooks/managed-hooks-registry.cjs +1 -0
  380. package/package.json +13 -9
  381. package/scripts/benchmark-compact-content-variants.cjs +298 -0
  382. package/scripts/benchmark-compact-content.cjs +368 -0
  383. package/scripts/build-hooks.js +11 -4
  384. package/scripts/check-contract-drift.cjs +4 -1
  385. package/scripts/check-env.cjs +36 -8
  386. package/scripts/check-glossary-refs.cjs +25 -21
  387. package/scripts/ci-next-health.cjs +271 -0
  388. package/scripts/ci-prepare-test-scope.cjs +7 -7
  389. package/scripts/ci-test-scope.cjs +133 -20
  390. package/scripts/ci-timeout-report.cjs +1 -1
  391. package/scripts/diff-touches-shipped-paths.cjs +1 -1
  392. package/scripts/docs-guard-registry.cjs +17 -2
  393. package/scripts/gen-adr-index.cjs +8 -2
  394. package/scripts/gen-inventory-manifest.cjs +12 -0
  395. package/scripts/gen-loop-host-contract.cjs +67 -15
  396. package/scripts/gen-platform-conformance-tier.cjs +557 -0
  397. package/scripts/lib/drift-scan.cjs +1 -1
  398. package/scripts/lib/macos-conformance-tier.generated.cjs +210 -0
  399. package/scripts/lib/npm-version-check-diagnosis.cjs +59 -0
  400. package/scripts/lib/platform-conformance-tier.generated.cjs +276 -0
  401. package/scripts/lib/shellcheck-fetch.cjs +247 -0
  402. package/scripts/lib/suite-detection.cjs +32 -0
  403. package/scripts/lint-allow-test-rule-refs.allowlist.json +0 -6
  404. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +1 -1
  405. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
  406. package/scripts/lint-allowed-tools-parity.cjs +221 -0
  407. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +24 -2
  408. package/scripts/lint-phase-enumeration-drift.cjs +24 -6
  409. package/scripts/lint-phase-id-drift.cjs +465 -15
  410. package/scripts/lint-portable-grep.cjs +176 -0
  411. package/scripts/lint-response-language-coverage.cjs +530 -0
  412. package/scripts/lint-source-test-name-collision.cjs +1 -1
  413. package/scripts/lint-test-file-count.allowlist.json +4 -1
  414. package/scripts/lint-vendored-deps.cjs +128 -17
  415. package/scripts/lint-workflow-shellcheck-baseline.json +1112 -0
  416. package/scripts/lint-workflow-shellcheck.cjs +614 -0
  417. package/scripts/npm-audit-baseline.cjs +376 -0
  418. package/scripts/prompt-injection-scan.sh +22 -0
  419. package/scripts/require-issue-link-policy.cjs +16 -1
  420. package/scripts/workflow-size.cjs +139 -0
  421. package/skills/gsd-cleanup/SKILL.md +1 -0
  422. package/skills/gsd-code-review/SKILL.md +2 -1
  423. package/skills/gsd-complete-milestone/SKILL.md +1 -0
  424. package/skills/gsd-config/SKILL.md +1 -0
  425. package/skills/gsd-debug/SKILL.md +1 -0
  426. package/skills/gsd-execute-phase/SKILL.md +1 -1
  427. package/skills/gsd-graphify/SKILL.md +1 -0
  428. package/skills/gsd-health/SKILL.md +1 -0
  429. package/skills/gsd-mempalace-capture/SKILL.md +1 -0
  430. package/skills/gsd-mempalace-recall/SKILL.md +1 -0
  431. package/skills/gsd-new-milestone/SKILL.md +1 -0
  432. package/skills/gsd-new-project/SKILL.md +1 -0
  433. package/skills/gsd-next/SKILL.md +1 -0
  434. package/skills/gsd-ns-workflow/SKILL.md +1 -0
  435. package/skills/gsd-pause-work/SKILL.md +1 -0
  436. package/skills/gsd-phase/SKILL.md +2 -1
  437. package/skills/gsd-pr-branch/SKILL.md +1 -0
  438. package/skills/gsd-quick-batch/SKILL.md +105 -0
  439. package/skills/gsd-resume-work/SKILL.md +1 -0
  440. package/skills/gsd-review-backlog/SKILL.md +1 -0
  441. package/skills/gsd-settings/SKILL.md +2 -1
  442. package/skills/gsd-stats/SKILL.md +1 -0
  443. package/skills/gsd-surface/SKILL.md +18 -8
  444. package/skills/gsd-thread/SKILL.md +1 -0
  445. package/skills/gsd-workspace/SKILL.md +1 -0
  446. package/skills/gsd-workstreams/SKILL.md +1 -0
  447. package/vscode/package.json +1 -1
  448. package/gsd-core/templates/claude-md.md +0 -145
  449. package/gsd-core/templates/codebase/concerns.md +0 -310
  450. package/gsd-core/templates/codebase/conventions.md +0 -307
  451. package/gsd-core/templates/codebase/integrations.md +0 -280
  452. package/gsd-core/templates/codebase/structure.md +0 -285
  453. package/gsd-core/templates/codebase/testing.md +0 -480
  454. package/gsd-core/templates/debug-subagent-prompt.md +0 -91
  455. package/gsd-core/templates/discovery.md +0 -146
@@ -276,8 +276,22 @@ const kiloAgentPermissionOrder = [
276
276
  'codesearch',
277
277
  'lsp',
278
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
+ */
279
289
  function convertClaudeToKiloPermissionTool(claudeTool) {
280
- 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;
281
295
  }
282
296
  function buildKiloAgentPermissionBlock(claudeTools) {
283
297
  const allowedPermissions = new Set();
@@ -291,6 +305,11 @@ function buildKiloAgentPermissionBlock(claudeTools) {
291
305
  for (const permission of kiloAgentPermissionOrder) {
292
306
  lines.push(` ${permission}: ${allowedPermissions.has(permission) ? 'allow' : 'deny'}`);
293
307
  }
308
+ for (const permission of allowedPermissions) {
309
+ if (kiloAgentPermissionOrder.includes(permission))
310
+ continue;
311
+ lines.push(` ${permission}: allow`);
312
+ }
294
313
  return lines;
295
314
  }
296
315
  function replaceRelativePathReference(content, fromPath, toPath) {
@@ -645,6 +664,137 @@ function convertClaudeCommandToKimiCodeSkill(content, skillName, _runtime = null
645
664
  return convertClaudeCommandToKimiSkill(content, skillName, _runtime, cmdNames);
646
665
  }
647
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
+ }
648
798
  function parseKimiAgentSource(source) {
649
799
  if (typeof source === 'string') {
650
800
  return {
@@ -672,7 +822,9 @@ function parseFrontmatterTools(frontmatter) {
672
822
  continue;
673
823
  if (collecting) {
674
824
  if (trimmed.startsWith('- ')) {
675
- tools.push(trimmed.slice(2).trim());
825
+ const tool = decodeToolScalar(trimmed.slice(2));
826
+ if (tool !== null)
827
+ tools.push(tool);
676
828
  continue;
677
829
  }
678
830
  collecting = false;
@@ -683,10 +835,13 @@ function parseFrontmatterTools(frontmatter) {
683
835
  }
684
836
  if (trimmed.startsWith('tools:') || trimmed.startsWith('allowed-tools:')) {
685
837
  const value = trimmed.slice(trimmed.indexOf(':') + 1).trim();
686
- if (value) {
687
- for (const tool of value.split(',')) {
688
- const name = tool.trim();
689
- 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)
690
845
  tools.push(name);
691
846
  }
692
847
  }
@@ -856,7 +1011,7 @@ function buildKimiAgentArtifacts({ rootAgent = '', subagents = [], requestedSuba
856
1011
  * @param {boolean} [isGlobal=false] - Whether this is a global install
857
1012
  */
858
1013
  function convertClaudeToAntigravityContent(content, isGlobal = false) {
859
- let c = content;
1014
+ let c = filterRuntimeNotesForTarget(content, 'antigravity');
860
1015
  if (isGlobal) {
861
1016
  // #3738: global skills install under ~/.gemini/config/skills (the dir AGY
862
1017
  // scans for global discovery), so skills-path references must divert there
@@ -948,7 +1103,7 @@ function convertSlashCommandsToCursorSkillMentions(content) {
948
1103
  return content.replace(/gsd:/gi, 'gsd-');
949
1104
  }
950
1105
  function convertClaudeToCursorMarkdown(content) {
951
- let converted = convertSlashCommandsToCursorSkillMentions(content);
1106
+ let converted = convertSlashCommandsToCursorSkillMentions(filterRuntimeNotesForTarget(content, 'cursor'));
952
1107
  // Replace tool name references in body text
953
1108
  converted = converted.replace(/\bBash\(/g, 'Shell(');
954
1109
  converted = converted.replace(/\bEdit\(/g, 'StrReplace(');
@@ -1048,7 +1203,7 @@ function convertSlashCommandsToWindsurfSkillMentions(content) {
1048
1203
  return content.replace(/gsd:/gi, 'gsd-');
1049
1204
  }
1050
1205
  function convertClaudeToWindsurfMarkdown(content) {
1051
- let converted = convertSlashCommandsToWindsurfSkillMentions(content);
1206
+ let converted = convertSlashCommandsToWindsurfSkillMentions(filterRuntimeNotesForTarget(content, 'windsurf'));
1052
1207
  // Replace tool name references in body text
1053
1208
  converted = converted.replace(/\bBash\(/g, 'Shell(');
1054
1209
  converted = converted.replace(/\bEdit\(/g, 'StrReplace(');
@@ -1207,7 +1362,7 @@ function convertSlashCommandsToAugmentSkillMentions(content) {
1207
1362
  return content.replace(/gsd:/gi, 'gsd-');
1208
1363
  }
1209
1364
  function convertClaudeToAugmentMarkdown(content) {
1210
- let converted = convertSlashCommandsToAugmentSkillMentions(content);
1365
+ let converted = convertSlashCommandsToAugmentSkillMentions(filterRuntimeNotesForTarget(content, 'augment'));
1211
1366
  converted = converted.replace(/\bBash\(/g, 'launch-process(');
1212
1367
  converted = converted.replace(/\bEdit\(/g, 'str-replace-editor(');
1213
1368
  converted = converted.replace(/\bRead\(/g, 'view(');
@@ -1285,7 +1440,7 @@ function convertSlashCommandsToTraeSkillMentions(content) {
1285
1440
  });
1286
1441
  }
1287
1442
  function convertClaudeToTraeMarkdown(content) {
1288
- let converted = convertSlashCommandsToTraeSkillMentions(content);
1443
+ let converted = convertSlashCommandsToTraeSkillMentions(filterRuntimeNotesForTarget(content, 'trae'));
1289
1444
  converted = converted.replace(/\bBash\(/g, 'Shell(');
1290
1445
  converted = converted.replace(/\bEdit\(/g, 'StrReplace(');
1291
1446
  // Replace general-purpose subagent type with Trae's equivalent "general_purpose_task"
@@ -1393,7 +1548,7 @@ function convertSlashCommandsToCodebuddySkillMentions(content) {
1393
1548
  });
1394
1549
  }
1395
1550
  function convertClaudeToCodebuddyMarkdown(content) {
1396
- let converted = convertSlashCommandsToCodebuddySkillMentions(content);
1551
+ let converted = convertSlashCommandsToCodebuddySkillMentions(filterRuntimeNotesForTarget(content, 'codebuddy'));
1397
1552
  // CodeBuddy uses the same tool names as Claude Code (Bash, Edit, Read, Write, etc.)
1398
1553
  // No tool name conversion needed
1399
1554
  converted = converted.replace(/\$ARGUMENTS\b/g, '{{GSD_ARGS}}');
@@ -1470,7 +1625,7 @@ function convertClaudeCommandToCodebuddyCommand(content, commandName) {
1470
1625
  }
1471
1626
  // ── Cline converters ────────────────────────────────────────────────────────
1472
1627
  function convertClaudeToCliineMarkdown(content) {
1473
- let converted = content;
1628
+ let converted = filterRuntimeNotesForTarget(content, 'cline');
1474
1629
  // Cline uses the same tool names as Claude Code — no tool name conversion needed
1475
1630
  converted = converted.replace(/`\.\/CLAUDE\.md`/g, '`.clinerules`');
1476
1631
  converted = converted.replace(/\.\/CLAUDE\.md/g, '.clinerules');
@@ -1557,7 +1712,7 @@ function rewriteBareGsdToolsCommandsForCodex(content) {
1557
1712
  .replace(/((?:&&|\|\||[;|])\s*)gsd-tools(?=\s)/g, `$1${CODEX_GSD_TOOLS_INVOCATION}`);
1558
1713
  }
1559
1714
  function convertClaudeToCodexMarkdown(content) {
1560
- let converted = convertSlashCommandsToCodexSkillMentions(content);
1715
+ let converted = convertSlashCommandsToCodexSkillMentions(filterRuntimeNotesForTarget(content, 'codex'));
1561
1716
  converted = converted.replace(/\$ARGUMENTS\b/g, '{{GSD_ARGS}}');
1562
1717
  // Remove /clear references — Codex has no equivalent command
1563
1718
  // Handle backtick-wrapped: `\/clear` then: → (removed)
@@ -1623,26 +1778,37 @@ Execute mode fallback:
1623
1778
  ## C. Task() → spawn_agent Mapping
1624
1779
  GSD workflows use \`Task(...)\` (Claude Code syntax). Translate to Codex collaboration tools:
1625
1780
 
1626
- **Schema detection (required first step):** Codex exposes two \`spawn_agent\` schemas:
1627
- - **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.
1628
- - **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.
1629
1787
 
1630
- 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.
1631
1790
 
1632
1791
  Typed mapping (agent_type-capable schema only):
1633
1792
  - \`Task(subagent_type="X", prompt="Y")\` → \`spawn_agent(agent_type="X", message="Y")\`
1634
1793
  - \`Agent(subagent_type="X", prompt="Y")\` → \`spawn_agent(agent_type="X", message="Y")\`
1635
- - \`Task(model="...")\` → omit. \`spawn_agent\` has no inline \`model\` parameter;
1636
- GSD embeds the resolved per-agent model directly into each agent's \`.toml\`
1637
- at install time so \`model_overrides\` from \`.planning/config.json\` and
1638
- \`~/.gsd/defaults.json\` are honored automatically by Codex's agent router.
1639
- - Resolved \`reasoning_effort="low|medium|high|xhigh"\` (\`xhigh\` is a GSD/Codex tier, not a generic runtime enum) → pass \`reasoning_effort\`
1640
- to \`spawn_agent\` when the runtime/tool supports it. Omit missing, empty,
1641
- inherited, or unsupported values; do not invent one-off effort literals in
1642
- 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.
1643
1809
  - \`fork_context: false\` by default — GSD agents load their own context via \`<required_reading>\` blocks
1644
- - \`task_name\` — required by the collaboration schema; provide a descriptive name for each spawned task
1645
- - \`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)
1646
1812
  - \`Task(isolation="worktree")\` / \`Agent(isolation="worktree")\` → no direct \`spawn_agent\` mapping,
1647
1813
  but Codex declares \`dispatch.isolation: orchestrator-worktree\` (#2584). Codex
1648
1814
  \`spawn_agent\` still does not create or bind a git worktree; instead GSD itself
@@ -1735,9 +1901,24 @@ function frontmatterScalar(key, value) {
1735
1901
  ? `${key} "${frontmatterModule.escapeDoubleQuotedScalar(value)}"`
1736
1902
  : `${key} ${value}`;
1737
1903
  }
1904
+ const RUNTIME_NOTE_AUDIENCE_BY_HEADING = new Map([
1905
+ ['copilot (vs code)', 'copilot'],
1906
+ ]);
1907
+ function filterRuntimeNotesForTarget(content, targetRuntime) {
1908
+ return content.replace(/<runtime_note(?:\s+runtime=["']([^"']+)["'])?>([\s\S]*?)<\/runtime_note>/g, (whole, declaredAudience, inner) => {
1909
+ if (declaredAudience && declaredAudience.toLowerCase() !== targetRuntime)
1910
+ return '';
1911
+ const remaining = inner.replace(/(?:^|\n)[ \t]*\*\*([^*\n]+):\*\*[^\n]*(?:\n(?![ \t]*\n)[^\n]*)*/g, (section, heading) => {
1912
+ const audience = RUNTIME_NOTE_AUDIENCE_BY_HEADING.get(heading.trim().toLowerCase());
1913
+ return audience && audience !== targetRuntime ? '' : section;
1914
+ });
1915
+ const body = remaining.trim();
1916
+ return body ? `<runtime_note>\n${body}\n</runtime_note>` : '';
1917
+ });
1918
+ }
1738
1919
  function convertClaudeToOpencodeFrontmatter(content, { isAgent = false, modelOverride = null, variant = null } = {}) {
1739
1920
  // Replace tool name references in content (applies to all files)
1740
- let convertedContent = content;
1921
+ let convertedContent = filterRuntimeNotesForTarget(content, 'opencode');
1741
1922
  convertedContent = convertedContent.replace(/\bAskUserQuestion\b/g, 'question');
1742
1923
  convertedContent = convertedContent.replace(/\bSlashCommand\b/g, 'skill');
1743
1924
  convertedContent = convertedContent.replace(/\bTodoWrite\b/g, 'todowrite');
@@ -1898,7 +2079,7 @@ function convertClaudeToOpencodeFrontmatter(content, { isAgent = false, modelOve
1898
2079
  // (#2093).
1899
2080
  function convertClaudeToKiloFrontmatter(content, { isAgent = false, modelOverride = null } = {}) {
1900
2081
  // Replace tool name references in content (applies to all files)
1901
- let convertedContent = content;
2082
+ let convertedContent = filterRuntimeNotesForTarget(content, 'kilo');
1902
2083
  convertedContent = convertedContent.replace(/\bAskUserQuestion\b/g, 'question');
1903
2084
  convertedContent = convertedContent.replace(/\bSlashCommand\b/g, 'skill');
1904
2085
  convertedContent = convertedContent.replace(/\bTodoWrite\b/g, 'todowrite');
@@ -1948,7 +2129,9 @@ function convertClaudeToKiloFrontmatter(content, { isAgent = false, modelOverrid
1948
2129
  }
1949
2130
  if (isAgent && inAgentTools) {
1950
2131
  if (trimmed.startsWith('- ')) {
1951
- agentTools.push(trimmed.substring(2).trim());
2132
+ const tool = decodeToolScalar(trimmed.substring(2));
2133
+ if (tool !== null)
2134
+ agentTools.push(tool);
1952
2135
  continue;
1953
2136
  }
1954
2137
  if (trimmed && !trimmed.startsWith('-')) {
@@ -1959,8 +2142,11 @@ function convertClaudeToKiloFrontmatter(content, { isAgent = false, modelOverrid
1959
2142
  if (trimmed.startsWith('tools:')) {
1960
2143
  if (isAgent) {
1961
2144
  const toolsValue = trimmed.substring(6).trim();
1962
- if (toolsValue) {
1963
- const tools = toolsValue.split(',').map(t => t.trim()).filter(t => t);
2145
+ // A comment-only value (`tools: # note`) is not real inline content —
2146
+ // fall through to the block-list scan (`inAgentTools`) instead of
2147
+ // decoding the comment as a bogus tool name and dropping the list.
2148
+ if (toolsValue && !toolsValue.startsWith('#')) {
2149
+ const tools = splitToolScalars(toolsValue).map(decodeToolScalar).filter((tool) => tool !== null);
1964
2150
  agentTools.push(...tools);
1965
2151
  }
1966
2152
  else {
@@ -2022,7 +2208,9 @@ function convertClaudeToKiloFrontmatter(content, { isAgent = false, modelOverrid
2022
2208
  if (trimmed.startsWith('- ')) {
2023
2209
  const tool = trimmed.substring(2).trim();
2024
2210
  if (isAgent) {
2025
- agentTools.push(tool);
2211
+ const decoded = decodeToolScalar(tool);
2212
+ if (decoded !== null)
2213
+ agentTools.push(decoded);
2026
2214
  }
2027
2215
  else {
2028
2216
  allowedTools.push(tool);
@@ -2355,11 +2543,16 @@ function convertClaudeAgentToQwenAgent(content) {
2355
2543
  * Byte-identical for an agent with no `mcp__*` grants (the common case) and
2356
2544
  * for an agent with no frontmatter at all.
2357
2545
  */
2546
+ /** Fail-closed: an undecodable scalar is dropped, never kept (ZCode's contract is "never emit mcp__*"). */
2547
+ function zcodeKeepsGrant(rawTool) {
2548
+ const decoded = decodeToolScalar(rawTool);
2549
+ return decoded !== null && !decoded.startsWith('mcp__');
2550
+ }
2358
2551
  function convertClaudeAgentToZcodeAgent(content) {
2359
- // Fast path: no MCP grant token anywhere means nothing to strip. (A body
2360
- // mention alone is not a grant — the line scan below finds no tools-line
2361
- // change and returns `content` unchanged anyway; this just skips the scan.)
2362
- if (!content.includes('mcp__'))
2552
+ // A double-quoted YAML scalar may encode the leading "m" in mcp__ as an
2553
+ // escape, so only skip the shared scalar-decoder scan when neither form is
2554
+ // present. The unchanged scan below still preserves byte-identical content.
2555
+ if (!content.includes('mcp__') && !content.includes('\\'))
2363
2556
  return content;
2364
2557
  const lines = content.split('\n');
2365
2558
  if (lines[0] !== '---')
@@ -2379,9 +2572,14 @@ function convertClaudeAgentToZcodeAgent(content) {
2379
2572
  while (i < fmEnd) {
2380
2573
  const line = lines[i];
2381
2574
  const inlineTools = /^tools:[ \t]*(.+)$/.exec(line);
2382
- if (inlineTools) {
2383
- const grants = inlineTools[1].split(',').map((tool) => tool.trim()).filter((tool) => tool !== '');
2384
- const kept = grants.filter((tool) => !tool.startsWith('mcp__'));
2575
+ // A header that is ONLY a comment (`tools: # note`) is not real inline
2576
+ // content — fall through to the block-list scan below instead of
2577
+ // matching here, or a following block list's mcp__* items never get
2578
+ // scanned and leak through unstripped.
2579
+ const commentOnlyHeader = inlineTools !== null && inlineTools[1].trim().startsWith('#');
2580
+ if (inlineTools && !commentOnlyHeader) {
2581
+ const grants = splitToolScalars(inlineTools[1]).map((tool) => tool.trim()).filter((tool) => tool !== '');
2582
+ const kept = grants.filter((tool) => zcodeKeepsGrant(tool));
2385
2583
  if (kept.length === grants.length) {
2386
2584
  out.push(line); // no mcp__* grants — keep the line byte-identical
2387
2585
  }
@@ -2395,7 +2593,7 @@ function convertClaudeAgentToZcodeAgent(content) {
2395
2593
  i++;
2396
2594
  continue;
2397
2595
  }
2398
- if (/^tools:[ \t]*$/.test(line)) {
2596
+ if (/^tools:[ \t]*$/.test(line) || commentOnlyHeader) {
2399
2597
  // Block-list form: collect the following `- item` lines.
2400
2598
  const items = [];
2401
2599
  let j = i + 1;
@@ -2405,7 +2603,7 @@ function convertClaudeAgentToZcodeAgent(content) {
2405
2603
  }
2406
2604
  const kept = items.filter((item) => {
2407
2605
  const name = /^([ \t]*)-[ \t]*(\S.*)$/.exec(item)[2].trim();
2408
- return !name.startsWith('mcp__');
2606
+ return zcodeKeepsGrant(name);
2409
2607
  });
2410
2608
  if (kept.length !== items.length) {
2411
2609
  changed = true;
@@ -2762,6 +2960,7 @@ function restoreClaudeGlobalAtRefTilde(content, pathPrefix) {
2762
2960
  function _applyRuntimeRewrites(content, runtime, pathPrefix, isGlobal = false, attribution = undefined) {
2763
2961
  const dirName = getDirName(runtime);
2764
2962
  const normalizedPathPrefix = pathPrefix.replace(/\/$/, '');
2963
+ content = filterRuntimeNotesForTarget(content, runtime);
2765
2964
  // #1521: stamp runtime identity + use_worktrees=false for every non-Claude runtime
2766
2965
  // before brand-specific path rewrites, so the replace operates on the pristine
2767
2966
  // source line and is idempotent regardless of subsequent path substitutions.
@@ -2940,6 +3139,20 @@ function _applyRuntimeRewrites(content, runtime, pathPrefix, isGlobal = false, a
2940
3139
  content = content.replace(/\.\/\.claude\b/g, `./${dirName}`);
2941
3140
  content = processAttribution(content, attribution);
2942
3141
  break;
3142
+ case 'zcode':
3143
+ // #4002: ZCode is a Claude-Code-shaped host (dot-home `.zcode`, `@~`-ref
3144
+ // expansion, `~/.zcode/...` documented paths) whose commands install with
3145
+ // `converter: null` — this pass is their only chance to receive
3146
+ // runtime-correct paths. Same shape as `claude`, including the tilde
3147
+ // restore: the tilde form is what ZCode expands and what its docs use.
3148
+ // `${_GSD_RUNTIME_ROOT}/.claude/…` matches none of these regexes and
3149
+ // survives as the project-local fallback, exactly as on every sibling.
3150
+ content = content.replace(/~\/\.claude\//g, pathPrefix);
3151
+ content = content.replace(/\$HOME\/\.claude\//g, pathPrefix);
3152
+ content = content.replace(/\.\/\.claude\//g, `./${dirName}/`);
3153
+ content = restoreClaudeGlobalAtRefTilde(content, pathPrefix);
3154
+ content = processAttribution(content, attribution);
3155
+ break;
2943
3156
  default:
2944
3157
  // Unknown runtime — no rewrites (OpenCode/Kilo handled by their own install path).
2945
3158
  break;
@@ -3364,6 +3577,7 @@ function processAttribution(content, attribution) {
3364
3577
  }
3365
3578
  module.exports = {
3366
3579
  processAttribution,
3580
+ appendAgentTools,
3367
3581
  // #2103: public accessor for hostBehaviors.agentFileExtension, exported so
3368
3582
  // surface.cts's _syncGsdDir can derive the .agent.md rename from the SAME
3369
3583
  // descriptor read as install-engine.cts (folds a duplicated hardcoded
@@ -3415,11 +3629,14 @@ module.exports = {
3415
3629
  neutralizeAgentReferences,
3416
3630
  convertClaudeCommandToOpencodeSkill,
3417
3631
  convertClaudeCommandToKiloSkill,
3632
+ filterRuntimeNotesForTarget,
3418
3633
  // #2087 — opencode/kilo command-frontmatter converters, exported so the
3419
3634
  // layout-driven `convertedCommandsKind` can resolve them by name (routes the
3420
3635
  // opencode/kilo command install through the engine instead of the bespoke path).
3421
3636
  convertClaudeToOpencodeFrontmatter,
3422
3637
  convertClaudeToKiloFrontmatter,
3638
+ _decodeToolScalar: decodeToolScalar,
3639
+ _splitToolScalars: splitToolScalars,
3423
3640
  readGsdCommandNames,
3424
3641
  transformContentToHyphen,
3425
3642
  // #1383: version resolver (exported for regression test of the Codex
@@ -9,6 +9,7 @@
9
9
  // In .cts (CommonJS output) files, `require` is available as a global.
10
10
  const _require = require;
11
11
  const path = _require('node:path');
12
+ const { tryWithinRootLexical } = _require('./security.cjs');
12
13
  // #2870: InstallScope is owned by install-scope.cts, not re-declared here.
13
14
  // `isGlobalScope` centralizes the `scope === 'global'` boolean projection
14
15
  // this module needs at `_computePathPrefix`'s `isGlobal: boolean` boundary
@@ -33,11 +34,19 @@ function assertDestWithinConfigHome(configDir, destSubpath) {
33
34
  throw new Error(`destSubpath "${destSubpath}" contains a NUL byte and is not valid`);
34
35
  }
35
36
  const root = path.resolve(configDir);
36
- const resolved = path.resolve(configDir, destSubpath);
37
- if (resolved === root || !resolved.startsWith(root + path.sep)) {
37
+ // `resolved === root` is a DELIBERATE ADDITIONAL rejection, separate from
38
+ // the containment decision: `tryWithinRootLexical` treats target === root
39
+ // as CONTAINED, but a destSubpath of "" (or one that resolves to configDir
40
+ // itself) must never be accepted here — this is the strict-subpath
41
+ // requirement Phase B of ADR-1239 imposes on third-party descriptors, and
42
+ // it prevents a descriptor from writing at configHome itself. Kept as its
43
+ // own check per ADR-4650 decision 6 (a wrapper may add its own conditions
44
+ // on top of the canonical predicate, never invert it).
45
+ const contained = tryWithinRootLexical(destSubpath, configDir);
46
+ if (contained === null || contained === root) {
38
47
  throw new Error(`destSubpath "${destSubpath}" must be a strict subpath of configHome "${configDir}" — not configHome itself or outside it (escapes configHome)`);
39
48
  }
40
- return resolved;
49
+ return contained;
41
50
  }
42
51
  function errorMessage(err) {
43
52
  if (err instanceof Error)
@@ -51,7 +60,7 @@ function addCleanupDir(cleanupDirs, stagedDir, rewrittenDir) {
51
60
  return sourceDir;
52
61
  }
53
62
  function createRuntimeArtifactInstallPlan(args) {
54
- const { layout, resolvedProfile, homedir, platform, resolveAttribution, deps = {}, } = args;
63
+ const { layout, resolvedProfile, homedir, platform, resolveAttribution, projectDir, deps = {}, } = args;
55
64
  const conversionExports = _require('./runtime-artifact-conversion.cjs');
56
65
  const rewriteStagedSkillBodies = deps.rewriteStagedSkillBodies ?? conversionExports.rewriteStagedSkillBodies;
57
66
  const rewriteStagedCommandBodies = deps.rewriteStagedCommandBodies ?? conversionExports.rewriteStagedCommandBodies;
@@ -66,11 +75,10 @@ function createRuntimeArtifactInstallPlan(args) {
66
75
  platform,
67
76
  resolveAttribution,
68
77
  };
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).
78
+ // ADR-1235 §1: build the staging context once per plan. Agent kinds apply
79
+ // the CORRECT pre-converter cross-cutting (path rewrites → attribution →
80
+ // converter → normalize). This
81
+ // mirrors the exact per-file order in the former inline agent loop.
74
82
  // NO _stampNonClaudeRuntimeDefaults — agents are NOT stamped in the inline loop.
75
83
  const os = _require('node:os');
76
84
  const { posixNormalize } = _require('./shell-command-projection.cjs');
@@ -88,19 +96,19 @@ function createRuntimeArtifactInstallPlan(args) {
88
96
  const attribution = resolveAttribution ? resolveAttribution(layout.runtime) : undefined;
89
97
  // #2875 Part 2 (row I1): layout.configDir IS the install root the inline
90
98
  // agent loop called `targetDir` — same value, same resolution.
91
- const agentCtx = { runtime: layout.runtime, pathPrefix, attribution, targetDir: layout.configDir };
99
+ const agentCtx = {
100
+ runtime: layout.runtime,
101
+ pathPrefix,
102
+ attribution,
103
+ targetDir: layout.configDir,
104
+ projectDir: projectDir ?? layout.configDir,
105
+ };
92
106
  for (const kind of layout.kinds) {
93
107
  let stagedDir;
94
108
  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
- }
109
+ // Agent kinds use the context for their pre-converter cross-cutting
110
+ // sequence; other kinds ignore it.
111
+ stagedDir = kind.stage(resolvedProfile, agentCtx);
104
112
  }
105
113
  catch (err) {
106
114
  return { ok: false, kind: 'stage_failed', message: errorMessage(err), cleanupDirs, failedKind: kind.kind };
@@ -115,7 +123,7 @@ function createRuntimeArtifactInstallPlan(args) {
115
123
  const rewrittenDir = rewriteStagedSkillBodies(stagedDir, rewriteOpts);
116
124
  sourceDir = addCleanupDir(cleanupDirs, stagedDir, rewrittenDir);
117
125
  }
118
- // agents kind: cross-cutting already applied INSIDE kind.stage() via agentCtx.
126
+ // Agent kinds: cross-cutting already applied INSIDE kind.stage() via agentCtx.
119
127
  // No POST-step needed. sourceDir stays as stagedDir.
120
128
  }
121
129
  catch (err) {