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,460 @@
1
+ // `openspec instructions <artifact> --change <id> [--json]` over the vendored
2
+ // engine, plus the two special targets the /opsx skills use: `apply` and
3
+ // `archive`.
4
+ //
5
+ // Reconstructed from src/commands/workflow/instructions.ts, minus store /
6
+ // root-selection, the referenced-store index, and project-config-driven
7
+ // context/rules/operation-inputs. Artifact instructions are faithful; `apply`
8
+ // reimplements the schema-aware apply state machine (blocked / all_done / ready)
9
+ // against the change's tracked-tasks file; `archive` returns the archive-inputs brief:
10
+ // the project context and the operation guidance from `openspec/config.yaml`
11
+ // (`operations.archive.guidance`, the upstream shape) merged with the schema's own
12
+ // `archive.guidance` list (the FreeHarness spec-driven override carries the compound step).
13
+ import * as fs from 'node:fs';
14
+ import * as path from 'node:path';
15
+ import { parse as parseYaml } from 'yaml';
16
+ import { loadChangeContext, generateInstructions, resolveSchema, resolveSchemaForChange, getSchemaDir, resolveArtifactOutputPath, resolveArtifactOutputs, parseTaskLines, METADATA_FILENAME, } from '../../vendor/openspec/engine/index.js';
17
+ import { planningHomeStub, printJson, validateChangeExists, validateSchemaExists } from './shared.js';
18
+ const SPECIAL_TARGETS = new Set(['apply', 'archive']);
19
+ export function instructionsHandler(projectRoot, artifactId, options) {
20
+ const changeName = validateChangeExists(options.change, projectRoot);
21
+ if (options.schema) {
22
+ validateSchemaExists(options.schema, projectRoot);
23
+ }
24
+ if (artifactId === 'apply') {
25
+ return applyInstructions(projectRoot, changeName, options);
26
+ }
27
+ if (artifactId === 'archive') {
28
+ return archiveInstructions(projectRoot, changeName, options);
29
+ }
30
+ const context = loadChangeContext(projectRoot, changeName, options.schema);
31
+ if (!artifactId) {
32
+ const validIds = context.graph.getAllArtifacts().map((a) => a.id);
33
+ throw new Error(`Missing required argument <artifact>. Valid artifacts:\n ${validIds.join('\n ')}\n apply\n archive`);
34
+ }
35
+ const artifact = context.graph.getArtifact(artifactId);
36
+ if (!artifact) {
37
+ const validIds = context.graph.getAllArtifacts().map((a) => a.id);
38
+ throw new Error(`Artifact '${artifactId}' not found in schema '${context.schemaName}'. Valid artifacts:\n ${validIds.join('\n ')}`);
39
+ }
40
+ const instructions = generateInstructions(context, artifactId);
41
+ const isBlocked = instructions.dependencies.some((d) => !d.done);
42
+ if (options.json) {
43
+ printJson({ ...instructions, planningHome: planningHomeStub(projectRoot) });
44
+ return 0;
45
+ }
46
+ printInstructionsText(instructions, isBlocked);
47
+ return 0;
48
+ }
49
+ export function printInstructionsText(instructions, isBlocked) {
50
+ const { artifactId, changeName, schemaName, changeDir, resolvedOutputPath, description, instruction, template, dependencies, unlocks, } = instructions;
51
+ console.log(`<artifact id="${artifactId}" change="${changeName}" schema="${schemaName}">`);
52
+ console.log();
53
+ if (instructions.skipped) {
54
+ console.log('<warning>');
55
+ console.log(instructions.warning ?? 'This artifact is skipped (skip_specs is set in .openspec.yaml).');
56
+ console.log('</warning>');
57
+ console.log();
58
+ console.log('</artifact>');
59
+ return;
60
+ }
61
+ if (isBlocked) {
62
+ const missing = dependencies.filter((d) => !d.done).map((d) => d.id);
63
+ console.log('<warning>');
64
+ console.log('This artifact has unmet dependencies. Complete them first or proceed with caution.');
65
+ console.log(`Missing: ${missing.join(', ')}`);
66
+ console.log('</warning>');
67
+ console.log();
68
+ }
69
+ console.log('<task>');
70
+ console.log(`Create the ${artifactId} artifact for change "${changeName}".`);
71
+ console.log(description);
72
+ console.log('</task>');
73
+ console.log();
74
+ if (dependencies.length > 0) {
75
+ console.log('<dependencies>');
76
+ console.log('Read the current contents of these files before creating this artifact (re-read them from disk even if you saw them earlier - they may have been edited):');
77
+ console.log();
78
+ for (const dep of dependencies) {
79
+ if (dep.skipped) {
80
+ console.log(`<dependency id="${dep.id}" status="skipped">`);
81
+ console.log(' <description>Skipped: the change declares skip_specs, so this artifact has no files to read.</description>');
82
+ console.log('</dependency>');
83
+ continue;
84
+ }
85
+ const status = dep.done ? 'done' : 'missing';
86
+ const fullPath = path.join(changeDir, dep.path);
87
+ console.log(`<dependency id="${dep.id}" status="${status}">`);
88
+ console.log(` <path>${fullPath}</path>`);
89
+ console.log(` <description>${dep.description}</description>`);
90
+ console.log('</dependency>');
91
+ }
92
+ console.log('</dependencies>');
93
+ console.log();
94
+ }
95
+ console.log('<output>');
96
+ console.log(`Write to: ${resolvedOutputPath}`);
97
+ console.log('</output>');
98
+ console.log();
99
+ if (instruction) {
100
+ console.log('<instruction>');
101
+ console.log(instruction.trim());
102
+ console.log('</instruction>');
103
+ console.log();
104
+ }
105
+ console.log('<template>');
106
+ console.log('<!-- Use this as the structure for your output file. Fill in the sections. -->');
107
+ console.log(template.trim());
108
+ console.log('</template>');
109
+ console.log();
110
+ if (unlocks.length > 0) {
111
+ console.log('<unlocks>');
112
+ console.log(`Completing this artifact enables: ${unlocks.join(', ')}`);
113
+ console.log('</unlocks>');
114
+ console.log();
115
+ }
116
+ console.log('</artifact>');
117
+ }
118
+ function toTaskItems(parsed) {
119
+ const tasks = [];
120
+ for (const task of parsed) {
121
+ if (task.description.length === 0)
122
+ continue;
123
+ tasks.push({ id: `${tasks.length + 1}`, description: task.description, done: task.done });
124
+ }
125
+ return tasks;
126
+ }
127
+ const SPECS_PATH_PREFIX = 'specs/';
128
+ /** Whether an artifact's `generates` path lands inside the specs/ tree. */
129
+ function isSpecsArtifactPath(generates) {
130
+ return generates.replace(/^(?:\.\/)+/, '').startsWith(SPECS_PATH_PREFIX);
131
+ }
132
+ /**
133
+ * Every artifact still to build before apply's own gate is satisfied, in the
134
+ * schema's declared build order - the transitive closure of `apply.requires`.
135
+ *
136
+ * Apply blocks on the first artifact in `requiredArtifactIds` that is not yet
137
+ * complete, so naming only that one hides the rest of the chain: a change
138
+ * holding only a proposal, whose schema chains specs -> design -> tasks,
139
+ * would be told only "Missing artifacts: tasks" - an instruction that, taken
140
+ * literally, skips every artifact tasks itself depends on.
141
+ */
142
+ /**
143
+ * Every artifact still to build (`missing`), plus a warning for any id in the
144
+ * `requires` chain that names no artifact in the schema. An unknown id used to
145
+ * be dropped by the `if (!artifact) continue` below with no trace anywhere in
146
+ * the instructions payload - a typo in a schema's `requires` list read as an
147
+ * empty, satisfied dependency instead of the configuration error it is.
148
+ */
149
+ function collectMissingPrerequisites(requiredArtifactIds, schema, buildOrder, completed) {
150
+ const byId = new Map(schema.artifacts.map((artifact) => [artifact.id, artifact]));
151
+ const missing = new Set();
152
+ const unknownIds = [];
153
+ const queue = [...requiredArtifactIds];
154
+ const seen = new Set(queue);
155
+ while (queue.length > 0) {
156
+ const id = queue.shift();
157
+ const artifact = byId.get(id);
158
+ if (!artifact) {
159
+ unknownIds.push(id);
160
+ continue;
161
+ }
162
+ if (!completed.has(id))
163
+ missing.add(id);
164
+ for (const dependency of artifact.requires) {
165
+ if (seen.has(dependency))
166
+ continue;
167
+ seen.add(dependency);
168
+ queue.push(dependency);
169
+ }
170
+ }
171
+ const order = new Map(buildOrder.map((id, index) => [id, index]));
172
+ // An id absent from `order` (the build order the schema graph produced) is
173
+ // itself a schema defect, not a "comes first" signal - sorting it to the
174
+ // front (the old `?? 0`) silently promoted a broken reference ahead of every
175
+ // real artifact. Pushing it to the end keeps real artifacts in their proper
176
+ // order and leaves the broken one visibly last.
177
+ const missingSorted = [...missing].sort((a, b) => (order.get(a) ?? Number.MAX_SAFE_INTEGER) - (order.get(b) ?? Number.MAX_SAFE_INTEGER));
178
+ const warnings = unknownIds.length > 0
179
+ ? [`Schema declares a dependency on an artifact id not defined in this schema: ${unknownIds.join(', ')}.`]
180
+ : [];
181
+ return { missing: missingSorted, warnings };
182
+ }
183
+ /**
184
+ * Non-blocking problems with an otherwise-ready-or-complete change.
185
+ *
186
+ * Apply gates on the schema's `apply.requires` alone, so a change whose tasks
187
+ * file was written ahead of its specs reads as ready even though it has no
188
+ * delta spec at all - the exact state `openspec validate` rejects. Naming the
189
+ * gap here, instead of blocking on it, is what keeps apply from being the one
190
+ * surface that green-lights implementation ahead of every other check.
191
+ *
192
+ * Fires only once apply's own gate is satisfied: for a change still missing a
193
+ * required artifact, the absent specs are the next step, not a warning. A
194
+ * schema with no spec-producing artifact, or a change carrying `skip_specs`,
195
+ * never triggers it.
196
+ */
197
+ function collectApplyWarnings(state, schema, changeDir, changeName, skippedArtifacts) {
198
+ if (state === 'blocked')
199
+ return [];
200
+ const specArtifacts = schema.artifacts.filter((artifact) => isSpecsArtifactPath(artifact.generates));
201
+ if (specArtifacts.length === 0)
202
+ return [];
203
+ if (specArtifacts.some((artifact) => skippedArtifacts?.has(artifact.id)))
204
+ return [];
205
+ const hasDeltas = specArtifacts.some((artifact) => resolveArtifactOutputs(changeDir, artifact.generates).length > 0);
206
+ if (hasDeltas)
207
+ return [];
208
+ const metadataPath = path.join(changeDir, METADATA_FILENAME);
209
+ // Names the artifact this schema actually declares rather than the literal
210
+ // "specs": a schema whose spec-producing artifact is, say, "contracts" would
211
+ // otherwise be told to run a command naming an artifact it does not have.
212
+ // With more than one such artifact there is no single right answer, so the
213
+ // id becomes a placeholder instead of a guess.
214
+ const specTarget = specArtifacts.length === 1 ? specArtifacts[0].id : '<artifact-id>';
215
+ return [
216
+ `This change has no delta specs and does not declare \`skip_specs: true\`, so \`openspec validate ${changeName}\` fails on it. ` +
217
+ `Write the delta specs before implementing (\`openspec instructions ${specTarget} --change ${changeName}\`), ` +
218
+ `or add \`skip_specs: true\` to ${metadataPath} if this change really changes no specified behavior.`,
219
+ ];
220
+ }
221
+ function buildApplyInstructions(projectRoot, changeName, schemaName) {
222
+ const context = loadChangeContext(projectRoot, changeName, schemaName);
223
+ const changeDir = context.changeDir;
224
+ const schema = resolveSchema(context.schemaName, projectRoot);
225
+ const applyConfig = schema.apply;
226
+ const requiredArtifactIds = applyConfig?.requires ?? schema.artifacts.map((a) => a.id);
227
+ const tracksFile = applyConfig?.tracks ?? null;
228
+ const schemaInstruction = applyConfig?.instruction ?? null;
229
+ const missingArtifacts = [];
230
+ for (const artifactId of requiredArtifactIds) {
231
+ if (context.skippedArtifacts?.has(artifactId))
232
+ continue;
233
+ const artifact = schema.artifacts.find((a) => a.id === artifactId);
234
+ if (artifact && resolveArtifactOutputs(changeDir, artifact.generates).length === 0) {
235
+ missingArtifacts.push(artifactId);
236
+ }
237
+ }
238
+ const contextFiles = {};
239
+ for (const artifact of schema.artifacts) {
240
+ const outputs = resolveArtifactOutputs(changeDir, artifact.generates);
241
+ if (outputs.length > 0)
242
+ contextFiles[artifact.id] = outputs;
243
+ }
244
+ let parsedTasks = [];
245
+ let tracksFileExists = false;
246
+ if (tracksFile) {
247
+ const tracksPath = resolveArtifactOutputPath(changeDir, tracksFile);
248
+ tracksFileExists = fs.existsSync(tracksPath);
249
+ if (tracksFileExists) {
250
+ parsedTasks = parseTaskLines(fs.readFileSync(tracksPath, 'utf-8'));
251
+ }
252
+ }
253
+ const tasks = toTaskItems(parsedTasks);
254
+ const total = parsedTasks.length;
255
+ const complete = parsedTasks.filter((t) => t.done).length;
256
+ const remaining = total - complete;
257
+ let state;
258
+ let instruction;
259
+ if (missingArtifacts.length > 0) {
260
+ state = 'blocked';
261
+ instruction = `Cannot apply this change yet. Missing artifacts: ${missingArtifacts.join(', ')}.\nUse the openspec-continue-change skill to create the missing artifacts first.`;
262
+ }
263
+ else if (tracksFile && !tracksFileExists) {
264
+ state = 'blocked';
265
+ instruction = `The ${path.basename(tracksFile)} file is missing and must be created.\nUse openspec-continue-change to generate the tracking file.`;
266
+ }
267
+ else if (tracksFile && tracksFileExists && tasks.length === 0) {
268
+ state = 'blocked';
269
+ instruction = `The ${path.basename(tracksFile)} file exists but contains no tasks to work on.\nAdd tasks or regenerate it with openspec-continue-change.`;
270
+ }
271
+ else if (tracksFile && remaining === 0 && total > 0) {
272
+ state = 'all_done';
273
+ instruction = 'All tasks are complete! This change is ready to be archived.';
274
+ }
275
+ else if (!tracksFile) {
276
+ state = 'ready';
277
+ instruction = schemaInstruction?.trim() ?? 'All required artifacts complete. Proceed with implementation.';
278
+ }
279
+ else {
280
+ state = 'ready';
281
+ instruction =
282
+ schemaInstruction?.trim() ??
283
+ 'Read context files, work through pending tasks, mark complete as you go.\nPause if you hit blockers or need clarification.';
284
+ }
285
+ // Computed regardless of state: a "ready" change (apply.requires satisfied)
286
+ // can still be missing the artifacts its own required artifact transitively
287
+ // depends on - the schema's own gate does not require them, so this is the
288
+ // only place that names the rest of the chain.
289
+ const { missing: missingPrerequisites, warnings: unknownIdWarnings } = collectMissingPrerequisites(requiredArtifactIds, schema, context.graph.getBuildOrder(), context.completed);
290
+ const warnings = [
291
+ ...unknownIdWarnings,
292
+ ...collectApplyWarnings(state, schema, changeDir, changeName, context.skippedArtifacts),
293
+ ];
294
+ return {
295
+ changeName,
296
+ changeDir,
297
+ schemaName: context.schemaName,
298
+ contextFiles,
299
+ progress: { total, complete, remaining },
300
+ tasks,
301
+ state,
302
+ ...(missingArtifacts.length > 0 ? { missingArtifacts } : {}),
303
+ ...(missingPrerequisites.length > 0 ? { missingPrerequisites } : {}),
304
+ ...(warnings.length > 0 ? { warnings } : {}),
305
+ instruction,
306
+ };
307
+ }
308
+ /**
309
+ * Whether the "Not created yet, in build order" line would repeat information
310
+ * the "Missing artifacts" line already gave in full.
311
+ *
312
+ * Compared as sets, not lengths: two equal-length lists naming different ids
313
+ * (e.g. a schema whose transitive chain swaps one artifact for another at the
314
+ * same depth) are NOT the same information, and a length-only compare (the
315
+ * prior `missingPrerequisites.length <= missingArtifacts.length`) would
316
+ * silently drop the second list even though it names something new.
317
+ * Exported for direct unit coverage of the comparison rule.
318
+ */
319
+ export function isChainAlreadyNamed(state, missingArtifacts, missingPrerequisites) {
320
+ if (state !== 'blocked' || missingArtifacts === undefined)
321
+ return false;
322
+ const missingArtifactsSet = new Set(missingArtifacts);
323
+ return (missingPrerequisites ?? []).every((id) => missingArtifactsSet.has(id));
324
+ }
325
+ function applyInstructions(projectRoot, changeName, options) {
326
+ const instructions = buildApplyInstructions(projectRoot, changeName, options.schema);
327
+ if (options.json) {
328
+ printJson({ ...instructions, planningHome: planningHomeStub(projectRoot) });
329
+ return 0;
330
+ }
331
+ console.log(`## Apply: ${instructions.changeName}`);
332
+ console.log(`Schema: ${instructions.schemaName}`);
333
+ console.log();
334
+ if (instructions.state === 'blocked' && instructions.missingArtifacts) {
335
+ console.log('### Blocked');
336
+ console.log(`Missing artifacts: ${instructions.missingArtifacts.join(', ')}`);
337
+ console.log();
338
+ }
339
+ // Named once: when blocked and the chain says nothing past `missingArtifacts`,
340
+ // the line above already names it in full.
341
+ const chainAlreadyNamed = isChainAlreadyNamed(instructions.state, instructions.missingArtifacts, instructions.missingPrerequisites);
342
+ if (instructions.missingPrerequisites && instructions.missingPrerequisites.length > 0 && !chainAlreadyNamed) {
343
+ console.log(`Not created yet, in build order: ${instructions.missingPrerequisites.join(', ')}`);
344
+ console.log();
345
+ }
346
+ if (instructions.warnings && instructions.warnings.length > 0) {
347
+ console.log('### Warnings');
348
+ for (const warning of instructions.warnings) {
349
+ console.log(`- ${warning}`);
350
+ }
351
+ console.log();
352
+ }
353
+ const contextEntries = Object.entries(instructions.contextFiles);
354
+ if (contextEntries.length > 0) {
355
+ console.log('### Context Files');
356
+ for (const [id, files] of contextEntries) {
357
+ for (const file of files)
358
+ console.log(`- ${id}: ${file}`);
359
+ }
360
+ console.log();
361
+ }
362
+ if (instructions.progress.total > 0 || instructions.tasks.length > 0) {
363
+ console.log('### Progress');
364
+ console.log(`${instructions.progress.complete}/${instructions.progress.total} complete`);
365
+ console.log();
366
+ }
367
+ if (instructions.tasks.length > 0) {
368
+ console.log('### Tasks');
369
+ for (const task of instructions.tasks) {
370
+ console.log(`- ${task.done ? '[x]' : '[ ]'} ${task.description}`);
371
+ }
372
+ console.log();
373
+ }
374
+ console.log('### Instruction');
375
+ console.log(instructions.instruction);
376
+ return 0;
377
+ }
378
+ /**
379
+ * Reads a string list at `keys` inside a parsed YAML document; non-lists yield [].
380
+ * @param doc Parsed document.
381
+ * @param keys Path of keys.
382
+ * @returns The strings found.
383
+ */
384
+ function stringList(doc, keys) {
385
+ let cur = doc;
386
+ for (const k of keys) {
387
+ if (!cur || typeof cur !== 'object' || Array.isArray(cur))
388
+ return [];
389
+ cur = cur[k];
390
+ }
391
+ return Array.isArray(cur) ? cur.filter((x) => typeof x === 'string' && x.trim().length > 0) : [];
392
+ }
393
+ /**
394
+ * Parses a YAML file when present; a missing or malformed file yields undefined.
395
+ * @param file Path.
396
+ * @returns Parsed document.
397
+ */
398
+ function readYamlIfPresent(file) {
399
+ if (!fs.existsSync(file))
400
+ return undefined;
401
+ try {
402
+ return parseYaml(fs.readFileSync(file, 'utf8'));
403
+ }
404
+ catch {
405
+ return undefined;
406
+ }
407
+ }
408
+ /**
409
+ * Builds the archive inputs: project context (`openspec/config.yaml` `context`), the
410
+ * project's `operations.archive.guidance`, then the schema's `archive.guidance`.
411
+ * @param projectRoot Project root.
412
+ * @param changeName Change id.
413
+ * @param explicitSchema `--schema` override.
414
+ * @returns The brief the archive skill prints.
415
+ */
416
+ export function buildArchiveInstructions(projectRoot, changeName, explicitSchema) {
417
+ const config = readYamlIfPresent(path.join(projectRoot, 'openspec', 'config.yaml'));
418
+ const contextRaw = config && typeof config === 'object' ? config.context : undefined;
419
+ const context = typeof contextRaw === 'string' && contextRaw.trim().length > 0 ? contextRaw : undefined;
420
+ const guidance = stringList(config, ['operations', 'archive', 'guidance']);
421
+ const changeDir = path.join(projectRoot, 'openspec', 'changes', changeName);
422
+ const schemaName = resolveSchemaForChange(changeDir, explicitSchema, projectRoot);
423
+ const schemaDir = getSchemaDir(schemaName, projectRoot);
424
+ if (schemaDir) {
425
+ for (const g of stringList(readYamlIfPresent(path.join(schemaDir, 'schema.yaml')), ['archive', 'guidance'])) {
426
+ if (!guidance.includes(g))
427
+ guidance.push(g);
428
+ }
429
+ }
430
+ return {
431
+ changeName,
432
+ ...(context !== undefined ? { context } : {}),
433
+ ...(guidance.length > 0 ? { operationGuidance: guidance } : {}),
434
+ };
435
+ }
436
+ function archiveInstructions(projectRoot, changeName, options) {
437
+ const payload = buildArchiveInstructions(projectRoot, changeName, options.schema);
438
+ if (options.json) {
439
+ printJson({ ...payload, planningHome: planningHomeStub(projectRoot) });
440
+ return 0;
441
+ }
442
+ console.log(`## Archive Inputs: ${changeName}`);
443
+ console.log();
444
+ if (payload.context) {
445
+ console.log('### Project Context (required instruction input)');
446
+ console.log(payload.context);
447
+ console.log();
448
+ }
449
+ if (payload.operationGuidance) {
450
+ console.log('### Operation Guidance (advisory)');
451
+ for (const g of payload.operationGuidance)
452
+ console.log(`- ${g}`);
453
+ console.log();
454
+ }
455
+ if (!payload.context && !payload.operationGuidance) {
456
+ console.log('No project context or operation guidance configured.');
457
+ }
458
+ return 0;
459
+ }
460
+ export { SPECIAL_TARGETS };
@@ -0,0 +1,5 @@
1
+ export interface ListOptions {
2
+ json?: boolean;
3
+ sort?: 'recent' | 'name';
4
+ }
5
+ export declare function listHandler(projectRoot: string, options: ListOptions): Promise<number>;
@@ -0,0 +1,95 @@
1
+ // `openspec list [--json]` over the vendored engine.
2
+ //
3
+ // Reconstructed from src/core/list.ts (changes mode), minus store/root-selection.
4
+ // JSON shape matches upstream: { changes: [{ name, completedTasks, totalTasks,
5
+ // lastModified, status }] }, sorted most-recently-modified first by default.
6
+ import * as fs from 'node:fs';
7
+ import * as path from 'node:path';
8
+ import { getTaskProgressForChange, formatTaskStatus } from '../../vendor/openspec/engine/index.js';
9
+ import { changesDirFor, printableId, printJson } from './shared.js';
10
+ /** Most recent mtime of any file under a directory (recursive). */
11
+ function getLastModified(dirPath) {
12
+ let latest = null;
13
+ const walk = (dir) => {
14
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
15
+ const full = path.join(dir, entry.name);
16
+ if (entry.isDirectory()) {
17
+ walk(full);
18
+ }
19
+ else {
20
+ const stat = fs.statSync(full);
21
+ if (latest === null || stat.mtime > latest)
22
+ latest = stat.mtime;
23
+ }
24
+ }
25
+ };
26
+ walk(dirPath);
27
+ return latest ?? fs.statSync(dirPath).mtime;
28
+ }
29
+ export async function listHandler(projectRoot, options) {
30
+ const { json = false, sort = 'recent' } = options;
31
+ const changesDir = changesDirFor(projectRoot);
32
+ let entries;
33
+ try {
34
+ entries = fs.readdirSync(changesDir, { withFileTypes: true });
35
+ }
36
+ catch (error) {
37
+ if (error.code === 'ENOENT')
38
+ entries = [];
39
+ else
40
+ throw error;
41
+ }
42
+ const changeDirs = entries
43
+ .filter((e) => e.isDirectory() && e.name !== 'archive' && !e.name.startsWith('.'))
44
+ .map((e) => e.name);
45
+ if (changeDirs.length === 0) {
46
+ if (json)
47
+ printJson({ changes: [] });
48
+ else
49
+ console.log('No active changes found.');
50
+ return 0;
51
+ }
52
+ const changes = [];
53
+ for (const name of changeDirs) {
54
+ const progress = await getTaskProgressForChange(changesDir, name, projectRoot);
55
+ changes.push({
56
+ name,
57
+ completedTasks: progress.completed,
58
+ totalTasks: progress.total,
59
+ openTasks: progress.open,
60
+ dispositionedTasks: progress.dispositioned,
61
+ lastModified: getLastModified(path.join(changesDir, name)),
62
+ });
63
+ }
64
+ if (sort === 'recent') {
65
+ changes.sort((a, b) => b.lastModified.getTime() - a.lastModified.getTime());
66
+ }
67
+ else {
68
+ changes.sort((a, b) => a.name.localeCompare(b.name));
69
+ }
70
+ if (json) {
71
+ printJson({
72
+ changes: changes.map((c) => ({
73
+ name: c.name,
74
+ completedTasks: c.completedTasks,
75
+ totalTasks: c.totalTasks,
76
+ lastModified: c.lastModified.toISOString(),
77
+ status: c.totalTasks === 0 ? 'no-tasks' : c.openTasks === 0 ? 'complete' : 'in-progress',
78
+ })),
79
+ });
80
+ return 0;
81
+ }
82
+ console.log('Changes:');
83
+ const names = new Map(changes.map((c) => [c.name, printableId(c.name)]));
84
+ const nameWidth = Math.max(...[...names.values()].map((n) => n.length));
85
+ for (const change of changes) {
86
+ const status = formatTaskStatus({
87
+ total: change.totalTasks,
88
+ completed: change.completedTasks,
89
+ open: change.openTasks,
90
+ dispositioned: change.dispositionedTasks,
91
+ });
92
+ console.log(` ${names.get(change.name).padEnd(nameWidth)} ${status}`);
93
+ }
94
+ return 0;
95
+ }
@@ -0,0 +1,6 @@
1
+ export interface NewChangeOptions {
2
+ schema?: string;
3
+ description?: string;
4
+ json?: boolean;
5
+ }
6
+ export declare function newChangeHandler(projectRoot: string, name: string | undefined, options: NewChangeOptions): number;