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,170 @@
1
+ import type { ExecStep, HarnessTarget, Profile, Scope, SelectItem, Tier } from "@freeharness/core";
2
+ import type { ProfileRecord } from "../infra/manifest.js";
3
+ /** On-disk shape of a `claude-code-env` profile (local-ollama.json). */
4
+ export interface EnvProfileFile {
5
+ name: string;
6
+ kind: "claude-code-env";
7
+ base_url: string;
8
+ auth_token?: string;
9
+ models: Record<Tier, string>;
10
+ probe?: {
11
+ kind: string;
12
+ path: string;
13
+ };
14
+ notes?: string[];
15
+ }
16
+ /** On-disk shape of an `opencode-provider` profile (local-llamacpp.json). */
17
+ export interface ProviderProfileFile {
18
+ name: string;
19
+ kind: "opencode-provider";
20
+ provider_id: string;
21
+ provider: Record<string, unknown>;
22
+ models: Record<Tier, string>;
23
+ notes_file: string;
24
+ notes_source: string;
25
+ }
26
+ /** One catalog entry of the `mcp` profile. */
27
+ export interface McpCatalogServer {
28
+ name: string;
29
+ description: string;
30
+ command?: string;
31
+ args?: string[];
32
+ env?: Record<string, string>;
33
+ type?: "stdio" | "http" | "sse";
34
+ url?: string;
35
+ tools_approx: number;
36
+ context_cost: string;
37
+ }
38
+ /** On-disk shape of the `mcp-catalog` profile (mcp.json). */
39
+ export interface McpProfileFile {
40
+ name: string;
41
+ kind: "mcp-catalog";
42
+ servers: McpCatalogServer[];
43
+ }
44
+ export type ProfileFile = EnvProfileFile | ProviderProfileFile | McpProfileFile;
45
+ /**
46
+ * Reads a profile data file from canonical/profiles/.
47
+ * @param canonicalDir Resolved canonical directory.
48
+ * @param profile Registry entry.
49
+ * @returns Parsed file.
50
+ */
51
+ export declare function loadProfileFile(canonicalDir: string, profile: Profile): ProfileFile;
52
+ /**
53
+ * Resolves a `--profile` value: a registry id, or `none`.
54
+ * @param id Value passed on the command line.
55
+ * @returns The registry entry (undefined for `none`).
56
+ */
57
+ export declare function resolveProfile(id: string): Profile | undefined;
58
+ /** Outcome of the env merge preview/apply. */
59
+ export interface EnvMerge {
60
+ /** Keys written with the profile value (new, or previously ours). */
61
+ set: Record<string, string>;
62
+ /** Keys present in the env block that were not ours: kept with the user's value. */
63
+ kept: Record<string, unknown>;
64
+ /** Keys previously ours whose value changed. */
65
+ updated: string[];
66
+ }
67
+ /**
68
+ * Plans (and, unless dry, applies) the additive env merge of a local-model profile into a
69
+ * Claude Code settings.json: the profile keys are added; a key already present and not
70
+ * recorded as ours in the manifest keeps the user's value; a key recorded as ours is updated
71
+ * to the profile value. Foreign keys and every other settings key are untouched.
72
+ * @param settingsPath The settings.json (created when missing).
73
+ * @param env The env block from `tierEnv`.
74
+ * @param ours Keys recorded as written by this profile earlier (manifest).
75
+ * @param dry When true nothing is written.
76
+ * @returns What was set, kept and updated.
77
+ */
78
+ export declare function mergeEnvProfile(settingsPath: string, env: Record<string, string>, ours: string[], dry: boolean): EnvMerge;
79
+ /**
80
+ * Removes from the env block exactly the keys a profile wrote; an empty env block is
81
+ * dropped. Nothing else in the file changes.
82
+ * @param settingsPath The settings.json.
83
+ * @param keys Keys recorded in the manifest.
84
+ * @param dry When true nothing is written.
85
+ * @returns Keys removed (those still present).
86
+ */
87
+ export declare function removeEnvKeys(settingsPath: string, keys: string[], dry: boolean): string[];
88
+ /**
89
+ * Removes a `provider.<id>` block from an opencode.json (only when it was ours); an empty
90
+ * `provider` map is dropped.
91
+ * @param file opencode.json path.
92
+ * @param providerId Provider id recorded in the manifest.
93
+ * @param dry When true nothing is written.
94
+ * @returns True when the block was removed.
95
+ */
96
+ export declare function removeProviderBlock(file: string, providerId: string, dry: boolean): boolean;
97
+ /** One planned change of a profile pass, printable. */
98
+ export interface ProfilePlan {
99
+ profileId: string;
100
+ target: HarnessTarget;
101
+ scope: Scope;
102
+ /** Preview lines (`write:` / `note:` style). */
103
+ lines: string[];
104
+ /** Side-effecting actions (MCP registrations). */
105
+ actions: ExecStep[];
106
+ /** Manifest record (null when the pass removes the profile; undefined when nothing to record). */
107
+ record?: ProfileRecord | null;
108
+ /** Files this pass writes (for the manifest `files` list). */
109
+ written: string[];
110
+ }
111
+ /** Inputs shared by the profile passes. */
112
+ export interface ProfileContext {
113
+ canonicalDir: string;
114
+ scope: Scope;
115
+ projectRoot: string;
116
+ /** `~/.claude` for user scope, `<project>/.claude` for project scope. */
117
+ claudeDir: string;
118
+ dryRun: boolean;
119
+ /** Existing manifest records, by profile id. */
120
+ existing: Record<string, ProfileRecord>;
121
+ }
122
+ /**
123
+ * Applies (or previews) the `claude-code-env` profile: the tier env merged into the scope's
124
+ * settings.json.
125
+ * @param profile Registry entry.
126
+ * @param data Profile file.
127
+ * @param ctx Pass context.
128
+ * @returns The plan with its manifest record.
129
+ */
130
+ export declare function applyEnvProfile(profile: Profile, data: EnvProfileFile, ctx: ProfileContext): ProfilePlan;
131
+ /**
132
+ * Applies (or previews) the `opencode-provider` profile: the provider block merged into
133
+ * `<project>/opencode.json` and the notes file written next to it.
134
+ * @param profile Registry entry.
135
+ * @param data Profile file.
136
+ * @param ctx Pass context.
137
+ * @returns The plan with its manifest record.
138
+ */
139
+ export declare function applyProviderProfile(profile: Profile, data: ProviderProfileFile, ctx: ProfileContext): ProfilePlan;
140
+ /**
141
+ * Selectable items of the MCP catalog (id + label with tool count and cost).
142
+ * @param data Catalog file.
143
+ * @returns Items in catalog order.
144
+ */
145
+ export declare function mcpCatalogItems(data: McpProfileFile): SelectItem[];
146
+ /**
147
+ * The `claude mcp add` command for a catalog entry (same shape the `mcp` capability emits).
148
+ * @param s Catalog entry.
149
+ * @param scope user -> `-s user`, project -> `-s local`.
150
+ * @returns Shell command.
151
+ */
152
+ export declare function mcpAddCommand(s: McpCatalogServer, scope: Scope): string;
153
+ /**
154
+ * Builds the MCP profile plan for a selection: one `claude mcp add` action per selected
155
+ * server, nothing for an empty selection.
156
+ * @param profile Registry entry.
157
+ * @param data Catalog file.
158
+ * @param selected Selected server names (unknown names are reported and ignored).
159
+ * @param ctx Pass context.
160
+ * @returns The plan (no manifest record: registrations live in ~/.claude.json, owned by `claude`).
161
+ */
162
+ export declare function applyMcpProfile(profile: Profile, data: McpProfileFile, selected: string[], ctx: ProfileContext): ProfilePlan;
163
+ /**
164
+ * Plans (or applies) the removal of every profile recorded in the manifest: env keys and
165
+ * provider blocks we wrote, and the notes files. Foreign keys are never touched.
166
+ * @param existing Manifest records.
167
+ * @param dry When true nothing is written.
168
+ * @returns One plan per recorded profile (record = null).
169
+ */
170
+ export declare function removeProfiles(existing: Record<string, ProfileRecord>, dry: boolean): ProfilePlan[];
@@ -0,0 +1,285 @@
1
+ // Opt-in profiles (v4 P6): `init --profile <id>` applies one data file from
2
+ // canonical/profiles/ to an existing target. Three kinds: a Claude Code env block
3
+ // (local-ollama), an OpenCode provider block + notes file (local-llamacpp) and an MCP
4
+ // catalog with a selection prompt (mcp). Every write is additive (a key the user set is
5
+ // kept), previewed first, confirmed second, and recorded in the install manifest so
6
+ // `--profile none` removes exactly the keys and files a profile wrote. index.ts composes
7
+ // the two passes; nothing here prompts.
8
+ import fs from "node:fs";
9
+ import path from "node:path";
10
+ import { PROFILES, PROFILE_NONE, getProfile, tierEnv } from "@freeharness/core";
11
+ import { ensureDir } from "../infra/fsutil.js";
12
+ /**
13
+ * Reads a profile data file from canonical/profiles/.
14
+ * @param canonicalDir Resolved canonical directory.
15
+ * @param profile Registry entry.
16
+ * @returns Parsed file.
17
+ */
18
+ export function loadProfileFile(canonicalDir, profile) {
19
+ const file = path.join(canonicalDir, "profiles", profile.file);
20
+ if (!fs.existsSync(file))
21
+ throw new Error(`profile ${profile.id}: data file missing at ${file}`);
22
+ return JSON.parse(fs.readFileSync(file, "utf8"));
23
+ }
24
+ /**
25
+ * Resolves a `--profile` value: a registry id, or `none`.
26
+ * @param id Value passed on the command line.
27
+ * @returns The registry entry (undefined for `none`).
28
+ */
29
+ export function resolveProfile(id) {
30
+ if (id === PROFILE_NONE)
31
+ return undefined;
32
+ const p = getProfile(id);
33
+ if (!p)
34
+ throw new Error(`Unknown profile: ${id}. Valid: ${PROFILES.map((x) => x.id).join(", ")}, ${PROFILE_NONE}`);
35
+ return p;
36
+ }
37
+ /**
38
+ * Reads a JSON file when present.
39
+ * @param file Path.
40
+ * @returns Parsed object or {} when absent.
41
+ */
42
+ function readJsonOr(file) {
43
+ try {
44
+ return JSON.parse(fs.readFileSync(file, "utf8"));
45
+ }
46
+ catch {
47
+ return {};
48
+ }
49
+ }
50
+ /**
51
+ * Writes a JSON file (2-space indent, trailing newline), creating its directory.
52
+ * @param file Path.
53
+ * @param value Serializable value.
54
+ * @param dry When true nothing is written.
55
+ */
56
+ function writeJson(file, value, dry) {
57
+ if (dry)
58
+ return;
59
+ ensureDir(path.dirname(file), false);
60
+ fs.writeFileSync(file, JSON.stringify(value, null, 2) + "\n", "utf8");
61
+ }
62
+ /**
63
+ * Plans (and, unless dry, applies) the additive env merge of a local-model profile into a
64
+ * Claude Code settings.json: the profile keys are added; a key already present and not
65
+ * recorded as ours in the manifest keeps the user's value; a key recorded as ours is updated
66
+ * to the profile value. Foreign keys and every other settings key are untouched.
67
+ * @param settingsPath The settings.json (created when missing).
68
+ * @param env The env block from `tierEnv`.
69
+ * @param ours Keys recorded as written by this profile earlier (manifest).
70
+ * @param dry When true nothing is written.
71
+ * @returns What was set, kept and updated.
72
+ */
73
+ export function mergeEnvProfile(settingsPath, env, ours, dry) {
74
+ const settings = readJsonOr(settingsPath);
75
+ const block = { ...(settings.env ?? {}) };
76
+ const out = { set: {}, kept: {}, updated: [] };
77
+ for (const [k, v] of Object.entries(env)) {
78
+ const present = Object.prototype.hasOwnProperty.call(block, k);
79
+ if (present && !ours.includes(k)) {
80
+ out.kept[k] = block[k];
81
+ continue;
82
+ }
83
+ if (present && block[k] !== v)
84
+ out.updated.push(k);
85
+ block[k] = v;
86
+ out.set[k] = v;
87
+ }
88
+ if (!dry && Object.keys(out.set).length > 0)
89
+ writeJson(settingsPath, { ...settings, env: block }, false);
90
+ return out;
91
+ }
92
+ /**
93
+ * Removes from the env block exactly the keys a profile wrote; an empty env block is
94
+ * dropped. Nothing else in the file changes.
95
+ * @param settingsPath The settings.json.
96
+ * @param keys Keys recorded in the manifest.
97
+ * @param dry When true nothing is written.
98
+ * @returns Keys removed (those still present).
99
+ */
100
+ export function removeEnvKeys(settingsPath, keys, dry) {
101
+ if (!fs.existsSync(settingsPath))
102
+ return [];
103
+ const settings = readJsonOr(settingsPath);
104
+ const block = { ...(settings.env ?? {}) };
105
+ const removed = keys.filter((k) => Object.prototype.hasOwnProperty.call(block, k));
106
+ for (const k of removed)
107
+ delete block[k];
108
+ if (removed.length > 0 && !dry) {
109
+ const next = { ...settings };
110
+ if (Object.keys(block).length > 0)
111
+ next.env = block;
112
+ else
113
+ delete next.env;
114
+ writeJson(settingsPath, next, false);
115
+ }
116
+ return removed;
117
+ }
118
+ /**
119
+ * Removes a `provider.<id>` block from an opencode.json (only when it was ours); an empty
120
+ * `provider` map is dropped.
121
+ * @param file opencode.json path.
122
+ * @param providerId Provider id recorded in the manifest.
123
+ * @param dry When true nothing is written.
124
+ * @returns True when the block was removed.
125
+ */
126
+ export function removeProviderBlock(file, providerId, dry) {
127
+ if (!fs.existsSync(file))
128
+ return false;
129
+ const cfg = readJsonOr(file);
130
+ if (!cfg.provider || !(providerId in cfg.provider))
131
+ return false;
132
+ const provider = { ...cfg.provider };
133
+ delete provider[providerId];
134
+ const next = { ...cfg };
135
+ if (Object.keys(provider).length > 0)
136
+ next.provider = provider;
137
+ else
138
+ delete next.provider;
139
+ writeJson(file, next, dry);
140
+ return true;
141
+ }
142
+ /**
143
+ * Applies (or previews) the `claude-code-env` profile: the tier env merged into the scope's
144
+ * settings.json.
145
+ * @param profile Registry entry.
146
+ * @param data Profile file.
147
+ * @param ctx Pass context.
148
+ * @returns The plan with its manifest record.
149
+ */
150
+ export function applyEnvProfile(profile, data, ctx) {
151
+ const settingsPath = path.join(ctx.claudeDir, "settings.json");
152
+ const env = tierEnv({ baseUrl: data.base_url, models: data.models, authToken: data.auth_token });
153
+ const ours = ctx.existing[profile.id]?.keys ?? [];
154
+ const merge = mergeEnvProfile(settingsPath, env, ours, ctx.dryRun);
155
+ const lines = [` edit: ${settingsPath} (env block, additive)`];
156
+ for (const [k, v] of Object.entries(merge.set))
157
+ lines.push(` ${merge.updated.includes(k) ? "update" : "set "} ${k}=${v}`);
158
+ for (const [k, v] of Object.entries(merge.kept))
159
+ lines.push(` keep ${k}=${String(v)} (set by you; not overwritten)`);
160
+ for (const n of data.notes ?? [])
161
+ lines.push(` note: ${n}`);
162
+ lines.push(" note: remove with `freeharness init --profile none`; doctor probes the base URL.");
163
+ const record = { target: "claude-code", file: settingsPath, keys: Object.keys(merge.set), files: [], appliedAt: new Date().toISOString() };
164
+ return { profileId: profile.id, target: "claude-code", scope: ctx.scope, lines, actions: [], record, written: [] };
165
+ }
166
+ /**
167
+ * Applies (or previews) the `opencode-provider` profile: the provider block merged into
168
+ * `<project>/opencode.json` and the notes file written next to it.
169
+ * @param profile Registry entry.
170
+ * @param data Profile file.
171
+ * @param ctx Pass context.
172
+ * @returns The plan with its manifest record.
173
+ */
174
+ export function applyProviderProfile(profile, data, ctx) {
175
+ const file = path.join(ctx.projectRoot, "opencode.json");
176
+ const cfg = readJsonOr(file);
177
+ const provider = { ...(cfg.provider ?? {}) };
178
+ const ours = ctx.existing[profile.id]?.keys ?? [];
179
+ const key = `provider.${data.provider_id}`;
180
+ const present = Object.prototype.hasOwnProperty.call(provider, data.provider_id);
181
+ const lines = [];
182
+ let keys = [];
183
+ if (present && !ours.includes(key)) {
184
+ lines.push(` keep: ${file} already has provider.${data.provider_id} (set by you; not overwritten)`);
185
+ }
186
+ else {
187
+ provider[data.provider_id] = data.provider;
188
+ const next = { ...(cfg.$schema ? {} : { $schema: "https://opencode.ai/config.json" }), ...cfg, provider };
189
+ writeJson(file, next, ctx.dryRun);
190
+ lines.push(` edit: ${file} (${present ? "update" : "add"} provider.${data.provider_id}, other providers kept)`);
191
+ keys = [key];
192
+ }
193
+ const notesFile = path.join(ctx.projectRoot, data.notes_file);
194
+ const notesSrc = path.join(ctx.canonicalDir, "profiles", data.notes_source);
195
+ if (!ctx.dryRun) {
196
+ ensureDir(path.dirname(notesFile), false);
197
+ fs.writeFileSync(notesFile, fs.readFileSync(notesSrc, "utf8"), "utf8");
198
+ }
199
+ lines.push(` write: ${notesFile} (Jinja template guidance, context size, tier placeholders)`);
200
+ for (const tier of ["strong", "standard", "fast"])
201
+ lines.push(` note: ${tier} -> ${data.models[tier]} (export OPENCODE_${tier.toUpperCase()}_MODEL=${data.models[tier]})`);
202
+ const record = { target: "opencode", file, keys, files: [notesFile], appliedAt: new Date().toISOString() };
203
+ return { profileId: profile.id, target: "opencode", scope: ctx.scope, lines, actions: [], record, written: [notesFile] };
204
+ }
205
+ /**
206
+ * Selectable items of the MCP catalog (id + label with tool count and cost).
207
+ * @param data Catalog file.
208
+ * @returns Items in catalog order.
209
+ */
210
+ export function mcpCatalogItems(data) {
211
+ return data.servers.map((s) => ({ id: s.name, label: `~${s.tools_approx} tools — ${s.description} [${s.context_cost}]` }));
212
+ }
213
+ /**
214
+ * The `claude mcp add` command for a catalog entry (same shape the `mcp` capability emits).
215
+ * @param s Catalog entry.
216
+ * @param scope user -> `-s user`, project -> `-s local`.
217
+ * @returns Shell command.
218
+ */
219
+ export function mcpAddCommand(s, scope) {
220
+ const sc = scope === "user" ? "user" : "local";
221
+ const envFlags = Object.entries(s.env ?? {}).map(([k, v]) => `-e ${k}=${v}`).join(" ");
222
+ if (s.type === "http" || s.type === "sse")
223
+ return `claude mcp add --transport ${s.type} ${s.name} -s ${sc} ${s.url}`;
224
+ return `claude mcp add ${s.name} -s ${sc}${envFlags ? ` ${envFlags}` : ""} -- ${s.command} ${(s.args ?? []).join(" ")}`;
225
+ }
226
+ /**
227
+ * Builds the MCP profile plan for a selection: one `claude mcp add` action per selected
228
+ * server, nothing for an empty selection.
229
+ * @param profile Registry entry.
230
+ * @param data Catalog file.
231
+ * @param selected Selected server names (unknown names are reported and ignored).
232
+ * @param ctx Pass context.
233
+ * @returns The plan (no manifest record: registrations live in ~/.claude.json, owned by `claude`).
234
+ */
235
+ export function applyMcpProfile(profile, data, selected, ctx) {
236
+ const lines = [];
237
+ const actions = [];
238
+ const unknown = selected.filter((n) => !data.servers.some((s) => s.name === n));
239
+ for (const u of unknown)
240
+ lines.push(` note: unknown server '${u}' ignored (catalog: ${data.servers.map((s) => s.name).join(", ")})`);
241
+ const chosen = data.servers.filter((s) => selected.includes(s.name));
242
+ if (chosen.length === 0) {
243
+ lines.push(" note: no server selected; nothing is registered (pass --select a,b or answer the prompt).");
244
+ return { profileId: profile.id, target: "claude-code", scope: ctx.scope, lines, actions, written: [] };
245
+ }
246
+ for (const s of chosen) {
247
+ lines.push(` mcp: ${s.name} (~${s.tools_approx} tools) — ${s.context_cost}`);
248
+ if (s.env)
249
+ lines.push(` env placeholders to set: ${Object.keys(s.env).join(", ")}`);
250
+ actions.push({ description: `Register MCP server ${s.name} (~${s.tools_approx} tools; profile mcp)`, command: mcpAddCommand(s, ctx.scope), optional: true });
251
+ }
252
+ lines.push(" note: tool schemas ride on every request; `freeharness doctor` lists the registered servers with these counts. Remove one with `claude mcp remove <name>`.");
253
+ return { profileId: profile.id, target: "claude-code", scope: ctx.scope, lines, actions, written: [] };
254
+ }
255
+ /**
256
+ * Plans (or applies) the removal of every profile recorded in the manifest: env keys and
257
+ * provider blocks we wrote, and the notes files. Foreign keys are never touched.
258
+ * @param existing Manifest records.
259
+ * @param dry When true nothing is written.
260
+ * @returns One plan per recorded profile (record = null).
261
+ */
262
+ export function removeProfiles(existing, dry) {
263
+ const plans = [];
264
+ for (const [id, rec] of Object.entries(existing)) {
265
+ const lines = [];
266
+ const envKeys = rec.keys.filter((k) => !k.startsWith("provider."));
267
+ if (envKeys.length > 0) {
268
+ const removed = removeEnvKeys(rec.file, envKeys, dry);
269
+ lines.push(` edit: ${rec.file} (remove ${removed.length > 0 ? removed.join(", ") : "nothing: keys already gone"}; other env keys kept)`);
270
+ }
271
+ for (const k of rec.keys.filter((x) => x.startsWith("provider."))) {
272
+ const gone = removeProviderBlock(rec.file, k.slice("provider.".length), dry);
273
+ lines.push(` edit: ${rec.file} (${gone ? `remove ${k}` : `${k} already gone`}; other providers kept)`);
274
+ }
275
+ for (const f of rec.files) {
276
+ if (fs.existsSync(f)) {
277
+ if (!dry)
278
+ fs.rmSync(f);
279
+ lines.push(` rm: ${f}`);
280
+ }
281
+ }
282
+ plans.push({ profileId: id, target: rec.target, scope: "user", lines, actions: [], record: null, written: [] });
283
+ }
284
+ return plans;
285
+ }
@@ -0,0 +1,10 @@
1
+ import type { AdapterResult, InstallContext } from "@freeharness/core";
2
+ import type { InstallPlan } from "@freeharness/core";
3
+ /**
4
+ * Applies every step of the plan through its target adapter. One adapter instance per
5
+ * target per pass, so adapters that emit shared scaffolding (the plugin manifest) do it once.
6
+ * @param plan The ordered install plan.
7
+ * @param base Install context shared by every step.
8
+ * @returns One result per step, in plan order.
9
+ */
10
+ export declare function runPlan(plan: InstallPlan, base: InstallContext): Promise<AdapterResult[]>;
@@ -0,0 +1,27 @@
1
+ // Runner: emit files for an install plan through the harness adapters. The heavier
2
+ // side effects are returned as actions and handled by the executor.
3
+ import { getAdapter } from "../adapters/harness/index.js";
4
+ import { getCapability } from "@freeharness/core";
5
+ /**
6
+ * Applies every step of the plan through its target adapter. One adapter instance per
7
+ * target per pass, so adapters that emit shared scaffolding (the plugin manifest) do it once.
8
+ * @param plan The ordered install plan.
9
+ * @param base Install context shared by every step.
10
+ * @returns One result per step, in plan order.
11
+ */
12
+ export async function runPlan(plan, base) {
13
+ const results = [];
14
+ const adapters = new Map();
15
+ for (const step of plan.steps) {
16
+ const cap = getCapability(step.capabilityId);
17
+ if (!cap)
18
+ continue;
19
+ let adapter = adapters.get(step.target);
20
+ if (!adapter) {
21
+ adapter = getAdapter(step.target);
22
+ adapters.set(step.target, adapter);
23
+ }
24
+ results.push(await adapter.apply(cap, base));
25
+ }
26
+ return results;
27
+ }
@@ -0,0 +1,65 @@
1
+ import type { Scope } from "@freeharness/core";
2
+ /** Command substrings that identify the hook entries FreeHarness writes into settings.json. */
3
+ export declare const OUR_HOOK_MARKERS: readonly ["freeharness-session-start", "freeharness-memory-guard", "freeharness-config-guard", "freeharness-repeat-tool", "freeharness-security-guidance", "freeharness-cost-tracker", "freeharness-output-pruner", "freeharness-context-monitor", "freeharness-precompact", "freeharness-auto-memory", "freeharness-converge"];
4
+ /** What an uninstall pass would (or did) do. */
5
+ export interface UninstallPlan {
6
+ manifest: string;
7
+ /** Files removed (or to remove). */
8
+ remove: string[];
9
+ /** Manifest entries already gone. */
10
+ missing: string[];
11
+ /** Manifest entries kept on purpose, with the reason. */
12
+ kept: {
13
+ path: string;
14
+ reason: string;
15
+ }[];
16
+ /** settings.json files whose FreeHarness hook entries are pruned. */
17
+ settings: string[];
18
+ /** Directories pruned because they became empty. */
19
+ prunedDirs: string[];
20
+ }
21
+ interface HookEntry {
22
+ matcher?: string;
23
+ hooks?: {
24
+ command?: string;
25
+ }[];
26
+ }
27
+ /**
28
+ * Tells whether a hook entry is one FreeHarness wrote.
29
+ * @param e A settings.json hook entry.
30
+ * @returns True when any of its commands carries our marker.
31
+ */
32
+ export declare function isOurHook(e: HookEntry): boolean;
33
+ /**
34
+ * Tells whether a hook entry is an upstream claude-mem wired into settings.json (`npx
35
+ * claude-mem start ...`); the plugin ships its own hooks.json, so the entry duplicates it.
36
+ * @param e A settings.json hook entry.
37
+ * @returns True when a command names claude-mem and the entry is not ours.
38
+ */
39
+ export declare function isClaudeMemHook(e: HookEntry): boolean;
40
+ /**
41
+ * Removes the hook entries of a settings.json that satisfy a predicate; every other entry
42
+ * and key is untouched. Emptied events and an emptied `hooks` object are dropped.
43
+ * @param settingsPath The settings.json.
44
+ * @param predicate Which entries to remove.
45
+ * @param dryRun Report only.
46
+ * @returns Number of entries removed (or that would be); 0 when the file is unreadable.
47
+ */
48
+ export declare function pruneHooksMatching(settingsPath: string, predicate: (e: HookEntry) => boolean, dryRun: boolean): number;
49
+ /**
50
+ * Removes FreeHarness hook entries from a settings.json; foreign entries, keys and
51
+ * `enabledPlugins` are untouched.
52
+ * @param settingsPath The settings.json.
53
+ * @param dryRun Report only.
54
+ * @returns Number of entries removed (or that would be).
55
+ */
56
+ export declare function pruneOurHooks(settingsPath: string, dryRun: boolean): number;
57
+ /**
58
+ * Runs (or previews) an uninstall for a scope.
59
+ * @param scope user | project.
60
+ * @param projectRoot Project root (project scope).
61
+ * @param dryRun Compute the plan without deleting anything.
62
+ * @returns The plan; undefined when no manifest exists.
63
+ */
64
+ export declare function uninstallScope(scope: Scope, projectRoot: string, dryRun: boolean): UninstallPlan | undefined;
65
+ export {};