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,110 @@
1
+ // Vendored faithfully from @fission-ai/openspec@1.8.0
2
+ // src/core/artifact-graph/schema.ts
3
+ // No behavioural changes. Part of the schema-validation slice.
4
+ import * as fs from 'node:fs';
5
+ import { parse as parseYaml } from 'yaml';
6
+ import { SchemaYamlSchema } from './types.js';
7
+ export class SchemaValidationError extends Error {
8
+ constructor(message) {
9
+ super(message);
10
+ this.name = 'SchemaValidationError';
11
+ }
12
+ }
13
+ /**
14
+ * Loads and validates an artifact schema from a YAML file.
15
+ */
16
+ export function loadSchema(filePath) {
17
+ const content = fs.readFileSync(filePath, 'utf-8');
18
+ return parseSchema(content);
19
+ }
20
+ /**
21
+ * Parses and validates an artifact schema from YAML content.
22
+ */
23
+ export function parseSchema(yamlContent) {
24
+ const parsed = parseYaml(yamlContent);
25
+ // Validate with Zod
26
+ const result = SchemaYamlSchema.safeParse(parsed);
27
+ if (!result.success) {
28
+ const errors = result.error.issues.map(e => `${e.path.join('.')}: ${e.message}`).join(', ');
29
+ throw new SchemaValidationError(`Invalid schema: ${errors}`);
30
+ }
31
+ const schema = result.data;
32
+ // Check for duplicate artifact IDs
33
+ validateNoDuplicateIds(schema.artifacts);
34
+ // Check that all requires references are valid
35
+ validateRequiresReferences(schema.artifacts);
36
+ // Check for cycles
37
+ validateNoCycles(schema.artifacts);
38
+ return schema;
39
+ }
40
+ /**
41
+ * Validates that there are no duplicate artifact IDs.
42
+ */
43
+ function validateNoDuplicateIds(artifacts) {
44
+ const seen = new Set();
45
+ for (const artifact of artifacts) {
46
+ if (seen.has(artifact.id)) {
47
+ throw new SchemaValidationError(`Duplicate artifact ID: ${artifact.id}`);
48
+ }
49
+ seen.add(artifact.id);
50
+ }
51
+ }
52
+ /**
53
+ * Validates that all `requires` references point to valid artifact IDs.
54
+ */
55
+ function validateRequiresReferences(artifacts) {
56
+ const validIds = new Set(artifacts.map(a => a.id));
57
+ for (const artifact of artifacts) {
58
+ for (const req of artifact.requires) {
59
+ if (!validIds.has(req)) {
60
+ throw new SchemaValidationError(`Invalid dependency reference in artifact '${artifact.id}': '${req}' does not exist`);
61
+ }
62
+ }
63
+ }
64
+ }
65
+ /**
66
+ * Validates that there are no cyclic dependencies.
67
+ * Uses DFS to detect cycles and reports the full cycle path.
68
+ */
69
+ function validateNoCycles(artifacts) {
70
+ const artifactMap = new Map(artifacts.map(a => [a.id, a]));
71
+ const visited = new Set();
72
+ const inStack = new Set();
73
+ const parent = new Map();
74
+ function dfs(id) {
75
+ visited.add(id);
76
+ inStack.add(id);
77
+ const artifact = artifactMap.get(id);
78
+ if (!artifact)
79
+ return null;
80
+ for (const dep of artifact.requires) {
81
+ if (!visited.has(dep)) {
82
+ parent.set(dep, id);
83
+ const cycle = dfs(dep);
84
+ if (cycle)
85
+ return cycle;
86
+ }
87
+ else if (inStack.has(dep)) {
88
+ // Found a cycle - reconstruct the path
89
+ const cyclePath = [dep];
90
+ let current = id;
91
+ while (current !== dep) {
92
+ cyclePath.unshift(current);
93
+ current = parent.get(current);
94
+ }
95
+ cyclePath.unshift(dep);
96
+ return cyclePath.join(' → ');
97
+ }
98
+ }
99
+ inStack.delete(id);
100
+ return null;
101
+ }
102
+ for (const artifact of artifacts) {
103
+ if (!visited.has(artifact.id)) {
104
+ const cycle = dfs(artifact.id);
105
+ if (cycle) {
106
+ throw new SchemaValidationError(`Cyclic dependency detected: ${cycle}`);
107
+ }
108
+ }
109
+ }
110
+ }
@@ -0,0 +1,11 @@
1
+ import type { CompletedSet } from './types.js';
2
+ import type { ArtifactGraph } from './graph.js';
3
+ /**
4
+ * Detects which artifacts are completed by checking file existence in the change directory.
5
+ * Returns a Set of completed artifact IDs.
6
+ *
7
+ * @param graph - The artifact graph to check
8
+ * @param changeDir - The change directory to scan for files
9
+ * @returns Set of artifact IDs whose generated files exist
10
+ */
11
+ export declare function detectCompleted(graph: ArtifactGraph, changeDir: string): CompletedSet;
@@ -0,0 +1,32 @@
1
+ // Vendored VERBATIM from @fission-ai/openspec@1.8.0 src/core/artifact-graph/state.ts
2
+ // (import paths already resolve within this vendored engine directory).
3
+ import * as fs from 'node:fs';
4
+ import { artifactOutputExists } from './outputs.js';
5
+ /**
6
+ * Detects which artifacts are completed by checking file existence in the change directory.
7
+ * Returns a Set of completed artifact IDs.
8
+ *
9
+ * @param graph - The artifact graph to check
10
+ * @param changeDir - The change directory to scan for files
11
+ * @returns Set of artifact IDs whose generated files exist
12
+ */
13
+ export function detectCompleted(graph, changeDir) {
14
+ const completed = new Set();
15
+ // Handle missing change directory gracefully
16
+ if (!fs.existsSync(changeDir)) {
17
+ return completed;
18
+ }
19
+ for (const artifact of graph.getAllArtifacts()) {
20
+ if (isArtifactComplete(artifact.generates, changeDir)) {
21
+ completed.add(artifact.id);
22
+ }
23
+ }
24
+ return completed;
25
+ }
26
+ /**
27
+ * Checks if an artifact is complete by checking if its generated file(s) exist.
28
+ * Supports both simple paths and glob patterns.
29
+ */
30
+ function isArtifactComplete(generates, changeDir) {
31
+ return artifactOutputExists(changeDir, generates);
32
+ }
@@ -0,0 +1,33 @@
1
+ export interface ParsedTask {
2
+ done: boolean;
3
+ description: string;
4
+ }
5
+ export declare function parseTaskLines(content: string): ParsedTask[];
6
+ export interface TaskProgress {
7
+ total: number;
8
+ /** Upstream field name, an alias of `done`. */
9
+ completed: number;
10
+ /** Checked tasks. Same count as `completed`. */
11
+ done: number;
12
+ /** Unchecked tasks carrying no disposition. */
13
+ open: number;
14
+ /** Unchecked tasks carrying a `Disposition:` line. */
15
+ dispositioned: number;
16
+ }
17
+ export declare function countTasksFromContent(content: string): TaskProgress;
18
+ /** Resolves the task files selected by the schema's apply tracking rule. */
19
+ export declare function resolveTaskFilesForChange(changeDir: string, projectRoot: string): string[];
20
+ /**
21
+ * Computes a change's task progress by resolving its tracked-tasks artifact and
22
+ * counting checkboxes across every matched file, falling back to a single
23
+ * top-level `tasks.md`.
24
+ */
25
+ export declare function getTaskProgressForChange(changesDir: string, changeName: string, projectRoot: string): Promise<TaskProgress>;
26
+ /**
27
+ * One-line task status. A caller that knows the disposition-aware counts passes them: a
28
+ * change with no open task is complete even while an unchecked, dispositioned task remains,
29
+ * and the dispositioned count is named so the gap between `completed` and `total` is
30
+ * accounted for. A caller passing only the two upstream fields reads every unchecked task
31
+ * as open.
32
+ */
33
+ export declare function formatTaskStatus(progress: Pick<TaskProgress, 'total' | 'completed'> & Partial<Pick<TaskProgress, 'open' | 'dispositioned'>>): string;
@@ -0,0 +1,149 @@
1
+ // Vendored (store-free) from @fission-ai/openspec@1.8.0 src/utils/task-progress.ts.
2
+ // The checkbox parsing (parseTaskLines / countTasksFromContent) and the
3
+ // tracked-tasks resolution (schema apply.tracks -> generates glob ->
4
+ // resolveArtifactOutputs, with a single top-level tasks.md fallback) are
5
+ // faithful. The only changes are import paths (rewritten to this engine
6
+ // directory) and dropping the run-scoped SchemaGlobCache / --archived plumbing,
7
+ // which the list shim does not need. Schema resolution goes through the
8
+ // store-free resolveSchemaForChange (explicit -> metadata -> spec-driven).
9
+ import { promises as fs } from 'node:fs';
10
+ import * as path from 'node:path';
11
+ import { resolveSchema } from './resolver.js';
12
+ import { resolveArtifactOutputs } from './outputs.js';
13
+ import { resolveSchemaForChange } from './change-metadata.js';
14
+ /**
15
+ * A Markdown task line: a `-`/`*` bullet carrying a `[ ]` or `[x]` checkbox.
16
+ * Leading whitespace is allowed so nested sub-tasks count like their parents.
17
+ */
18
+ const TASK_LINE_PATTERN = /^\s*[-*]\s*\[([\sxX])\]\s*(.*)/;
19
+ export function parseTaskLines(content) {
20
+ const tasks = [];
21
+ for (const line of content.split('\n')) {
22
+ const match = line.match(TASK_LINE_PATTERN);
23
+ if (match) {
24
+ tasks.push({ done: match[1].toLowerCase() === 'x', description: match[2].trim() });
25
+ }
26
+ }
27
+ return tasks;
28
+ }
29
+ // ---------------------------------------------------------------------------
30
+ // FreeHarness: disposition-aware counting. Not in upstream.
31
+ //
32
+ // This file keeps its own faithful-to-upstream `parseTaskLines` above (no
33
+ // annotation awareness) so task-numbering-style consumers are unaffected;
34
+ // `countTasksFromContent` needs to tell a plain open task from one resolved
35
+ // elsewhere, so it scans annotation lines locally rather than importing the
36
+ // validation-layer parser (this engine directory does not depend on
37
+ // ../validation).
38
+ // ---------------------------------------------------------------------------
39
+ // The trailing `\s*` absorbs the `\r` of a CRLF file, which `.` never matches; without it no
40
+ // annotation of such a file parses and every disposition in it is dropped.
41
+ const TASK_ANNOTATION_PATTERN = /^\s*(?:Verify|Interfaces|Boundary|Depends|Disposition):\s*(.*)\s*$/;
42
+ const DISPOSITION_LINE_PATTERN = /^\s*Disposition:\s*(\S+)/;
43
+ /** Kinds that resolve a task. Any other kind leaves it open, and validate refuses it. */
44
+ const DISPOSITION_KINDS = new Set(['superseded', 'moved', 'external']);
45
+ /** Parses task lines, marking each unchecked task that carries a `Disposition:` line. */
46
+ function parseTasksWithDisposition(content) {
47
+ const tasks = [];
48
+ let current;
49
+ for (const line of content.split('\n')) {
50
+ const task = line.match(TASK_LINE_PATTERN);
51
+ if (task) {
52
+ current = { done: task[1].toLowerCase() === 'x', description: task[2].trim(), dispositioned: false };
53
+ tasks.push(current);
54
+ continue;
55
+ }
56
+ if (current && TASK_ANNOTATION_PATTERN.test(line)) {
57
+ const disposition = DISPOSITION_LINE_PATTERN.exec(line);
58
+ if (disposition && DISPOSITION_KINDS.has(disposition[1]))
59
+ current.dispositioned = true;
60
+ continue;
61
+ }
62
+ current = undefined;
63
+ }
64
+ return tasks;
65
+ }
66
+ export function countTasksFromContent(content) {
67
+ const tasks = parseTasksWithDisposition(content);
68
+ const done = tasks.filter((task) => task.done).length;
69
+ const dispositioned = tasks.filter((task) => !task.done && task.dispositioned).length;
70
+ const open = tasks.length - done - dispositioned;
71
+ return { total: tasks.length, completed: done, done, open, dispositioned };
72
+ }
73
+ /**
74
+ * Identifies the change's tracked-tasks artifact: the artifact whose `generates`
75
+ * equals the schema's `apply.tracks`, falling back to the artifact with id
76
+ * `tasks` when no `apply` block declares what it tracks.
77
+ */
78
+ function findTrackedTasksArtifact(schema) {
79
+ const tracks = schema.apply?.tracks;
80
+ if (tracks != null) {
81
+ return schema.artifacts.find((a) => a.generates === tracks);
82
+ }
83
+ return schema.artifacts.find((a) => a.id === 'tasks');
84
+ }
85
+ function resolveTrackedTasksGlob(changeDir, projectRoot) {
86
+ try {
87
+ const schemaName = resolveSchemaForChange(changeDir, undefined, projectRoot);
88
+ const schema = resolveSchema(schemaName, projectRoot);
89
+ return findTrackedTasksArtifact(schema)?.generates;
90
+ }
91
+ catch {
92
+ return undefined;
93
+ }
94
+ }
95
+ /** Resolves the task files selected by the schema's apply tracking rule. */
96
+ export function resolveTaskFilesForChange(changeDir, projectRoot) {
97
+ const generates = resolveTrackedTasksGlob(changeDir, projectRoot);
98
+ return generates ? resolveArtifactOutputs(changeDir, generates) : [];
99
+ }
100
+ async function countTaskFile(file) {
101
+ try {
102
+ const content = await fs.readFile(file, 'utf-8');
103
+ return countTasksFromContent(content);
104
+ }
105
+ catch {
106
+ return { total: 0, completed: 0, done: 0, open: 0, dispositioned: 0 };
107
+ }
108
+ }
109
+ /**
110
+ * Computes a change's task progress by resolving its tracked-tasks artifact and
111
+ * counting checkboxes across every matched file, falling back to a single
112
+ * top-level `tasks.md`.
113
+ */
114
+ export async function getTaskProgressForChange(changesDir, changeName, projectRoot) {
115
+ const changeDir = path.join(changesDir, changeName);
116
+ const files = resolveTaskFilesForChange(changeDir, projectRoot);
117
+ const targets = files.length > 0 ? files : [path.join(changeDir, 'tasks.md')];
118
+ let total = 0;
119
+ let completed = 0;
120
+ let done = 0;
121
+ let open = 0;
122
+ let dispositioned = 0;
123
+ for (const file of targets) {
124
+ const progress = await countTaskFile(file);
125
+ total += progress.total;
126
+ completed += progress.completed;
127
+ done += progress.done;
128
+ open += progress.open;
129
+ dispositioned += progress.dispositioned;
130
+ }
131
+ return { total, completed, done, open, dispositioned };
132
+ }
133
+ /**
134
+ * One-line task status. A caller that knows the disposition-aware counts passes them: a
135
+ * change with no open task is complete even while an unchecked, dispositioned task remains,
136
+ * and the dispositioned count is named so the gap between `completed` and `total` is
137
+ * accounted for. A caller passing only the two upstream fields reads every unchecked task
138
+ * as open.
139
+ */
140
+ export function formatTaskStatus(progress) {
141
+ if (progress.total === 0)
142
+ return 'No tasks';
143
+ const open = progress.open ?? progress.total - progress.completed;
144
+ if (open === 0)
145
+ return '✓ Complete';
146
+ const dispositioned = progress.dispositioned ?? 0;
147
+ const aside = dispositioned > 0 ? ` (${dispositioned} dispositioned)` : '';
148
+ return `${progress.completed}/${progress.total} tasks${aside}`;
149
+ }
@@ -0,0 +1,39 @@
1
+ import { z } from 'zod';
2
+ export declare const ArtifactSchema: z.ZodObject<{
3
+ id: z.ZodString;
4
+ generates: z.ZodString;
5
+ description: z.ZodString;
6
+ template: z.ZodString;
7
+ instruction: z.ZodOptional<z.ZodString>;
8
+ requires: z.ZodDefault<z.ZodArray<z.ZodString>>;
9
+ }, z.core.$strip>;
10
+ export declare const ApplyPhaseSchema: z.ZodObject<{
11
+ requires: z.ZodArray<z.ZodString>;
12
+ tracks: z.ZodOptional<z.ZodNullable<z.ZodString>>;
13
+ instruction: z.ZodOptional<z.ZodString>;
14
+ }, z.core.$strip>;
15
+ export declare const SchemaYamlSchema: z.ZodObject<{
16
+ name: z.ZodString;
17
+ version: z.ZodNumber;
18
+ description: z.ZodOptional<z.ZodString>;
19
+ artifacts: z.ZodArray<z.ZodObject<{
20
+ id: z.ZodString;
21
+ generates: z.ZodString;
22
+ description: z.ZodString;
23
+ template: z.ZodString;
24
+ instruction: z.ZodOptional<z.ZodString>;
25
+ requires: z.ZodDefault<z.ZodArray<z.ZodString>>;
26
+ }, z.core.$strip>>;
27
+ apply: z.ZodOptional<z.ZodObject<{
28
+ requires: z.ZodArray<z.ZodString>;
29
+ tracks: z.ZodOptional<z.ZodNullable<z.ZodString>>;
30
+ instruction: z.ZodOptional<z.ZodString>;
31
+ }, z.core.$strip>>;
32
+ }, z.core.$strip>;
33
+ export type Artifact = z.infer<typeof ArtifactSchema>;
34
+ export type ApplyPhase = z.infer<typeof ApplyPhaseSchema>;
35
+ export type SchemaYaml = z.infer<typeof SchemaYamlSchema>;
36
+ export type CompletedSet = Set<string>;
37
+ export interface BlockedArtifacts {
38
+ [artifactId: string]: string[];
39
+ }
@@ -0,0 +1,49 @@
1
+ // Vendored faithfully from @fission-ai/openspec@1.8.0
2
+ // src/core/artifact-graph/types.ts
3
+ // No behavioural changes. Part of the schema-validation slice.
4
+ import * as path from 'node:path';
5
+ import { z } from 'zod';
6
+ function relativePathSchema(fieldName) {
7
+ return z
8
+ .string()
9
+ .min(1, { error: `${fieldName} is required` })
10
+ .superRefine((value, ctx) => {
11
+ const segments = value.split(/[\\/]+/u);
12
+ const isDrivePath = /^[A-Za-z]:/u.test(value);
13
+ const isAbsolute = path.posix.isAbsolute(value) || path.win32.isAbsolute(value) || isDrivePath;
14
+ const escapes = segments.includes('..');
15
+ if (isAbsolute || escapes || value.includes('\0')) {
16
+ ctx.addIssue({
17
+ code: 'custom',
18
+ message: `${fieldName} must be a relative path inside its allowed directory`,
19
+ });
20
+ }
21
+ });
22
+ }
23
+ // Artifact definition schema
24
+ export const ArtifactSchema = z.object({
25
+ id: z.string().min(1, { error: 'Artifact ID is required' }),
26
+ generates: relativePathSchema('generates field'),
27
+ description: z.string(),
28
+ template: relativePathSchema('template field'),
29
+ instruction: z.string().optional(),
30
+ requires: z.array(z.string()).default([]),
31
+ });
32
+ // Apply phase configuration for schema-aware apply instructions
33
+ export const ApplyPhaseSchema = z.object({
34
+ // Artifact IDs that must exist before apply is available
35
+ requires: z.array(z.string()).min(1, { error: 'At least one required artifact' }),
36
+ // Path to file with checkboxes for progress (relative to change dir), or null if no tracking
37
+ tracks: relativePathSchema('apply.tracks').nullable().optional(),
38
+ // Custom guidance for the apply phase
39
+ instruction: z.string().optional(),
40
+ });
41
+ // Full schema YAML structure
42
+ export const SchemaYamlSchema = z.object({
43
+ name: z.string().min(1, { error: 'Schema name is required' }),
44
+ version: z.number().int().positive({ error: 'Version must be a positive integer' }),
45
+ description: z.string().optional(),
46
+ artifacts: z.array(ArtifactSchema).min(1, { error: 'At least one artifact required' }),
47
+ // Optional apply phase configuration (for schema-aware apply instructions)
48
+ apply: ApplyPhaseSchema.optional(),
49
+ });
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Claude Code Command Adapter
3
+ *
4
+ * Formats commands for Claude Code following its frontmatter specification.
5
+ */
6
+ import type { ToolCommandAdapter } from '../types.js';
7
+ /**
8
+ * Claude Code adapter for command generation.
9
+ * File path: .claude/commands/opsx/<id>.md
10
+ * Frontmatter: name, description, allowed-tools, category, tags
11
+ */
12
+ export declare const claudeAdapter: ToolCommandAdapter;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Claude Code Command Adapter
3
+ *
4
+ * Formats commands for Claude Code following its frontmatter specification.
5
+ */
6
+ import path from 'path';
7
+ import { escapeYamlValue, formatTagsArray } from '../yaml.js';
8
+ import { OPENSPEC_CLI_ALLOWED_TOOLS } from '../../shared/allowed-tools.js';
9
+ /**
10
+ * Claude Code adapter for command generation.
11
+ * File path: .claude/commands/opsx/<id>.md
12
+ * Frontmatter: name, description, allowed-tools, category, tags
13
+ */
14
+ export const claudeAdapter = {
15
+ toolId: 'claude',
16
+ getFilePath(commandId) {
17
+ return path.join('.claude', 'commands', 'opsx', `${commandId}.md`);
18
+ },
19
+ formatFile(content) {
20
+ return `---
21
+ name: ${escapeYamlValue(content.name)}
22
+ description: ${escapeYamlValue(content.description)}
23
+ allowed-tools: ${OPENSPEC_CLI_ALLOWED_TOOLS}
24
+ category: ${escapeYamlValue(content.category)}
25
+ tags: ${formatTagsArray(content.tags)}
26
+ ---
27
+
28
+ ${content.body}
29
+ `;
30
+ },
31
+ };
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Command Adapters Index
3
+ *
4
+ * Re-exports the tool command adapters.
5
+ *
6
+ * FreeHarness trim: reduced from the upstream 29-adapter re-export to the two
7
+ * harnesses FreeHarness targets (Claude Code + OpenCode).
8
+ */
9
+ export { claudeAdapter } from './claude.js';
10
+ export { opencodeAdapter } from './opencode.js';
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Command Adapters Index
3
+ *
4
+ * Re-exports the tool command adapters.
5
+ *
6
+ * FreeHarness trim: reduced from the upstream 29-adapter re-export to the two
7
+ * harnesses FreeHarness targets (Claude Code + OpenCode).
8
+ */
9
+ export { claudeAdapter } from './claude.js';
10
+ export { opencodeAdapter } from './opencode.js';
@@ -0,0 +1,12 @@
1
+ /**
2
+ * OpenCode Command Adapter
3
+ *
4
+ * Formats commands for OpenCode following its frontmatter specification.
5
+ */
6
+ import type { ToolCommandAdapter } from '../types.js';
7
+ /**
8
+ * OpenCode adapter for command generation.
9
+ * File path: .opencode/commands/opsx-<id>.md
10
+ * Frontmatter: description
11
+ */
12
+ export declare const opencodeAdapter: ToolCommandAdapter;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * OpenCode Command Adapter
3
+ *
4
+ * Formats commands for OpenCode following its frontmatter specification.
5
+ */
6
+ import path from 'path';
7
+ import { escapeYamlValue } from '../yaml.js';
8
+ /**
9
+ * OpenCode adapter for command generation.
10
+ * File path: .opencode/commands/opsx-<id>.md
11
+ * Frontmatter: description
12
+ */
13
+ export const opencodeAdapter = {
14
+ toolId: 'opencode',
15
+ getFilePath(commandId) {
16
+ return path.join('.opencode', 'commands', `opsx-${commandId}.md`);
17
+ },
18
+ formatFile(content) {
19
+ return `---
20
+ description: ${escapeYamlValue(content.description)}
21
+ ---
22
+
23
+ ${content.body}
24
+ `;
25
+ },
26
+ };
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Command Generator
3
+ *
4
+ * Functions for generating command files using tool adapters.
5
+ */
6
+ import type { CommandContent, ToolCommandAdapter, GeneratedCommand } from './types.js';
7
+ /**
8
+ * Generate a single command file using the provided adapter.
9
+ *
10
+ * Command bodies are authored with `/opsx:<id>` references. Tools whose command
11
+ * files are invoked by filename register `/opsx-<id>` instead, and Amazon Q
12
+ * surfaces them in its prompt library as `@opsx-<id>`, so the body is rewritten
13
+ * to the form that tool answers to before the adapter formats it. Doing it here
14
+ * rather than per adapter keeps every tool in step (#727, #1307); adapters stay
15
+ * pure formatters.
16
+ *
17
+ * @param content - The tool-agnostic command content
18
+ * @param adapter - The tool-specific adapter
19
+ * @returns Generated command with path and file content
20
+ */
21
+ export declare function generateCommand(content: CommandContent, adapter: ToolCommandAdapter): GeneratedCommand;
22
+ /**
23
+ * Generate multiple command files using the provided adapter.
24
+ * @param contents - Array of tool-agnostic command contents
25
+ * @param adapter - The tool-specific adapter
26
+ * @returns Array of generated commands with paths and file contents
27
+ */
28
+ export declare function generateCommands(contents: CommandContent[], adapter: ToolCommandAdapter): GeneratedCommand[];
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Command Generator
3
+ *
4
+ * Functions for generating command files using tool adapters.
5
+ */
6
+ import { getInvocationForAdapter, needsInvocationRewrite } from './invocation.js';
7
+ // FreeHarness: command-references vendored alongside generation/ (was ../../utils).
8
+ import { transformCommandInvocations } from '../command-references.js';
9
+ /**
10
+ * Generate a single command file using the provided adapter.
11
+ *
12
+ * Command bodies are authored with `/opsx:<id>` references. Tools whose command
13
+ * files are invoked by filename register `/opsx-<id>` instead, and Amazon Q
14
+ * surfaces them in its prompt library as `@opsx-<id>`, so the body is rewritten
15
+ * to the form that tool answers to before the adapter formats it. Doing it here
16
+ * rather than per adapter keeps every tool in step (#727, #1307); adapters stay
17
+ * pure formatters.
18
+ *
19
+ * @param content - The tool-agnostic command content
20
+ * @param adapter - The tool-specific adapter
21
+ * @returns Generated command with path and file content
22
+ */
23
+ export function generateCommand(content, adapter) {
24
+ const invocation = getInvocationForAdapter(adapter);
25
+ const formatted = needsInvocationRewrite(invocation)
26
+ ? { ...content, body: transformCommandInvocations(content.body, invocation) }
27
+ : content;
28
+ return {
29
+ path: adapter.getFilePath(content.id),
30
+ fileContent: adapter.formatFile(formatted),
31
+ };
32
+ }
33
+ /**
34
+ * Generate multiple command files using the provided adapter.
35
+ * @param contents - Array of tool-agnostic command contents
36
+ * @param adapter - The tool-specific adapter
37
+ * @returns Array of generated commands with paths and file contents
38
+ */
39
+ export function generateCommands(contents, adapter) {
40
+ return contents.map((content) => generateCommand(content, adapter));
41
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Command Generation Module
3
+ *
4
+ * Generic command generation system with tool-specific adapters.
5
+ *
6
+ * FreeHarness trim: adapter re-export reduced to claude + opencode.
7
+ *
8
+ * Usage:
9
+ * ```typescript
10
+ * import { generateCommands, CommandAdapterRegistry, type CommandContent } from './command-generation/index.js';
11
+ *
12
+ * const contents: CommandContent[] = [...];
13
+ * const adapter = CommandAdapterRegistry.get('claude');
14
+ * if (adapter) {
15
+ * const commands = generateCommands(contents, adapter);
16
+ * // Write commands to disk
17
+ * }
18
+ * ```
19
+ */
20
+ export type { CommandContent, ToolCommandAdapter, GeneratedCommand, } from './types.js';
21
+ export { CommandAdapterRegistry } from './registry.js';
22
+ export { generateCommand, generateCommands } from './generator.js';
23
+ export { claudeAdapter, opencodeAdapter } from './adapters/index.js';
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Command Generation Module
3
+ *
4
+ * Generic command generation system with tool-specific adapters.
5
+ *
6
+ * FreeHarness trim: adapter re-export reduced to claude + opencode.
7
+ *
8
+ * Usage:
9
+ * ```typescript
10
+ * import { generateCommands, CommandAdapterRegistry, type CommandContent } from './command-generation/index.js';
11
+ *
12
+ * const contents: CommandContent[] = [...];
13
+ * const adapter = CommandAdapterRegistry.get('claude');
14
+ * if (adapter) {
15
+ * const commands = generateCommands(contents, adapter);
16
+ * // Write commands to disk
17
+ * }
18
+ * ```
19
+ */
20
+ // Registry
21
+ export { CommandAdapterRegistry } from './registry.js';
22
+ // Generator functions
23
+ export { generateCommand, generateCommands } from './generator.js';
24
+ // Adapters (for direct access if needed)
25
+ export { claudeAdapter, opencodeAdapter } from './adapters/index.js';