@opengsd/gsd-core 1.17.0 → 1.19.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 (369) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +2 -1
  3. package/.opencode/plugins/gsd-core.js +2 -3
  4. package/agents/gsd-advisor-researcher.compact.md +1 -1
  5. package/agents/gsd-advisor-researcher.md +1 -1
  6. package/agents/gsd-assumptions-analyzer.compact.md +1 -1
  7. package/agents/gsd-assumptions-analyzer.md +1 -1
  8. package/agents/gsd-code-fixer.compact.md +3 -3
  9. package/agents/gsd-code-fixer.md +5 -4
  10. package/agents/gsd-code-reviewer.compact.md +1 -1
  11. package/agents/gsd-code-reviewer.md +1 -1
  12. package/agents/gsd-codebase-mapper.compact.md +1 -1
  13. package/agents/gsd-codebase-mapper.md +1 -1
  14. package/agents/gsd-debugger.md +1 -1
  15. package/agents/gsd-doc-verifier.compact.md +4 -4
  16. package/agents/gsd-doc-verifier.md +4 -3
  17. package/agents/gsd-doc-writer.compact.md +23 -5
  18. package/agents/gsd-doc-writer.md +19 -6
  19. package/agents/gsd-eval-auditor.compact.md +1 -1
  20. package/agents/gsd-eval-auditor.md +1 -1
  21. package/agents/gsd-executor.md +7 -3
  22. package/agents/gsd-integration-checker.compact.md +1 -1
  23. package/agents/gsd-integration-checker.md +1 -1
  24. package/agents/gsd-nyquist-auditor.compact.md +1 -1
  25. package/agents/gsd-nyquist-auditor.md +1 -1
  26. package/agents/gsd-phase-researcher.md +1 -1
  27. package/agents/gsd-plan-checker.md +2 -1
  28. package/agents/gsd-planner.md +5 -4
  29. package/agents/gsd-project-researcher.compact.md +1 -1
  30. package/agents/gsd-project-researcher.md +1 -1
  31. package/agents/gsd-research-synthesizer.compact.md +5 -5
  32. package/agents/gsd-research-synthesizer.md +5 -5
  33. package/agents/gsd-roadmapper.compact.md +1 -1
  34. package/agents/gsd-roadmapper.md +1 -1
  35. package/agents/gsd-security-auditor.compact.md +1 -1
  36. package/agents/gsd-security-auditor.md +1 -1
  37. package/agents/gsd-ui-auditor.compact.md +1 -1
  38. package/agents/gsd-ui-auditor.md +1 -1
  39. package/agents/gsd-ui-checker.compact.md +1 -1
  40. package/agents/gsd-ui-checker.md +1 -1
  41. package/agents/gsd-ui-researcher.compact.md +13 -1
  42. package/agents/gsd-ui-researcher.md +28 -1
  43. package/agents/gsd-verifier.md +2 -2
  44. package/bin/install.js +460 -105
  45. package/commands/gsd/code-review.md +8 -0
  46. package/commands/gsd/pause-work.md +1 -1
  47. package/gsd-core/bin/gsd-tools.cjs +124 -18
  48. package/gsd-core/bin/lib/agent-install-check.cjs +29 -3
  49. package/gsd-core/bin/lib/args-terminator.cjs +114 -0
  50. package/gsd-core/bin/lib/broken-windows.cjs +59 -1
  51. package/gsd-core/bin/lib/capability-ledger.cjs +25 -0
  52. package/gsd-core/bin/lib/capability-lock.cjs +41 -8
  53. package/gsd-core/bin/lib/capability-registry.cjs +162 -74
  54. package/gsd-core/bin/lib/capability-source.cjs +3 -1
  55. package/gsd-core/bin/lib/capability-state.cjs +20 -11
  56. package/gsd-core/bin/lib/capability-validator.cjs +23 -4
  57. package/gsd-core/bin/lib/commands.cjs +5 -1
  58. package/gsd-core/bin/lib/config-loader.cjs +13 -3
  59. package/gsd-core/bin/lib/config.cjs +256 -58
  60. package/gsd-core/bin/lib/core-utils.cjs +34 -0
  61. package/gsd-core/bin/lib/decision-coverage-support.cjs +93 -0
  62. package/gsd-core/bin/lib/gate-context-drift.cjs +8 -3
  63. package/gsd-core/bin/lib/gate-decision-coverage-plan.cjs +21 -1
  64. package/gsd-core/bin/lib/gate-decision-coverage-verify.cjs +19 -1
  65. package/gsd-core/bin/lib/gate-evaluation-scope.cjs +134 -13
  66. package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +23 -3
  67. package/gsd-core/bin/lib/gate-predicate.cjs +8 -12
  68. package/gsd-core/bin/lib/gate-tdd-review-checkpoint.cjs +114 -18
  69. package/gsd-core/bin/lib/gate-ui-safety.cjs +23 -5
  70. package/gsd-core/bin/lib/git-info-exclude.cjs +57 -0
  71. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +18 -3
  72. package/gsd-core/bin/lib/health-diagnostic-types.cjs +4 -0
  73. package/gsd-core/bin/lib/health-diagnostic.cjs +52 -1
  74. package/gsd-core/bin/lib/host-integration.cjs +13 -6
  75. package/gsd-core/bin/lib/init.cjs +76 -5
  76. package/gsd-core/bin/lib/install-effort-resolver.cjs +2 -2
  77. package/gsd-core/bin/lib/install-engine.cjs +246 -32
  78. package/gsd-core/bin/lib/install-model-override-resolver.cjs +4 -3
  79. package/gsd-core/bin/lib/install-profiles.cjs +14 -7
  80. package/gsd-core/bin/lib/installer-migration-report.cjs +2 -0
  81. package/gsd-core/bin/lib/markdown-line-diff.cjs +147 -0
  82. package/gsd-core/bin/lib/markdown-sectionizer.cjs +113 -0
  83. package/gsd-core/bin/lib/milestone-lock.cjs +8 -1
  84. package/gsd-core/bin/lib/milestone-release-map.cjs +244 -0
  85. package/gsd-core/bin/lib/milestone-release-tags.cjs +440 -0
  86. package/gsd-core/bin/lib/milestone.cjs +43 -1
  87. package/gsd-core/bin/lib/model-catalog.cjs +8 -0
  88. package/gsd-core/bin/lib/normalize-test-command.cjs +67 -0
  89. package/gsd-core/bin/lib/phase-id.cjs +21 -4
  90. package/gsd-core/bin/lib/phase-lifecycle.cjs +37 -4
  91. package/gsd-core/bin/lib/phase.cjs +235 -37
  92. package/gsd-core/bin/lib/planning-snapshot.cjs +3 -1
  93. package/gsd-core/bin/lib/planning-workspace.cjs +18 -0
  94. package/gsd-core/bin/lib/pristine-baseline.cjs +11 -3
  95. package/gsd-core/bin/lib/read-only-git-env.cjs +58 -0
  96. package/gsd-core/bin/lib/report-parser.cjs +57 -1
  97. package/gsd-core/bin/lib/review-lane-descriptor.cjs +35 -2
  98. package/gsd-core/bin/lib/review-lane-invocation.cjs +40 -0
  99. package/gsd-core/bin/lib/review-lane-runner.cjs +33 -4
  100. package/gsd-core/bin/lib/review-reviewer-selection.cjs +20 -1
  101. package/gsd-core/bin/lib/roadmap-parser.cjs +12 -0
  102. package/gsd-core/bin/lib/roadmap-upgrade.cjs +39 -2
  103. package/gsd-core/bin/lib/roadmap.cjs +89 -30
  104. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +428 -16
  105. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +8 -4
  106. package/gsd-core/bin/lib/runtime-homes.cjs +18 -0
  107. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +60 -16
  108. package/gsd-core/bin/lib/shell-command-projection.cjs +123 -16
  109. package/gsd-core/bin/lib/smart-entry.cjs +37 -16
  110. package/gsd-core/bin/lib/state-contract.cjs +29 -9
  111. package/gsd-core/bin/lib/state-document.cjs +47 -5
  112. package/gsd-core/bin/lib/state-transition.cjs +150 -34
  113. package/gsd-core/bin/lib/state.cjs +140 -88
  114. package/gsd-core/bin/lib/surface.cjs +9 -0
  115. package/gsd-core/bin/lib/task-command-router.cjs +7 -28
  116. package/gsd-core/bin/lib/task-content-resolution.cjs +46 -1
  117. package/gsd-core/bin/lib/tdd-red-evidence.cjs +5 -0
  118. package/gsd-core/bin/lib/tdd-test-files.cjs +42 -0
  119. package/gsd-core/bin/lib/verification.cjs +96 -9
  120. package/gsd-core/bin/lib/verify.cjs +38 -1
  121. package/gsd-core/bin/lib/worktree-safety.cjs +22 -1
  122. package/gsd-core/bin/shared/config-defaults.manifest.json +1 -0
  123. package/gsd-core/bin/shared/config-schema.manifest.json +1 -0
  124. package/gsd-core/references/agent-contracts.md +1 -1
  125. package/gsd-core/references/agent-skills-bootstrap.md +26 -7
  126. package/gsd-core/references/git-integration.md +14 -3
  127. package/gsd-core/references/loop-hook-dispatch.md +13 -6
  128. package/gsd-core/references/planner-reversibility.md +18 -4
  129. package/gsd-core/references/planner-verify-command-grounding.md +18 -0
  130. package/gsd-core/references/planning-config.md +2 -0
  131. package/gsd-core/references/tdd.md +5 -4
  132. package/gsd-core/references/verifier-phase-gates.md +8 -1
  133. package/gsd-core/templates/DEBUG.md +16 -0
  134. package/gsd-core/templates/config.json +2 -1
  135. package/gsd-core/templates/verification-report.md +1 -1
  136. package/gsd-core/workflows/add-backlog.md +10 -2
  137. package/gsd-core/workflows/add-phase.md +5 -1
  138. package/gsd-core/workflows/add-tests.md +5 -1
  139. package/gsd-core/workflows/add-todo.md +5 -1
  140. package/gsd-core/workflows/ai-integration-phase.md +5 -1
  141. package/gsd-core/workflows/audit-fix.md +2 -1
  142. package/gsd-core/workflows/audit-milestone.md +21 -9
  143. package/gsd-core/workflows/autonomous/templates/minimal-context.md +41 -0
  144. package/gsd-core/workflows/autonomous.md +52 -64
  145. package/gsd-core/workflows/check-todos.md +5 -1
  146. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +10 -1
  147. package/gsd-core/workflows/code-review-fix.md +5 -1
  148. package/gsd-core/workflows/code-review.md +66 -8
  149. package/gsd-core/workflows/complete-milestone/detail/elaboration.md +5 -1
  150. package/gsd-core/workflows/complete-milestone/steps/project-md-evolution-review.md +145 -0
  151. package/gsd-core/workflows/complete-milestone/steps/release-map.md +80 -0
  152. package/gsd-core/workflows/complete-milestone.md +64 -157
  153. package/gsd-core/workflows/debug.md +5 -1
  154. package/gsd-core/workflows/diagnose-issues.md +34 -6
  155. package/gsd-core/workflows/discuss-phase/modes/chain.md +5 -1
  156. package/gsd-core/workflows/discuss-phase/modes/power.md +1 -1
  157. package/gsd-core/workflows/discuss-phase-assumptions.md +44 -5
  158. package/gsd-core/workflows/discuss-phase-power.md +19 -2
  159. package/gsd-core/workflows/discuss-phase.md +11 -11
  160. package/gsd-core/workflows/docs-update/detail/elaboration.md +7 -6
  161. package/gsd-core/workflows/docs-update.md +27 -5
  162. package/gsd-core/workflows/edit-phase.md +5 -1
  163. package/gsd-core/workflows/eval-review.md +11 -3
  164. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +5 -1
  165. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +13 -7
  166. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +19 -8
  167. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +21 -3
  168. package/gsd-core/workflows/execute-phase/steps/regression-gate.md +18 -1
  169. package/gsd-core/workflows/execute-phase/steps/verify-phase-goal.md +7 -3
  170. package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +11 -2
  171. package/gsd-core/workflows/execute-phase.md +46 -11
  172. package/gsd-core/workflows/execute-plan.md +8 -4
  173. package/gsd-core/workflows/extract-learnings.md +6 -2
  174. package/gsd-core/workflows/forensics.md +5 -1
  175. package/gsd-core/workflows/health.md +2 -1
  176. package/gsd-core/workflows/import.md +6 -2
  177. package/gsd-core/workflows/insert-phase.md +5 -1
  178. package/gsd-core/workflows/manager.md +10 -2
  179. package/gsd-core/workflows/map-codebase.md +5 -1
  180. package/gsd-core/workflows/milestone-summary.md +10 -2
  181. package/gsd-core/workflows/new-milestone.md +13 -5
  182. package/gsd-core/workflows/new-project.md +9 -5
  183. package/gsd-core/workflows/next.md +8 -4
  184. package/gsd-core/workflows/pause-work.md +3 -3
  185. package/gsd-core/workflows/plan-phase/steps/auto-advance-check.md +70 -0
  186. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +7 -3
  187. package/gsd-core/workflows/plan-phase/steps/closed-phase-gate.md +6 -2
  188. package/gsd-core/workflows/plan-phase.md +54 -86
  189. package/gsd-core/workflows/plan-review-convergence.md +17 -5
  190. package/gsd-core/workflows/plant-seed.md +8 -4
  191. package/gsd-core/workflows/progress.md +6 -2
  192. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +1 -1
  193. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +8 -1
  194. package/gsd-core/workflows/quick-batch/steps/plan-checker-loop.md +2 -1
  195. package/gsd-core/workflows/quick-batch.md +5 -1
  196. package/gsd-core/workflows/quick.md +23 -8
  197. package/gsd-core/workflows/remove-phase.md +5 -1
  198. package/gsd-core/workflows/resume-project.md +5 -1
  199. package/gsd-core/workflows/review.md +22 -15
  200. package/gsd-core/workflows/scan.md +5 -1
  201. package/gsd-core/workflows/section-manifest.json +5 -0
  202. package/gsd-core/workflows/secure-phase.md +6 -2
  203. package/gsd-core/workflows/settings.md +4 -3
  204. package/gsd-core/workflows/ship.md +16 -14
  205. package/gsd-core/workflows/spec-phase.md +3 -6
  206. package/gsd-core/workflows/thread.md +10 -2
  207. package/gsd-core/workflows/transition.md +5 -1
  208. package/gsd-core/workflows/ui-phase.md +5 -1
  209. package/gsd-core/workflows/ui-review.md +6 -2
  210. package/gsd-core/workflows/ultraplan-phase.md +5 -1
  211. package/gsd-core/workflows/update.md +5 -1
  212. package/gsd-core/workflows/validate-phase.md +6 -2
  213. package/gsd-core/workflows/verify-work/detail/elaboration.md +1 -1
  214. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +5 -1
  215. package/gsd-core/workflows/verify-work.md +15 -6
  216. package/hooks/dist/gsd-agent-isolation-guard.js +14 -2
  217. package/hooks/dist/gsd-cursor-subagent-start.js +8 -3
  218. package/hooks/dist/gsd-path-export.js +95 -0
  219. package/hooks/dist/gsd-secret-read-guard.js +244 -53
  220. package/hooks/dist/gsd-statusline.js +35 -2
  221. package/hooks/dist/gsd-validate-commit.sh +27 -5
  222. package/hooks/dist/gsd-windsurf-pre-write.js +28 -1
  223. package/hooks/dist/gsd-workflow-guard.js +1 -1
  224. package/hooks/dist/gsd-worktree-path-guard.js +28 -1
  225. package/hooks/dist/lib/isolation-sentinel.js +44 -0
  226. package/hooks/dist/managed-hooks-registry.cjs +1 -0
  227. package/hooks/gsd-agent-isolation-guard.js +14 -2
  228. package/hooks/gsd-cursor-subagent-start.js +8 -3
  229. package/hooks/gsd-path-export.js +95 -0
  230. package/hooks/gsd-secret-read-guard.js +244 -53
  231. package/hooks/gsd-statusline.js +35 -2
  232. package/hooks/gsd-validate-commit.sh +27 -5
  233. package/hooks/gsd-windsurf-pre-write.js +28 -1
  234. package/hooks/gsd-workflow-guard.js +1 -1
  235. package/hooks/gsd-worktree-path-guard.js +28 -1
  236. package/hooks/hooks.json +1 -0
  237. package/hooks/lib/isolation-sentinel.js +44 -0
  238. package/hooks/managed-hooks-registry.cjs +1 -0
  239. package/package.json +13 -6
  240. package/pi/gsd.cjs +1047 -10
  241. package/pi/package-agents/gsd-advisor-researcher.md +113 -0
  242. package/pi/package-agents/gsd-ai-researcher.md +111 -0
  243. package/pi/package-agents/gsd-assumptions-analyzer.md +110 -0
  244. package/pi/package-agents/gsd-code-fixer.md +769 -0
  245. package/pi/package-agents/gsd-code-reviewer.md +402 -0
  246. package/pi/package-agents/gsd-codebase-mapper.md +850 -0
  247. package/pi/package-agents/gsd-debug-session-manager.md +416 -0
  248. package/pi/package-agents/gsd-debugger.md +1274 -0
  249. package/pi/package-agents/gsd-doc-classifier.md +269 -0
  250. package/pi/package-agents/gsd-doc-synthesizer.md +259 -0
  251. package/pi/package-agents/gsd-doc-verifier.md +212 -0
  252. package/pi/package-agents/gsd-doc-writer.md +626 -0
  253. package/pi/package-agents/gsd-dom-verifier.md +164 -0
  254. package/pi/package-agents/gsd-domain-researcher.md +144 -0
  255. package/pi/package-agents/gsd-eval-auditor.md +185 -0
  256. package/pi/package-agents/gsd-eval-planner.md +149 -0
  257. package/pi/package-agents/gsd-executor.md +894 -0
  258. package/pi/package-agents/gsd-framework-selector.md +159 -0
  259. package/pi/package-agents/gsd-integration-checker.md +476 -0
  260. package/pi/package-agents/gsd-intel-updater.md +338 -0
  261. package/pi/package-agents/gsd-mempalace-curator.md +49 -0
  262. package/pi/package-agents/gsd-nyquist-auditor.md +200 -0
  263. package/pi/package-agents/gsd-pattern-mapper.md +340 -0
  264. package/pi/package-agents/gsd-phase-researcher.md +897 -0
  265. package/pi/package-agents/gsd-plan-checker.md +1077 -0
  266. package/pi/package-agents/gsd-planner.md +1003 -0
  267. package/pi/package-agents/gsd-project-researcher.md +611 -0
  268. package/pi/package-agents/gsd-research-synthesizer.md +259 -0
  269. package/pi/package-agents/gsd-roadmapper.md +779 -0
  270. package/pi/package-agents/gsd-security-auditor.md +171 -0
  271. package/pi/package-agents/gsd-ui-auditor.md +581 -0
  272. package/pi/package-agents/gsd-ui-checker.md +417 -0
  273. package/pi/package-agents/gsd-ui-researcher.md +469 -0
  274. package/pi/package-agents/gsd-user-profiler.md +174 -0
  275. package/pi/package-agents/gsd-verifier.md +963 -0
  276. package/pi/package-agents/manifest.json +39 -0
  277. package/pi/package-skills/gsd-add-tests/SKILL.md +39 -0
  278. package/pi/package-skills/gsd-ai-integration-phase/SKILL.md +36 -0
  279. package/pi/package-skills/gsd-audit-fix/SKILL.md +34 -0
  280. package/pi/package-skills/gsd-audit-milestone/SKILL.md +40 -0
  281. package/pi/package-skills/gsd-audit-uat/SKILL.md +26 -0
  282. package/pi/package-skills/gsd-autonomous/SKILL.md +52 -0
  283. package/pi/package-skills/gsd-capture/SKILL.md +68 -0
  284. package/pi/package-skills/gsd-cleanup/SKILL.md +25 -0
  285. package/pi/package-skills/gsd-code-review/SKILL.md +71 -0
  286. package/pi/package-skills/gsd-complete-milestone/SKILL.md +147 -0
  287. package/pi/package-skills/gsd-config/SKILL.md +60 -0
  288. package/pi/package-skills/gsd-debug/SKILL.md +64 -0
  289. package/pi/package-skills/gsd-discuss-phase/SKILL.md +74 -0
  290. package/pi/package-skills/gsd-docs-update/SKILL.md +50 -0
  291. package/pi/package-skills/gsd-eval-review/SKILL.md +35 -0
  292. package/pi/package-skills/gsd-execute-phase/SKILL.md +62 -0
  293. package/pi/package-skills/gsd-explore/SKILL.md +26 -0
  294. package/pi/package-skills/gsd-extract-learnings/SKILL.md +25 -0
  295. package/pi/package-skills/gsd-fast/SKILL.md +33 -0
  296. package/pi/package-skills/gsd-forensics/SKILL.md +59 -0
  297. package/pi/package-skills/gsd-graphify/SKILL.md +210 -0
  298. package/pi/package-skills/gsd-health/SKILL.md +36 -0
  299. package/pi/package-skills/gsd-help/SKILL.md +37 -0
  300. package/pi/package-skills/gsd-import/SKILL.md +46 -0
  301. package/pi/package-skills/gsd-inbox/SKILL.md +42 -0
  302. package/pi/package-skills/gsd-ingest-docs/SKILL.md +43 -0
  303. package/pi/package-skills/gsd-manager/SKILL.md +46 -0
  304. package/pi/package-skills/gsd-map-codebase/SKILL.md +85 -0
  305. package/pi/package-skills/gsd-mempalace-capture/SKILL.md +111 -0
  306. package/pi/package-skills/gsd-mempalace-recall/SKILL.md +111 -0
  307. package/pi/package-skills/gsd-milestone-summary/SKILL.md +54 -0
  308. package/pi/package-skills/gsd-mvp-phase/SKILL.md +45 -0
  309. package/pi/package-skills/gsd-new-milestone/SKILL.md +49 -0
  310. package/pi/package-skills/gsd-new-project/SKILL.md +49 -0
  311. package/pi/package-skills/gsd-next/SKILL.md +34 -0
  312. package/pi/package-skills/gsd-ns-context/SKILL.md +31 -0
  313. package/pi/package-skills/gsd-ns-ideate/SKILL.md +30 -0
  314. package/pi/package-skills/gsd-ns-manage/SKILL.md +42 -0
  315. package/pi/package-skills/gsd-ns-project/SKILL.md +34 -0
  316. package/pi/package-skills/gsd-ns-review/SKILL.md +35 -0
  317. package/pi/package-skills/gsd-ns-workflow/SKILL.md +44 -0
  318. package/pi/package-skills/gsd-onboard/SKILL.md +46 -0
  319. package/pi/package-skills/gsd-pause-work/SKILL.md +48 -0
  320. package/pi/package-skills/gsd-phase/SKILL.md +61 -0
  321. package/pi/package-skills/gsd-plan-phase/SKILL.md +62 -0
  322. package/pi/package-skills/gsd-plan-review-convergence/SKILL.md +63 -0
  323. package/pi/package-skills/gsd-pr-branch/SKILL.md +31 -0
  324. package/pi/package-skills/gsd-profile-user/SKILL.md +48 -0
  325. package/pi/package-skills/gsd-progress/SKILL.md +51 -0
  326. package/pi/package-skills/gsd-quick/SKILL.md +179 -0
  327. package/pi/package-skills/gsd-quick-batch/SKILL.md +114 -0
  328. package/pi/package-skills/gsd-resume-work/SKILL.md +31 -0
  329. package/pi/package-skills/gsd-review/SKILL.md +50 -0
  330. package/pi/package-skills/gsd-review-backlog/SKILL.md +65 -0
  331. package/pi/package-skills/gsd-secure-phase/SKILL.md +37 -0
  332. package/pi/package-skills/gsd-settings/SKILL.md +30 -0
  333. package/pi/package-skills/gsd-ship/SKILL.md +27 -0
  334. package/pi/package-skills/gsd-sketch/SKILL.md +56 -0
  335. package/pi/package-skills/gsd-spec-phase/SKILL.md +63 -0
  336. package/pi/package-skills/gsd-spike/SKILL.md +53 -0
  337. package/pi/package-skills/gsd-stats/SKILL.md +22 -0
  338. package/pi/package-skills/gsd-surface/SKILL.md +177 -0
  339. package/pi/package-skills/gsd-thread/SKILL.md +29 -0
  340. package/pi/package-skills/gsd-ui-phase/SKILL.md +35 -0
  341. package/pi/package-skills/gsd-ui-review/SKILL.md +35 -0
  342. package/pi/package-skills/gsd-ultraplan-phase/SKILL.md +38 -0
  343. package/pi/package-skills/gsd-undo/SKILL.md +38 -0
  344. package/pi/package-skills/gsd-update/SKILL.md +51 -0
  345. package/pi/package-skills/gsd-validate-phase/SKILL.md +37 -0
  346. package/pi/package-skills/gsd-verify-work/SKILL.md +41 -0
  347. package/pi/package-skills/gsd-workspace/SKILL.md +57 -0
  348. package/pi/package-skills/gsd-workstreams/SKILL.md +73 -0
  349. package/scripts/audit-workflow-script-paths.cjs +1 -1
  350. package/scripts/build-hooks.js +4 -0
  351. package/scripts/command-contract-helpers.cjs +1 -1
  352. package/scripts/diagnose-windows-spawn-watcher.cjs +317 -0
  353. package/scripts/docs-guard-registry.cjs +22 -7
  354. package/scripts/gen-health-docs.cjs +13 -1
  355. package/scripts/gen-pi-package-skills.cjs +217 -0
  356. package/scripts/lib/macos-conformance-tier.generated.cjs +19 -0
  357. package/scripts/lib/platform-conformance-tier.generated.cjs +41 -0
  358. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +3 -3
  359. package/scripts/lint-phase-arg-assignment.cjs +2 -2
  360. package/scripts/lint-retired-runtime-name.cjs +5 -0
  361. package/scripts/lint-workflow-shellcheck-baseline.json +16 -16
  362. package/scripts/npm-audit-baseline.cjs +41 -7
  363. package/scripts/release-tarball-smoke.cjs +1 -0
  364. package/scripts/reviewed-or-maintainer-policy.cjs +181 -0
  365. package/scripts/select-docs-guards.cjs +1 -1
  366. package/scripts/self-test-report-policy.cjs +350 -0
  367. package/skills/gsd-code-review/SKILL.md +8 -0
  368. package/skills/gsd-pause-work/SKILL.md +1 -1
  369. package/vscode/package.json +1 -1
@@ -52,6 +52,7 @@ const userArtifactStaging = require("./user-artifact-staging.cjs");
52
52
  // module-level doc comment on `isGlobalScope` for why the projection is
53
53
  // centralized rather than eliminated).
54
54
  const install_scope_cjs_1 = require("./install-scope.cjs");
55
+ const args_terminator_cjs_1 = require("./args-terminator.cjs");
55
56
  const { processAttribution } = runtimeArtifactConversion;
56
57
  // resolveRuntimeArtifactLayout: accessed via module ref (not destructured) so
57
58
  // test stubs that monkeypatch the module's exports are seen at call time.
@@ -233,7 +234,8 @@ function applyOpencodeFamilyPathPrefix(content, runtime, pathPrefix) {
233
234
  content = content.replace(/\.\/\.claude\//g, `./${getDirName(runtime)}/`);
234
235
  content = content.replace(/~\/\.opencode\//g, pathPrefix);
235
236
  content = content.replace(/~\/\.kilo\//g, pathPrefix);
236
- return content;
237
+ // #5637: the typed-text capture heredoc ends at a terminator the typed text cannot know.
238
+ return (0, args_terminator_cjs_1.stampInstalledContent)(content);
237
239
  }
238
240
  /**
239
241
  * Convert a Claude command (.md) to an OpenCode skill (SKILL.md).
@@ -755,10 +757,17 @@ function _copyStaged(stagedDir, destDir, kind, configDir, runtime) {
755
757
  * For the prefix='' case: the destSubpath IS the namespace — remove the entire
756
758
  * destDir. (No current runtime uses prefix='' after #947 reversed Hermes; kept
757
759
  * as a defensive guard for future runtimes.)
760
+ *
761
+ * `owns` (#5161): when supplied, a prefix match is necessary but NOT
762
+ * sufficient — an entry is removed only when `owns(name)` is true, and every
763
+ * prefix-matching entry it rejects is returned so the caller can name it.
764
+ * Omitted (agents, commands, uninstall), every prefix match is removed as
765
+ * before and the return value is always empty.
758
766
  */
759
- function _removeGsdEntries(destDir, kind) {
767
+ function _removeGsdEntries(destDir, kind, owns) {
768
+ const preserved = [];
760
769
  if (!installFs().existsSync(destDir))
761
- return;
770
+ return preserved;
762
771
  if (kind.kind === 'kimi-agents') {
763
772
  for (const fileName of ['gsd.yaml', 'gsd.md']) {
764
773
  installFs().rmSync(node_path_1.default.join(destDir, fileName), { force: true });
@@ -775,19 +784,158 @@ function _removeGsdEntries(destDir, kind) {
775
784
  installFs().rmSync(node_path_1.default.join(subagentsDir, entry.name), { force: true });
776
785
  }
777
786
  }
778
- return;
787
+ return preserved;
779
788
  }
780
789
  if (kind.prefix === '') {
781
790
  // Whole-namespace removal (Hermes nested case — destSubpath is skills/gsd)
782
791
  // The directory itself is the GSD namespace, so remove it entirely.
783
792
  installFs().rmSync(destDir, { recursive: true, force: true });
784
- return;
793
+ return preserved;
785
794
  }
786
795
  for (const entry of installFs().readdirSync(destDir, { withFileTypes: true })) {
787
796
  if (!entry.name.startsWith(kind.prefix))
788
797
  continue;
798
+ if (owns && !owns(entry.name)) {
799
+ preserved.push(entry.name);
800
+ continue;
801
+ }
789
802
  installFs().rmSync(node_path_1.default.join(destDir, entry.name), { recursive: true, force: true });
790
803
  }
804
+ return preserved;
805
+ }
806
+ // ---------------------------------------------------------------------------
807
+ // Skill-dir ownership (#5161)
808
+ // ---------------------------------------------------------------------------
809
+ /**
810
+ * GSD-prefixed skill dirs the user owns and GSD never reinstalls from source
811
+ * (#2973). The skills writers snapshot them across the prune and restore them.
812
+ */
813
+ const USER_OWNED_SKILL_DIRS = ['gsd-dev-preferences'];
814
+ /** The skill dirs each writer wrote, keyed on the resolved skills dir (recordWrittenSkillDirs). */
815
+ const writtenSkillDirs = new Map();
816
+ /**
817
+ * Record the skill dirs a writer just wrote into `skillsDir`, replacing that
818
+ * dir's entry. Called only once the write has returned, so a writer that threw
819
+ * records nothing.
820
+ */
821
+ function recordWrittenSkillDirs(skillsDir, names) {
822
+ writtenSkillDirs.set(node_path_1.default.resolve(skillsDir), new Set(names));
823
+ }
824
+ /** Start an install's record empty, so no earlier install's writes are read. */
825
+ function clearWrittenSkillDirs() {
826
+ writtenSkillDirs.clear();
827
+ }
828
+ /**
829
+ * Build the predicate that decides whether a prefix-matching dir in
830
+ * `skillsDir` is GSD-owned (#5161). A prefix match is necessary but NOT
831
+ * sufficient — the rule surface.cts pruneSkillDirs already applies. A dir is
832
+ * GSD-owned when any of these hold:
833
+ * - it is a first-party skill: `<prefix><stem>` for a commands/gsd/<stem>.md
834
+ * in the install source;
835
+ * - it carries the capability-skill marker (a third-party capability skill
836
+ * GSD staged, install-profiles.cts CAPABILITY_SKILL_MARKER);
837
+ * - `includeManifest` is not false and the previous install's
838
+ * gsd-file-manifest.json records a file under it (a skill GSD installed
839
+ * before that has since been retired or left the active profile).
840
+ * Anything else is user-owned or unknown. The first-time baseline migration
841
+ * may already have resolved it to `keep`, and the prune must honor that.
842
+ *
843
+ * writeManifest builds this with `includeManifest: false`: a preserved user
844
+ * dir recorded into the manifest would read back as GSD-owned on the next
845
+ * install and be deleted then.
846
+ *
847
+ * `manifestIfSourceUnresolved` is writeManifest's answer when the install
848
+ * source cannot be read, which leaves no first-party leg. It turns the manifest
849
+ * leg back on for that case only, so the dirs the previous install recorded
850
+ * stay recorded and the fallback adds no dir the previous manifest does not
851
+ * already record (beyond capability-marked ones). Owning every dir instead
852
+ * would record a user's kept dir, and the next install would read it back as
853
+ * GSD-owned and delete it: the #5161 failure, reached through a fallback. The
854
+ * cost is a skill first shipped by this release going unrecorded until the
855
+ * next install with a readable source. A prune never needs the flag: it keeps
856
+ * every dir it cannot otherwise prove, and its manifest leg is already on.
857
+ *
858
+ * `includeWritten` adds the skill dirs this install wrote into `skillsDir`
859
+ * (recordWrittenSkillDirs). The first-party lookups can miss the corpus a run
860
+ * staged: staging resolves its provider under the layout's requirement and the
861
+ * installed corpus's manifest, so it can take a corpus a `.gsd-source` marker
862
+ * names that neither lookup reaches, and its skills would then go uncounted
863
+ * and unrecorded. Only the skill counts and writeManifest pass the flag, since
864
+ * they must own what the install wrote. Every prune leaves it unset, so the
865
+ * record never widens what is deleted.
866
+ */
867
+ function createSkillDirOwnership(runtime, configDir, skillsDir, prefix, opts = {}) {
868
+ // First-party stems come from BOTH the configDir-resolved source and the
869
+ // executing package's own source. Staging resolves its provider with the
870
+ // commands+agents requirement while a commands-only lookup can accept a
871
+ // different provider (a commands-only `.gsd-source` marker), so either root
872
+ // alone can miss the corpus the run staged. Both are GSD corpora, so the
873
+ // union only ever widens what GSD owns.
874
+ const firstParty = new Set();
875
+ let sourceResolved = false;
876
+ let lastError = null;
877
+ const roots = [
878
+ () => runtimeArtifactLayout.findInstallSourceRoot(configDir),
879
+ () => runtimeArtifactLayout.findInstallSourceRoot(undefined),
880
+ ];
881
+ for (const root of roots) {
882
+ try {
883
+ const commandsGsdDir = root();
884
+ // A regular `.md` file only — the filter every skills writer stages
885
+ // with. A source counts as resolved only once it yields a stem.
886
+ for (const entry of installFs().readdirSync(commandsGsdDir, { withFileTypes: true })) {
887
+ if (!entry.isFile() || !entry.name.endsWith('.md'))
888
+ continue;
889
+ firstParty.add(prefix + entry.name.slice(0, -3));
890
+ sourceResolved = true;
891
+ }
892
+ }
893
+ catch (err) {
894
+ lastError = err;
895
+ }
896
+ }
897
+ if (!sourceResolved) {
898
+ console.warn(` [gsd] could not read the install source to classify ${skillsDir} (${lastError?.message}) — ${opts.manifestIfSourceUnresolved ? 'treating as GSD-owned only the gsd- skill dirs the previous install manifest records or that carry the capability-skill marker' : 'keeping every gsd- skill dir GSD cannot otherwise prove it owns'}.`);
899
+ }
900
+ const manifestNames = new Set();
901
+ if (opts.includeManifest !== false || (!sourceResolved && opts.manifestIfSourceUnresolved === true)) {
902
+ // The prefix must describe the root being pruned: a manifest name under one
903
+ // root says nothing about a same-named dir under another (Hermes' flat
904
+ // pre-#2841 root vs its nested skills/gsd/ root).
905
+ const manifestPrefix = opts.manifestPrefix ?? (hostBehaviorsFor(runtime).skillsManifestPrefix || 'skills/');
906
+ for (const key of Object.keys(installerMigrations.readInstallManifest(configDir).files)) {
907
+ if (!key.startsWith(manifestPrefix))
908
+ continue;
909
+ const rest = key.slice(manifestPrefix.length);
910
+ const slash = rest.indexOf('/');
911
+ if (slash > 0)
912
+ manifestNames.add(rest.slice(0, slash));
913
+ }
914
+ }
915
+ const written = opts.includeWritten === true ? writtenSkillDirs.get(node_path_1.default.resolve(skillsDir)) : undefined;
916
+ return (name) => firstParty.has(name) ||
917
+ manifestNames.has(name) ||
918
+ written?.has(name) === true ||
919
+ installFs().existsSync(node_path_1.default.join(skillsDir, name, installProfiles.CAPABILITY_SKILL_MARKER));
920
+ }
921
+ /**
922
+ * Report each prefix-matching skill dir the prune preserved as not GSD-owned,
923
+ * by path (#5161). The deletion this replaces was silent.
924
+ *
925
+ * A USER_OWNED_SKILL_DIRS entry is never named: GSD special-cases it (the
926
+ * writers restore it and writeManifest records it), so "GSD does not own it,
927
+ * rename it" would be false. It reaches this list whenever no previous
928
+ * manifest records it yet, e.g. the first update after the user generates it.
929
+ *
930
+ * The message names no manifest: the legacy-location cleanups decide without
931
+ * one, so "not in the previous install manifest" would be false there.
932
+ */
933
+ function _warnPreservedSkillDirs(skillsDir, names) {
934
+ for (const name of names) {
935
+ if (USER_OWNED_SKILL_DIRS.includes(name))
936
+ continue;
937
+ console.warn(` [gsd] Preserved ${node_path_1.default.join(skillsDir, name)} — it matches the gsd- skill prefix but nothing shows GSD owns it here. Rename it if it should not share GSD's prefix.`);
938
+ }
791
939
  }
792
940
  // ---------------------------------------------------------------------------
793
941
  // _snapshotDir / _restoreDir
@@ -833,14 +981,17 @@ function _restoreDir(dir, snapshot) {
833
981
  *
834
982
  * @param nestedGsdDir absolute path to skills/gsd/ category dir
835
983
  */
836
- function _removeHermesBareStemDirs(nestedGsdDir) {
984
+ function _removeHermesBareStemDirs(nestedGsdDir, owns) {
837
985
  if (!installFs().existsSync(nestedGsdDir))
838
986
  return;
839
987
  const entries = installFs().readdirSync(nestedGsdDir, { withFileTypes: true });
840
988
  // Collect the set of stems that were installed as gsd-<stem>/ this run.
989
+ // #5161: the prune now keeps gsd-* dirs GSD does not own, so "present" no
990
+ // longer means "installed". With `owns`, only an owned gsd-<stem>/ counts,
991
+ // and a user's own <stem>/ beside their own gsd-<stem>/ is left alone.
841
992
  const installedStems = new Set();
842
993
  for (const entry of entries) {
843
- if (entry.isDirectory() && entry.name.startsWith('gsd-')) {
994
+ if (entry.isDirectory() && entry.name.startsWith('gsd-') && (!owns || owns(entry.name))) {
844
995
  installedStems.add(entry.name.slice('gsd-'.length)); // e.g. 'quick', 'dev-preferences'
845
996
  }
846
997
  }
@@ -893,15 +1044,37 @@ function _runLegacyInstallMigrations(runtime, configDir, scope = 'global') {
893
1044
  }
894
1045
  }
895
1046
  // Hermes: remove pre-#2841 flat skills/gsd-*/ entries that lived alongside
896
- // the new skills/gsd/ nested layout. (#5169: `hostBehaviors.legacyFlatSkillsCleanup`.)
1047
+ // the new skills/gsd/ nested layout (#5169: `hostBehaviors.legacyFlatSkillsCleanup`).
1048
+ // #5161: skills/ is also Hermes' own skills root, so this runs on every
1049
+ // install against dirs the user may own — remove only what GSD owns, keep
1050
+ // and name the rest.
897
1051
  if (hostBehaviorsFor(runtime).legacyFlatSkillsCleanup) {
898
1052
  const flatSkillsDir = node_path_1.default.join(configDir, 'skills');
899
1053
  if (installFs().existsSync(flatSkillsDir)) {
1054
+ // The flat root's manifest entries were recorded as skills/gsd-<x>/…, not
1055
+ // under Hermes' current nested prefix.
1056
+ const ownsSkillDir = createSkillDirOwnership(runtime, configDir, flatSkillsDir, 'gsd-', { manifestPrefix: 'skills/' });
1057
+ const kept = [];
900
1058
  for (const entry of installFs().readdirSync(flatSkillsDir, { withFileTypes: true })) {
901
- if (entry.isDirectory() && entry.name.startsWith('gsd-')) {
902
- installFs().rmSync(node_path_1.default.join(flatSkillsDir, entry.name), { recursive: true });
1059
+ if (!entry.name.startsWith('gsd-'))
1060
+ continue;
1061
+ // A symlink is never removed here (as before); name it when unowned.
1062
+ if (entry.isSymbolicLink()) {
1063
+ if (!ownsSkillDir(entry.name))
1064
+ kept.push(entry.name);
1065
+ continue;
903
1066
  }
1067
+ if (!entry.isDirectory())
1068
+ continue;
1069
+ // gsd-dev-preferences is user content even when an old manifest records
1070
+ // it, and nothing here restores it (#2973), so it is never removed.
1071
+ if (!ownsSkillDir(entry.name) || USER_OWNED_SKILL_DIRS.includes(entry.name)) {
1072
+ kept.push(entry.name);
1073
+ continue;
1074
+ }
1075
+ installFs().rmSync(node_path_1.default.join(flatSkillsDir, entry.name), { recursive: true });
904
1076
  }
1077
+ _warnPreservedSkillDirs(flatSkillsDir, kept);
905
1078
  }
906
1079
  // Hermes: bare-stem skills/gsd/<stem>/ cleanup is deferred to AFTER the
907
1080
  // layout-driven install loop in installRuntimeArtifacts, where the exact set
@@ -1117,6 +1290,8 @@ function _runLegacyUninstallCleanup(runtime, configDir, scope = 'global') {
1117
1290
  */
1118
1291
  function installRuntimeArtifacts(runtime, configDir, scope, resolvedProfile, resolveAttribution = () => undefined, capabilityRegistry, deps = {}) {
1119
1292
  return withInstallFs(deps.fs, () => {
1293
+ // #5161: this install's record of the skill dirs it writes starts empty.
1294
+ clearWrittenSkillDirs();
1120
1295
  const layout = runtimeArtifactLayout.resolveRuntimeArtifactLayout(runtime, configDir, scope, capabilityRegistry);
1121
1296
  // A removed descriptor kind is no longer visited by the layout loop, so it
1122
1297
  // cannot prune its own previous output. Clean manifest-proven retired files
@@ -1253,7 +1428,9 @@ function installRuntimeArtifacts(runtime, configDir, scope, resolvedProfile, res
1253
1428
  }
1254
1429
  installFs().mkdirSync(dest, { recursive: true });
1255
1430
  const preserved = [];
1256
- if (kind.kind === 'skills' && installFs().existsSync(dest)) {
1431
+ // #5161: keyed on the kind alone, so the non-skills branch below can
1432
+ // never reach a skills dest with the prune that ignores ownership.
1433
+ if (kind.kind === 'skills') {
1257
1434
  // Pre-prune: snapshot user-owned content before _removeGsdEntries wipes it,
1258
1435
  // then restore after. This preserves user dirs across a wipe-and-replace
1259
1436
  // install (#2973 / #3664).
@@ -1264,24 +1441,37 @@ function installRuntimeArtifacts(runtime, configDir, scope, resolvedProfile, res
1264
1441
  // gsd-dev-preferences, which GSD does not reinstall from source but must
1265
1442
  // survive the prune (#2973).
1266
1443
  const toPreserve = new Map(); // dirName -> Map<relPath, Buffer>
1267
- {
1268
- // Preserve explicitly user-owned GSD-prefixed skill dirs.
1269
- // gsd-dev-preferences is the sole user-customisable skill in this category.
1270
- const USER_OWNED_SKILL_DIRS = ['gsd-dev-preferences'];
1271
- for (const dirName of USER_OWNED_SKILL_DIRS) {
1272
- const skillDir = node_path_1.default.join(dest, dirName);
1273
- if (!installFs().existsSync(skillDir))
1274
- continue;
1275
- const snap = _snapshotDir(skillDir);
1276
- if (snap.size > 0)
1277
- toPreserve.set(dirName, snap);
1278
- }
1444
+ for (const dirName of USER_OWNED_SKILL_DIRS) {
1445
+ const skillDir = node_path_1.default.join(dest, dirName);
1446
+ if (!installFs().existsSync(skillDir))
1447
+ continue;
1448
+ const snap = _snapshotDir(skillDir);
1449
+ if (snap.size > 0)
1450
+ toPreserve.set(dirName, snap);
1279
1451
  }
1280
- _removeGsdEntries(dest, kind);
1452
+ // #5161: prune only what GSD owns — a dir this run is about to write,
1453
+ // or one createSkillDirOwnership proves GSD's. Any other gsd-* dir is
1454
+ // user-owned or unknown: keep it and name it.
1455
+ const stagedNames = new Set(installFs().existsSync(item.sourceDir) ? installFs().readdirSync(item.sourceDir) : []);
1456
+ const ownsSkillDir = createSkillDirOwnership(runtime, configDir, dest, kind.prefix);
1457
+ // A USER_OWNED_SKILL_DIRS entry is never pruned, even when the manifest
1458
+ // leg owns it: the restore below skips symlinks, so a prune-then-restore
1459
+ // loses a symlinked SKILL.md. The restore remains for prune paths that
1460
+ // do not consult `owns`.
1461
+ const notOwned = _removeGsdEntries(dest, kind, (name) => !USER_OWNED_SKILL_DIRS.includes(name) && (stagedNames.has(name) || ownsSkillDir(name)));
1462
+ _warnPreservedSkillDirs(dest, notOwned);
1281
1463
  _copyStaged(item.sourceDir, dest, kind, configDir, runtime);
1282
- // Restore user-owned dirs after the prune+copy
1464
+ // The dirs _copyStaged just wrote: each directory child of the stage.
1465
+ recordWrittenSkillDirs(dest, installFs().existsSync(item.sourceDir)
1466
+ ? installFs().readdirSync(item.sourceDir, { withFileTypes: true })
1467
+ .filter((e) => e.isDirectory()).map((e) => e.name)
1468
+ : []);
1469
+ // Restore user-owned dirs after the prune+copy — only one a prune
1470
+ // branch that does not consult `owns` actually removed. Writing over
1471
+ // the kept dir would fail on a read-only file the user left there.
1283
1472
  for (const [dirName, snap] of toPreserve) {
1284
- _restoreDir(node_path_1.default.join(dest, dirName), snap);
1473
+ if (!installFs().existsSync(node_path_1.default.join(dest, dirName)))
1474
+ _restoreDir(node_path_1.default.join(dest, dirName), snap);
1285
1475
  preserved.push(dirName);
1286
1476
  }
1287
1477
  }
@@ -1322,7 +1512,10 @@ function installRuntimeArtifacts(runtime, configDir, scope, resolvedProfile, res
1322
1512
  let hermesBareStemCleanup = false;
1323
1513
  if (hostBehaviorsFor(runtime).bareStemSkillsCleanup) {
1324
1514
  const nestedGsdDirForCleanup = node_path_1.default.join(configDir, 'skills', 'gsd');
1325
- _removeHermesBareStemDirs(nestedGsdDirForCleanup);
1515
+ // gsd-dev-preferences is restored rather than staged, and its legacy bare
1516
+ // dev-preferences/ twin is one this cleanup exists for (#947).
1517
+ const ownsNested = createSkillDirOwnership(runtime, configDir, nestedGsdDirForCleanup, 'gsd-', { includeManifest: false });
1518
+ _removeHermesBareStemDirs(nestedGsdDirForCleanup, (name) => ownsNested(name) || USER_OWNED_SKILL_DIRS.includes(name));
1326
1519
  hermesBareStemCleanup = true;
1327
1520
  }
1328
1521
  // Generic-branch nativePlugin staging (ADR-1239 / #2102 Stage 1): runtimes
@@ -1427,7 +1620,6 @@ function installOpencodeFamilySkills(runtime, targetDir, rawCommandsDir, pathPre
1427
1620
  // and lives at <configDir>/skills/gsd-dev-preferences — _removeGsdEntries
1428
1621
  // would otherwise wipe it. Mirrors the preservation in installRuntimeArtifacts
1429
1622
  // (#2973).
1430
- const USER_OWNED_SKILL_DIRS = ['gsd-dev-preferences'];
1431
1623
  const toPreserve = new Map(); // dirName -> Map<relPath, Buffer>
1432
1624
  for (const dirName of USER_OWNED_SKILL_DIRS) {
1433
1625
  const skillDir = node_path_1.default.join(dest, dirName);
@@ -1437,8 +1629,20 @@ function installOpencodeFamilySkills(runtime, targetDir, rawCommandsDir, pathPre
1437
1629
  if (snap.size > 0)
1438
1630
  toPreserve.set(dirName, snap);
1439
1631
  }
1440
- _removeGsdEntries(dest, skillsKindEntry);
1632
+ // #5161: same ownership gate as installRuntimeArtifacts' skills kind. The
1633
+ // first-party set is rawDir's stems (exactly what this writer is about to
1634
+ // write); third-party capability skills carry the marker.
1635
+ // Same entry filter as the write loop below (a regular `.md` file), so a
1636
+ // name is owned here only if this writer is about to rewrite it.
1637
+ const rawStemNames = new Set(installFs().readdirSync(rawDir, { withFileTypes: true })
1638
+ .filter((e) => e.isFile() && e.name.endsWith('.md'))
1639
+ .map((e) => `${skillsKindEntry.prefix}${e.name.slice(0, -3)}`));
1640
+ const ownsSkillDir = createSkillDirOwnership(runtime, targetDir, dest, skillsKindEntry.prefix);
1641
+ _warnPreservedSkillDirs(dest,
1642
+ // Never pruned, as in installRuntimeArtifacts: the restore skips symlinks.
1643
+ _removeGsdEntries(dest, skillsKindEntry, (name) => !USER_OWNED_SKILL_DIRS.includes(name) && (rawStemNames.has(name) || ownsSkillDir(name))));
1441
1644
  let count = 0;
1645
+ const written = new Set();
1442
1646
  const firstPartyStems = new Set();
1443
1647
  for (const entry of installFs().readdirSync(rawDir, { withFileTypes: true })) {
1444
1648
  if (!entry.isFile() || !entry.name.endsWith('.md'))
@@ -1453,6 +1657,7 @@ function installOpencodeFamilySkills(runtime, targetDir, rawCommandsDir, pathPre
1453
1657
  const skillDir = node_path_1.default.join(dest, skillName);
1454
1658
  installFs().mkdirSync(skillDir, { recursive: true });
1455
1659
  installFs().writeFileSync(node_path_1.default.join(skillDir, 'SKILL.md'), content);
1660
+ written.add(skillName);
1456
1661
  count++;
1457
1662
  }
1458
1663
  // #2362: materialize installed THIRD-PARTY capability skills, bound to their
@@ -1506,13 +1711,17 @@ function installOpencodeFamilySkills(runtime, targetDir, rawCommandsDir, pathPre
1506
1711
  // capability is uninstalled/unsurfaced and no longer appears in any
1507
1712
  // registry view.
1508
1713
  installFs().writeFileSync(node_path_1.default.join(skillDir, installProfiles.CAPABILITY_SKILL_MARKER), found.capId + '\n', 'utf8');
1714
+ written.add(skillName);
1509
1715
  count++;
1510
1716
  }
1511
1717
  }
1512
- // Restore user-owned dirs after the prune+copy.
1718
+ // Restore user-owned dirs after the prune+copy, only where a prune removed
1719
+ // one; the kept dir is left untouched (it may hold read-only files).
1513
1720
  for (const [dirName, snap] of toPreserve) {
1514
- _restoreDir(node_path_1.default.join(dest, dirName), snap);
1721
+ if (!installFs().existsSync(node_path_1.default.join(dest, dirName)))
1722
+ _restoreDir(node_path_1.default.join(dest, dirName), snap);
1515
1723
  }
1724
+ recordWrittenSkillDirs(dest, written);
1516
1725
  return count;
1517
1726
  }
1518
1727
  // ---------------------------------------------------------------------------
@@ -1544,7 +1753,7 @@ function installOpencodeFamilySkills(runtime, targetDir, rawCommandsDir, pathPre
1544
1753
  * (`layout.kinds` → `agentsKindEntry.stage(resolvedProfile, agentCtx)` →
1545
1754
  * `_copyStaged`), rather than forking a second agent-staging pipeline. A
1546
1755
  * runtime/scope whose resolved layout declares no `agents` kind at all
1547
- * (e.g. pi, whose `artifactLayout` is empty for both scopes) is a no-op
1756
+ * (e.g. pi, whose `artifactLayout` is skills-only for both scopes, #5547) is a no-op
1548
1757
  * (`null`) — mirrors `installOpencodeFamilySkills`'s own
1549
1758
  * `if (!skillsKindEntry) return 0` contract.
1550
1759
  *
@@ -2038,6 +2247,11 @@ module.exports = {
2038
2247
  _runLegacyInstallMigrations,
2039
2248
  _runLegacyUninstallCleanup,
2040
2249
  _removeGsdEntries,
2250
+ createSkillDirOwnership,
2251
+ recordWrittenSkillDirs,
2252
+ clearWrittenSkillDirs,
2253
+ _warnPreservedSkillDirs,
2254
+ USER_OWNED_SKILL_DIRS,
2041
2255
  _snapshotDir,
2042
2256
  _restoreDir,
2043
2257
  _removeHermesBareStemDirs,
@@ -34,6 +34,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
34
34
  */
35
35
  const node_path_1 = __importDefault(require("node:path"));
36
36
  const node_os_1 = __importDefault(require("node:os"));
37
+ const runtime_homes_cjs_1 = require("./runtime-homes.cjs");
37
38
  // eslint-disable-next-line @typescript-eslint/no-require-imports -- install-fs-adapter.cjs is an export= CommonJS module
38
39
  const installFsAdapter = require("./install-fs-adapter.cjs");
39
40
  const { installFs } = installFsAdapter;
@@ -57,7 +58,7 @@ const { resolveTierEntry: gsdResolveTierEntry, resolveModelPolicy: gsdResolveMod
57
58
  */
58
59
  function readGsdGlobalModelOverrides(options = {}) {
59
60
  try {
60
- const home = options.homedir ? options.homedir() : node_os_1.default.homedir();
61
+ const home = (0, runtime_homes_cjs_1.resolveGsdHome)(options.homedir ? options.homedir() : node_os_1.default.homedir());
61
62
  const defaultsPath = node_path_1.default.join(home, '.gsd', 'defaults.json');
62
63
  if (!installFs().existsSync(defaultsPath))
63
64
  return null;
@@ -139,7 +140,7 @@ function readGsdAgentTools(config) {
139
140
  * model override resolver.
140
141
  */
141
142
  function readGsdEffectiveAgentTools(targetDir = null, options = {}) {
142
- const home = options.homedir ? options.homedir() : node_os_1.default.homedir();
143
+ const home = (0, runtime_homes_cjs_1.resolveGsdHome)(options.homedir ? options.homedir() : node_os_1.default.homedir());
143
144
  const globalConfig = _readGsdConfigFile(node_path_1.default.join(home, '.gsd', 'defaults.json'), 'global defaults');
144
145
  let projectConfig = null;
145
146
  if (targetDir) {
@@ -170,7 +171,7 @@ function readGsdEffectiveAgentTools(targetDir = null, options = {}) {
170
171
  * baked, letting the runtime's own default/session model govern).
171
172
  */
172
173
  function readGsdRuntimeProfileResolver(targetDir = null) {
173
- const homeDefaults = _readGsdConfigFile(node_path_1.default.join(node_os_1.default.homedir(), '.gsd', 'defaults.json'), '~/.gsd/defaults.json');
174
+ const homeDefaults = _readGsdConfigFile(node_path_1.default.join((0, runtime_homes_cjs_1.resolveGsdHome)(), '.gsd', 'defaults.json'), '~/.gsd/defaults.json');
174
175
  // #2875 defect fix (Generative Fix Divergence): same shared walk as
175
176
  // readGsdEffectiveModelOverrides above — see that call site's comment.
176
177
  let projectConfig = null;
@@ -31,6 +31,8 @@ const frontmatter_fence_cjs_1 = require("./frontmatter-fence.cjs");
31
31
  // #2322: reuse the existing pure path-containment seam (ADR-1239 Phase C-2)
32
32
  // instead of hand-rolling a new traversal check for capability skill stems.
33
33
  const external_descriptor_trust_cjs_1 = require("./external-descriptor-trust.cjs");
34
+ // eslint-disable-next-line @typescript-eslint/no-require-imports -- capability-ledger.cjs is an export= CommonJS module
35
+ const capabilityLedger = require("./capability-ledger.cjs");
34
36
  // eslint-disable-next-line @typescript-eslint/no-require-imports
35
37
  const conversionModule = require("./runtime-artifact-conversion.cjs");
36
38
  const { applyAgentPathRewrites: _applyAgentPathRewrites, processAttribution: _processAttribution, normalizeAgentBodyForRuntime: _normalizeAgentBodyForRuntime, readGsdCommandNames: _readGsdCommandNames, deriveAgentName: _deriveAgentName, applyAgentFrontmatterExtensions: _applyAgentFrontmatterExtensions, appendAgentTools: _appendAgentTools, } = conversionModule;
@@ -300,7 +302,7 @@ function _capabilitySkillsForMode(mode, registry) {
300
302
  /**
301
303
  * Resolve a profile (or composed profiles) to a typed result object.
302
304
  */
303
- function resolveProfile({ modes, manifest, _profilesOverride, registry } = {}) {
305
+ function resolveProfile({ modes, manifest, _profilesOverride, registry, agentManifest } = {}) {
304
306
  const profiles = _profilesOverride || PROFILES;
305
307
  const activeModes = (modes && modes.length > 0) ? modes : ['full'];
306
308
  const normalizedModes = activeModes
@@ -335,10 +337,13 @@ function resolveProfile({ modes, manifest, _profilesOverride, registry } = {}) {
335
337
  }
336
338
  // Derive agents: union of all agent names referenced in the body text of
337
339
  // every skill in unionSkills. Agent names are stored in the manifest under
338
- // _calls_agents_<stem> keys (populated by loadSkillsManifest).
340
+ // _calls_agents_<stem> keys (populated by loadSkillsManifest). #5503: read from
341
+ // `agentManifest` when given, so a profile that skips the skill closure still
342
+ // stages the agents its own skills spawn.
343
+ const agentMan = agentManifest || man;
339
344
  const unionAgents = new Set();
340
345
  for (const skillStem of unionSkills) {
341
- const agentRefs = man.get(`_calls_agents_${skillStem}`) || [];
346
+ const agentRefs = agentMan.get(`_calls_agents_${skillStem}`) || [];
342
347
  for (const agentStem of agentRefs) {
343
348
  unionAgents.add(agentStem);
344
349
  }
@@ -748,9 +753,9 @@ function readInstalledCapabilitySkill(stem, registry) {
748
753
  // installed as a capability skill (epic #4636).
749
754
  if (node_fs_1.default.lstatSync(skillPath).isSymbolicLink())
750
755
  return null;
751
- if (!node_fs_1.default.statSync(skillPath).isFile())
752
- return null;
753
- return { capId, content: node_fs_1.default.readFileSync(skillPath, 'utf8') };
756
+ // #5121: the bounded regular-file read — a FIFO/device/oversized SKILL.md is skipped like a missing one.
757
+ const content = capabilityLedger.readSkillFile(skillPath);
758
+ return content === null ? null : { capId, content };
754
759
  }
755
760
  catch {
756
761
  return null; // missing / unreadable / corrupt entry -> skip
@@ -938,7 +943,7 @@ function stageSkillsForRuntimeAsSkills(srcCommandsDir, resolvedProfile, converte
938
943
  * @param isGlobal install scope passed through to the converter
939
944
  * @param agentCtx optional cross-cutting context (ADR-1235 §1)
940
945
  */
941
- function stageAgentsForRuntimeWithConverter(srcAgentsDir, resolvedProfile, converter, isGlobal = false, agentCtx) {
946
+ function stageAgentsForRuntimeWithConverter(srcAgentsDir, resolvedProfile, converter, isGlobal = false, agentCtx, excludeSuffixes) {
942
947
  if (!installFs().existsSync(srcAgentsDir))
943
948
  return srcAgentsDir;
944
949
  const stageDir = mkInstallTempDir('gsd-profile-runtime-agents-');
@@ -974,6 +979,8 @@ function stageAgentsForRuntimeWithConverter(srcAgentsDir, resolvedProfile, conve
974
979
  continue;
975
980
  if (!entry.name.endsWith('.md'))
976
981
  continue;
982
+ if (excludeSuffixes && excludeSuffixes.some((s) => entry.name.endsWith(s)))
983
+ continue;
977
984
  // For tiered profiles, gate by agent stem (full filename without extension).
978
985
  if (resolvedProfile.skills !== '*') {
979
986
  const stem = entry.name.slice(0, -3);
@@ -51,6 +51,8 @@ exports.BUNDLED_GSD_HOOK_FILES = Object.freeze(new Set([
51
51
  // #3662: portable node resolver staged into hooks/ (not itself a lifecycle
52
52
  // hook — managed JS hook commands route through it under --portable-hooks).
53
53
  'hooks/gsd-node-runner.sh',
54
+ // #5465: SessionStart PATH persistence through $CLAUDE_ENV_FILE.
55
+ 'hooks/gsd-path-export.js',
54
56
  'hooks/gsd-phase-boundary.sh',
55
57
  'hooks/gsd-prompt-guard.js',
56
58
  'hooks/gsd-read-guard.js',