@opengsd/gsd-core 1.13.0 → 1.15.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 (441) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.ja-JP.md +3 -3
  4. package/README.ko-KR.md +3 -3
  5. package/README.pt-BR.md +3 -3
  6. package/README.zh-CN.md +3 -3
  7. package/agents/gsd-advisor-researcher.compact.md +85 -0
  8. package/agents/gsd-ai-researcher.compact.md +96 -0
  9. package/agents/gsd-assumptions-analyzer.compact.md +81 -0
  10. package/agents/gsd-code-fixer.compact.md +459 -0
  11. package/agents/gsd-code-fixer.md +9 -8
  12. package/agents/gsd-code-reviewer.compact.md +269 -0
  13. package/agents/gsd-code-reviewer.md +15 -3
  14. package/agents/gsd-codebase-mapper.compact.md +760 -0
  15. package/agents/gsd-debug-session-manager.compact.md +360 -0
  16. package/agents/gsd-debug-session-manager.md +17 -2
  17. package/agents/gsd-debugger.md +2 -2
  18. package/agents/gsd-doc-classifier.compact.md +192 -0
  19. package/agents/gsd-doc-synthesizer.compact.md +200 -0
  20. package/agents/gsd-doc-verifier.compact.md +143 -0
  21. package/agents/gsd-doc-writer.compact.md +440 -0
  22. package/agents/gsd-dom-verifier.compact.md +138 -0
  23. package/agents/gsd-domain-researcher.compact.md +141 -0
  24. package/agents/gsd-eval-auditor.compact.md +160 -0
  25. package/agents/gsd-eval-auditor.md +1 -1
  26. package/agents/gsd-eval-planner.compact.md +137 -0
  27. package/agents/gsd-executor.md +13 -8
  28. package/agents/gsd-framework-selector.compact.md +82 -0
  29. package/agents/gsd-integration-checker.compact.md +245 -0
  30. package/agents/gsd-intel-updater.compact.md +226 -0
  31. package/agents/gsd-intel-updater.md +1 -1
  32. package/agents/gsd-mempalace-curator.compact.md +45 -0
  33. package/agents/gsd-nyquist-auditor.compact.md +179 -0
  34. package/agents/gsd-pattern-mapper.compact.md +275 -0
  35. package/agents/gsd-phase-researcher.md +19 -11
  36. package/agents/gsd-plan-checker.md +8 -7
  37. package/agents/gsd-planner.md +12 -8
  38. package/agents/gsd-project-researcher.compact.md +587 -0
  39. package/agents/gsd-project-researcher.md +1 -1
  40. package/agents/gsd-research-synthesizer.compact.md +212 -0
  41. package/agents/gsd-research-synthesizer.md +1 -1
  42. package/agents/gsd-roadmapper.compact.md +454 -0
  43. package/agents/gsd-roadmapper.md +13 -0
  44. package/agents/gsd-security-auditor.compact.md +162 -0
  45. package/agents/gsd-ui-auditor.compact.md +404 -0
  46. package/agents/gsd-ui-auditor.md +155 -17
  47. package/agents/gsd-ui-checker.compact.md +277 -0
  48. package/agents/gsd-ui-researcher.compact.md +282 -0
  49. package/agents/gsd-ui-researcher.md +1 -1
  50. package/agents/gsd-user-profiler.compact.md +108 -0
  51. package/agents/gsd-verifier.md +10 -9
  52. package/bin/install.js +848 -163
  53. package/commands/gsd/autonomous.md +2 -2
  54. package/commands/gsd/capture.md +1 -1
  55. package/commands/gsd/cleanup.md +1 -0
  56. package/commands/gsd/code-review.md +2 -1
  57. package/commands/gsd/complete-milestone.md +1 -0
  58. package/commands/gsd/config.md +1 -0
  59. package/commands/gsd/debug.md +1 -0
  60. package/commands/gsd/graphify.md +1 -0
  61. package/commands/gsd/health.md +1 -0
  62. package/commands/gsd/mempalace-capture.md +8 -3
  63. package/commands/gsd/mempalace-recall.md +1 -0
  64. package/commands/gsd/new-milestone.md +1 -0
  65. package/commands/gsd/new-project.md +1 -0
  66. package/commands/gsd/next.md +1 -0
  67. package/commands/gsd/pause-work.md +1 -0
  68. package/commands/gsd/phase.md +1 -0
  69. package/commands/gsd/plan-review-convergence.md +6 -6
  70. package/commands/gsd/pr-branch.md +1 -0
  71. package/commands/gsd/progress.md +1 -1
  72. package/commands/gsd/quick-batch.md +1 -1
  73. package/commands/gsd/resume-work.md +1 -0
  74. package/commands/gsd/review-backlog.md +1 -0
  75. package/commands/gsd/review.md +2 -3
  76. package/commands/gsd/settings.md +2 -1
  77. package/commands/gsd/stats.md +1 -0
  78. package/commands/gsd/thread.md +1 -0
  79. package/commands/gsd/workspace.md +1 -0
  80. package/commands/gsd/workstreams.md +1 -0
  81. package/gsd-core/bin/check-latest-version.cjs +8 -3
  82. package/gsd-core/bin/gsd-tools.cjs +672 -146
  83. package/gsd-core/bin/lib/adr-parser.cjs +4 -2
  84. package/gsd-core/bin/lib/artifacts.cjs +2 -1
  85. package/gsd-core/bin/lib/audit.cjs +119 -34
  86. package/gsd-core/bin/lib/broken-windows.cjs +168 -49
  87. package/gsd-core/bin/lib/capability-lifecycle.cjs +10 -6
  88. package/gsd-core/bin/lib/capability-loader.cjs +135 -1
  89. package/gsd-core/bin/lib/capability-registry.cjs +96 -189
  90. package/gsd-core/bin/lib/capability-source.cjs +19 -2
  91. package/gsd-core/bin/lib/capability-validator.cjs +14 -2
  92. package/gsd-core/bin/lib/check-command-router.cjs +213 -49
  93. package/gsd-core/bin/lib/code-review-depth.cjs +2 -2
  94. package/gsd-core/bin/lib/codex-agent-toml.cjs +21 -25
  95. package/gsd-core/bin/lib/commands.cjs +823 -112
  96. package/gsd-core/bin/lib/config-loader.cjs +66 -4
  97. package/gsd-core/bin/lib/config.cjs +186 -45
  98. package/gsd-core/bin/lib/coverage.cjs +1 -1
  99. package/gsd-core/bin/lib/decisions.cjs +164 -45
  100. package/gsd-core/bin/lib/external-descriptor-trust.cjs +29 -14
  101. package/gsd-core/bin/lib/frontmatter.cjs +13 -0
  102. package/gsd-core/bin/lib/graphify.cjs +10 -2
  103. package/gsd-core/bin/lib/gsd2-import.cjs +1 -2
  104. package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +12 -1
  105. package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +1 -1
  106. package/gsd-core/bin/lib/host-runtime-detection.cjs +9 -0
  107. package/gsd-core/bin/lib/init.cjs +614 -86
  108. package/gsd-core/bin/lib/install-engine.cjs +29 -3
  109. package/gsd-core/bin/lib/install-profiles.cjs +14 -0
  110. package/gsd-core/bin/lib/installer-migrations.cjs +41 -5
  111. package/gsd-core/bin/lib/loop-resolver.cjs +50 -31
  112. package/gsd-core/bin/lib/mcp-catalog.cjs +2 -2
  113. package/gsd-core/bin/lib/milestone.cjs +37 -13
  114. package/gsd-core/bin/lib/model-resolver.cjs +253 -53
  115. package/gsd-core/bin/lib/phase-command-router.cjs +16 -2
  116. package/gsd-core/bin/lib/phase-id-card.cjs +32 -0
  117. package/gsd-core/bin/lib/phase-id-display.cjs +78 -0
  118. package/gsd-core/bin/lib/phase-id.cjs +268 -27
  119. package/gsd-core/bin/lib/phase-lifecycle.cjs +61 -0
  120. package/gsd-core/bin/lib/phase-locator.cjs +29 -10
  121. package/gsd-core/bin/lib/phase.cjs +393 -88
  122. package/gsd-core/bin/lib/plan-document.cjs +49 -1
  123. package/gsd-core/bin/lib/planning-document.cjs +459 -0
  124. package/gsd-core/bin/lib/planning-inspect.cjs +52 -19
  125. package/gsd-core/bin/lib/planning-snapshot.cjs +61 -12
  126. package/gsd-core/bin/lib/planning-workspace.cjs +57 -3
  127. package/gsd-core/bin/lib/pr-branch-patterns.cjs +57 -0
  128. package/gsd-core/bin/lib/pristine-baseline.cjs +182 -0
  129. package/gsd-core/bin/lib/probe-core.cjs +7 -1
  130. package/gsd-core/bin/lib/prohibition-enforcement.cjs +91 -4
  131. package/gsd-core/bin/lib/project-root.cjs +41 -2
  132. package/gsd-core/bin/lib/quick-batch.cjs +1 -1
  133. package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +61 -2
  134. package/gsd-core/bin/lib/research-store.cjs +11 -12
  135. package/gsd-core/bin/lib/review-lane-descriptor.cjs +10 -30
  136. package/gsd-core/bin/lib/review-lane-invocation.cjs +23 -0
  137. package/gsd-core/bin/lib/review-reviewer-selection.cjs +2 -2
  138. package/gsd-core/bin/lib/reviewer-step-dispatch.cjs +337 -0
  139. package/gsd-core/bin/lib/roadmap-command-router.cjs +12 -4
  140. package/gsd-core/bin/lib/roadmap-parser.cjs +219 -18
  141. package/gsd-core/bin/lib/roadmap-upgrade.cjs +1539 -13
  142. package/gsd-core/bin/lib/roadmap.cjs +356 -42
  143. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +310 -41
  144. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +15 -4
  145. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +13 -5
  146. package/gsd-core/bin/lib/runtime-homes.cjs +4 -0
  147. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +408 -37
  148. package/gsd-core/bin/lib/runtime-name-policy.cjs +111 -1
  149. package/gsd-core/bin/lib/security.cjs +126 -7
  150. package/gsd-core/bin/lib/shell-command-projection.cjs +10 -6
  151. package/gsd-core/bin/lib/state-document.cjs +130 -28
  152. package/gsd-core/bin/lib/state-md-schema.cjs +21 -14
  153. package/gsd-core/bin/lib/state-transition.cjs +181 -30
  154. package/gsd-core/bin/lib/state.cjs +265 -27
  155. package/gsd-core/bin/lib/surface.cjs +77 -3
  156. package/gsd-core/bin/lib/task-command-router.cjs +12 -6
  157. package/gsd-core/bin/lib/tdd-red-evidence.cjs +78 -5
  158. package/gsd-core/bin/lib/uat-predicate.cjs +47 -4
  159. package/gsd-core/bin/lib/uat.cjs +9 -1
  160. package/gsd-core/bin/lib/ui-consideration-probe.cjs +15 -2
  161. package/gsd-core/bin/lib/ui-frontend-evidence.cjs +100 -9
  162. package/gsd-core/bin/lib/undo-commit-selection.cjs +131 -0
  163. package/gsd-core/bin/lib/update-context.cjs +30 -24
  164. package/gsd-core/bin/lib/vendor/js-yaml.cjs +11 -3
  165. package/gsd-core/bin/lib/verification.cjs +315 -30
  166. package/gsd-core/bin/lib/verify-command-grounding.cjs +47 -3
  167. package/gsd-core/bin/lib/verify.cjs +320 -48
  168. package/gsd-core/bin/lib/workstream-inventory.cjs +1 -0
  169. package/gsd-core/bin/lib/worktree-base-ref.cjs +482 -73
  170. package/gsd-core/bin/lib/worktree-safety.cjs +797 -58
  171. package/gsd-core/bin/shared/config-defaults.manifest.json +4 -0
  172. package/gsd-core/bin/shared/config-schema.manifest.json +6 -0
  173. package/gsd-core/bin/verify-reapply-patches.cjs +439 -80
  174. package/gsd-core/references/checkpoints.md +5 -3
  175. package/gsd-core/references/compact-content-gate.md +66 -0
  176. package/gsd-core/references/edge-probe-fixtures/01-round-half-even/expected-coverage.json +28 -3
  177. package/gsd-core/references/edge-probe-fixtures/02-merge-intervals/expected-coverage.json +37 -4
  178. package/gsd-core/references/edge-probe-fixtures/03-truncate-graphemes/expected-coverage.json +28 -3
  179. package/gsd-core/references/edge-probe-fixtures/04-money-rounding/expected-coverage.json +28 -3
  180. package/gsd-core/references/edge-probe-fixtures/05-list-dedupe/expected-coverage.json +37 -4
  181. package/gsd-core/references/edge-probe-fixtures/06-resolved-mixed/expected-coverage.json +37 -4
  182. package/gsd-core/references/edge-probe.md +195 -21
  183. package/gsd-core/references/execute-phase-between-wave-reset.md +7 -6
  184. package/gsd-core/references/execute-phase-wave-guard.md +22 -11
  185. package/gsd-core/references/gsd-run-resolver.md +1 -1
  186. package/gsd-core/references/loop-hook-dispatch.md +18 -0
  187. package/gsd-core/references/model-profiles.md +13 -4
  188. package/gsd-core/references/phase-argument-parsing.md +9 -7
  189. package/gsd-core/references/phase-id-convention.md +28 -0
  190. package/gsd-core/references/planner-gap-closure.md +2 -0
  191. package/gsd-core/references/planner-load-graph-context.md +24 -13
  192. package/gsd-core/references/planner-verify-command-grounding.md +14 -0
  193. package/gsd-core/references/planning-config.md +14 -2
  194. package/gsd-core/references/tdd.md +30 -4
  195. package/gsd-core/references/thinking-models-planning.md +18 -2
  196. package/gsd-core/references/ui-consideration-probe.md +10 -5
  197. package/gsd-core/references/verification-patterns.md +17 -4
  198. package/gsd-core/references/verify-command-path-resolvability.md +10 -2
  199. package/gsd-core/references/worktree-path-safety.md +433 -2
  200. package/gsd-core/templates/README.md +7 -1
  201. package/gsd-core/templates/state.md +6 -3
  202. package/gsd-core/templates/summary.compact.md +212 -0
  203. package/gsd-core/templates/user-setup.compact.md +199 -0
  204. package/gsd-core/templates/user-setup.md +0 -9
  205. package/gsd-core/templates/verification-report.md +1 -1
  206. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
  207. package/gsd-core/workflows/add-backlog.md +1 -1
  208. package/gsd-core/workflows/add-phase.md +1 -1
  209. package/gsd-core/workflows/add-tests.md +2 -2
  210. package/gsd-core/workflows/add-todo.md +6 -5
  211. package/gsd-core/workflows/ai-integration-phase.md +11 -3
  212. package/gsd-core/workflows/audit-fix.md +1 -1
  213. package/gsd-core/workflows/audit-milestone.md +1 -1
  214. package/gsd-core/workflows/audit-uat.md +1 -1
  215. package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +9 -18
  216. package/gsd-core/workflows/autonomous.md +29 -16
  217. package/gsd-core/workflows/check-todos.md +6 -4
  218. package/gsd-core/workflows/cleanup.md +5 -3
  219. package/gsd-core/workflows/code-review/steps/dispatch-fix.md +4 -3
  220. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +8 -1
  221. package/gsd-core/workflows/code-review-fix.md +108 -22
  222. package/gsd-core/workflows/code-review.md +216 -73
  223. package/gsd-core/workflows/complete-milestone/detail/elaboration.md +274 -0
  224. package/gsd-core/workflows/complete-milestone.md +41 -264
  225. package/gsd-core/workflows/debug.md +3 -3
  226. package/gsd-core/workflows/diagnose-issues.md +1 -1
  227. package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
  228. package/gsd-core/workflows/discuss-phase/modes/chain.md +1 -1
  229. package/gsd-core/workflows/discuss-phase-assumptions.md +1 -1
  230. package/gsd-core/workflows/discuss-phase.md +1 -1
  231. package/gsd-core/workflows/do.md +2 -2
  232. package/gsd-core/workflows/docs-update/detail/elaboration.md +179 -0
  233. package/gsd-core/workflows/docs-update.md +17 -158
  234. package/gsd-core/workflows/edit-phase.md +1 -1
  235. package/gsd-core/workflows/eval-review.md +10 -3
  236. package/gsd-core/workflows/execute-phase/detail/elaboration.md +124 -0
  237. package/gsd-core/workflows/execute-phase/steps/code-review-disposition.md +1017 -0
  238. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +19 -4
  239. package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +56 -0
  240. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +43 -4
  241. package/gsd-core/workflows/execute-phase/steps/executor-progress-policy.md +43 -0
  242. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +1 -1
  243. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +1 -1
  244. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
  245. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +1 -1
  246. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +46 -9
  247. package/gsd-core/workflows/execute-phase/steps/protected-branch.md +1 -1
  248. package/gsd-core/workflows/execute-phase/steps/ready-wave-gate.md +37 -0
  249. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +1 -1
  250. package/gsd-core/workflows/execute-phase/steps/sequential-root-pin.md +35 -0
  251. package/gsd-core/workflows/execute-phase/steps/stale-reverification.md +24 -0
  252. package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +1 -1
  253. package/gsd-core/workflows/execute-phase/steps/threat-id-gate.md +28 -0
  254. package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +1 -1
  255. package/gsd-core/workflows/execute-phase/steps/worktree-base-check.md +25 -0
  256. package/gsd-core/workflows/execute-phase.md +83 -172
  257. package/gsd-core/workflows/execute-plan.md +24 -10
  258. package/gsd-core/workflows/explore.md +3 -3
  259. package/gsd-core/workflows/extract-learnings.md +2 -1
  260. package/gsd-core/workflows/fast.md +1 -1
  261. package/gsd-core/workflows/forensics.md +1 -1
  262. package/gsd-core/workflows/graduation.md +1 -1
  263. package/gsd-core/workflows/health.md +2 -2
  264. package/gsd-core/workflows/help/modes/full.compact.md +398 -0
  265. package/gsd-core/workflows/help/modes/full.md +5 -5
  266. package/gsd-core/workflows/help/modes/topic.md +15 -5
  267. package/gsd-core/workflows/help.md +1 -1
  268. package/gsd-core/workflows/import.md +2 -2
  269. package/gsd-core/workflows/inbox.md +2 -2
  270. package/gsd-core/workflows/ingest-docs.md +3 -3
  271. package/gsd-core/workflows/insert-phase.md +1 -1
  272. package/gsd-core/workflows/list-seeds.md +1 -1
  273. package/gsd-core/workflows/list-workspaces.md +1 -1
  274. package/gsd-core/workflows/manager.md +2 -2
  275. package/gsd-core/workflows/map-codebase.md +52 -5
  276. package/gsd-core/workflows/milestone-summary.md +1 -1
  277. package/gsd-core/workflows/mvp-phase.md +1 -1
  278. package/gsd-core/workflows/new-milestone.md +56 -14
  279. package/gsd-core/workflows/new-project/detail/elaboration.md +216 -0
  280. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +3 -3
  281. package/gsd-core/workflows/new-project/steps/codebase-map-offer.md +1 -1
  282. package/gsd-core/workflows/new-project.md +39 -209
  283. package/gsd-core/workflows/new-workspace.md +2 -2
  284. package/gsd-core/workflows/next.md +1 -1
  285. package/gsd-core/workflows/note.md +1 -1
  286. package/gsd-core/workflows/onboard.md +1 -1
  287. package/gsd-core/workflows/pause-work.md +1 -1
  288. package/gsd-core/workflows/plan-phase/detail/elaboration.md +209 -0
  289. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +17 -5
  290. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +1 -1
  291. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +23 -5
  292. package/gsd-core/workflows/plan-phase.md +45 -187
  293. package/gsd-core/workflows/plan-review-convergence.md +21 -5
  294. package/gsd-core/workflows/plant-seed.md +62 -20
  295. package/gsd-core/workflows/pr-branch.md +132 -20
  296. package/gsd-core/workflows/profile-user.md +2 -2
  297. package/gsd-core/workflows/progress.md +1 -1
  298. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +25 -0
  299. package/gsd-core/workflows/quick/steps/quick-verification.md +1 -1
  300. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +1 -1
  301. package/gsd-core/workflows/quick-batch/steps/batch-init.md +1 -1
  302. package/gsd-core/workflows/quick-batch/steps/completion.md +1 -1
  303. package/gsd-core/workflows/quick-batch/steps/merge-wave.md +1 -1
  304. package/gsd-core/workflows/quick-batch/steps/planner-wave.md +1 -1
  305. package/gsd-core/workflows/quick-batch/steps/research-phase.md +1 -1
  306. package/gsd-core/workflows/quick-batch/steps/resume-mode.md +1 -1
  307. package/gsd-core/workflows/quick-batch/steps/verification-wave.md +1 -1
  308. package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +1 -1
  309. package/gsd-core/workflows/quick-batch.md +1 -1
  310. package/gsd-core/workflows/quick.md +29 -10
  311. package/gsd-core/workflows/reapply-patches.md +86 -6
  312. package/gsd-core/workflows/remove-phase.md +1 -1
  313. package/gsd-core/workflows/remove-workspace.md +2 -2
  314. package/gsd-core/workflows/resume-project.md +1 -1
  315. package/gsd-core/workflows/review.md +31 -16
  316. package/gsd-core/workflows/scan.md +1 -1
  317. package/gsd-core/workflows/secure-phase.md +3 -2
  318. package/gsd-core/workflows/settings-advanced.md +30 -10
  319. package/gsd-core/workflows/settings-integrations.md +2 -3
  320. package/gsd-core/workflows/settings.md +22 -9
  321. package/gsd-core/workflows/ship.md +3 -2
  322. package/gsd-core/workflows/sketch-wrap-up.md +1 -1
  323. package/gsd-core/workflows/sketch.md +1 -1
  324. package/gsd-core/workflows/smart-entry.md +2 -2
  325. package/gsd-core/workflows/spec-phase.md +15 -5
  326. package/gsd-core/workflows/spike-wrap-up.md +1 -1
  327. package/gsd-core/workflows/spike.md +1 -1
  328. package/gsd-core/workflows/stats.md +1 -1
  329. package/gsd-core/workflows/sync-skills.md +5 -5
  330. package/gsd-core/workflows/thread.md +1 -1
  331. package/gsd-core/workflows/transition.md +1 -1
  332. package/gsd-core/workflows/ui-phase.md +44 -8
  333. package/gsd-core/workflows/ui-review.md +18 -4
  334. package/gsd-core/workflows/ultraplan-phase.md +1 -1
  335. package/gsd-core/workflows/undo.md +339 -20
  336. package/gsd-core/workflows/update.md +14 -12
  337. package/gsd-core/workflows/validate-phase.md +3 -2
  338. package/gsd-core/workflows/verify-work/detail/elaboration.md +230 -0
  339. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +1 -1
  340. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
  341. package/gsd-core/workflows/verify-work.md +101 -196
  342. package/hooks/dist/gsd-agent-isolation-guard.js +66 -16
  343. package/hooks/dist/gsd-context-monitor.js +88 -15
  344. package/hooks/dist/gsd-cursor-subagent-start.js +34 -14
  345. package/hooks/dist/gsd-secret-read-guard.js +71 -19
  346. package/hooks/dist/gsd-statusline.js +81 -20
  347. package/hooks/dist/gsd-validate-commit.sh +97 -8
  348. package/hooks/dist/gsd-worktree-path-guard.js +25 -14
  349. package/hooks/dist/gsd-write-guard.js +46 -1
  350. package/hooks/dist/lib/dispatch-identity.js +187 -0
  351. package/hooks/dist/lib/filename-classification.js +64 -0
  352. package/hooks/dist/lib/isolation-deny-reason.js +53 -1
  353. package/hooks/dist/lib/isolation-sentinel.js +58 -19
  354. package/hooks/gsd-agent-isolation-guard.js +66 -16
  355. package/hooks/gsd-context-monitor.js +88 -15
  356. package/hooks/gsd-cursor-subagent-start.js +34 -14
  357. package/hooks/gsd-secret-read-guard.js +71 -19
  358. package/hooks/gsd-statusline.js +81 -20
  359. package/hooks/gsd-validate-commit.sh +97 -8
  360. package/hooks/gsd-worktree-path-guard.js +25 -14
  361. package/hooks/gsd-write-guard.js +46 -1
  362. package/hooks/lib/dispatch-identity.js +187 -0
  363. package/hooks/lib/filename-classification.js +64 -0
  364. package/hooks/lib/isolation-deny-reason.js +53 -1
  365. package/hooks/lib/isolation-sentinel.js +58 -19
  366. package/package.json +11 -6
  367. package/scripts/benchmark-compact-content-variants.cjs +298 -0
  368. package/scripts/benchmark-compact-content.cjs +368 -0
  369. package/scripts/build-hooks.js +15 -6
  370. package/scripts/check-contract-drift.cjs +131 -12
  371. package/scripts/check-env.cjs +36 -8
  372. package/scripts/check-glossary-refs.cjs +25 -21
  373. package/scripts/ci-next-health.cjs +271 -0
  374. package/scripts/ci-prepare-test-scope.cjs +7 -7
  375. package/scripts/ci-test-scope.cjs +126 -20
  376. package/scripts/ci-timeout-report.cjs +1 -1
  377. package/scripts/command-contract-helpers.cjs +3 -0
  378. package/scripts/diff-touches-shipped-paths.cjs +1 -1
  379. package/scripts/docs-guard-registry.cjs +35 -2
  380. package/scripts/gen-adr-index.cjs +8 -2
  381. package/scripts/gen-inventory-manifest.cjs +12 -0
  382. package/scripts/gen-loop-host-contract.cjs +69 -0
  383. package/scripts/gen-platform-conformance-tier.cjs +557 -0
  384. package/scripts/lib/drift-scan.cjs +1 -1
  385. package/scripts/lib/macos-conformance-tier.generated.cjs +224 -0
  386. package/scripts/lib/ndjson-reporter.cjs +3 -2
  387. package/scripts/lib/npm-version-check-diagnosis.cjs +59 -0
  388. package/scripts/lib/platform-conformance-tier.generated.cjs +287 -0
  389. package/scripts/lib/suite-detection.cjs +32 -0
  390. package/scripts/lint-allowed-tools-parity.cjs +221 -0
  391. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +47 -3
  392. package/scripts/lint-phase-arg-assignment.cjs +257 -0
  393. package/scripts/lint-phase-id-drift.cjs +623 -13
  394. package/scripts/lint-pr-branch-pattern-drift.cjs +148 -0
  395. package/scripts/lint-response-language-coverage.cjs +9 -3
  396. package/scripts/lint-retired-runtime-name.cjs +619 -0
  397. package/scripts/lint-source-test-name-collision.cjs +1 -1
  398. package/scripts/lint-state-write-path-drift.cjs +93 -0
  399. package/scripts/lint-test-file-count.allowlist.json +29 -9
  400. package/scripts/lint-vendored-deps.cjs +128 -17
  401. package/scripts/lint-workflow-shellcheck-baseline.json +100 -0
  402. package/scripts/prompt-injection-scan.sh +18 -0
  403. package/scripts/release-tarball-smoke.cjs +194 -1
  404. package/scripts/workflow-size.cjs +139 -0
  405. package/skills/gsd-autonomous/SKILL.md +2 -2
  406. package/skills/gsd-capture/SKILL.md +1 -1
  407. package/skills/gsd-cleanup/SKILL.md +1 -0
  408. package/skills/gsd-code-review/SKILL.md +2 -1
  409. package/skills/gsd-complete-milestone/SKILL.md +1 -0
  410. package/skills/gsd-config/SKILL.md +1 -0
  411. package/skills/gsd-debug/SKILL.md +1 -0
  412. package/skills/gsd-graphify/SKILL.md +1 -0
  413. package/skills/gsd-health/SKILL.md +1 -0
  414. package/skills/gsd-mempalace-capture/SKILL.md +8 -3
  415. package/skills/gsd-mempalace-recall/SKILL.md +1 -0
  416. package/skills/gsd-new-milestone/SKILL.md +1 -0
  417. package/skills/gsd-new-project/SKILL.md +1 -0
  418. package/skills/gsd-next/SKILL.md +1 -0
  419. package/skills/gsd-pause-work/SKILL.md +1 -0
  420. package/skills/gsd-phase/SKILL.md +1 -0
  421. package/skills/gsd-plan-review-convergence/SKILL.md +5 -5
  422. package/skills/gsd-pr-branch/SKILL.md +1 -0
  423. package/skills/gsd-progress/SKILL.md +1 -1
  424. package/skills/gsd-quick-batch/SKILL.md +1 -1
  425. package/skills/gsd-resume-work/SKILL.md +1 -0
  426. package/skills/gsd-review/SKILL.md +2 -3
  427. package/skills/gsd-review-backlog/SKILL.md +1 -0
  428. package/skills/gsd-settings/SKILL.md +2 -1
  429. package/skills/gsd-stats/SKILL.md +1 -0
  430. package/skills/gsd-thread/SKILL.md +1 -0
  431. package/skills/gsd-workspace/SKILL.md +1 -0
  432. package/skills/gsd-workstreams/SKILL.md +1 -0
  433. package/vscode/package.json +1 -1
  434. package/gsd-core/templates/claude-md.md +0 -145
  435. package/gsd-core/templates/codebase/concerns.md +0 -310
  436. package/gsd-core/templates/codebase/conventions.md +0 -307
  437. package/gsd-core/templates/codebase/integrations.md +0 -280
  438. package/gsd-core/templates/codebase/structure.md +0 -285
  439. package/gsd-core/templates/codebase/testing.md +0 -480
  440. package/gsd-core/templates/debug-subagent-prompt.md +0 -91
  441. package/gsd-core/templates/discovery.md +0 -146
@@ -457,7 +457,10 @@ function convertClaudeCommandToClaudeSkill(content, skillName, runtime = null, c
457
457
  // calls fall back to reading the list.
458
458
  const names = cmdNames || readGsdCommandNames();
459
459
  const normalizedBody = transformContentToHyphen(body, names);
460
- const description = extractFrontmatterField(frontmatter, 'description') || '';
460
+ // #4324: the description is the text the host's skill picker renders, so it
461
+ // needs the same hyphen normalisation the body gets — otherwise a `/gsd:<cmd>`
462
+ // mention in a command description ships the retired colon form to the user.
463
+ const description = transformContentToHyphen(extractFrontmatterField(frontmatter, 'description') || '', names);
461
464
  const argumentHint = extractFrontmatterField(frontmatter, 'argument-hint');
462
465
  const agent = extractFrontmatterField(frontmatter, 'agent');
463
466
  // #769: preserve context: from source command files so it is emitted into
@@ -1011,7 +1014,7 @@ function buildKimiAgentArtifacts({ rootAgent = '', subagents = [], requestedSuba
1011
1014
  * @param {boolean} [isGlobal=false] - Whether this is a global install
1012
1015
  */
1013
1016
  function convertClaudeToAntigravityContent(content, isGlobal = false) {
1014
- let c = content;
1017
+ let c = filterRuntimeNotesForTarget(content, 'antigravity');
1015
1018
  if (isGlobal) {
1016
1019
  // #3738: global skills install under ~/.gemini/config/skills (the dir AGY
1017
1020
  // scans for global discovery), so skills-path references must divert there
@@ -1103,7 +1106,7 @@ function convertSlashCommandsToCursorSkillMentions(content) {
1103
1106
  return content.replace(/gsd:/gi, 'gsd-');
1104
1107
  }
1105
1108
  function convertClaudeToCursorMarkdown(content) {
1106
- let converted = convertSlashCommandsToCursorSkillMentions(content);
1109
+ let converted = convertSlashCommandsToCursorSkillMentions(filterRuntimeNotesForTarget(content, 'cursor'));
1107
1110
  // Replace tool name references in body text
1108
1111
  converted = converted.replace(/\bBash\(/g, 'Shell(');
1109
1112
  converted = converted.replace(/\bEdit\(/g, 'StrReplace(');
@@ -1203,7 +1206,7 @@ function convertSlashCommandsToWindsurfSkillMentions(content) {
1203
1206
  return content.replace(/gsd:/gi, 'gsd-');
1204
1207
  }
1205
1208
  function convertClaudeToWindsurfMarkdown(content) {
1206
- let converted = convertSlashCommandsToWindsurfSkillMentions(content);
1209
+ let converted = convertSlashCommandsToWindsurfSkillMentions(filterRuntimeNotesForTarget(content, 'windsurf'));
1207
1210
  // Replace tool name references in body text
1208
1211
  converted = converted.replace(/\bBash\(/g, 'Shell(');
1209
1212
  converted = converted.replace(/\bEdit\(/g, 'StrReplace(');
@@ -1362,7 +1365,7 @@ function convertSlashCommandsToAugmentSkillMentions(content) {
1362
1365
  return content.replace(/gsd:/gi, 'gsd-');
1363
1366
  }
1364
1367
  function convertClaudeToAugmentMarkdown(content) {
1365
- let converted = convertSlashCommandsToAugmentSkillMentions(content);
1368
+ let converted = convertSlashCommandsToAugmentSkillMentions(filterRuntimeNotesForTarget(content, 'augment'));
1366
1369
  converted = converted.replace(/\bBash\(/g, 'launch-process(');
1367
1370
  converted = converted.replace(/\bEdit\(/g, 'str-replace-editor(');
1368
1371
  converted = converted.replace(/\bRead\(/g, 'view(');
@@ -1440,7 +1443,7 @@ function convertSlashCommandsToTraeSkillMentions(content) {
1440
1443
  });
1441
1444
  }
1442
1445
  function convertClaudeToTraeMarkdown(content) {
1443
- let converted = convertSlashCommandsToTraeSkillMentions(content);
1446
+ let converted = convertSlashCommandsToTraeSkillMentions(filterRuntimeNotesForTarget(content, 'trae'));
1444
1447
  converted = converted.replace(/\bBash\(/g, 'Shell(');
1445
1448
  converted = converted.replace(/\bEdit\(/g, 'StrReplace(');
1446
1449
  // Replace general-purpose subagent type with Trae's equivalent "general_purpose_task"
@@ -1548,7 +1551,7 @@ function convertSlashCommandsToCodebuddySkillMentions(content) {
1548
1551
  });
1549
1552
  }
1550
1553
  function convertClaudeToCodebuddyMarkdown(content) {
1551
- let converted = convertSlashCommandsToCodebuddySkillMentions(content);
1554
+ let converted = convertSlashCommandsToCodebuddySkillMentions(filterRuntimeNotesForTarget(content, 'codebuddy'));
1552
1555
  // CodeBuddy uses the same tool names as Claude Code (Bash, Edit, Read, Write, etc.)
1553
1556
  // No tool name conversion needed
1554
1557
  converted = converted.replace(/\$ARGUMENTS\b/g, '{{GSD_ARGS}}');
@@ -1625,7 +1628,7 @@ function convertClaudeCommandToCodebuddyCommand(content, commandName) {
1625
1628
  }
1626
1629
  // ── Cline converters ────────────────────────────────────────────────────────
1627
1630
  function convertClaudeToCliineMarkdown(content) {
1628
- let converted = content;
1631
+ let converted = filterRuntimeNotesForTarget(content, 'cline');
1629
1632
  // Cline uses the same tool names as Claude Code — no tool name conversion needed
1630
1633
  converted = converted.replace(/`\.\/CLAUDE\.md`/g, '`.clinerules`');
1631
1634
  converted = converted.replace(/\.\/CLAUDE\.md/g, '.clinerules');
@@ -1670,6 +1673,8 @@ function convertClaudeCommandToClineSkill(content, skillName, _runtime = null, c
1670
1673
  if (!description)
1671
1674
  description = `Run GSD workflow ${skillName}.`;
1672
1675
  description = toSingleLine(description);
1676
+ // #4324: same reason as the Claude skill converter above.
1677
+ description = transformContentToHyphen(description, names);
1673
1678
  // Cline documented max is 1024 code points (not UTF-16 code units).
1674
1679
  // Use Array.from to iterate by code point so that multibyte characters
1675
1680
  // (e.g. emoji, astral-plane chars) are never split, which would produce
@@ -1712,7 +1717,7 @@ function rewriteBareGsdToolsCommandsForCodex(content) {
1712
1717
  .replace(/((?:&&|\|\||[;|])\s*)gsd-tools(?=\s)/g, `$1${CODEX_GSD_TOOLS_INVOCATION}`);
1713
1718
  }
1714
1719
  function convertClaudeToCodexMarkdown(content) {
1715
- let converted = convertSlashCommandsToCodexSkillMentions(content);
1720
+ let converted = convertSlashCommandsToCodexSkillMentions(filterRuntimeNotesForTarget(content, 'codex'));
1716
1721
  converted = converted.replace(/\$ARGUMENTS\b/g, '{{GSD_ARGS}}');
1717
1722
  // Remove /clear references — Codex has no equivalent command
1718
1723
  // Handle backtick-wrapped: `\/clear` then: → (removed)
@@ -1818,6 +1823,22 @@ Typed mapping (agent_type-capable schema only):
1818
1823
  never fabricate a manual worktree protocol — route through the negotiated
1819
1824
  isolation adapter, which still fails closed for hosts declaring \`none\` (#3360).
1820
1825
 
1826
+ Foreground handoffs:
1827
+ - spawn_agent is asynchronous. When the source Agent(...) or Task(...) declares
1828
+ run_in_background=false, call collaboration.wait_agent(timeout_ms=...) immediately after
1829
+ spawn and keep the parent turn active until that child returns a terminal result.
1830
+ - collaboration.wait_agent is a mailbox wakeup, NOT a completion oracle: "Wait completed"
1831
+ can mean only that a child sent an interim MESSAGE or status update. After every wakeup,
1832
+ inspect the named child's update/status. Only a FINAL_ANSWER or a terminal agent status
1833
+ (completed, failed, or cancelled) ends the foreground handoff.
1834
+ - On an interim MESSAGE or any non-terminal status, do not report an outcome, send a
1835
+ continuation, start parent work, or end the parent turn. Call collaboration.wait_agent
1836
+ again for the same child. If a terminal response is absent after an abnormal end, reconcile
1837
+ the workflow's durable artifacts before classifying the child.
1838
+ - This applies to one foreground child as well as fan-out. The child retains its workflow's
1839
+ own checkpoint loop; do not report an outcome or start any further parent work before its
1840
+ terminal result is available.
1841
+
1821
1842
  Generic-agent workaround (multi_agent_v1 schema — NO agent_type field):
1822
1843
  When only the generic \`multi_agent_v1\` schema is available, typed GSD agent dispatch
1823
1844
  (\`gsd-planner\`, \`gsd-executor\`, etc.) is NOT possible. This is a known Codex limitation
@@ -1845,6 +1866,9 @@ Spawn restriction:
1845
1866
  defaulting to inline execution.
1846
1867
 
1847
1868
  Parallel fan-out:
1869
+ - For each child, loop on collaboration.wait_agent(timeout_ms=...) until its own terminal
1870
+ result is observed. A mailbox update from one child never completes another child, and an
1871
+ interim MESSAGE never completes its sender.
1848
1872
  - Spawn multiple agents → collect agent IDs → \`collaboration.wait_agent(timeout_ms=...)\` for each to complete
1849
1873
  - Do NOT use \`functions.wait(cell_id=...)\` — that is an unrelated exec-cell tool, not the collaboration wait
1850
1874
 
@@ -1901,9 +1925,24 @@ function frontmatterScalar(key, value) {
1901
1925
  ? `${key} "${frontmatterModule.escapeDoubleQuotedScalar(value)}"`
1902
1926
  : `${key} ${value}`;
1903
1927
  }
1928
+ const RUNTIME_NOTE_AUDIENCE_BY_HEADING = new Map([
1929
+ ['copilot (vs code)', 'copilot'],
1930
+ ]);
1931
+ function filterRuntimeNotesForTarget(content, targetRuntime) {
1932
+ return content.replace(/<runtime_note(?:\s+runtime=["']([^"']+)["'])?>([\s\S]*?)<\/runtime_note>/g, (whole, declaredAudience, inner) => {
1933
+ if (declaredAudience && declaredAudience.toLowerCase() !== targetRuntime)
1934
+ return '';
1935
+ const remaining = inner.replace(/(?:^|\n)[ \t]*\*\*([^*\n]+):\*\*[^\n]*(?:\n(?![ \t]*\n)[^\n]*)*/g, (section, heading) => {
1936
+ const audience = RUNTIME_NOTE_AUDIENCE_BY_HEADING.get(heading.trim().toLowerCase());
1937
+ return audience && audience !== targetRuntime ? '' : section;
1938
+ });
1939
+ const body = remaining.trim();
1940
+ return body ? `<runtime_note>\n${body}\n</runtime_note>` : '';
1941
+ });
1942
+ }
1904
1943
  function convertClaudeToOpencodeFrontmatter(content, { isAgent = false, modelOverride = null, variant = null } = {}) {
1905
1944
  // Replace tool name references in content (applies to all files)
1906
- let convertedContent = content;
1945
+ let convertedContent = filterRuntimeNotesForTarget(content, 'opencode');
1907
1946
  convertedContent = convertedContent.replace(/\bAskUserQuestion\b/g, 'question');
1908
1947
  convertedContent = convertedContent.replace(/\bSlashCommand\b/g, 'skill');
1909
1948
  convertedContent = convertedContent.replace(/\bTodoWrite\b/g, 'todowrite');
@@ -2064,7 +2103,7 @@ function convertClaudeToOpencodeFrontmatter(content, { isAgent = false, modelOve
2064
2103
  // (#2093).
2065
2104
  function convertClaudeToKiloFrontmatter(content, { isAgent = false, modelOverride = null } = {}) {
2066
2105
  // Replace tool name references in content (applies to all files)
2067
- let convertedContent = content;
2106
+ let convertedContent = filterRuntimeNotesForTarget(content, 'kilo');
2068
2107
  convertedContent = convertedContent.replace(/\bAskUserQuestion\b/g, 'question');
2069
2108
  convertedContent = convertedContent.replace(/\bSlashCommand\b/g, 'skill');
2070
2109
  convertedContent = convertedContent.replace(/\bTodoWrite\b/g, 'todowrite');
@@ -2258,38 +2297,45 @@ const claudeToCopilotTools = {
2258
2297
  AskUserQuestion: 'ask_user',
2259
2298
  SlashCommand: 'skill',
2260
2299
  };
2261
- // Tool name mapping from Claude Code to Gemini CLI
2262
- // Gemini CLI uses snake_case built-in tool names
2263
- const claudeToGeminiTools = {
2264
- Read: 'read_file',
2300
+ // Tool name mapping from Claude Code to Antigravity
2301
+ // Antigravity uses Gemini's snake_case built-in tool names
2302
+ // #4705: values are Antigravity-NATIVE tool names per the documented subagent
2303
+ // contract (antigravity.google/docs/subagents: view_file, replace_file_content,
2304
+ // grep_search, run_command are the documented examples; the catalog is
2305
+ // non-exhaustive, so unmapped entries keep their best-known grant rather than
2306
+ // being dropped — dropping would silently remove a restriction). The old
2307
+ // values were Gemini CLI dialect names, which Antigravity's tool validation
2308
+ // does not document and may hang the subagent on.
2309
+ const claudeToAntigravityTools = {
2310
+ Read: 'view_file',
2265
2311
  Write: 'write_file',
2266
- Edit: 'replace',
2267
- Bash: 'run_shell_command',
2312
+ Edit: 'replace_file_content',
2313
+ Bash: 'run_command',
2268
2314
  Glob: 'glob',
2269
- Grep: 'search_file_content',
2315
+ Grep: 'grep_search',
2270
2316
  WebSearch: 'google_web_search',
2271
2317
  WebFetch: 'web_fetch',
2272
2318
  TodoWrite: 'write_todos',
2273
2319
  };
2274
2320
  /**
2275
- * Convert a Claude Code tool name to Gemini CLI format
2276
- * - Applies Claude→Gemini mapping (Read→read_file, Bash→run_shell_command, etc.)
2277
- * - Filters out MCP tools (mcp__*) — they are auto-discovered at runtime in Gemini
2278
- * - Filters out Task/Agent — agents are auto-registered as tools in Gemini
2279
- * @returns {string|null} Gemini tool name, or null if tool should be excluded
2321
+ * Convert a Claude Code tool name to Antigravity format
2322
+ * - Applies Claude→Antigravity mapping (Read→read_file, Bash→run_shell_command, etc.)
2323
+ * - Filters out MCP tools (mcp__*) — they are auto-discovered at runtime in Antigravity
2324
+ * - Filters out Task/Agent — agents are auto-registered as tools in Antigravity
2325
+ * @returns {string|null} Antigravity tool name, or null if tool should be excluded
2280
2326
  */
2281
- function convertGeminiToolName(claudeTool) {
2327
+ function convertAntigravityToolName(claudeTool) {
2282
2328
  // MCP tools: exclude — auto-discovered from mcpServers config at runtime
2283
2329
  if (claudeTool.startsWith('mcp__')) {
2284
2330
  return null;
2285
2331
  }
2286
2332
  // Task/Agent: exclude — agents are auto-registered as callable tools.
2287
- // AskUserQuestion: exclude — Gemini CLI does not expose an ask_user tool;
2288
- // emitting it causes frontmatter validation errors (#3362).
2289
- // Skill/SlashCommand: exclude — Gemini CLI has no 'skill' built-in tool;
2290
- // the lowercase fallback would emit an invalid 'skill'/'slashcommand' name
2291
- // that fails frontmatter validation (tools.N: Invalid tool name) and aborts
2292
- // the entire agent load (#1394).
2333
+ // AskUserQuestion: exclude — Antigravity (Gemini tool dialect) does not expose
2334
+ // an ask_user tool; emitting it causes frontmatter validation errors (#3362).
2335
+ // Skill/SlashCommand: exclude — Antigravity (Gemini tool dialect) has no 'skill'
2336
+ // built-in tool; the lowercase fallback would emit an invalid
2337
+ // 'skill'/'slashcommand' name that fails frontmatter validation
2338
+ // (tools.N: Invalid tool name) and aborts the entire agent load (#1394).
2293
2339
  if (claudeTool === 'Task' ||
2294
2340
  claudeTool === 'Agent' ||
2295
2341
  claudeTool === 'AskUserQuestion' ||
@@ -2299,8 +2345,8 @@ function convertGeminiToolName(claudeTool) {
2299
2345
  return null;
2300
2346
  }
2301
2347
  // Check for explicit mapping
2302
- if (claudeToGeminiTools[claudeTool]) {
2303
- return claudeToGeminiTools[claudeTool];
2348
+ if (claudeToAntigravityTools[claudeTool]) {
2349
+ return claudeToAntigravityTools[claudeTool];
2304
2350
  }
2305
2351
  // Default: lowercase
2306
2352
  return claudeTool.toLowerCase();
@@ -2356,7 +2402,7 @@ function convertClaudeAgentToCopilotAgent(content, isGlobal = false) {
2356
2402
  }
2357
2403
  /**
2358
2404
  * Convert a Claude agent (.md) to an Antigravity agent.
2359
- * Uses Gemini tool names since Antigravity runs on Gemini 3 backend.
2405
+ * Uses Antigravity's Gemini tool dialect since Antigravity runs on Gemini 3 backend.
2360
2406
  */
2361
2407
  function convertClaudeAgentToAntigravityAgent(content, isGlobal = false) {
2362
2408
  const converted = convertClaudeToAntigravityContent(content, isGlobal);
@@ -2367,11 +2413,17 @@ function convertClaudeAgentToAntigravityAgent(content, isGlobal = false) {
2367
2413
  const description = extractFrontmatterField(frontmatter, 'description') || '';
2368
2414
  const color = extractFrontmatterField(frontmatter, 'color');
2369
2415
  const toolsRaw = extractFrontmatterField(frontmatter, 'tools') || '';
2370
- // Map tools to Gemini equivalents (reuse existing convertGeminiToolName)
2416
+ // Map tools to Antigravity equivalents (reuse existing convertAntigravityToolName)
2371
2417
  const claudeTools = toolsRaw.split(',').map(t => t.trim()).filter(Boolean);
2372
- const mappedTools = claudeTools.map(t => convertGeminiToolName(t)).filter(Boolean);
2418
+ const mappedTools = claudeTools.map(t => convertAntigravityToolName(t)).filter(Boolean);
2373
2419
  // #2876: quote description for the same reason as the skill variant.
2374
- let fm = `---\nname: ${name}\ndescription: ${yamlQuote(description)}\ntools: ${mappedTools.join(', ')}\n`;
2420
+ // #4705: tools is a YAML SEQUENCE of native names (one `- name` item per
2421
+ // line), not a comma-separated scalar. Empty mapped set -> `tools: []` so an
2422
+ // agent whose every tool was filtered stays explicitly restricted.
2423
+ const toolsBlock = mappedTools.length > 0
2424
+ ? `tools:\n${mappedTools.map((t) => `- ${t}`).join('\n')}\n`
2425
+ : 'tools: []\n';
2426
+ let fm = `---\nname: ${name}\ndescription: ${yamlQuote(description)}\n${toolsBlock}`;
2375
2427
  if (color)
2376
2428
  fm += `color: ${color}\n`;
2377
2429
  fm += '---';
@@ -2754,15 +2806,53 @@ function convertClaudeCommandToKiloSkill(content, skillName) {
2754
2806
  // Relocated from bin/install.js (#1511). Behavior is byte-for-behavior identical
2755
2807
  // to the originals; the only change is the injected `attribution` 5th param in
2756
2808
  // _applyRuntimeRewrites (replacing the internal getCommitAttribution() call).
2809
+ /**
2810
+ * #4377: is the project-relative include style opted in?
2811
+ *
2812
+ * Dual-sourced exactly like `--portable-hooks`/`GSD_PORTABLE_HOOKS`:
2813
+ * `bin/install.js` sets the variable when the flag is passed, so the flag and
2814
+ * the environment cannot disagree, and every seam that computes a path prefix
2815
+ * (the installer copy path, the install engine, the two rewrite entry points,
2816
+ * the install plan, and `applySurface`) reads the same answer without six signatures having to
2817
+ * grow a parameter each and stay in sync.
2818
+ *
2819
+ * Opt-in, not the new default. Making relative the default would change every
2820
+ * existing single-checkout local install — which works today — to fix a
2821
+ * multi-worktree case those users do not have.
2822
+ *
2823
+ * @param env - Environment to read (injectable for tests).
2824
+ * @returns Whether local installs should emit project-relative includes.
2825
+ */
2826
+ function relativeIncludesEnabled(env = process.env) {
2827
+ return env.GSD_RELATIVE_INCLUDES === '1';
2828
+ }
2757
2829
  /**
2758
2830
  * Compute the path prefix for a runtime install.
2759
2831
  * Global installs under $HOME use $HOME/... form; others use the resolved target.
2760
2832
  * isOpencode excludes OpenCode (uses ~/.config/opencode which breaks $HOME shorthand).
2761
2833
  * isWindowsHost is not used today but reserved for future Windows-specific logic.
2762
2834
  *
2835
+ * #4377: a LOCAL install can instead emit a project-relative prefix, so a repo
2836
+ * worked from several git worktrees does not get every worktree's `@` includes
2837
+ * baked to whichever checkout happened to run the installer. Absolute is still
2838
+ * the default; `projectRelative` opts in.
2839
+ *
2840
+ * `localDirName` is the runtime's own `localConfigDir` descriptor value
2841
+ * (via `getDirName`), never a hardcoded literal — the same value the rewrite
2842
+ * engine already uses for its `./.claude/` -> `./<dir>/` substitutions, and
2843
+ * exactly what `resolveScope` joins onto the cwd to produce `resolvedTarget`
2844
+ * for a local install. Copilot and Antigravity have shipped this shape for
2845
+ * local installs since they were added, with hardcoded `.github/` and
2846
+ * `.agents/`; this is the same behavior, derived instead of written down.
2847
+ *
2848
+ * Fails safe to the absolute prefix: no opt-in, a global install, a missing
2849
+ * dir name, or the `configHome.kind === 'none'` sentinel all fall through. A
2850
+ * wrong-but-absolute include still resolves to a real file; a wrong relative
2851
+ * one silently resolves against whatever the reader's cwd happens to be.
2852
+ *
2763
2853
  * @private — exported as `_computePathPrefix` for tests.
2764
2854
  */
2765
- function computePathPrefix({ isGlobal, isOpencode, isWindowsHost: _isWindowsHost, resolvedTarget, homeDir }) {
2855
+ function computePathPrefix({ isGlobal, isOpencode, isWindowsHost: _isWindowsHost, resolvedTarget, homeDir, projectRelative = relativeIncludesEnabled(), localDirName, projectRoot = process.cwd(), projectRelativePath, }) {
2766
2856
  // #1615: normalize Windows backslashes to forward slashes. This prefix is
2767
2857
  // substituted into markdown @-references (e.g. Windsurf workflow files),
2768
2858
  // which use POSIX paths universally. Idempotent on POSIX (no backslashes).
@@ -2774,8 +2864,62 @@ function computePathPrefix({ isGlobal, isOpencode, isWindowsHost: _isWindowsHost
2774
2864
  if (isGlobal && posixTarget.startsWith(posixHome) && !isOpencode) {
2775
2865
  return '$HOME' + posixTarget.slice(posixHome.length) + '/';
2776
2866
  }
2867
+ if (!isGlobal && projectRelative) {
2868
+ // An explicit local config dir need not be the descriptor's conventional
2869
+ // `.claude`-style directory. Derive from the resolved target first; only
2870
+ // use the descriptor as the legacy fallback when no project root exists.
2871
+ const relative = projectRelativePrefix(projectRelativePath)
2872
+ || projectRelativePrefixFromProjectRoot(projectRoot, resolvedTarget)
2873
+ || projectRelativePrefix(localDirName);
2874
+ if (relative)
2875
+ return relative;
2876
+ }
2777
2877
  return `${posixTarget}/`;
2778
2878
  }
2879
+ /** Return a safe project-relative prefix for a resolved install target. */
2880
+ function projectRelativePrefixFromProjectRoot(projectRoot, resolvedTarget) {
2881
+ if (typeof projectRoot !== 'string' || typeof resolvedTarget !== 'string')
2882
+ return '';
2883
+ const relative = (0, shell_command_projection_cjs_1.posixNormalize)(node_path_1.default.relative(projectRoot, resolvedTarget));
2884
+ if (!relative || relative === '.' || relative === '..' || relative.startsWith('../') || node_path_1.default.isAbsolute(relative))
2885
+ return '';
2886
+ return projectRelativePrefix(relative);
2887
+ }
2888
+ /**
2889
+ * A runtime installed directly at the project root cannot use its descriptor
2890
+ * directory in a project-relative include: that directory was never created.
2891
+ */
2892
+ function localIncludeDirName(runtime) {
2893
+ return _hostBehaviors(runtime).localTargetIsProjectRoot === true ? undefined : getDirName(runtime);
2894
+ }
2895
+ /**
2896
+ * #4377: the project-relative prefix for a local install, or `''` when the
2897
+ * runtime cannot express one and the caller must fall back to absolute.
2898
+ *
2899
+ * Rejects the `configHome.kind === 'none'` sentinel (a runtime with no local
2900
+ * config dir at all — interpolating it would produce a literal
2901
+ * `(no-local-config-dir)/` path segment), anything absolute, and anything that
2902
+ * climbs out of the project with `..`. Trailing slashes are normalized so a
2903
+ * descriptor value written either way yields one prefix.
2904
+ *
2905
+ * @param localDirName - The runtime's `localConfigDir` descriptor value.
2906
+ * @returns A `dir/` prefix, or `''` to signal "use the absolute form".
2907
+ */
2908
+ function projectRelativePrefix(localDirName) {
2909
+ if (typeof localDirName !== 'string' || localDirName.length === 0)
2910
+ return '';
2911
+ if (localDirName === runtimeNamePolicy.NO_LOCAL_CONFIG_DIR_SENTINEL)
2912
+ return '';
2913
+ const normalized = (0, shell_command_projection_cjs_1.posixNormalize)(localDirName).replace(/\/+$/, '');
2914
+ if (!normalized || normalized.startsWith('/') || /^[A-Za-z]:/.test(normalized))
2915
+ return '';
2916
+ // Reject a climb in ANY segment, not only at the beginning. posixNormalize
2917
+ // deliberately normalizes separators rather than resolving path segments,
2918
+ // so `nested/../../outside` must be caught explicitly here.
2919
+ if (normalized.split('/').includes('..'))
2920
+ return '';
2921
+ return `${normalized}/`;
2922
+ }
2779
2923
  /**
2780
2924
  * Canonical list of every non-Claude runtime that gsd-core emits artifacts for.
2781
2925
  * DERIVED from the capability registry (ADR-1239 Phase B, #1679) — the registry's
@@ -2942,9 +3086,111 @@ function restoreClaudeGlobalAtRefTilde(content, pathPrefix) {
2942
3086
  *
2943
3087
  * @private — exported as `_applyRuntimeRewrites` for tests.
2944
3088
  */
3089
+ /**
3090
+ * #4377: is this prefix a project-relative one?
3091
+ *
3092
+ * Anything not rooted -- no leading `/`, no `$HOME`, no `~`, no drive letter.
3093
+ * Used only to decide whether the shell-default guard below needs to run, so
3094
+ * an absolute install is byte-for-byte untouched by any of this.
3095
+ *
3096
+ * @param pathPrefix - The computed prefix.
3097
+ * @returns Whether it resolves relative to something.
3098
+ */
3099
+ function isRelativePathPrefix(pathPrefix) {
3100
+ if (typeof pathPrefix !== 'string' || pathPrefix.length === 0)
3101
+ return false;
3102
+ return !(pathPrefix.startsWith('/')
3103
+ || pathPrefix.startsWith('$HOME')
3104
+ || pathPrefix.startsWith('~')
3105
+ || /^[A-Za-z]:/.test(pathPrefix));
3106
+ }
3107
+ /**
3108
+ * #4377: shield `${VAR:-default}` shell defaults from a RELATIVE path prefix.
3109
+ *
3110
+ * The runtime launcher snippet probes for gsd-tools through a chain of shell
3111
+ * defaults -- `${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/...`, one per
3112
+ * runtime. Those are shell word expansions, not markdown `@` includes, and
3113
+ * they are the one place where substituting a project-relative prefix makes
3114
+ * things WORSE rather than better: `$HOME/.claude` resolves the same from
3115
+ * anywhere, while a bare `.claude` resolves against whatever directory the
3116
+ * shell happens to be sitting in. Trading an include that points at the wrong
3117
+ * checkout for a path that points at nothing is not a fix.
3118
+ *
3119
+ * The issue asked for project-relative INCLUDES, and this keeps the change to
3120
+ * exactly that. The launcher already handles the multi-worktree case on its
3121
+ * own, and better -- it probes `$(git rev-parse --show-toplevel)/.claude/...`
3122
+ * first, so it finds the current worktree's copy long before it reaches these
3123
+ * defaults.
3124
+ *
3125
+ * The mask token is `@@GSD4377:<n>@@`. It has to survive every substitution in
3126
+ * the rewrite body untouched, so it deliberately contains no `.claude`, no
3127
+ * `~`, no `$HOME` and no path separator -- there is nothing in it for those
3128
+ * regexes to match. A collision would need that literal to already exist in
3129
+ * the shipped corpus, which is asserted against in the tests.
3130
+ *
3131
+ * Only runs when the prefix is relative, so an absolute install never sees
3132
+ * this transformation at all.
3133
+ *
3134
+ * @param content - The body being rewritten.
3135
+ * @param rewrite - The substitution pass to run on the unguarded remainder.
3136
+ * @returns The rewritten body, with every shell default restored verbatim.
3137
+ */
3138
+ function withShellDefaultsPreserved(content, rewrite) {
3139
+ const preserved = [];
3140
+ let masked = '';
3141
+ let copiedThrough = 0;
3142
+ let searchFrom = 0;
3143
+ // Scan balanced `${...}` expansions instead of stopping at the first `}`.
3144
+ // The launcher has nested defaults such as `${A:-${B:-$HOME/.x}}`; a
3145
+ // single `[^}]*` regex only recognizes a prefix of that expression and
3146
+ // makes preservation depend accidentally on where the rewritten text sits.
3147
+ while (searchFrom < content.length) {
3148
+ const start = content.indexOf('${', searchFrom);
3149
+ if (start === -1)
3150
+ break;
3151
+ const opener = /^\$\{[A-Za-z_][A-Za-z0-9_]*:-/.exec(content.slice(start));
3152
+ if (!opener) {
3153
+ searchFrom = start + 2;
3154
+ continue;
3155
+ }
3156
+ let depth = 1;
3157
+ let end = start + opener[0].length;
3158
+ while (end < content.length && depth > 0) {
3159
+ if (content.startsWith('${', end)) {
3160
+ depth += 1;
3161
+ end += 2;
3162
+ continue;
3163
+ }
3164
+ if (content[end] === '}')
3165
+ depth -= 1;
3166
+ end += 1;
3167
+ }
3168
+ if (depth !== 0) {
3169
+ searchFrom = start + 2;
3170
+ continue;
3171
+ }
3172
+ masked += content.slice(copiedThrough, start);
3173
+ preserved.push(content.slice(start, end));
3174
+ masked += `@@GSD4377:${preserved.length - 1}@@`;
3175
+ copiedThrough = end;
3176
+ searchFrom = end;
3177
+ }
3178
+ masked += content.slice(copiedThrough);
3179
+ return rewrite(masked).replace(/@@GSD4377:(\d+)@@/g, (_m, i) => preserved[Number(i)]);
3180
+ }
2945
3181
  function _applyRuntimeRewrites(content, runtime, pathPrefix, isGlobal = false, attribution = undefined) {
3182
+ // #4377: with a project-relative prefix, run the whole substitution body
3183
+ // with `${VAR:-default}` shell defaults masked out, so the launcher shim
3184
+ // keeps its absolute fallbacks. A no-op for the absolute (default) prefix.
3185
+ if (isRelativePathPrefix(pathPrefix)) {
3186
+ return withShellDefaultsPreserved(content, (masked) => _applyRuntimeRewritesInner(masked, runtime, pathPrefix, isGlobal, attribution));
3187
+ }
3188
+ return _applyRuntimeRewritesInner(content, runtime, pathPrefix, isGlobal, attribution);
3189
+ }
3190
+ function _applyRuntimeRewritesInner(content, runtime, pathPrefix, isGlobal = false, attribution = undefined) {
2946
3191
  const dirName = getDirName(runtime);
2947
3192
  const normalizedPathPrefix = pathPrefix.replace(/\/$/, '');
3193
+ content = filterRuntimeNotesForTarget(content, runtime);
2948
3194
  // #1521: stamp runtime identity + use_worktrees=false for every non-Claude runtime
2949
3195
  // before brand-specific path rewrites, so the replace operates on the pristine
2950
3196
  // source line and is idempotent regardless of subsequent path substitutions.
@@ -3280,7 +3526,9 @@ function rewriteStagedSkillBodies(stagedDir, opts) {
3280
3526
  const isGlobal = (0, install_scope_cjs_1.isGlobalScope)(scope);
3281
3527
  const isOpencode = false; // #2087: opencode installs via the combined-family engine path, never through the generic rewrite
3282
3528
  const isWindowsHost = platform === 'win32';
3283
- const pathPrefix = computePathPrefix({ isGlobal, isOpencode, isWindowsHost, resolvedTarget, homeDir });
3529
+ // #4377: localDirName lets a local install emit a project-relative prefix
3530
+ // when opted in; ignored for a global install and when the opt-in is off.
3531
+ const pathPrefix = computePathPrefix({ isGlobal, isOpencode, isWindowsHost, resolvedTarget, homeDir, localDirName: localIncludeDirName(runtime) });
3284
3532
  const attribution = resolveAttribution ? resolveAttribution(runtime) : undefined;
3285
3533
  applyRuntimeContentRewritesInPlace(stagedDir, runtime, pathPrefix, isGlobal, attribution);
3286
3534
  // #2873 (4b): claude, global scope only — see
@@ -3323,7 +3571,9 @@ function rewriteStagedCommandBodies(stagedDir, opts) {
3323
3571
  const isGlobal = (0, install_scope_cjs_1.isGlobalScope)(scope);
3324
3572
  const isOpencode = false; // #2087: opencode installs via the combined-family engine path, never through the generic rewrite
3325
3573
  const isWindowsHost = platform === 'win32';
3326
- const pathPrefix = computePathPrefix({ isGlobal, isOpencode, isWindowsHost, resolvedTarget, homeDir });
3574
+ // #4377: localDirName lets a local install emit a project-relative prefix
3575
+ // when opted in; ignored for a global install and when the opt-in is off.
3576
+ const pathPrefix = computePathPrefix({ isGlobal, isOpencode, isWindowsHost, resolvedTarget, homeDir, localDirName: localIncludeDirName(runtime) });
3327
3577
  const attribution = resolveAttribution ? resolveAttribution(runtime) : undefined;
3328
3578
  return applyRuntimeContentRewritesForCommandsInPlace(stagedDir, runtime, pathPrefix, isGlobal, attribution);
3329
3579
  }
@@ -3373,6 +3623,18 @@ function normalizeAgentBodyForRuntime(content, runtime, cmdNames) {
3373
3623
  function applyAgentPathRewrites(content, runtime, pathPrefix) {
3374
3624
  if (_hostBehaviors(runtime).noPathRewrite === true)
3375
3625
  return content;
3626
+ // #4377: the agents pipeline is the third emit path that substitutes this
3627
+ // prefix (skills/commands via _applyRuntimeRewrites, the gsd-core spec tree
3628
+ // via copyWithPathReplacement, and here). All three carry the same guard:
3629
+ // with a project-relative prefix, `${VAR:-default}` shell defaults are
3630
+ // masked out so the runtime launcher keeps its absolute fallbacks. A no-op
3631
+ // for the absolute prefix. See withShellDefaultsPreserved for why.
3632
+ if (isRelativePathPrefix(pathPrefix)) {
3633
+ return withShellDefaultsPreserved(content, (masked) => applyAgentPathRewritesInner(masked, runtime, pathPrefix));
3634
+ }
3635
+ return applyAgentPathRewritesInner(content, runtime, pathPrefix);
3636
+ }
3637
+ function applyAgentPathRewritesInner(content, runtime, pathPrefix) {
3376
3638
  const normalizedPathPrefix = pathPrefix.replace(/\/$/, '');
3377
3639
  content = content.replace(/~\/\.claude\//g, pathPrefix);
3378
3640
  content = content.replace(/\$HOME\/\.claude\//g, pathPrefix);
@@ -3613,6 +3875,7 @@ module.exports = {
3613
3875
  neutralizeAgentReferences,
3614
3876
  convertClaudeCommandToOpencodeSkill,
3615
3877
  convertClaudeCommandToKiloSkill,
3878
+ filterRuntimeNotesForTarget,
3616
3879
  // #2087 — opencode/kilo command-frontmatter converters, exported so the
3617
3880
  // layout-driven `convertedCommandsKind` can resolve them by name (routes the
3618
3881
  // opencode/kilo command install through the engine instead of the bespoke path).
@@ -3628,8 +3891,8 @@ module.exports = {
3628
3891
  // #1182: agent converters + tool-name table dependency closure
3629
3892
  claudeToCopilotTools,
3630
3893
  convertCopilotToolName,
3631
- claudeToGeminiTools,
3632
- convertGeminiToolName,
3894
+ claudeToAntigravityTools,
3895
+ convertAntigravityToolName,
3633
3896
  convertClaudeAgentToCopilotAgent,
3634
3897
  convertClaudeAgentToAntigravityAgent,
3635
3898
  convertClaudeAgentToCursorAgent,
@@ -3673,6 +3936,12 @@ module.exports = {
3673
3936
  READONLY_AGENT_DISALLOWED_TOOLS,
3674
3937
  applyAgentFrontmatterExtensions,
3675
3938
  _computePathPrefix: computePathPrefix,
3939
+ _withShellDefaultsPreserved: withShellDefaultsPreserved,
3940
+ _isRelativePathPrefix: isRelativePathPrefix,
3941
+ _relativeIncludesEnabled: relativeIncludesEnabled,
3942
+ _projectRelativePrefix: projectRelativePrefix,
3943
+ _projectRelativePrefixFromProjectRoot: projectRelativePrefixFromProjectRoot,
3944
+ _localIncludeDirName: localIncludeDirName,
3676
3945
  _restoreClaudeGlobalAtRefTilde: restoreClaudeGlobalAtRefTilde,
3677
3946
  _applyRuntimeRewrites,
3678
3947
  _stampNonClaudeRuntimeDefaults,
@@ -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)
@@ -83,7 +92,9 @@ function createRuntimeArtifactInstallPlan(args) {
83
92
  const isGlobal = (0, install_scope_cjs_1.isGlobalScope)(scope);
84
93
  const isOpencode = layout.runtime === 'opencode';
85
94
  const isWindowsHost = (platform ?? process.platform) === 'win32';
86
- const pathPrefix = conversionExports._computePathPrefix({ isGlobal, isOpencode, isWindowsHost, resolvedTarget, homeDir });
95
+ // #4377: descriptor-derived local dir name, so an opted-in local install
96
+ // emits a project-relative prefix instead of this checkout's absolute path.
97
+ const pathPrefix = conversionExports._computePathPrefix({ isGlobal, isOpencode, isWindowsHost, resolvedTarget, homeDir, localDirName: conversionExports._localIncludeDirName(layout.runtime) });
87
98
  const attribution = resolveAttribution ? resolveAttribution(layout.runtime) : undefined;
88
99
  // #2875 Part 2 (row I1): layout.configDir IS the install root the inline
89
100
  // agent loop called `targetDir` — same value, same resolution.