@opengsd/gsd-core 1.17.0 → 1.18.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 (176) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/agents/gsd-advisor-researcher.compact.md +1 -1
  4. package/agents/gsd-advisor-researcher.md +1 -1
  5. package/agents/gsd-assumptions-analyzer.compact.md +1 -1
  6. package/agents/gsd-assumptions-analyzer.md +1 -1
  7. package/agents/gsd-code-fixer.compact.md +1 -1
  8. package/agents/gsd-code-fixer.md +1 -1
  9. package/agents/gsd-code-reviewer.compact.md +1 -1
  10. package/agents/gsd-code-reviewer.md +1 -1
  11. package/agents/gsd-codebase-mapper.compact.md +1 -1
  12. package/agents/gsd-codebase-mapper.md +1 -1
  13. package/agents/gsd-debugger.md +1 -1
  14. package/agents/gsd-doc-verifier.compact.md +4 -4
  15. package/agents/gsd-doc-verifier.md +4 -3
  16. package/agents/gsd-doc-writer.compact.md +23 -5
  17. package/agents/gsd-doc-writer.md +19 -6
  18. package/agents/gsd-eval-auditor.compact.md +1 -1
  19. package/agents/gsd-eval-auditor.md +1 -1
  20. package/agents/gsd-executor.md +7 -3
  21. package/agents/gsd-integration-checker.compact.md +1 -1
  22. package/agents/gsd-integration-checker.md +1 -1
  23. package/agents/gsd-nyquist-auditor.compact.md +1 -1
  24. package/agents/gsd-nyquist-auditor.md +1 -1
  25. package/agents/gsd-phase-researcher.md +1 -1
  26. package/agents/gsd-plan-checker.md +2 -1
  27. package/agents/gsd-planner.md +5 -4
  28. package/agents/gsd-project-researcher.compact.md +1 -1
  29. package/agents/gsd-project-researcher.md +1 -1
  30. package/agents/gsd-research-synthesizer.compact.md +5 -5
  31. package/agents/gsd-research-synthesizer.md +5 -5
  32. package/agents/gsd-roadmapper.compact.md +1 -1
  33. package/agents/gsd-roadmapper.md +1 -1
  34. package/agents/gsd-security-auditor.compact.md +1 -1
  35. package/agents/gsd-security-auditor.md +1 -1
  36. package/agents/gsd-ui-auditor.compact.md +1 -1
  37. package/agents/gsd-ui-auditor.md +1 -1
  38. package/agents/gsd-ui-checker.compact.md +1 -1
  39. package/agents/gsd-ui-checker.md +1 -1
  40. package/agents/gsd-ui-researcher.compact.md +13 -1
  41. package/agents/gsd-ui-researcher.md +28 -1
  42. package/agents/gsd-verifier.md +1 -1
  43. package/bin/install.js +38 -2
  44. package/commands/gsd/code-review.md +8 -0
  45. package/commands/gsd/pause-work.md +1 -1
  46. package/gsd-core/bin/gsd-tools.cjs +18 -11
  47. package/gsd-core/bin/lib/capability-ledger.cjs +25 -0
  48. package/gsd-core/bin/lib/capability-lock.cjs +29 -7
  49. package/gsd-core/bin/lib/capability-registry.cjs +70 -64
  50. package/gsd-core/bin/lib/capability-source.cjs +3 -1
  51. package/gsd-core/bin/lib/capability-state.cjs +6 -3
  52. package/gsd-core/bin/lib/capability-validator.cjs +6 -4
  53. package/gsd-core/bin/lib/commands.cjs +5 -1
  54. package/gsd-core/bin/lib/config-loader.cjs +3 -3
  55. package/gsd-core/bin/lib/decision-coverage-support.cjs +19 -0
  56. package/gsd-core/bin/lib/gate-decision-coverage-plan.cjs +15 -0
  57. package/gsd-core/bin/lib/gate-decision-coverage-verify.cjs +13 -0
  58. package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +23 -3
  59. package/gsd-core/bin/lib/gate-predicate.cjs +8 -12
  60. package/gsd-core/bin/lib/gate-tdd-review-checkpoint.cjs +60 -5
  61. package/gsd-core/bin/lib/init.cjs +11 -4
  62. package/gsd-core/bin/lib/install-effort-resolver.cjs +2 -2
  63. package/gsd-core/bin/lib/install-model-override-resolver.cjs +4 -3
  64. package/gsd-core/bin/lib/install-profiles.cjs +5 -3
  65. package/gsd-core/bin/lib/phase.cjs +120 -11
  66. package/gsd-core/bin/lib/report-parser.cjs +57 -1
  67. package/gsd-core/bin/lib/review-lane-invocation.cjs +40 -0
  68. package/gsd-core/bin/lib/review-reviewer-selection.cjs +20 -1
  69. package/gsd-core/bin/lib/roadmap.cjs +56 -5
  70. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +47 -2
  71. package/gsd-core/bin/lib/runtime-homes.cjs +18 -0
  72. package/gsd-core/bin/lib/shell-command-projection.cjs +2 -0
  73. package/gsd-core/bin/lib/smart-entry.cjs +24 -16
  74. package/gsd-core/bin/lib/state-document.cjs +37 -3
  75. package/gsd-core/bin/lib/state-transition.cjs +31 -10
  76. package/gsd-core/bin/lib/state.cjs +90 -60
  77. package/gsd-core/bin/lib/task-command-router.cjs +2 -3
  78. package/gsd-core/bin/lib/tdd-red-evidence.cjs +5 -0
  79. package/gsd-core/bin/lib/tdd-test-files.cjs +42 -0
  80. package/gsd-core/bin/lib/verify.cjs +36 -1
  81. package/gsd-core/references/agent-contracts.md +1 -1
  82. package/gsd-core/references/agent-skills-bootstrap.md +26 -7
  83. package/gsd-core/references/git-integration.md +3 -3
  84. package/gsd-core/references/planner-reversibility.md +18 -4
  85. package/gsd-core/references/planner-verify-command-grounding.md +18 -0
  86. package/gsd-core/references/tdd.md +4 -3
  87. package/gsd-core/references/verifier-phase-gates.md +8 -1
  88. package/gsd-core/workflows/add-backlog.md +10 -2
  89. package/gsd-core/workflows/add-phase.md +5 -1
  90. package/gsd-core/workflows/add-tests.md +5 -1
  91. package/gsd-core/workflows/add-todo.md +5 -1
  92. package/gsd-core/workflows/ai-integration-phase.md +5 -1
  93. package/gsd-core/workflows/audit-milestone.md +21 -9
  94. package/gsd-core/workflows/autonomous/templates/minimal-context.md +41 -0
  95. package/gsd-core/workflows/autonomous.md +52 -64
  96. package/gsd-core/workflows/check-todos.md +5 -1
  97. package/gsd-core/workflows/code-review-fix.md +5 -1
  98. package/gsd-core/workflows/code-review.md +5 -1
  99. package/gsd-core/workflows/complete-milestone/detail/elaboration.md +5 -1
  100. package/gsd-core/workflows/complete-milestone.md +25 -5
  101. package/gsd-core/workflows/debug.md +5 -1
  102. package/gsd-core/workflows/diagnose-issues.md +5 -1
  103. package/gsd-core/workflows/discuss-phase/modes/chain.md +5 -1
  104. package/gsd-core/workflows/discuss-phase-assumptions.md +11 -3
  105. package/gsd-core/workflows/discuss-phase.md +5 -1
  106. package/gsd-core/workflows/docs-update/detail/elaboration.md +7 -6
  107. package/gsd-core/workflows/docs-update.md +27 -5
  108. package/gsd-core/workflows/edit-phase.md +5 -1
  109. package/gsd-core/workflows/eval-review.md +11 -3
  110. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +5 -1
  111. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +12 -6
  112. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +19 -2
  113. package/gsd-core/workflows/execute-phase/steps/regression-gate.md +18 -1
  114. package/gsd-core/workflows/execute-phase/steps/verify-phase-goal.md +5 -1
  115. package/gsd-core/workflows/execute-phase.md +37 -6
  116. package/gsd-core/workflows/execute-plan.md +8 -4
  117. package/gsd-core/workflows/extract-learnings.md +6 -2
  118. package/gsd-core/workflows/forensics.md +5 -1
  119. package/gsd-core/workflows/import.md +5 -1
  120. package/gsd-core/workflows/insert-phase.md +5 -1
  121. package/gsd-core/workflows/manager.md +10 -2
  122. package/gsd-core/workflows/map-codebase.md +5 -1
  123. package/gsd-core/workflows/milestone-summary.md +10 -2
  124. package/gsd-core/workflows/new-milestone.md +13 -5
  125. package/gsd-core/workflows/new-project.md +9 -5
  126. package/gsd-core/workflows/next.md +8 -4
  127. package/gsd-core/workflows/pause-work.md +3 -3
  128. package/gsd-core/workflows/plan-phase/steps/auto-advance-check.md +70 -0
  129. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +5 -1
  130. package/gsd-core/workflows/plan-phase/steps/closed-phase-gate.md +6 -2
  131. package/gsd-core/workflows/plan-phase.md +41 -73
  132. package/gsd-core/workflows/plan-review-convergence.md +17 -5
  133. package/gsd-core/workflows/plant-seed.md +8 -4
  134. package/gsd-core/workflows/progress.md +6 -2
  135. package/gsd-core/workflows/quick-batch.md +5 -1
  136. package/gsd-core/workflows/quick.md +22 -7
  137. package/gsd-core/workflows/remove-phase.md +5 -1
  138. package/gsd-core/workflows/resume-project.md +5 -1
  139. package/gsd-core/workflows/review.md +6 -2
  140. package/gsd-core/workflows/scan.md +5 -1
  141. package/gsd-core/workflows/secure-phase.md +6 -2
  142. package/gsd-core/workflows/settings.md +3 -3
  143. package/gsd-core/workflows/ship.md +13 -10
  144. package/gsd-core/workflows/thread.md +10 -2
  145. package/gsd-core/workflows/transition.md +5 -1
  146. package/gsd-core/workflows/ui-phase.md +5 -1
  147. package/gsd-core/workflows/ui-review.md +6 -2
  148. package/gsd-core/workflows/ultraplan-phase.md +5 -1
  149. package/gsd-core/workflows/update.md +5 -1
  150. package/gsd-core/workflows/validate-phase.md +6 -2
  151. package/gsd-core/workflows/verify-work/detail/elaboration.md +1 -1
  152. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +5 -1
  153. package/gsd-core/workflows/verify-work.md +11 -3
  154. package/hooks/dist/gsd-agent-isolation-guard.js +3 -1
  155. package/hooks/dist/gsd-cursor-subagent-start.js +2 -1
  156. package/hooks/dist/gsd-secret-read-guard.js +72 -14
  157. package/hooks/dist/gsd-validate-commit.sh +27 -5
  158. package/hooks/gsd-agent-isolation-guard.js +3 -1
  159. package/hooks/gsd-cursor-subagent-start.js +2 -1
  160. package/hooks/gsd-secret-read-guard.js +72 -14
  161. package/hooks/gsd-validate-commit.sh +27 -5
  162. package/package.json +1 -1
  163. package/scripts/audit-workflow-script-paths.cjs +1 -1
  164. package/scripts/diagnose-validate-commit-in-tier.cjs +270 -0
  165. package/scripts/diagnose-validate-commit-phases.cjs +348 -0
  166. package/scripts/diagnose-windows-spawn-watcher.cjs +317 -0
  167. package/scripts/docs-guard-registry.cjs +2 -0
  168. package/scripts/lib/macos-conformance-tier.generated.cjs +9 -0
  169. package/scripts/lib/platform-conformance-tier.generated.cjs +16 -0
  170. package/scripts/lint-phase-arg-assignment.cjs +2 -2
  171. package/scripts/lint-workflow-shellcheck-baseline.json +16 -16
  172. package/scripts/release-tarball-smoke.cjs +1 -0
  173. package/scripts/xtrace-phase-timing.cjs +205 -0
  174. package/skills/gsd-code-review/SKILL.md +8 -0
  175. package/skills/gsd-pause-work/SKILL.md +1 -1
  176. package/vscode/package.json +1 -1
@@ -23,7 +23,7 @@ Job: transform requirements into a phase structure that delivers the project. Ev
23
23
  **Context budget:** load project skills first (lightweight); read implementation files incrementally, only what each check requires.
24
24
 
25
25
  **Project skills:** check `.claude/skills/` or `.agents/skills/`:
26
- **agent_skills:** self-load per @~/.claude/gsd-core/references/agent-skills-bootstrap.md
26
+ **agent_skills:** self-load per @~/.claude/gsd-core/references/agent-skills-bootstrap.md (agent type: `gsd-roadmapper`)
27
27
  1. List available skills (subdirectories)
28
28
  2. Read `SKILL.md` per skill (lightweight index ~130 lines)
29
29
  3. Load specific `rules/*.md` as needed
@@ -27,7 +27,7 @@ If the prompt contains a `<required_reading>` block, you MUST use the `Read` too
27
27
 
28
28
  **Project skills:** Check `.claude/skills/` or `.agents/skills/` directory if either exists:
29
29
 
30
- **agent_skills:** self-load per @~/.claude/gsd-core/references/agent-skills-bootstrap.md
30
+ **agent_skills:** self-load per @~/.claude/gsd-core/references/agent-skills-bootstrap.md (agent type: `gsd-roadmapper`)
31
31
  1. List available skills (subdirectories)
32
32
  2. Read `SKILL.md` for each skill (lightweight index ~130 lines)
33
33
  3. Load specific `rules/*.md` files as needed during implementation
@@ -44,7 +44,7 @@ Read ALL `<required_reading>` files. Extract:
44
44
 
45
45
  **Project skills:** check `.claude/skills/` or `.agents/skills/` if either exists.
46
46
 
47
- **agent_skills:** self-load per @~/.claude/gsd-core/references/agent-skills-bootstrap.md — list skill subdirs, read each `SKILL.md` (~130-line index), load `rules/*.md` as needed. NEVER load full `AGENTS.md` (100KB+ cost). Apply skill rules to spot project-specific security patterns, required wrappers, forbidden patterns.
47
+ **agent_skills:** self-load per @~/.claude/gsd-core/references/agent-skills-bootstrap.md (agent type: `gsd-security-auditor`) — list skill subdirs, read each `SKILL.md` (~130-line index), load `rules/*.md` as needed. NEVER load full `AGENTS.md` (100KB+ cost). Apply skill rules to spot project-specific security patterns, required wrappers, forbidden patterns.
48
48
  </step>
49
49
 
50
50
  <step name="analyze_threats">
@@ -50,7 +50,7 @@ Read ALL files from `<required_reading>`. Extract:
50
50
 
51
51
  **Project skills:** Check `.claude/skills/` or `.agents/skills/` directory if either exists:
52
52
 
53
- **agent_skills:** self-load per @~/.claude/gsd-core/references/agent-skills-bootstrap.md
53
+ **agent_skills:** self-load per @~/.claude/gsd-core/references/agent-skills-bootstrap.md (agent type: `gsd-security-auditor`)
54
54
  1. List available skills (subdirectories)
55
55
  2. Read `SKILL.md` for each skill (lightweight index ~130 lines)
56
56
  3. Load specific `rules/*.md` files as needed during implementation
@@ -48,7 +48,7 @@ Before auditing, discover project context:
48
48
  **Project instructions:** Read `./CLAUDE.md` if present; follow all project-specific guidelines.
49
49
 
50
50
  **Project skills:** Check `.claude/skills/` or `.agents/skills/`.
51
- **agent_skills:** self-load per @~/.claude/gsd-core/references/agent-skills-bootstrap.md
51
+ **agent_skills:** self-load per @~/.claude/gsd-core/references/agent-skills-bootstrap.md (agent type: `gsd-ui-auditor`)
52
52
  1. List available skills 2. Read `SKILL.md` for each 3. Do NOT load full `AGENTS.md` (100KB+ context cost)
53
53
  </project_context>
54
54
 
@@ -50,7 +50,7 @@ Before auditing, discover project context:
50
50
 
51
51
  **Project skills:** Check `.claude/skills/` or `.agents/skills/` directory if either exists:
52
52
 
53
- **agent_skills:** self-load per @~/.claude/gsd-core/references/agent-skills-bootstrap.md
53
+ **agent_skills:** self-load per @~/.claude/gsd-core/references/agent-skills-bootstrap.md (agent type: `gsd-ui-auditor`)
54
54
  1. List available skills (subdirectories)
55
55
  2. Read `SKILL.md` for each skill
56
56
  3. Do NOT load full `AGENTS.md` files (100KB+ context cost)
@@ -63,7 +63,7 @@ Before verifying: read `./CLAUDE.md` if present, follow project-specific guideli
63
63
 
64
64
  Check `.claude/skills/` or `.agents/skills/` if either exists.
65
65
 
66
- **agent_skills:** self-load per @~/.claude/gsd-core/references/agent-skills-bootstrap.md — list
66
+ **agent_skills:** self-load per @~/.claude/gsd-core/references/agent-skills-bootstrap.md (agent type: `gsd-ui-checker`) — list
67
67
  skills, read each `SKILL.md` (~130 lines), load `rules/*.md` as needed during verification. Do
68
68
  NOT load full `AGENTS.md` (100KB+ cost). This ensures verification respects project-specific
69
69
  design conventions.
@@ -62,7 +62,7 @@ Before verifying, discover project context:
62
62
 
63
63
  **Project skills:** Check `.claude/skills/` or `.agents/skills/` directory if either exists:
64
64
 
65
- **agent_skills:** self-load per @~/.claude/gsd-core/references/agent-skills-bootstrap.md
65
+ **agent_skills:** self-load per @~/.claude/gsd-core/references/agent-skills-bootstrap.md (agent type: `gsd-ui-checker`)
66
66
  1. List available skills (subdirectories)
67
67
  2. Read `SKILL.md` for each skill (lightweight index ~130 lines)
68
68
  3. Load specific `rules/*.md` files as needed during verification
@@ -29,7 +29,7 @@ GSD UI researcher, spawned by `/gsd:ui-phase`. Answer "What visual and interacti
29
29
  <project_context>
30
30
  Before researching: read `./CLAUDE.md` if it exists (follow project guidelines/security/conventions). Check `.claude/skills/` or `.agents/skills/`:
31
31
 
32
- **agent_skills:** self-load per @~/.claude/gsd-core/references/agent-skills-bootstrap.md — list skill subdirectories; read each `SKILL.md` (~130 lines); load `rules/*.md` as needed; do NOT load full `AGENTS.md` (100KB+ cost); account for project skill patterns in the design contract.
32
+ **agent_skills:** self-load per @~/.claude/gsd-core/references/agent-skills-bootstrap.md (agent type: `gsd-ui-researcher`) — list skill subdirectories; read each `SKILL.md` (~130 lines); load `rules/*.md` as needed; do NOT load full `AGENTS.md` (100KB+ cost); account for project skill patterns in the design contract.
33
33
  </project_context>
34
34
 
35
35
  <upstream_input>
@@ -99,6 +99,18 @@ node -p "require('<pkg>/package.json').version" # RES
99
99
  ```
100
100
  A first-party CLI with a JSON mode, or an MCP tool the design system ships, beats all three. What matters: the command is **recorded and re-runnable**. Take the version from the installed package, not the range in your dependent's `package.json` (a caret range hides staleness).
101
101
 
102
+ **Cross-check the first answer — always.** A tool's count is a claim: `npx shadcn info` reports "No components installed" on projects with hand-authored or pre-CLI primitives. After the first command answers, count component files on disk as a second source (shadcn: the `aliases.ui` dir in `components.json`, else `components/ui` / `src/components/ui`):
103
+ ```bash
104
+ ls <ui-dir>/*.tsx 2>/dev/null | wc -l # filesystem count
105
+ ```
106
+ If they disagree (including a tool reporting none while files exist), do not pick silently: record the larger filesystem-backed count with the command that produced it, and add directly under the provenance line `Mismatch: <tool> reported <A>, filesystem has <B>.`
107
+
108
+ **A failed lookup is a failure, never a pass-through.** `2>/dev/null` hides why `node -p` died: treat empty output, a non-zero exit, or the literal `undefined` as that step failing. With `node_modules` absent the `require()` version lookup fails; resolve from the lockfile instead (still not the caret range):
109
+ ```bash
110
+ node -p "(require('./package-lock.json').packages['node_modules/<pkg>']||{}).version"
111
+ ```
112
+ For `pnpm-lock.yaml` / `yarn.lock`, read `<pkg>`'s resolved version from that file. If the lockfile cannot answer, write `<version unresolved: <reason>>` in the version slot instead of leaving it empty or guessing.
113
+
102
114
  Record it as the first line of the section, verbatim:
103
115
  ```
104
116
  Enumerated by `<command>` — <N> components — <package>@<version> — <YYYY-MM-DD>.
@@ -41,7 +41,7 @@ Before researching, discover project context:
41
41
 
42
42
  **Project skills:** Check `.claude/skills/` or `.agents/skills/` directory if either exists:
43
43
 
44
- **agent_skills:** self-load per @~/.claude/gsd-core/references/agent-skills-bootstrap.md
44
+ **agent_skills:** self-load per @~/.claude/gsd-core/references/agent-skills-bootstrap.md (agent type: `gsd-ui-researcher`)
45
45
  1. List available skills (subdirectories)
46
46
  2. Read `SKILL.md` for each skill (lightweight index ~130 lines)
47
47
  3. Load specific `rules/*.md` files as needed during research
@@ -166,6 +166,33 @@ A first-party CLI with a JSON mode, or an MCP tool the design system ships, beat
166
166
  matters is that the command is **recorded and re-runnable**. Take the version from the installed
167
167
  package, not the range in your dependent's `package.json` — a caret range hides staleness.
168
168
 
169
+ **Cross-check the first answer — always.** A tool's count is a claim, not a fact: `npx shadcn info`
170
+ reports "No components installed" on a project whose primitives were hand-authored or predate the
171
+ CLI's tracking. After the first command answers, count the component files on disk as an independent
172
+ second source (for shadcn, the `aliases.ui` directory in `components.json`, else `components/ui` or
173
+ `src/components/ui`):
174
+
175
+ ```bash
176
+ ls <ui-dir>/*.tsx 2>/dev/null | wc -l # filesystem count
177
+ ```
178
+
179
+ If the two disagree — including a tool that reports none while files exist — do not pick one
180
+ silently. Record the larger, filesystem-backed count with the command that produced it, and add a
181
+ line directly under the provenance line: `Mismatch: <tool> reported <A>, filesystem has <B>.`
182
+
183
+ **A failed lookup is a failure, never a pass-through.** `2>/dev/null` hides why a `node -p` call died,
184
+ so treat empty output, a non-zero exit, or the literal `undefined` as that step failing. When
185
+ `node_modules` is absent the `require()` version lookup fails; resolve the version from the lockfile
186
+ instead — still not the caret range:
187
+
188
+ ```bash
189
+ node -p "(require('./package-lock.json').packages['node_modules/<pkg>']||{}).version"
190
+ ```
191
+
192
+ For `pnpm-lock.yaml` or `yarn.lock`, read the resolved version for `<pkg>` from that file. If the
193
+ lockfile cannot answer either, say `<version unresolved: <reason>>` in the version slot rather than
194
+ leaving it empty or guessing.
195
+
169
196
  Record it as the first line of the section, verbatim:
170
197
 
171
198
  ```
@@ -55,7 +55,7 @@ Before verifying, discover project context:
55
55
  - Load `rules/*.md` as needed during **verification**.
56
56
  - Apply skill rules when scanning for anti-patterns and verifying quality.
57
57
 
58
- **agent_skills:** self-load per @~/.claude/gsd-core/references/agent-skills-bootstrap.md
58
+ **agent_skills:** self-load per @~/.claude/gsd-core/references/agent-skills-bootstrap.md (agent type: `gsd-verifier`)
59
59
  </project_context>
60
60
 
61
61
  <core_principle>
package/bin/install.js CHANGED
@@ -35,6 +35,7 @@ const {
35
35
  getGlobalSkillsBase,
36
36
  resolveKimiHooksTomlDir,
37
37
  isRegisteredRuntimeId,
38
+ resolveGsdHome,
38
39
  } = require('../gsd-core/bin/lib/runtime-homes.cjs');
39
40
  // #2870: the Install Scope Module — turns a bare 'global' | 'local' scope id
40
41
  // plus a runtime into one resolved value (configHome, settingsFile,
@@ -7033,7 +7034,7 @@ function recordDefaultsProvenance(gsdDir, runtime, defaults, setNow) {
7033
7034
  /** @returns {boolean} true when it removed or reverted something */
7034
7035
  function revertNonClaudeDefaults(runtime) {
7035
7036
  if (hostBehaviorsFor(runtime).nativeModelAliases || process.env.GSD_TEST_MODE) return false;
7036
- const gsdDir = path.join(os.homedir(), '.gsd');
7037
+ const gsdDir = path.join(resolveGsdHome(), '.gsd'); // #5017: GSD_HOME-aware, like the loader
7037
7038
  const provPath = path.join(gsdDir, DEFAULTS_PROVENANCE_NAME);
7038
7039
  if (!fs.existsSync(provPath)) return false;
7039
7040
  let releaseLock = null;
@@ -7086,7 +7087,7 @@ function revertNonClaudeDefaults(runtime) {
7086
7087
  */
7087
7088
  function writeNonClaudeDefaults(runtime) {
7088
7089
  if (hostBehaviorsFor(runtime).nativeModelAliases || process.env.GSD_TEST_MODE) return;
7089
- const gsdDir = path.join(os.homedir(), '.gsd');
7090
+ const gsdDir = path.join(resolveGsdHome(), '.gsd'); // #5017: GSD_HOME-aware, like the loader
7090
7091
  const defaultsPath = path.join(gsdDir, 'defaults.json');
7091
7092
  let releaseLock = null;
7092
7093
  try {
@@ -12565,6 +12566,41 @@ function install(isGlobal, runtime = DEFAULT_RUNTIME, options = {}) {
12565
12566
  }
12566
12567
  }
12567
12568
  }
12569
+ // #5123: the Copilot and Antigravity converters write their DEFAULT home
12570
+ // into `@` includes and Kimi's prompt converter leaves a prose "GSD core/"
12571
+ // path, none of which exist when the payload lives somewhere else. Point
12572
+ // them at the real install root (the same `$HOME/…` / absolute prefix the
12573
+ // other runtimes use). Global installs only: a local install resolves
12574
+ // against its project, which the converters already handle.
12575
+ const includeRetarget = hostBehaviorsFor(runtime);
12576
+ if (isGlobal && (includeRetarget.defaultHomeIncludeRoot || includeRetarget.retargetsGsdCoreProsePath === true)) {
12577
+ const includePrefix = runtimeArtifactConversion._computePathPrefix({
12578
+ isGlobal: true,
12579
+ isOpencode: false,
12580
+ resolvedTarget: targetDir,
12581
+ homeDir: os.homedir(),
12582
+ });
12583
+ for (const relPath of manifestFiles) {
12584
+ const fileName = path.basename(relPath);
12585
+ if (!(fileName.endsWith('.md') || fileName.endsWith('.toml'))) continue;
12586
+ if (fileName === 'CHANGELOG.md') continue;
12587
+ const retargetPath = path.join(targetDir, relPath);
12588
+ let retargetContent;
12589
+ try {
12590
+ retargetContent = fs.readFileSync(retargetPath, 'utf8');
12591
+ } catch (_retargetReadErr) {
12592
+ continue; // inaccessible or missing — never fail the install over this pass
12593
+ }
12594
+ const retargeted = runtimeArtifactConversion.retargetInstalledIncludes(retargetContent, includeRetarget, includePrefix);
12595
+ if (retargeted !== retargetContent) {
12596
+ try {
12597
+ fs.writeFileSync(retargetPath, retargeted);
12598
+ } catch (_retargetWriteErr) {
12599
+ continue;
12600
+ }
12601
+ }
12602
+ }
12603
+ }
12568
12604
  for (const relPath of manifestFiles) {
12569
12605
  const fileName = path.basename(relPath);
12570
12606
  if (!(fileName.endsWith('.md') || fileName.endsWith('.toml'))) continue;
@@ -48,6 +48,14 @@ Optional flags parsed from the `<arguments>` block:
48
48
  - `--files=file1,file2,...` — Explicit file list override. Has highest precedence for file scoping per D-08. When provided, workflow skips SUMMARY.md extraction and git diff fallback entirely.
49
49
 
50
50
  Context files (CLAUDE.md, SUMMARY.md, phase state) are resolved inside the workflow via `gsd-tools query init.phase-op` and delegated to agent via `<required_reading>` blocks.
51
+
52
+ ## Outside a phase
53
+
54
+ Reviewer lanes run without a phase (`gsd_run` is defined by the runtime-launcher preamble inside workflow fences; in a plain shell call `node <install>/gsd-core/bin/gsd-tools.cjs` instead): pipe canonical repo-relative file paths (one per line) to stdin of
55
+ `gsd_run review-lane dispatch-step --repo-root <root> --depth <quick|standard|deep> --base-sha <sha> --run-dir "$(mktemp -d)" --cap-id code-review --point execute:post --explicit <slugs> --raw`.
56
+ `review-lane` flags are space-separated (`--depth quick`), never `--flag=value`. `--explicit` (omitted, nothing dispatches yet the call exits ok), `--depth`, `--base-sha` (lane reviews changes relative to it; commit them first) and stdin paths are required; `--run-dir` should be a fresh temp dir (default `.` writes the prompt file into the current directory); read each lane's output path (`results[].reviewPath`) from the JSON before removing it. `--cap-id`/`--point` select the `code-review` capability, which must be enabled (`workflow.code_review`) and active at `--point` — `execute:post`, or `execute:wave:post` when `workflow.code_review_point` selects it; otherwise nothing dispatches.
57
+ `--explicit` takes comma-separated canonical slugs, no spaces (`codex,antigravity`), not flag aliases (`antigravity`, not `agy`); slugs: first column of `gsd_run review-lane sections` (`review-lane flags` lists flags/aliases).
58
+ Each lane declares its own model key, which is not always its slug (antigravity's is `review.models.agy`); see the `review.models.*` table in `docs/CONFIGURATION.md`. Unset = lane default model.
51
59
  </context>
52
60
 
53
61
  <process>
@@ -21,7 +21,7 @@ Routes to the pause-work workflow which handles:
21
21
  - Current phase detection from recent files
22
22
  - Complete state gathering (position, completed work, remaining work, decisions, blockers)
23
23
  - Handoff file creation with all context sections
24
- - Git commit as WIP
24
+ - Git commit handoff
25
25
  - Resume instructions
26
26
  </objective>
27
27
 
@@ -312,6 +312,7 @@ try {
312
312
  } catch { /* advisory — never block */ }
313
313
 
314
314
  const { resolveActiveWorkstream, applyResolvedWorkstreamEnv, peekActiveWorkstream } = require('./lib/active-workstream-store.cjs');
315
+ const { planningDir, planningRoot } = require('./lib/planning-workspace.cjs');
315
316
  const state = require('./lib/state.cjs');
316
317
  const phase = require('./lib/phase.cjs');
317
318
  const roadmap = require('./lib/roadmap.cjs');
@@ -1445,8 +1446,12 @@ function dispatchOverlayCapabilityCommand({ command, args, cwd, raw, error, load
1445
1446
  // Silent no-op when the section is absent or the table is already canonical
1446
1447
  // — the quick/fast workflows call this before their first append, so the
1447
1448
  // migration runs exactly once, on the first quick run, unprompted otherwise.
1448
- const statePath = path.join(cwd, '.planning', 'STATE.md');
1449
+ const planningPath = planningDir(cwd);
1450
+ const statePath = path.join(planningPath, 'STATE.md');
1449
1451
  if (!fs.existsSync(statePath)) {
1452
+ if (planningPath !== planningRoot(cwd)) {
1453
+ throw new ExitError(1, `quick-tasks-migrate: STATE.md not found at ${statePath}`);
1454
+ }
1450
1455
  output({ ok: true, migrated: false, reason: `STATE.md not found at ${statePath}` }, raw);
1451
1456
  return;
1452
1457
  }
@@ -1519,7 +1524,7 @@ function dispatchOverlayCapabilityCommand({ command, args, cwd, raw, error, load
1519
1524
  || (qtaQuickId && qtaSlug ? `[${qtaQuickId}-${qtaSlug}](./quick/${qtaQuickId}-${qtaSlug}/)` : undefined);
1520
1525
  const qtaStatus = qtaParsed['status'] || undefined;
1521
1526
 
1522
- const statePath = path.join(cwd, '.planning', 'STATE.md');
1527
+ const statePath = path.join(planningDir(cwd), 'STATE.md');
1523
1528
  if (!fs.existsSync(statePath)) {
1524
1529
  error(`quick-tasks-append: STATE.md not found at ${statePath}`, ERROR_REASON.USAGE);
1525
1530
  }
@@ -1593,7 +1598,7 @@ function dispatchOverlayCapabilityCommand({ command, args, cwd, raw, error, load
1593
1598
  const fsx = require('node:fs');
1594
1599
  const os = require('node:os');
1595
1600
  const { REVIEWER_LANES, mergeReviewerLanes } = require('./lib/review-lane-descriptor.cjs');
1596
- const { resolveLanePlan: resolveLanePlanBase, resolveLaneEffort, resolveLaneBudget } = require('./lib/review-lane-invocation.cjs');
1601
+ const { resolveLanePlan: resolveLanePlanBase, resolveLaneEffort, resolveLaneBudget, applyPromptOverride } = require('./lib/review-lane-invocation.cjs');
1597
1602
  // OpenCode 2.x argv differs from 1.x (no --variant; effort rides on the model as `#variant`;
1598
1603
  // ADR-5331 D5/D8). The generation is probed lazily, only when the opencode lane is resolved.
1599
1604
  const resolveLanePlan = (laneInput) => {
@@ -1945,7 +1950,7 @@ function dispatchOverlayCapabilityCommand({ command, args, cwd, raw, error, load
1945
1950
  const dispatchResult = await dispatchReviewerLanes(
1946
1951
  {
1947
1952
  trait,
1948
- selection: { explicitFlags, detected: rosterSlugs },
1953
+ selection: { explicitFlags, detected: rosterSlugs, lanes: mergedLanes },
1949
1954
  repoRoot,
1950
1955
  paths,
1951
1956
  depth,
@@ -2097,14 +2102,11 @@ function dispatchOverlayCapabilityCommand({ command, args, cwd, raw, error, load
2097
2102
  }
2098
2103
 
2099
2104
  // `--prompt-file` lets the caller substitute a budget-trimmed prompt. Applied to whichever
2100
- // channel this lane actually reads from, so one flag serves both transports.
2105
+ // channel this lane actually reads from (stdin, argv, an argv-embedded file reference, or the
2106
+ // http promptPath), so one flag serves every lane (#5049).
2101
2107
  const promptOverride = flag('--prompt-file');
2102
2108
  if (promptOverride) {
2103
- if (entry.plan.transport === 'spawn') {
2104
- if (entry.plan.stdin) entry.plan.stdin = promptOverride;
2105
- } else {
2106
- entry.plan.promptPath = promptOverride;
2107
- }
2109
+ entry.plan = applyPromptOverride(entry.plan, promptOverride, repoRoot);
2108
2110
  }
2109
2111
 
2110
2112
  // ADR-2782 D5 rule 4: re-resolve the consented destination at INVOCATION. `undefined` (no
@@ -3022,7 +3024,12 @@ function dispatchOverlayCapabilityCommand({ command, args, cwd, raw, error, load
3022
3024
  const jsonIdx = args.indexOf('--json');
3023
3025
  const agentSkillsJsonMode = jsonIdx !== -1;
3024
3026
  if (agentSkillsJsonMode) args.splice(jsonIdx, 1);
3025
- init.cmdAgentSkills(cwd, args[1], raw, agentSkillsJsonMode);
3027
+ // #5122: the agent's own self-load asks for configured skills only,
3028
+ // never the persona fallback served to orchestrator-side injection.
3029
+ const skillsOnlyIdx = args.indexOf('--skills-only');
3030
+ const agentSkillsOnly = skillsOnlyIdx !== -1;
3031
+ if (agentSkillsOnly) args.splice(skillsOnlyIdx, 1);
3032
+ init.cmdAgentSkills(cwd, args[1], raw, agentSkillsJsonMode, agentSkillsOnly);
3026
3033
  }
3027
3034
 
3028
3035
  function routeSkillManifest({ args, cwd, raw, error }) {
@@ -807,6 +807,28 @@ function reconcile(runtimeDir) {
807
807
  }
808
808
  return result;
809
809
  }
810
+ /**
811
+ * #5121: the one bounded read for a SKILL.md found by walking a skill root. A skill file is untrusted
812
+ * repository (or installed-runtime) content: a symlink to /dev/zero exhausts memory and a FIFO blocks
813
+ * the process, because a bare readFileSync does neither a type nor a size check. Reuses the fd protocol
814
+ * of readSmallRegularFile and maps its fail-closed "unreadable" conditions (not a regular file after
815
+ * following symlinks, over the cap) to null, so a caller treats the file as it treats a missing one.
816
+ * Any other IO error still throws, as the unbounded read did.
817
+ *
818
+ * 256 KiB: the largest shipped SKILL.md is ~21 KB, so the cap is >10x headroom while still bounding the
819
+ * allocation a hostile repository can force.
820
+ */
821
+ const SKILL_FILE_MAX_BYTES = 256 * 1024;
822
+ function readSkillFile(filePath) {
823
+ try {
824
+ return readSmallRegularFile(filePath, SKILL_FILE_MAX_BYTES);
825
+ }
826
+ catch (err) {
827
+ if (err instanceof LedgerIOError && (err.code === 'ENXIO' || err.code === 'EISDIR' || err.code === 'EFBIG'))
828
+ return null;
829
+ throw err;
830
+ }
831
+ }
810
832
  module.exports = {
811
833
  readLedger,
812
834
  readLedgerStrict,
@@ -822,6 +844,9 @@ module.exports = {
822
844
  // #1459 finding 1 (HIGH): the RAW-BYTES variant — the SOLE correct reader for the byte-exact,
823
845
  // injective consent content-hash binding (a utf8 decode is lossy and could collide binary artifacts).
824
846
  readSmallRegularFileBuffer,
847
+ // #5121: bounded SKILL.md read shared by skill discovery, the installed-runtime manifest and capability skills.
848
+ readSkillFile,
849
+ SKILL_FILE_MAX_BYTES,
825
850
  // Exported for testing / introspection
826
851
  LEDGER_FILE_NAME,
827
852
  CorruptLedgerError,
@@ -176,7 +176,8 @@ function isSameHost(parsed) {
176
176
  * equality comparison (never parsed as a date). The pair (pid, startTime) uniquely identifies a
177
177
  * process instance: even if a crashed holder's pid is REUSED, the new process's start-time differs.
178
178
  * Returns null on ANY error / unobtainable value (liveness cannot be VERIFIED → steal-eligible past
179
- * the deadman). The shell-outs only run on the rare STEAL-decision path, never the happy path.
179
+ * the deadman). Probing ANOTHER pid only happens on the rare STEAL-decision path; this process's own
180
+ * start-time is probed on its first lock acquire (see selfStartTime) — never at module load (#5327).
180
181
  */
181
182
  function getProcessStartTime(pid) {
182
183
  if (!Number.isInteger(pid) || pid <= 0)
@@ -208,11 +209,29 @@ function getProcessStartTime(pid) {
208
209
  return null;
209
210
  }
210
211
  }
211
- /** THIS process's start-time, captured ONCE at module load so we never re-shell on every lock write. */
212
- const _selfStartTime = getProcessStartTime(process.pid);
213
- /** Serialize the lockfile body: JSON carrying the owner token, pid, hostname, cached start-time, ts. */
214
- function lockFileBody(token) {
215
- return JSON.stringify({ token, pid: process.pid, hostname: node_os_1.default.hostname(), startTime: _selfStartTime, ts: Date.now() });
212
+ /**
213
+ * THIS process's start-time, probed on the first lock acquire and cached so later acquires never re-shell.
214
+ * Not probed at module load: every config read loads this module, and most never take a lock (#5327).
215
+ * Only a successful probe is cached. A failed one (a PowerShell launch past its 5 s timeout on a loaded
216
+ * Windows host) is retried on the next acquire, up to SELF_PROBE_ATTEMPTS probes in all, so a host whose
217
+ * probe never succeeds pays a bounded cost instead of one launch per acquire.
218
+ * Probed per acquire ATTEMPT, before the O_EXCL create, so a process whose first acquire meets a live
219
+ * holder still pays it: probing after a successful create instead would widen the empty-body window
220
+ * that the steal path's `LOCK_STALE_MS` floor relies on.
221
+ */
222
+ const SELF_PROBE_ATTEMPTS = 2;
223
+ let _selfStartTime = null;
224
+ let _selfProbeAttempts = 0;
225
+ function selfStartTime() {
226
+ if (_selfStartTime === null && _selfProbeAttempts < SELF_PROBE_ATTEMPTS) {
227
+ _selfProbeAttempts++;
228
+ _selfStartTime = getProcessStartTime(process.pid);
229
+ }
230
+ return _selfStartTime;
231
+ }
232
+ /** Serialize the lockfile body: JSON carrying the owner token, pid, hostname, start-time, ts. */
233
+ function lockFileBody(token, startTime) {
234
+ return JSON.stringify({ token, pid: process.pid, hostname: node_os_1.default.hostname(), startTime, ts: Date.now() });
216
235
  }
217
236
  // ---------------------------------------------------------------------------
218
237
  // Liveness probes (test seam)
@@ -364,6 +383,9 @@ function acquireLock(lockPath, opts) {
364
383
  ? opts.maxAttempts
365
384
  : LOCK_MAX_ATTEMPTS;
366
385
  const waitForFresh = !!(opts && opts.waitForFresh);
386
+ // Probe BEFORE the O_EXCL create: the first probe can be a PowerShell launch, and between the create
387
+ // and the body write a racing acquirer sees an empty lockfile. That window must stay sub-ms (#5327).
388
+ const startTime = selfStartTime();
367
389
  // A held lock that is NOT steal-eligible: fail-fast (return null) by default, or BACK OFF + RETRY
368
390
  // (continue) when waitForFresh and a retry budget remains — so a contended consent writer serializes.
369
391
  const blocked = (attempt) => {
@@ -382,7 +404,7 @@ function acquireLock(lockPath, opts) {
382
404
  // write/close error, best-effort unlink the file we just created and bail. fs.writeFileSync(fd, …)
383
405
  // flushes the WHOLE buffer (no short-write) unlike a bare fs.writeSync.
384
406
  try {
385
- node_fs_1.default.writeFileSync(fd, lockFileBody(token));
407
+ node_fs_1.default.writeFileSync(fd, lockFileBody(token, startTime));
386
408
  }
387
409
  catch (writeErr) {
388
410
  try {