freeharness 0.4.1

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 (375) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +108 -0
  3. package/README.md +134 -0
  4. package/canonical/HARVEST.yaml +858 -0
  5. package/canonical/PROVENANCE.yaml +740 -0
  6. package/canonical/agents/README.md +95 -0
  7. package/canonical/agents/agentic-architect.md +18 -0
  8. package/canonical/agents/database-reviewer.md +41 -0
  9. package/canonical/agents/explorer-ai-engineer-analyst.md +65 -0
  10. package/canonical/agents/pr-reviewer.md +96 -0
  11. package/canonical/agents/python-reviewer.md +55 -0
  12. package/canonical/agents/report-formatter.md +19 -0
  13. package/canonical/agents/security-reviewer.md +53 -0
  14. package/canonical/agents/test-writer.md +34 -0
  15. package/canonical/commands/fh-context.md +37 -0
  16. package/canonical/evals/promptfoo.redteam.yaml +108 -0
  17. package/canonical/hooks/cost-prices.json +14 -0
  18. package/canonical/hooks/freeharness-auto-memory.mjs +158 -0
  19. package/canonical/hooks/freeharness-config-guard.mjs +162 -0
  20. package/canonical/hooks/freeharness-context-monitor.mjs +198 -0
  21. package/canonical/hooks/freeharness-converge.mjs +227 -0
  22. package/canonical/hooks/freeharness-cost-tracker.mjs +1027 -0
  23. package/canonical/hooks/freeharness-memory-guard.mjs +57 -0
  24. package/canonical/hooks/freeharness-output-pruner.mjs +333 -0
  25. package/canonical/hooks/freeharness-precompact.mjs +323 -0
  26. package/canonical/hooks/freeharness-repeat-tool.mjs +208 -0
  27. package/canonical/hooks/freeharness-security-guidance.mjs +164 -0
  28. package/canonical/hooks/freeharness-session-start +583 -0
  29. package/canonical/hooks/hooks.auto-memory.claude-code.json +16 -0
  30. package/canonical/hooks/hooks.claude-code.json +17 -0
  31. package/canonical/hooks/hooks.config-guard.claude-code.json +16 -0
  32. package/canonical/hooks/hooks.context-monitor.claude-code.json +15 -0
  33. package/canonical/hooks/hooks.converge.claude-code.json +15 -0
  34. package/canonical/hooks/hooks.cost-tracker.claude-code.json +37 -0
  35. package/canonical/hooks/hooks.memory-guard.claude-code.json +16 -0
  36. package/canonical/hooks/hooks.output-pruner.claude-code.json +16 -0
  37. package/canonical/hooks/hooks.precompact.claude-code.json +15 -0
  38. package/canonical/hooks/hooks.repeat-tool.claude-code.json +25 -0
  39. package/canonical/hooks/hooks.security-guidance.claude-code.json +16 -0
  40. package/canonical/mcp/servers.json +20 -0
  41. package/canonical/openspec/config.base.yaml +89 -0
  42. package/canonical/openspec/schema.spec-driven.yaml +277 -0
  43. package/canonical/openspec/templates/data-contract.md +36 -0
  44. package/canonical/openspec/templates/design.md +84 -0
  45. package/canonical/openspec/templates/eval-plan.md +33 -0
  46. package/canonical/openspec/templates/follow-ups.md +2 -0
  47. package/canonical/openspec/templates/proposal.md +45 -0
  48. package/canonical/openspec/templates/spec.md +42 -0
  49. package/canonical/openspec/templates/tasks.md +38 -0
  50. package/canonical/profiles/local-llamacpp.LOCAL-MODELS.md +47 -0
  51. package/canonical/profiles/local-llamacpp.json +27 -0
  52. package/canonical/profiles/local-ollama.json +20 -0
  53. package/canonical/profiles/mcp.json +91 -0
  54. package/canonical/rules/CLAUDE.md +78 -0
  55. package/canonical/rules/project-CLAUDE.template.md +62 -0
  56. package/canonical/rules/routing.md +20 -0
  57. package/canonical/rules/safety.md +41 -0
  58. package/canonical/settings/settings.cache-hygiene.claude-code.json +5 -0
  59. package/canonical/skills/agent-evaluation/SKILL.md +102 -0
  60. package/canonical/skills/agent-evaluation/assets/evaluation_report_template.md +206 -0
  61. package/canonical/skills/agent-evaluation/evals/cases.yaml +106 -0
  62. package/canonical/skills/agent-evaluation/references/dataset-preparation.md +351 -0
  63. package/canonical/skills/agent-evaluation/references/scorers-constraints.md +165 -0
  64. package/canonical/skills/agent-evaluation/references/scorers.md +431 -0
  65. package/canonical/skills/agent-evaluation/references/setup-guide.md +252 -0
  66. package/canonical/skills/agent-evaluation/references/tracing-integration.md +164 -0
  67. package/canonical/skills/agent-evaluation/references/troubleshooting.md +514 -0
  68. package/canonical/skills/agent-evaluation/scripts/analyze_results.py +462 -0
  69. package/canonical/skills/agent-evaluation/scripts/create_dataset_template.py +382 -0
  70. package/canonical/skills/agent-evaluation/scripts/list_datasets.py +273 -0
  71. package/canonical/skills/agent-evaluation/scripts/run_evaluation_template.py +309 -0
  72. package/canonical/skills/agent-evaluation/scripts/setup_mlflow.py +353 -0
  73. package/canonical/skills/agent-evaluation/scripts/utils/__init__.py +27 -0
  74. package/canonical/skills/agent-evaluation/scripts/utils/env_validation.py +123 -0
  75. package/canonical/skills/agent-evaluation/scripts/utils/tracing_utils.py +108 -0
  76. package/canonical/skills/agent-evaluation/scripts/validate_agent_tracing.py +148 -0
  77. package/canonical/skills/agent-evaluation/scripts/validate_auth.py +240 -0
  78. package/canonical/skills/agent-evaluation/scripts/validate_environment.py +185 -0
  79. package/canonical/skills/agent-evaluation/scripts/validate_tracing_runtime.py +318 -0
  80. package/canonical/skills/agentic-architecture/SKILL.md +41 -0
  81. package/canonical/skills/agentic-architecture/evals/cases.yaml +94 -0
  82. package/canonical/skills/agentic-architecture/reference/context-engineering.md +75 -0
  83. package/canonical/skills/agentic-architecture/reference/patterns.md +76 -0
  84. package/canonical/skills/agentic-architecture/reference/reliability-observability.md +94 -0
  85. package/canonical/skills/agentic-architecture/reference/review-framework.md +59 -0
  86. package/canonical/skills/code-review/SKILL.md +52 -0
  87. package/canonical/skills/code-review/evals/cases.yaml +197 -0
  88. package/canonical/skills/git-workflow/SKILL.md +41 -0
  89. package/canonical/skills/git-workflow/evals/cases.yaml +92 -0
  90. package/canonical/skills/local-code/SKILL.md +24 -0
  91. package/canonical/skills/local-code/evals/cases.yaml +85 -0
  92. package/canonical/skills/local-code/scripts/query_llama.py +68 -0
  93. package/canonical/skills/report-formatting/SKILL.md +62 -0
  94. package/canonical/skills/report-formatting/evals/cases.yaml +83 -0
  95. package/canonical/skills/report-formatting/reference/ARCHITECTURE.md +135 -0
  96. package/canonical/skills/report-formatting/reference/HELPERS.md +120 -0
  97. package/canonical/skills/report-formatting/reference/PPTX.md +136 -0
  98. package/canonical/skills/report-formatting/reference/RELEASE.md +99 -0
  99. package/canonical/skills/report-formatting/reference/TEMPLATES.md +48 -0
  100. package/canonical/skills/report-formatting/reference/authoring.md +66 -0
  101. package/canonical/skills/report-formatting/scripts/architecture-template.md +271 -0
  102. package/canonical/skills/report-formatting/scripts/assets/claro-logo.png +0 -0
  103. package/canonical/skills/report-formatting/scripts/assets/claro-wordmark.svg +1 -0
  104. package/canonical/skills/report-formatting/scripts/build-architecture.js +57 -0
  105. package/canonical/skills/report-formatting/scripts/build-md-claro.js +224 -0
  106. package/canonical/skills/report-formatting/scripts/build-release.js +51 -0
  107. package/canonical/skills/report-formatting/scripts/check-env.js +58 -0
  108. package/canonical/skills/report-formatting/scripts/docmodel.js +283 -0
  109. package/canonical/skills/report-formatting/scripts/example-build.js +119 -0
  110. package/canonical/skills/report-formatting/scripts/example_build_ArchitectureReview_docx.js +195 -0
  111. package/canonical/skills/report-formatting/scripts/example_build_ExecutiveReport_docx.js +114 -0
  112. package/canonical/skills/report-formatting/scripts/package.json +17 -0
  113. package/canonical/skills/report-formatting/scripts/pptx/example_build_StatusReport_pptx.py +223 -0
  114. package/canonical/skills/report-formatting/scripts/pptx/example_build_WeeklyStatus_pptx.py +245 -0
  115. package/canonical/skills/report-formatting/scripts/pptx/pptx_office.py +144 -0
  116. package/canonical/skills/report-formatting/scripts/pptx/requirements.txt +7 -0
  117. package/canonical/skills/report-formatting/scripts/pptx/status_report_blocks.py +193 -0
  118. package/canonical/skills/report-formatting/scripts/pptx/theme_claro_pptx.py +473 -0
  119. package/canonical/skills/report-formatting/scripts/release-template.md +80 -0
  120. package/canonical/skills/report-formatting/scripts/render-mermaid.js +105 -0
  121. package/canonical/skills/report-formatting/scripts/theme-claro.js +403 -0
  122. package/canonical/skills/subagent-driven-development/SKILL.md +60 -0
  123. package/canonical/skills/subagent-driven-development/evals/cases.yaml +208 -0
  124. package/canonical/skills/subagent-driven-development/reference/brief.md +91 -0
  125. package/canonical/skills/subagent-driven-development/reference/handoff.md +118 -0
  126. package/canonical/skills/subagent-driven-development/scripts/validate-handoff.mjs +850 -0
  127. package/canonical/skills/systematic-debugging/SKILL.md +44 -0
  128. package/canonical/skills/systematic-debugging/evals/cases.yaml +90 -0
  129. package/canonical/skills/test-driven-development/SKILL.md +42 -0
  130. package/canonical/skills/test-driven-development/evals/cases.yaml +86 -0
  131. package/canonical/skills/test-driven-development/reference/writing-good-tests.md +52 -0
  132. package/canonical/skills/verification-before-completion/SKILL.md +53 -0
  133. package/canonical/skills/verification-before-completion/evals/cases.yaml +107 -0
  134. package/dist/adapters/content/language-lint.d.ts +46 -0
  135. package/dist/adapters/content/language-lint.js +191 -0
  136. package/dist/adapters/harness/claude-code.d.ts +57 -0
  137. package/dist/adapters/harness/claude-code.js +385 -0
  138. package/dist/adapters/harness/index.d.ts +3 -0
  139. package/dist/adapters/harness/index.js +17 -0
  140. package/dist/adapters/harness/opencode.d.ts +7 -0
  141. package/dist/adapters/harness/opencode.js +166 -0
  142. package/dist/adapters/harness/plugin.d.ts +22 -0
  143. package/dist/adapters/harness/plugin.js +257 -0
  144. package/dist/adapters/memory/doctor.d.ts +480 -0
  145. package/dist/adapters/memory/doctor.js +1217 -0
  146. package/dist/adapters/memory/vendored.d.ts +150 -0
  147. package/dist/adapters/memory/vendored.js +487 -0
  148. package/dist/adapters/package/node.d.ts +9 -0
  149. package/dist/adapters/package/node.js +20 -0
  150. package/dist/adapters/prompt/readline.d.ts +19 -0
  151. package/dist/adapters/prompt/readline.js +53 -0
  152. package/dist/adapters/sync/diff.d.ts +43 -0
  153. package/dist/adapters/sync/diff.js +380 -0
  154. package/dist/cli/cleanup.d.ts +86 -0
  155. package/dist/cli/cleanup.js +382 -0
  156. package/dist/cli/cost.d.ts +304 -0
  157. package/dist/cli/cost.js +501 -0
  158. package/dist/cli/doctor.d.ts +205 -0
  159. package/dist/cli/doctor.js +654 -0
  160. package/dist/cli/executor.d.ts +5 -0
  161. package/dist/cli/executor.js +48 -0
  162. package/dist/cli/plugin-validate.d.ts +37 -0
  163. package/dist/cli/plugin-validate.js +256 -0
  164. package/dist/cli/prefix.d.ts +68 -0
  165. package/dist/cli/prefix.js +218 -0
  166. package/dist/cli/profile.d.ts +170 -0
  167. package/dist/cli/profile.js +285 -0
  168. package/dist/cli/runner.d.ts +10 -0
  169. package/dist/cli/runner.js +27 -0
  170. package/dist/cli/uninstall.d.ts +65 -0
  171. package/dist/cli/uninstall.js +147 -0
  172. package/dist/index.d.ts +8 -0
  173. package/dist/index.js +989 -0
  174. package/dist/infra/dogfood.d.ts +31 -0
  175. package/dist/infra/dogfood.js +51 -0
  176. package/dist/infra/fsutil.d.ts +40 -0
  177. package/dist/infra/fsutil.js +143 -0
  178. package/dist/infra/manifest.d.ts +76 -0
  179. package/dist/infra/manifest.js +92 -0
  180. package/dist/infra/paths.d.ts +19 -0
  181. package/dist/infra/paths.js +74 -0
  182. package/dist/infra/routing.d.ts +4 -0
  183. package/dist/infra/routing.js +7 -0
  184. package/node_modules/@freeharness/core/dist/context.d.ts +30 -0
  185. package/node_modules/@freeharness/core/dist/context.js +1 -0
  186. package/node_modules/@freeharness/core/dist/index.d.ts +5 -0
  187. package/node_modules/@freeharness/core/dist/index.js +6 -0
  188. package/node_modules/@freeharness/core/dist/planner.d.ts +13 -0
  189. package/node_modules/@freeharness/core/dist/planner.js +18 -0
  190. package/node_modules/@freeharness/core/dist/ports.d.ts +90 -0
  191. package/node_modules/@freeharness/core/dist/ports.js +1 -0
  192. package/node_modules/@freeharness/core/dist/registry.d.ts +41 -0
  193. package/node_modules/@freeharness/core/dist/registry.js +124 -0
  194. package/node_modules/@freeharness/core/dist/tiers.d.ts +30 -0
  195. package/node_modules/@freeharness/core/dist/tiers.js +99 -0
  196. package/node_modules/@freeharness/core/package.json +34 -0
  197. package/node_modules/@freeharness/sdd/PROVENANCE.yaml +175 -0
  198. package/node_modules/@freeharness/sdd/dist/src/bin/openspec.d.ts +2 -0
  199. package/node_modules/@freeharness/sdd/dist/src/bin/openspec.js +166 -0
  200. package/node_modules/@freeharness/sdd/dist/src/index.d.ts +14 -0
  201. package/node_modules/@freeharness/sdd/dist/src/index.js +11 -0
  202. package/node_modules/@freeharness/sdd/dist/src/init.d.ts +39 -0
  203. package/node_modules/@freeharness/sdd/dist/src/init.js +190 -0
  204. package/node_modules/@freeharness/sdd/dist/src/root-resolver.d.ts +8 -0
  205. package/node_modules/@freeharness/sdd/dist/src/root-resolver.js +32 -0
  206. package/node_modules/@freeharness/sdd/dist/src/shim/archive.d.ts +81 -0
  207. package/node_modules/@freeharness/sdd/dist/src/shim/archive.js +483 -0
  208. package/node_modules/@freeharness/sdd/dist/src/shim/context.d.ts +4 -0
  209. package/node_modules/@freeharness/sdd/dist/src/shim/context.js +48 -0
  210. package/node_modules/@freeharness/sdd/dist/src/shim/follow-up.d.ts +57 -0
  211. package/node_modules/@freeharness/sdd/dist/src/shim/follow-up.js +279 -0
  212. package/node_modules/@freeharness/sdd/dist/src/shim/instructions.d.ts +67 -0
  213. package/node_modules/@freeharness/sdd/dist/src/shim/instructions.js +460 -0
  214. package/node_modules/@freeharness/sdd/dist/src/shim/list.d.ts +5 -0
  215. package/node_modules/@freeharness/sdd/dist/src/shim/list.js +95 -0
  216. package/node_modules/@freeharness/sdd/dist/src/shim/new-change.d.ts +6 -0
  217. package/node_modules/@freeharness/sdd/dist/src/shim/new-change.js +150 -0
  218. package/node_modules/@freeharness/sdd/dist/src/shim/schemas.d.ts +4 -0
  219. package/node_modules/@freeharness/sdd/dist/src/shim/schemas.js +23 -0
  220. package/node_modules/@freeharness/sdd/dist/src/shim/shared.d.ts +56 -0
  221. package/node_modules/@freeharness/sdd/dist/src/shim/shared.js +140 -0
  222. package/node_modules/@freeharness/sdd/dist/src/shim/status.d.ts +8 -0
  223. package/node_modules/@freeharness/sdd/dist/src/shim/status.js +85 -0
  224. package/node_modules/@freeharness/sdd/dist/src/shim/validate.d.ts +6 -0
  225. package/node_modules/@freeharness/sdd/dist/src/shim/validate.js +229 -0
  226. package/node_modules/@freeharness/sdd/dist/src/validate-change.d.ts +40 -0
  227. package/node_modules/@freeharness/sdd/dist/src/validate-change.js +114 -0
  228. package/node_modules/@freeharness/sdd/dist/src/validate.d.ts +24 -0
  229. package/node_modules/@freeharness/sdd/dist/src/validate.js +72 -0
  230. package/node_modules/@freeharness/sdd/dist/vendor/openspec/apply/specs-apply.d.ts +130 -0
  231. package/node_modules/@freeharness/sdd/dist/vendor/openspec/apply/specs-apply.js +981 -0
  232. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/change-metadata.d.ts +46 -0
  233. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/change-metadata.js +128 -0
  234. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/change-status-policy.d.ts +26 -0
  235. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/change-status-policy.js +32 -0
  236. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/file-system.d.ts +50 -0
  237. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/file-system.js +394 -0
  238. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/global-config.d.ts +15 -0
  239. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/global-config.js +49 -0
  240. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/graph.d.ts +71 -0
  241. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/graph.js +164 -0
  242. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/index.d.ts +11 -0
  243. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/index.js +21 -0
  244. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/instruction-loader.d.ts +102 -0
  245. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/instruction-loader.js +230 -0
  246. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/outputs.d.ts +18 -0
  247. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/outputs.js +138 -0
  248. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/resolver.d.ts +82 -0
  249. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/resolver.js +333 -0
  250. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/schema.d.ts +12 -0
  251. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/schema.js +110 -0
  252. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/state.d.ts +11 -0
  253. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/state.js +32 -0
  254. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/task-progress.d.ts +33 -0
  255. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/task-progress.js +149 -0
  256. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/types.d.ts +39 -0
  257. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/types.js +49 -0
  258. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/claude.d.ts +12 -0
  259. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/claude.js +31 -0
  260. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/index.d.ts +10 -0
  261. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/index.js +10 -0
  262. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/opencode.d.ts +12 -0
  263. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/opencode.js +26 -0
  264. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/generator.d.ts +28 -0
  265. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/generator.js +41 -0
  266. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/index.d.ts +23 -0
  267. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/index.js +25 -0
  268. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/invocation.d.ts +72 -0
  269. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/invocation.js +76 -0
  270. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/registry.d.ts +39 -0
  271. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/registry.js +53 -0
  272. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/types.d.ts +62 -0
  273. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/types.js +7 -0
  274. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/yaml.d.ts +35 -0
  275. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/yaml.js +47 -0
  276. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-references.d.ts +33 -0
  277. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-references.js +55 -0
  278. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/shared/allowed-tools.d.ts +11 -0
  279. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/shared/allowed-tools.js +11 -0
  280. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/shared/skill-generation.d.ts +48 -0
  281. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/shared/skill-generation.js +99 -0
  282. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/skill-templates.d.ts +19 -0
  283. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/skill-templates.js +18 -0
  284. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/types.d.ts +18 -0
  285. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/types.js +4 -0
  286. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/apply-change.d.ts +19 -0
  287. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/apply-change.js +207 -0
  288. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/archive-change.d.ts +12 -0
  289. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/archive-change.js +409 -0
  290. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/bulk-archive-change.d.ts +9 -0
  291. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/bulk-archive-change.js +673 -0
  292. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/continue-change.d.ts +9 -0
  293. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/continue-change.js +230 -0
  294. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/explore.d.ts +12 -0
  295. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/explore.js +550 -0
  296. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/feedback.d.ts +8 -0
  297. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/feedback.js +107 -0
  298. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/ff-change.d.ts +12 -0
  299. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/ff-change.js +228 -0
  300. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/new-change.d.ts +9 -0
  301. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/new-change.js +147 -0
  302. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/onboard.d.ts +9 -0
  303. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/onboard.js +571 -0
  304. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/propose.d.ts +12 -0
  305. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/propose.js +322 -0
  306. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/store-selection.d.ts +7 -0
  307. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/store-selection.js +7 -0
  308. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/sync-specs.d.ts +9 -0
  309. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/sync-specs.js +518 -0
  310. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/update-change.d.ts +9 -0
  311. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/update-change.js +176 -0
  312. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/verify-change.d.ts +9 -0
  313. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/verify-change.js +344 -0
  314. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/constants.d.ts +39 -0
  315. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/constants.js +54 -0
  316. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/delta-resolution.d.ts +35 -0
  317. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/delta-resolution.js +171 -0
  318. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/change-parser.d.ts +27 -0
  319. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/change-parser.js +210 -0
  320. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/code-fence.d.ts +14 -0
  321. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/code-fence.js +48 -0
  322. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/markdown-parser.d.ts +22 -0
  323. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/markdown-parser.js +186 -0
  324. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-blocks.d.ts +65 -0
  325. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-blocks.js +409 -0
  326. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-text.d.ts +55 -0
  327. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-text.js +98 -0
  328. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/spec-structure.d.ts +8 -0
  329. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/spec-structure.js +77 -0
  330. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/purpose-placeholder.d.ts +44 -0
  331. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/purpose-placeholder.js +116 -0
  332. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/base.schema.d.ts +12 -0
  333. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/base.schema.js +17 -0
  334. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/change.schema.d.ts +72 -0
  335. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/change.schema.js +30 -0
  336. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/index.d.ts +3 -0
  337. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/index.js +3 -0
  338. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/spec.schema.d.ts +17 -0
  339. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/spec.schema.js +14 -0
  340. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/spec-discovery.d.ts +39 -0
  341. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/spec-discovery.js +114 -0
  342. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/task-lines.d.ts +45 -0
  343. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/task-lines.js +105 -0
  344. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/task-numbering.d.ts +15 -0
  345. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/task-numbering.js +56 -0
  346. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/types.d.ts +17 -0
  347. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/types.js +1 -0
  348. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/validator.d.ts +94 -0
  349. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/validator.js +756 -0
  350. package/node_modules/@freeharness/sdd/package.json +57 -0
  351. package/node_modules/@freeharness/sdd/vendor/openspec/LICENSE.upstream +22 -0
  352. package/node_modules/@freeharness/sdd/vendor/openspec/assets/schema.upstream.yaml +232 -0
  353. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/README.md +19 -0
  354. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-apply-change/SKILL.md +187 -0
  355. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-archive-change/SKILL.md +181 -0
  356. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-bulk-archive-change/SKILL.md +338 -0
  357. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-continue-change/SKILL.md +117 -0
  358. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-explore/SKILL.md +342 -0
  359. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-ff-change/SKILL.md +116 -0
  360. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-new-change/SKILL.md +76 -0
  361. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-onboard/SKILL.md +560 -0
  362. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-propose/SKILL.md +162 -0
  363. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-sync-specs/SKILL.md +261 -0
  364. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-update-change/SKILL.md +90 -0
  365. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-verify-change/SKILL.md +174 -0
  366. package/package.json +70 -0
  367. package/provenance/canonical.PROVENANCE.yaml +740 -0
  368. package/provenance/claude-mem.LICENSE.upstream +202 -0
  369. package/provenance/memory.PROVENANCE.yaml +399 -0
  370. package/provenance/sdd.PROVENANCE.yaml +175 -0
  371. package/vendor-licenses/caveman.LICENSE +27 -0
  372. package/vendor-licenses/deepseek-harness.LICENSE +21 -0
  373. package/vendor-licenses/ecc.LICENSE +21 -0
  374. package/vendor-licenses/pi.LICENSE +21 -0
  375. package/vendor-licenses/superpowers.LICENSE +21 -0
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Checks if a path contains glob pattern characters.
3
+ */
4
+ export declare function isGlobPattern(pattern: string): boolean;
5
+ /**
6
+ * Resolves an artifact's `generates` value to an absolute path under the change
7
+ * directory, asserting the result stays confined below it.
8
+ */
9
+ export declare function resolveArtifactOutputPath(changeDir: string, generates: string): string;
10
+ /**
11
+ * Resolves an artifact's output path(s) to concrete files that currently exist.
12
+ * Returns absolute file paths. Glob matches are sorted for deterministic output.
13
+ */
14
+ export declare function resolveArtifactOutputs(changeDir: string, generates: string): string[];
15
+ /**
16
+ * Checks if an artifact has at least one resolved output file.
17
+ */
18
+ export declare function artifactOutputExists(changeDir: string, generates: string): boolean;
@@ -0,0 +1,138 @@
1
+ // RECONSTRUCTED (store-free, dependency-free) from
2
+ // @fission-ai/openspec@1.8.0 src/core/artifact-graph/outputs.ts
3
+ //
4
+ // The upstream module resolves an artifact's `generates` path (a literal path
5
+ // or a glob) to concrete files under the change directory, using `fast-glob`
6
+ // plus a hardened directory-traversal guard. To keep this slice free of the
7
+ // `fast-glob` dependency we reimplement the same PUBLIC surface
8
+ // (isGlobPattern / resolveArtifactOutputPath / resolveArtifactOutputs /
9
+ // artifactOutputExists) with a small internal glob matcher that covers the
10
+ // patterns OpenSpec schemas actually use (`proposal.md`, `specs/**/*.md`, ...).
11
+ // Path confinement below the change directory is preserved via
12
+ // FileSystemUtils.assertPathWithin.
13
+ import * as fs from 'node:fs';
14
+ import * as path from 'node:path';
15
+ import { FileSystemUtils } from './file-system.js';
16
+ /**
17
+ * Checks if a path contains glob pattern characters.
18
+ */
19
+ export function isGlobPattern(pattern) {
20
+ return pattern.includes('*') || pattern.includes('?') || pattern.includes('[');
21
+ }
22
+ /**
23
+ * Resolves an artifact's `generates` value to an absolute path under the change
24
+ * directory, asserting the result stays confined below it.
25
+ */
26
+ export function resolveArtifactOutputPath(changeDir, generates) {
27
+ const outputPath = path.join(changeDir, generates);
28
+ FileSystemUtils.assertPathWithin(changeDir, outputPath);
29
+ return outputPath;
30
+ }
31
+ /**
32
+ * Compiles a POSIX-style glob (relative, `/`-separated) into an anchored
33
+ * regular expression. Supports `**` (any number of path segments, including
34
+ * zero), `*` (any run of non-separator chars), `?` (a single non-separator
35
+ * char), and literal text. This is intentionally minimal: it matches the
36
+ * `generates` patterns OpenSpec schemas emit, not the full glob grammar.
37
+ */
38
+ function globToRegExp(pattern) {
39
+ let re = '';
40
+ for (let i = 0; i < pattern.length; i++) {
41
+ const ch = pattern[i];
42
+ if (ch === '*') {
43
+ if (pattern[i + 1] === '*') {
44
+ // `**` (optionally followed by `/`) matches across path separators.
45
+ i++;
46
+ if (pattern[i + 1] === '/') {
47
+ i++;
48
+ re += '(?:.*/)?';
49
+ }
50
+ else {
51
+ re += '.*';
52
+ }
53
+ }
54
+ else {
55
+ re += '[^/]*';
56
+ }
57
+ }
58
+ else if (ch === '?') {
59
+ re += '[^/]';
60
+ }
61
+ else if ('\\^$.|+()[]{}'.includes(ch)) {
62
+ re += '\\' + ch;
63
+ }
64
+ else {
65
+ re += ch;
66
+ }
67
+ }
68
+ return new RegExp('^' + re + '$');
69
+ }
70
+ /** Recursively lists every file below `dir`, returned as absolute paths. */
71
+ function walkFiles(dir) {
72
+ const out = [];
73
+ let entries;
74
+ try {
75
+ entries = fs.readdirSync(dir, { withFileTypes: true });
76
+ }
77
+ catch {
78
+ return out;
79
+ }
80
+ for (const entry of entries) {
81
+ const full = path.join(dir, entry.name);
82
+ if (entry.isDirectory()) {
83
+ out.push(...walkFiles(full));
84
+ }
85
+ else if (entry.isFile()) {
86
+ out.push(full);
87
+ }
88
+ else if (entry.isSymbolicLink()) {
89
+ try {
90
+ const stat = fs.statSync(full);
91
+ if (stat.isFile())
92
+ out.push(full);
93
+ else if (stat.isDirectory())
94
+ out.push(...walkFiles(full));
95
+ }
96
+ catch {
97
+ // Broken symlink — skip.
98
+ }
99
+ }
100
+ }
101
+ return out;
102
+ }
103
+ /**
104
+ * Resolves an artifact's output path(s) to concrete files that currently exist.
105
+ * Returns absolute file paths. Glob matches are sorted for deterministic output.
106
+ */
107
+ export function resolveArtifactOutputs(changeDir, generates) {
108
+ const outputPath = resolveArtifactOutputPath(changeDir, generates);
109
+ if (!isGlobPattern(generates)) {
110
+ try {
111
+ return fs.statSync(outputPath).isFile() ? [outputPath] : [];
112
+ }
113
+ catch {
114
+ return [];
115
+ }
116
+ }
117
+ const regex = globToRegExp(FileSystemUtils.toPosixPath(generates));
118
+ const matches = [];
119
+ for (const file of walkFiles(changeDir)) {
120
+ const rel = FileSystemUtils.toPosixPath(path.relative(changeDir, file));
121
+ if (!regex.test(rel))
122
+ continue;
123
+ try {
124
+ FileSystemUtils.assertPathWithin(changeDir, file);
125
+ }
126
+ catch {
127
+ continue;
128
+ }
129
+ matches.push(file);
130
+ }
131
+ return Array.from(new Set(matches)).sort();
132
+ }
133
+ /**
134
+ * Checks if an artifact has at least one resolved output file.
135
+ */
136
+ export function artifactOutputExists(changeDir, generates) {
137
+ return resolveArtifactOutputs(changeDir, generates).length > 0;
138
+ }
@@ -0,0 +1,82 @@
1
+ import * as fs from 'node:fs';
2
+ import type { SchemaYaml } from './types.js';
3
+ /**
4
+ * Error thrown when loading a schema fails.
5
+ */
6
+ export declare class SchemaLoadError extends Error {
7
+ readonly schemaPath: string;
8
+ readonly cause?: Error | undefined;
9
+ constructor(message: string, schemaPath: string, cause?: Error | undefined);
10
+ }
11
+ /**
12
+ * Gets the package's built-in schemas directory path.
13
+ * Uses import.meta.url to resolve relative to the current module.
14
+ */
15
+ export declare function getPackageSchemasDir(): string;
16
+ /**
17
+ * Gets the user's schema override directory path.
18
+ */
19
+ export declare function getUserSchemasDir(): string;
20
+ /**
21
+ * Gets the project-local schemas directory path.
22
+ * @param projectRoot - The project root directory
23
+ * @returns The path to the project's schemas directory
24
+ */
25
+ export declare function getProjectSchemasDir(projectRoot: string): string;
26
+ export declare function isSchemaDir(parentDir: string, entry: fs.Dirent): boolean;
27
+ /**
28
+ * Resolves a schema name to its directory path.
29
+ *
30
+ * Resolution order (when projectRoot is provided):
31
+ * 1. Project-local: <projectRoot>/openspec/schemas/<name>/schema.yaml
32
+ * 2. User override: ${XDG_DATA_HOME}/openspec/schemas/<name>/schema.yaml
33
+ * 3. Package built-in: <package>/schemas/<name>/schema.yaml
34
+ *
35
+ * When projectRoot is not provided, only user override and package built-in are checked
36
+ * (backward compatible behavior).
37
+ *
38
+ * @param name - Schema name (e.g., "spec-driven")
39
+ * @param projectRoot - Optional project root directory for project-local schema resolution
40
+ * @returns The path to the schema directory, or null if not found
41
+ */
42
+ export declare function getSchemaDir(name: string, projectRoot?: string): string | null;
43
+ /**
44
+ * Resolves a schema name to a SchemaYaml object.
45
+ *
46
+ * Resolution order (when projectRoot is provided):
47
+ * 1. Project-local: <projectRoot>/openspec/schemas/<name>/schema.yaml
48
+ * 2. User override: ${XDG_DATA_HOME}/openspec/schemas/<name>/schema.yaml
49
+ * 3. Package built-in: <package>/schemas/<name>/schema.yaml
50
+ *
51
+ * When projectRoot is not provided, only user override and package built-in are checked
52
+ * (backward compatible behavior).
53
+ *
54
+ * @param name - Schema name (e.g., "spec-driven")
55
+ * @param projectRoot - Optional project root directory for project-local schema resolution
56
+ * @returns The resolved schema object
57
+ * @throws Error if schema is not found in any location
58
+ */
59
+ export declare function resolveSchema(name: string, projectRoot?: string): SchemaYaml;
60
+ /**
61
+ * Lists all available schema names.
62
+ * Combines project-local, user override, and package built-in schemas.
63
+ *
64
+ * @param projectRoot - Optional project root directory for project-local schema resolution
65
+ */
66
+ export declare function listSchemas(projectRoot?: string): string[];
67
+ /**
68
+ * Schema info with metadata (name, description, artifacts).
69
+ */
70
+ export interface SchemaInfo {
71
+ name: string;
72
+ description: string;
73
+ artifacts: string[];
74
+ source: 'project' | 'user' | 'package';
75
+ }
76
+ /**
77
+ * Lists all available schemas with their descriptions and artifact lists.
78
+ * Useful for agent skills to present schema selection to users.
79
+ *
80
+ * @param projectRoot - Optional project root directory for project-local schema resolution
81
+ */
82
+ export declare function listSchemasWithInfo(projectRoot?: string): SchemaInfo[];
@@ -0,0 +1,333 @@
1
+ // Vendored from @fission-ai/openspec@1.8.0
2
+ // src/core/artifact-graph/resolver.ts
3
+ // ONLY change vs upstream: import paths rewritten so the slice resolves within
4
+ // this vendored engine directory:
5
+ // ../global-config.js -> ./global-config.js (store-free replacement)
6
+ // ../../utils/file-system.js -> ./file-system.js
7
+ // Behaviour is otherwise unchanged. Note: getPackageSchemasDir points at a
8
+ // <package>/schemas dir that this slice does not ship; the existsSync guards in
9
+ // resolveSchema/listSchemas make a missing package-schemas dir a no-op.
10
+ import * as fs from 'node:fs';
11
+ import * as path from 'node:path';
12
+ import { fileURLToPath } from 'node:url';
13
+ import { getGlobalDataDir } from './global-config.js';
14
+ import { FileSystemUtils } from './file-system.js';
15
+ import { parseSchema, SchemaValidationError } from './schema.js';
16
+ /**
17
+ * Error thrown when loading a schema fails.
18
+ */
19
+ export class SchemaLoadError extends Error {
20
+ schemaPath;
21
+ cause;
22
+ constructor(message, schemaPath, cause) {
23
+ super(message);
24
+ this.schemaPath = schemaPath;
25
+ this.cause = cause;
26
+ this.name = 'SchemaLoadError';
27
+ }
28
+ }
29
+ /**
30
+ * Gets the package's built-in schemas directory path.
31
+ * Uses import.meta.url to resolve relative to the current module.
32
+ */
33
+ export function getPackageSchemasDir() {
34
+ const currentFile = fileURLToPath(import.meta.url);
35
+ // Navigate from dist/core/artifact-graph/ to package root's schemas/
36
+ return path.join(path.dirname(currentFile), '..', '..', '..', 'schemas');
37
+ }
38
+ /**
39
+ * Gets the user's schema override directory path.
40
+ */
41
+ export function getUserSchemasDir() {
42
+ return path.join(getGlobalDataDir(), 'schemas');
43
+ }
44
+ /**
45
+ * Gets the project-local schemas directory path.
46
+ * @param projectRoot - The project root directory
47
+ * @returns The path to the project's schemas directory
48
+ */
49
+ export function getProjectSchemasDir(projectRoot) {
50
+ return path.join(projectRoot, 'openspec', 'schemas');
51
+ }
52
+ /**
53
+ * Determines whether a directory entry represents a schema directory candidate.
54
+ *
55
+ * Returns true for real directories and for symlinks whose target is a
56
+ * directory. `fs.Dirent.isDirectory()` reports the raw entry type, so a symlink
57
+ * (even one pointing at a directory) has `isDirectory() === false`; we
58
+ * dereference such entries via `fs.statSync` to admit symlinked schema dirs
59
+ * while still rejecting symlinks-to-files and broken/dangling symlinks.
60
+ *
61
+ * @param parentDir - The directory containing the entry
62
+ * @param entry - The directory entry from `fs.readdirSync(..., { withFileTypes: true })`
63
+ */
64
+ /**
65
+ * Directories `schema fork` creates transiently while swapping a fork into
66
+ * place: a staging copy (`.fork-staging-<rand>`, created via mkdtemp) and a
67
+ * backup of the previous destination (`<name>.fork-backup-<pid>-<ts>`). Either
68
+ * can briefly coexist with real schemas in the schemas dir, so discovery must
69
+ * never surface them. Real schema names are kebab-case (no dots), so excluding
70
+ * these dot-bearing temp names can never hide a legitimate schema.
71
+ */
72
+ function isOwnedForkTempDir(name) {
73
+ return name.startsWith('.fork-staging-') || name.includes('.fork-backup-');
74
+ }
75
+ export function isSchemaDir(parentDir, entry) {
76
+ if (isOwnedForkTempDir(entry.name)) {
77
+ return false;
78
+ }
79
+ if (entry.isDirectory()) {
80
+ return true;
81
+ }
82
+ if (entry.isSymbolicLink()) {
83
+ try {
84
+ // statSync follows the link; isDirectory() reflects the target type.
85
+ return fs.statSync(path.join(parentDir, entry.name)).isDirectory();
86
+ }
87
+ catch {
88
+ // Broken symlink (dangling target) — statSync throws; treat as non-dir.
89
+ return false;
90
+ }
91
+ }
92
+ return false;
93
+ }
94
+ /**
95
+ * Returns a schema directory only when its schema file stays within that
96
+ * directory's canonical trust boundary. The directory itself may be a symlink;
97
+ * external user schema links are an intentionally supported workflow.
98
+ */
99
+ function getSchemaCandidateDir(schemasDir, name) {
100
+ const schemaDir = path.join(schemasDir, name);
101
+ const schemaPath = path.join(schemaDir, 'schema.yaml');
102
+ if (!fs.existsSync(schemaPath)) {
103
+ return null;
104
+ }
105
+ try {
106
+ FileSystemUtils.assertPathWithin(schemaDir, schemaPath);
107
+ return schemaDir;
108
+ }
109
+ catch {
110
+ return null;
111
+ }
112
+ }
113
+ /**
114
+ * Resolves a schema name to its directory path.
115
+ *
116
+ * Resolution order (when projectRoot is provided):
117
+ * 1. Project-local: <projectRoot>/openspec/schemas/<name>/schema.yaml
118
+ * 2. User override: ${XDG_DATA_HOME}/openspec/schemas/<name>/schema.yaml
119
+ * 3. Package built-in: <package>/schemas/<name>/schema.yaml
120
+ *
121
+ * When projectRoot is not provided, only user override and package built-in are checked
122
+ * (backward compatible behavior).
123
+ *
124
+ * @param name - Schema name (e.g., "spec-driven")
125
+ * @param projectRoot - Optional project root directory for project-local schema resolution
126
+ * @returns The path to the schema directory, or null if not found
127
+ */
128
+ export function getSchemaDir(name, projectRoot) {
129
+ if (name.length === 0 ||
130
+ name === '.' ||
131
+ name === '..' ||
132
+ /[\\/]/u.test(name) ||
133
+ /^[A-Za-z]:/u.test(name) ||
134
+ path.posix.isAbsolute(name) ||
135
+ path.win32.isAbsolute(name)) {
136
+ return null;
137
+ }
138
+ // 1. Check project-local directory (if projectRoot provided)
139
+ if (projectRoot) {
140
+ const projectDir = getSchemaCandidateDir(getProjectSchemasDir(projectRoot), name);
141
+ if (projectDir) {
142
+ return projectDir;
143
+ }
144
+ }
145
+ // 2. Check user override directory
146
+ const userDir = getSchemaCandidateDir(getUserSchemasDir(), name);
147
+ if (userDir) {
148
+ return userDir;
149
+ }
150
+ // 3. Check package built-in directory
151
+ const packageDir = getSchemaCandidateDir(getPackageSchemasDir(), name);
152
+ if (packageDir) {
153
+ return packageDir;
154
+ }
155
+ return null;
156
+ }
157
+ /**
158
+ * Resolves a schema name to a SchemaYaml object.
159
+ *
160
+ * Resolution order (when projectRoot is provided):
161
+ * 1. Project-local: <projectRoot>/openspec/schemas/<name>/schema.yaml
162
+ * 2. User override: ${XDG_DATA_HOME}/openspec/schemas/<name>/schema.yaml
163
+ * 3. Package built-in: <package>/schemas/<name>/schema.yaml
164
+ *
165
+ * When projectRoot is not provided, only user override and package built-in are checked
166
+ * (backward compatible behavior).
167
+ *
168
+ * @param name - Schema name (e.g., "spec-driven")
169
+ * @param projectRoot - Optional project root directory for project-local schema resolution
170
+ * @returns The resolved schema object
171
+ * @throws Error if schema is not found in any location
172
+ */
173
+ export function resolveSchema(name, projectRoot) {
174
+ // Normalize name (remove .yaml extension if provided)
175
+ const normalizedName = name.replace(/\.ya?ml$/, '');
176
+ const schemaDir = getSchemaDir(normalizedName, projectRoot);
177
+ if (!schemaDir) {
178
+ const availableSchemas = listSchemas(projectRoot);
179
+ throw new Error(`Schema '${normalizedName}' not found. Available schemas: ${availableSchemas.join(', ')}`);
180
+ }
181
+ const schemaPath = path.join(schemaDir, 'schema.yaml');
182
+ // Load and parse the schema
183
+ let content;
184
+ try {
185
+ content = fs.readFileSync(schemaPath, 'utf-8');
186
+ }
187
+ catch (err) {
188
+ const ioError = err instanceof Error ? err : new Error(String(err));
189
+ throw new SchemaLoadError(`Failed to read schema at '${schemaPath}': ${ioError.message}`, schemaPath, ioError);
190
+ }
191
+ try {
192
+ return parseSchema(content);
193
+ }
194
+ catch (err) {
195
+ if (err instanceof SchemaValidationError) {
196
+ throw new SchemaLoadError(`Invalid schema at '${schemaPath}': ${err.message}`, schemaPath, err);
197
+ }
198
+ const parseError = err instanceof Error ? err : new Error(String(err));
199
+ throw new SchemaLoadError(`Failed to parse schema at '${schemaPath}': ${parseError.message}`, schemaPath, parseError);
200
+ }
201
+ }
202
+ /**
203
+ * Lists all available schema names.
204
+ * Combines project-local, user override, and package built-in schemas.
205
+ *
206
+ * @param projectRoot - Optional project root directory for project-local schema resolution
207
+ */
208
+ export function listSchemas(projectRoot) {
209
+ const schemas = new Set();
210
+ // Add package built-in schemas
211
+ const packageDir = getPackageSchemasDir();
212
+ if (fs.existsSync(packageDir)) {
213
+ for (const entry of fs.readdirSync(packageDir, { withFileTypes: true })) {
214
+ if (isSchemaDir(packageDir, entry)) {
215
+ const schemaPath = path.join(packageDir, entry.name, 'schema.yaml');
216
+ if (fs.existsSync(schemaPath)) {
217
+ schemas.add(entry.name);
218
+ }
219
+ }
220
+ }
221
+ }
222
+ // Add user override schemas (may override package schemas)
223
+ const userDir = getUserSchemasDir();
224
+ if (fs.existsSync(userDir)) {
225
+ for (const entry of fs.readdirSync(userDir, { withFileTypes: true })) {
226
+ if (isSchemaDir(userDir, entry)) {
227
+ const schemaPath = path.join(userDir, entry.name, 'schema.yaml');
228
+ if (fs.existsSync(schemaPath)) {
229
+ schemas.add(entry.name);
230
+ }
231
+ }
232
+ }
233
+ }
234
+ // Add project-local schemas (if projectRoot provided)
235
+ if (projectRoot) {
236
+ const projectDir = getProjectSchemasDir(projectRoot);
237
+ if (fs.existsSync(projectDir)) {
238
+ for (const entry of fs.readdirSync(projectDir, { withFileTypes: true })) {
239
+ if (isSchemaDir(projectDir, entry)) {
240
+ const schemaPath = path.join(projectDir, entry.name, 'schema.yaml');
241
+ if (fs.existsSync(schemaPath)) {
242
+ schemas.add(entry.name);
243
+ }
244
+ }
245
+ }
246
+ }
247
+ }
248
+ return Array.from(schemas).sort();
249
+ }
250
+ /**
251
+ * Lists all available schemas with their descriptions and artifact lists.
252
+ * Useful for agent skills to present schema selection to users.
253
+ *
254
+ * @param projectRoot - Optional project root directory for project-local schema resolution
255
+ */
256
+ export function listSchemasWithInfo(projectRoot) {
257
+ const schemas = [];
258
+ const seenNames = new Set();
259
+ // Add project-local schemas first (highest priority, if projectRoot provided)
260
+ if (projectRoot) {
261
+ const projectDir = getProjectSchemasDir(projectRoot);
262
+ if (fs.existsSync(projectDir)) {
263
+ for (const entry of fs.readdirSync(projectDir, { withFileTypes: true })) {
264
+ if (isSchemaDir(projectDir, entry)) {
265
+ const schemaPath = path.join(projectDir, entry.name, 'schema.yaml');
266
+ if (fs.existsSync(schemaPath)) {
267
+ try {
268
+ const schema = parseSchema(fs.readFileSync(schemaPath, 'utf-8'));
269
+ schemas.push({
270
+ name: entry.name,
271
+ description: schema.description || '',
272
+ artifacts: schema.artifacts.map((a) => a.id),
273
+ source: 'project',
274
+ });
275
+ seenNames.add(entry.name);
276
+ }
277
+ catch {
278
+ // Skip invalid schemas
279
+ }
280
+ }
281
+ }
282
+ }
283
+ }
284
+ }
285
+ // Add user override schemas (if not overridden by project)
286
+ const userDir = getUserSchemasDir();
287
+ if (fs.existsSync(userDir)) {
288
+ for (const entry of fs.readdirSync(userDir, { withFileTypes: true })) {
289
+ if (isSchemaDir(userDir, entry) && !seenNames.has(entry.name)) {
290
+ const schemaPath = path.join(userDir, entry.name, 'schema.yaml');
291
+ if (fs.existsSync(schemaPath)) {
292
+ try {
293
+ const schema = parseSchema(fs.readFileSync(schemaPath, 'utf-8'));
294
+ schemas.push({
295
+ name: entry.name,
296
+ description: schema.description || '',
297
+ artifacts: schema.artifacts.map((a) => a.id),
298
+ source: 'user',
299
+ });
300
+ seenNames.add(entry.name);
301
+ }
302
+ catch {
303
+ // Skip invalid schemas
304
+ }
305
+ }
306
+ }
307
+ }
308
+ }
309
+ // Add package built-in schemas (if not overridden by project or user)
310
+ const packageDir = getPackageSchemasDir();
311
+ if (fs.existsSync(packageDir)) {
312
+ for (const entry of fs.readdirSync(packageDir, { withFileTypes: true })) {
313
+ if (isSchemaDir(packageDir, entry) && !seenNames.has(entry.name)) {
314
+ const schemaPath = path.join(packageDir, entry.name, 'schema.yaml');
315
+ if (fs.existsSync(schemaPath)) {
316
+ try {
317
+ const schema = parseSchema(fs.readFileSync(schemaPath, 'utf-8'));
318
+ schemas.push({
319
+ name: entry.name,
320
+ description: schema.description || '',
321
+ artifacts: schema.artifacts.map((a) => a.id),
322
+ source: 'package',
323
+ });
324
+ }
325
+ catch {
326
+ // Skip invalid schemas
327
+ }
328
+ }
329
+ }
330
+ }
331
+ }
332
+ return schemas.sort((a, b) => a.name.localeCompare(b.name));
333
+ }
@@ -0,0 +1,12 @@
1
+ import { type SchemaYaml } from './types.js';
2
+ export declare class SchemaValidationError extends Error {
3
+ constructor(message: string);
4
+ }
5
+ /**
6
+ * Loads and validates an artifact schema from a YAML file.
7
+ */
8
+ export declare function loadSchema(filePath: string): SchemaYaml;
9
+ /**
10
+ * Parses and validates an artifact schema from YAML content.
11
+ */
12
+ export declare function parseSchema(yamlContent: string): SchemaYaml;