@kal-elsam/kairo-runtime 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (315) hide show
  1. package/README.md +937 -0
  2. package/bin/harness.js +11 -0
  3. package/bin/kairo-runtime.js +11 -0
  4. package/bin/kairo.js +11 -0
  5. package/global-template/components/catalog.json +25 -0
  6. package/global-template/components/orchestrator/orchestrator.md +55 -0
  7. package/global-template/components/sdd-core/handoff.md +38 -0
  8. package/global-template/components/sdd-core/spec-sizing.md +38 -0
  9. package/global-template/components/sdd-core/workflow.md +31 -0
  10. package/global-template/core/orchestrator.md +55 -0
  11. package/package.json +64 -0
  12. package/prompts/HARNESS_ENFORCEMENT_UPGRADE.md +11 -0
  13. package/prompts/HARNESS_ENTERPRISE.md +33 -0
  14. package/prompts/HARNESS_INSTALLER_MASTER.md +853 -0
  15. package/prompts/HARNESS_MINIMAL.md +30 -0
  16. package/prompts/HARNESS_SPEC_SIZING_UPGRADE.md +41 -0
  17. package/prompts/HARNESS_STANDARD.md +35 -0
  18. package/prompts/HARNESS_UNIVERSAL_PARITY.md +56 -0
  19. package/repo-template/.claude/agents/adapter-parity-reviewer.md +17 -0
  20. package/repo-template/.claude/agents/architect.md +17 -0
  21. package/repo-template/.claude/agents/eval-engineer.md +17 -0
  22. package/repo-template/.claude/agents/reviewer.md +17 -0
  23. package/repo-template/.claude/agents/sdd-reviewer.md +17 -0
  24. package/repo-template/.claude/agents/sdd-spec-writer.md +17 -0
  25. package/repo-template/.claude/skills/checkpoint/SKILL.md +13 -0
  26. package/repo-template/.claude/skills/eval-design/SKILL.md +3 -0
  27. package/repo-template/.claude/skills/evals/SKILL.md +13 -0
  28. package/repo-template/.claude/skills/loop-engineering/SKILL.md +16 -0
  29. package/repo-template/.claude/skills/maintainability-review/SKILL.md +3 -0
  30. package/repo-template/.claude/skills/quality-gate-review/SKILL.md +3 -0
  31. package/repo-template/.claude/skills/sdd/SKILL.md +13 -0
  32. package/repo-template/.claude/skills/spec-complexity-classifier/SKILL.md +10 -0
  33. package/repo-template/.claude/skills/spec-escalation-review/SKILL.md +10 -0
  34. package/repo-template/.claude/skills/spec-intake/SKILL.md +10 -0
  35. package/repo-template/.claude/skills/tdd/SKILL.md +13 -0
  36. package/repo-template/.claude/skills/trust-review/SKILL.md +3 -0
  37. package/repo-template/.codex/skills/adapter-parity/SKILL.md +29 -0
  38. package/repo-template/.codex/skills/checkpoint/SKILL.md +36 -0
  39. package/repo-template/.codex/skills/eval-design/SKILL.md +3 -0
  40. package/repo-template/.codex/skills/evals/SKILL.md +28 -0
  41. package/repo-template/.codex/skills/loop-engineering/SKILL.md +24 -0
  42. package/repo-template/.codex/skills/maintainability-review/SKILL.md +3 -0
  43. package/repo-template/.codex/skills/quality-gate-review/SKILL.md +3 -0
  44. package/repo-template/.codex/skills/sdd/SKILL.md +30 -0
  45. package/repo-template/.codex/skills/spec-complexity-classifier/SKILL.md +10 -0
  46. package/repo-template/.codex/skills/spec-escalation-review/SKILL.md +10 -0
  47. package/repo-template/.codex/skills/spec-intake/SKILL.md +10 -0
  48. package/repo-template/.codex/skills/tdd/SKILL.md +27 -0
  49. package/repo-template/.codex/skills/trust-review/SKILL.md +3 -0
  50. package/repo-template/.cursor/agents/adapter-parity-reviewer.md +29 -0
  51. package/repo-template/.cursor/agents/architect.md +27 -0
  52. package/repo-template/.cursor/agents/context-engineer.md +27 -0
  53. package/repo-template/.cursor/agents/debugger.md +27 -0
  54. package/repo-template/.cursor/agents/eval-engineer.md +27 -0
  55. package/repo-template/.cursor/agents/harness-orchestrator.md +27 -0
  56. package/repo-template/.cursor/agents/loop-controller.md +17 -0
  57. package/repo-template/.cursor/agents/loop-debugger.md +16 -0
  58. package/repo-template/.cursor/agents/reviewer.md +27 -0
  59. package/repo-template/.cursor/agents/sdd/sdd-acceptance-reviewer.md +31 -0
  60. package/repo-template/.cursor/agents/sdd/sdd-implementation-guardian.md +31 -0
  61. package/repo-template/.cursor/agents/sdd/sdd-intake-analyst.md +31 -0
  62. package/repo-template/.cursor/agents/sdd/sdd-orchestrator.md +31 -0
  63. package/repo-template/.cursor/agents/sdd/sdd-spec-reviewer.md +31 -0
  64. package/repo-template/.cursor/agents/sdd/sdd-spec-writer.md +31 -0
  65. package/repo-template/.cursor/agents/sdd/sdd-task-breakdown.md +31 -0
  66. package/repo-template/.cursor/agents/sdd/sdd-technical-planner.md +31 -0
  67. package/repo-template/.cursor/agents/sdd/sdd-test-planner.md +31 -0
  68. package/repo-template/.cursor/agents/spec-intake-analyst.md +14 -0
  69. package/repo-template/.cursor/agents/test-engineer.md +27 -0
  70. package/repo-template/.cursor/commands/adapter-parity.md +34 -0
  71. package/repo-template/.cursor/commands/checkpoint.md +30 -0
  72. package/repo-template/.cursor/commands/debug.md +13 -0
  73. package/repo-template/.cursor/commands/init-eval.md +12 -0
  74. package/repo-template/.cursor/commands/init-feature.md +12 -0
  75. package/repo-template/.cursor/commands/init-harness.md +13 -0
  76. package/repo-template/.cursor/commands/loop-debug.md +3 -0
  77. package/repo-template/.cursor/commands/loop-review.md +3 -0
  78. package/repo-template/.cursor/commands/loop-run.md +5 -0
  79. package/repo-template/.cursor/commands/review.md +21 -0
  80. package/repo-template/.cursor/commands/sdd-intake.md +18 -0
  81. package/repo-template/.cursor/commands/sdd-plan.md +18 -0
  82. package/repo-template/.cursor/commands/sdd-spec.md +18 -0
  83. package/repo-template/.cursor/commands/sdd-tasks.md +18 -0
  84. package/repo-template/.cursor/commands/sdd-validate.md +18 -0
  85. package/repo-template/.cursor/commands/spec-escalate.md +9 -0
  86. package/repo-template/.cursor/commands/spec-intake.md +10 -0
  87. package/repo-template/.cursor/commands/spec-size.md +21 -0
  88. package/repo-template/.cursor/rules/adapter-parity.mdc +20 -0
  89. package/repo-template/.cursor/rules/api.mdc +12 -0
  90. package/repo-template/.cursor/rules/core.mdc +21 -0
  91. package/repo-template/.cursor/rules/enforcement.mdc +16 -0
  92. package/repo-template/.cursor/rules/evals.mdc +10 -0
  93. package/repo-template/.cursor/rules/git.mdc +19 -0
  94. package/repo-template/.cursor/rules/harness.mdc +14 -0
  95. package/repo-template/.cursor/rules/loops.mdc +17 -0
  96. package/repo-template/.cursor/rules/testing.mdc +13 -0
  97. package/repo-template/.cursor/rules/ui.mdc +13 -0
  98. package/repo-template/.cursor/skills/api-design/SKILL.md +23 -0
  99. package/repo-template/.cursor/skills/architecture/SKILL.md +23 -0
  100. package/repo-template/.cursor/skills/code-review/SKILL.md +23 -0
  101. package/repo-template/.cursor/skills/context-graph/SKILL.md +23 -0
  102. package/repo-template/.cursor/skills/debugging/SKILL.md +23 -0
  103. package/repo-template/.cursor/skills/evals/SKILL.md +23 -0
  104. package/repo-template/.cursor/skills/git-workflow/SKILL.md +23 -0
  105. package/repo-template/.cursor/skills/testing/SKILL.md +23 -0
  106. package/repo-template/.cursor/skills/ui-design/SKILL.md +23 -0
  107. package/repo-template/.gentle-ai/README.md +37 -0
  108. package/repo-template/.gentle-ai/loops/README.md +27 -0
  109. package/repo-template/.gentle-ai/loops/sdd-tdd-repair.loop.md +27 -0
  110. package/repo-template/.gentle-ai/model-routing.md +25 -0
  111. package/repo-template/.github/copilot-instructions.md +37 -0
  112. package/repo-template/.github/dependabot.yml +11 -0
  113. package/repo-template/.github/instructions/harness.instructions.md +11 -0
  114. package/repo-template/.github/workflows/harness-quality-gate.yml +67 -0
  115. package/repo-template/.github/workflows/harness-security-gate.yml +32 -0
  116. package/repo-template/.harness/spec-sizing.json +33 -0
  117. package/repo-template/.opencode/README.md +71 -0
  118. package/repo-template/.opencode/agents/adapter-parity-reviewer.md +23 -0
  119. package/repo-template/.opencode/agents/architect.md +38 -0
  120. package/repo-template/.opencode/agents/checkpoint-reviewer.md +38 -0
  121. package/repo-template/.opencode/agents/eval-engineer.md +38 -0
  122. package/repo-template/.opencode/agents/loop-controller.md +38 -0
  123. package/repo-template/.opencode/agents/loop-debugger.md +38 -0
  124. package/repo-template/.opencode/agents/model-router.md +38 -0
  125. package/repo-template/.opencode/agents/sdd-orchestrator.md +38 -0
  126. package/repo-template/.opencode/agents/sdd-spec-reviewer.md +38 -0
  127. package/repo-template/.opencode/agents/spec-intake-analyst.md +19 -0
  128. package/repo-template/.opencode/agents/tdd-engineer.md +38 -0
  129. package/repo-template/.opencode/commands/checkpoint.md +3 -0
  130. package/repo-template/.opencode/commands/eval-design.md +3 -0
  131. package/repo-template/.opencode/commands/maintainability-review.md +3 -0
  132. package/repo-template/.opencode/commands/quality-gate.md +3 -0
  133. package/repo-template/.opencode/commands/spec-escalate.md +9 -0
  134. package/repo-template/.opencode/commands/spec-intake.md +10 -0
  135. package/repo-template/.opencode/commands/spec-size.md +21 -0
  136. package/repo-template/.opencode/commands/trust-review.md +3 -0
  137. package/repo-template/.opencode/loops/ai-behavior-improvement.loop.md +15 -0
  138. package/repo-template/.opencode/loops/bug-repair.loop.md +16 -0
  139. package/repo-template/.opencode/loops/documentation-sync.loop.md +13 -0
  140. package/repo-template/.opencode/loops/feature-development.loop.md +25 -0
  141. package/repo-template/.opencode/skills/spec-complexity-classifier/SKILL.md +10 -0
  142. package/repo-template/.opencode/skills/spec-escalation-review/SKILL.md +10 -0
  143. package/repo-template/.opencode/skills/spec-intake/SKILL.md +10 -0
  144. package/repo-template/.pi/README.md +21 -0
  145. package/repo-template/.pi/prompts/checkpoint.md +11 -0
  146. package/repo-template/.pi/prompts/loop-run.md +10 -0
  147. package/repo-template/.pi/prompts/sdd-plan.md +11 -0
  148. package/repo-template/.pi/prompts/sdd-spec.md +13 -0
  149. package/repo-template/.pi/prompts/spec-escalate.md +9 -0
  150. package/repo-template/.pi/prompts/spec-intake.md +10 -0
  151. package/repo-template/.pi/prompts/spec-size.md +21 -0
  152. package/repo-template/.pi/skills/adapter-parity/SKILL.md +7 -0
  153. package/repo-template/.pi/skills/checkpoint/SKILL.md +7 -0
  154. package/repo-template/.pi/skills/eval-design/SKILL.md +3 -0
  155. package/repo-template/.pi/skills/evals/SKILL.md +7 -0
  156. package/repo-template/.pi/skills/loop-engineering/SKILL.md +7 -0
  157. package/repo-template/.pi/skills/maintainability-review/SKILL.md +3 -0
  158. package/repo-template/.pi/skills/quality-gate-review/SKILL.md +3 -0
  159. package/repo-template/.pi/skills/sdd/SKILL.md +7 -0
  160. package/repo-template/.pi/skills/spec-complexity-classifier/SKILL.md +10 -0
  161. package/repo-template/.pi/skills/spec-escalation-review/SKILL.md +10 -0
  162. package/repo-template/.pi/skills/spec-intake/SKILL.md +10 -0
  163. package/repo-template/.pi/skills/tdd/SKILL.md +7 -0
  164. package/repo-template/.pi/skills/trust-review/SKILL.md +3 -0
  165. package/repo-template/AGENT.md +8 -0
  166. package/repo-template/AGENTS.md +165 -0
  167. package/repo-template/CLAUDE.md +9 -0
  168. package/repo-template/GEMINI.md +9 -0
  169. package/repo-template/docs/ai/adapter-parity.md +135 -0
  170. package/repo-template/docs/ai/agent-workflow.md +45 -0
  171. package/repo-template/docs/ai/api.md +28 -0
  172. package/repo-template/docs/ai/architecture.md +53 -0
  173. package/repo-template/docs/ai/context-budget.md +54 -0
  174. package/repo-template/docs/ai/context-graph.md +39 -0
  175. package/repo-template/docs/ai/conventions.md +34 -0
  176. package/repo-template/docs/ai/decision-log.md +5 -0
  177. package/repo-template/docs/ai/enforcement.md +63 -0
  178. package/repo-template/docs/ai/eval-strategy.md +42 -0
  179. package/repo-template/docs/ai/evals.md +44 -0
  180. package/repo-template/docs/ai/git-workflow.md +35 -0
  181. package/repo-template/docs/ai/governance.md +61 -0
  182. package/repo-template/docs/ai/harness.md +49 -0
  183. package/repo-template/docs/ai/installer-cli.md +34 -0
  184. package/repo-template/docs/ai/loop-log.md +5 -0
  185. package/repo-template/docs/ai/loop-observability.md +57 -0
  186. package/repo-template/docs/ai/loop-policy.md +86 -0
  187. package/repo-template/docs/ai/loops.md +95 -0
  188. package/repo-template/docs/ai/maintainability-gates.md +26 -0
  189. package/repo-template/docs/ai/memory.md +71 -0
  190. package/repo-template/docs/ai/model-policy.md +105 -0
  191. package/repo-template/docs/ai/observability-runtime.md +48 -0
  192. package/repo-template/docs/ai/provider-routing.md +138 -0
  193. package/repo-template/docs/ai/quality-gates.md +48 -0
  194. package/repo-template/docs/ai/rollback-runtime.md +25 -0
  195. package/repo-template/docs/ai/security.md +12 -0
  196. package/repo-template/docs/ai/spec-driven-development.md +124 -0
  197. package/repo-template/docs/ai/spec-escalation.md +44 -0
  198. package/repo-template/docs/ai/spec-intake.md +46 -0
  199. package/repo-template/docs/ai/spec-sizing.md +207 -0
  200. package/repo-template/docs/ai/test-driven-development.md +35 -0
  201. package/repo-template/docs/ai/testing.md +28 -0
  202. package/repo-template/docs/ai/tool-adapters.md +186 -0
  203. package/repo-template/docs/ai/trust-allowlist.md +5 -0
  204. package/repo-template/docs/ai/trust-policy.md +41 -0
  205. package/repo-template/docs/ai/ui.md +17 -0
  206. package/repo-template/docs/skills/adapter-parity-review.md +46 -0
  207. package/repo-template/docs/skills/api-design.md +37 -0
  208. package/repo-template/docs/skills/architecture.md +37 -0
  209. package/repo-template/docs/skills/code-review.md +37 -0
  210. package/repo-template/docs/skills/context-graph.md +38 -0
  211. package/repo-template/docs/skills/debugging.md +37 -0
  212. package/repo-template/docs/skills/eval-design.md +12 -0
  213. package/repo-template/docs/skills/evals.md +37 -0
  214. package/repo-template/docs/skills/git-workflow.md +37 -0
  215. package/repo-template/docs/skills/look-trust-review.md +12 -0
  216. package/repo-template/docs/skills/loop-debugging.md +16 -0
  217. package/repo-template/docs/skills/loop-design.md +39 -0
  218. package/repo-template/docs/skills/loop-retrospective.md +15 -0
  219. package/repo-template/docs/skills/loop-review.md +16 -0
  220. package/repo-template/docs/skills/maintainability-review.md +12 -0
  221. package/repo-template/docs/skills/model-selection.md +36 -0
  222. package/repo-template/docs/skills/quality-gate-review.md +12 -0
  223. package/repo-template/docs/skills/spec-complexity-classifier.md +41 -0
  224. package/repo-template/docs/skills/spec-escalation-review.md +34 -0
  225. package/repo-template/docs/skills/spec-intake.md +25 -0
  226. package/repo-template/docs/skills/testing.md +37 -0
  227. package/repo-template/docs/skills/tool-adapter-sync.md +36 -0
  228. package/repo-template/docs/skills/ui-design.md +37 -0
  229. package/repo-template/docs/specs/README.md +9 -0
  230. package/repo-template/docs/specs/templates/basic-spec.md +41 -0
  231. package/repo-template/docs/specs/templates/complex-spec.md +145 -0
  232. package/repo-template/docs/specs/templates/standard-spec.md +58 -0
  233. package/repo-template/evals/README.md +11 -0
  234. package/repo-template/evals/golden/sample-golden.json +12 -0
  235. package/repo-template/evals/loop-regression/README.md +11 -0
  236. package/repo-template/evals/regression/sample-regression.json +12 -0
  237. package/repo-template/evals/schema/sample-schema.json +12 -0
  238. package/repo-template/evals/tool-calls/sample-tool-calls.json +12 -0
  239. package/repo-template/opencode.json.sample +29 -0
  240. package/repo-template/scripts/harness/backup.mjs +7 -0
  241. package/repo-template/scripts/harness/doctor.mjs +20 -0
  242. package/repo-template/scripts/harness/run-evals.mjs +27 -0
  243. package/repo-template/setup-agent-links.sh +54 -0
  244. package/scripts/check-published-release.mjs +127 -0
  245. package/scripts/check-release-commit.mjs +32 -0
  246. package/scripts/install.sh +225 -0
  247. package/scripts/installer-smoke-test.sh +155 -0
  248. package/scripts/lib/attribution-guard.mjs +59 -0
  249. package/scripts/registry-smoke-test.sh +149 -0
  250. package/scripts/smoke-test.sh +197 -0
  251. package/scripts/ux-smoke-test.sh +140 -0
  252. package/src/cli.js +625 -0
  253. package/src/doctor.js +68 -0
  254. package/src/global/adapter-context.js +27 -0
  255. package/src/global/adapter-matrix.js +38 -0
  256. package/src/global/adapters/claude.js +8 -0
  257. package/src/global/adapters/codex.js +8 -0
  258. package/src/global/adapters/cursor.js +8 -0
  259. package/src/global/adapters/opencode.js +8 -0
  260. package/src/global/agents.js +7 -0
  261. package/src/global/apply-confirmation.js +62 -0
  262. package/src/global/backups.js +54 -0
  263. package/src/global/brand/cli.js +52 -0
  264. package/src/global/brand/index.js +85 -0
  265. package/src/global/clack/setup-preview.js +48 -0
  266. package/src/global/clack/setup-wizard-constants.js +6 -0
  267. package/src/global/clack/setup-wizard.js +207 -0
  268. package/src/global/clack/theme.js +145 -0
  269. package/src/global/component-authoring.js +121 -0
  270. package/src/global/component-builders.js +43 -0
  271. package/src/global/component-distribution.js +270 -0
  272. package/src/global/component-installer.js +106 -0
  273. package/src/global/component-paths.js +22 -0
  274. package/src/global/component-registry.js +89 -0
  275. package/src/global/components/orchestrator.js +14 -0
  276. package/src/global/components/sdd-core.js +17 -0
  277. package/src/global/diff.js +233 -0
  278. package/src/global/drift.js +264 -0
  279. package/src/global/explain.js +144 -0
  280. package/src/global/global-cli.js +1145 -0
  281. package/src/global/global-doctor.js +67 -0
  282. package/src/global/global-installer.js +284 -0
  283. package/src/global/history.js +313 -0
  284. package/src/global/ink/run-setup-ink.js +77 -0
  285. package/src/global/ink/setup-app.js +278 -0
  286. package/src/global/ink/setup-routing.js +51 -0
  287. package/src/global/ink/setup-state.js +180 -0
  288. package/src/global/ink/terminal.js +13 -0
  289. package/src/global/json-output.js +22 -0
  290. package/src/global/load-component-catalog.js +41 -0
  291. package/src/global/load-workspace-component-catalog.js +123 -0
  292. package/src/global/managed-body.js +28 -0
  293. package/src/global/managed-config-adapter.js +134 -0
  294. package/src/global/managed-section.js +73 -0
  295. package/src/global/npm-registry.js +25 -0
  296. package/src/global/paths.js +22 -0
  297. package/src/global/policy.js +344 -0
  298. package/src/global/preflight.js +65 -0
  299. package/src/global/registry.js +79 -0
  300. package/src/global/report.js +110 -0
  301. package/src/global/rollback.js +126 -0
  302. package/src/global/setup.js +284 -0
  303. package/src/global/state-migration.js +65 -0
  304. package/src/global/state.js +50 -0
  305. package/src/global/status.js +94 -0
  306. package/src/global/sync.js +129 -0
  307. package/src/global/upgrade.js +145 -0
  308. package/src/harness-files.js +145 -0
  309. package/src/harness-updater.js +120 -0
  310. package/src/hash.js +5 -0
  311. package/src/manifest.js +36 -0
  312. package/src/project-detection.js +105 -0
  313. package/src/template-installer.js +72 -0
  314. package/src/text-template.js +24 -0
  315. package/src/workspace-cli.js +115 -0
@@ -0,0 +1,1145 @@
1
+ import { GLOBAL_AGENT_IDS, detectInstalledAdapters } from "./registry.js";
2
+ import { describeBundledComponentCatalog, describeWorkspaceComponentCatalog } from "./component-registry.js";
3
+ import { initWorkspaceComponent, validateWorkspaceComponentsCatalog } from "./component-authoring.js";
4
+ import { importWorkspaceComponent, packWorkspaceComponent } from "./component-distribution.js";
5
+ import { installGlobalHarness, uninstallGlobalHarness, updateGlobalHarness } from "./global-installer.js";
6
+ import { resolveHomeDir, harnessHomePaths } from "./paths.js";
7
+ import { runGlobalDoctorChecks } from "./global-doctor.js";
8
+ import { describeBackupSnapshots, applyRollback, previewRollback } from "./rollback.js";
9
+ import { buildAdapterMatrixReport } from "./adapter-matrix.js";
10
+ import { buildControlPlaneJson, printJson } from "./json-output.js";
11
+ import { runHarnessSetup } from "./setup.js";
12
+ import { buildStatusReport } from "./status.js";
13
+ import { runHarnessSync } from "./sync.js";
14
+ import { runHarnessUpgrade } from "./upgrade.js";
15
+ import { buildExplainJson, buildExplainReport } from "./explain.js";
16
+ import { buildDiffJson, buildDiffReport } from "./diff.js";
17
+ import {
18
+ applyPolicyToOptions,
19
+ buildPolicyJson,
20
+ formatPolicyProfileLabel,
21
+ formatPolicySourceLabel,
22
+ loadPolicyFile,
23
+ resetPolicyFile,
24
+ resolvePolicy,
25
+ savePolicyField
26
+ } from "./policy.js";
27
+ import {
28
+ buildCheckSnapshot,
29
+ formatHistoryEvent,
30
+ getHistoryPath,
31
+ readHistoryEvents,
32
+ readLastHistoryEvent,
33
+ recordPolicyHistory,
34
+ recordRollbackHistory,
35
+ recordSetupHistory,
36
+ recordSyncHistory,
37
+ recordUninstallHistory,
38
+ recordUpgradeHistory
39
+ } from "./history.js";
40
+ import { buildDiagnosticsReport, buildReportJson, DEFAULT_HISTORY_LIMIT, writeReportFile } from "./report.js";
41
+ import { BRAND, commandHeader } from "./brand/index.js";
42
+ import { formatCliCommand } from "./brand/cli.js";
43
+
44
+ export async function runGlobalInstall(options, packageManifest, packageRoot, { update = false } = {}) {
45
+ const homeDir = resolveHomeDir();
46
+ const workspaceRoot = options.cwd;
47
+ const run = update ? updateGlobalHarness : installGlobalHarness;
48
+ const result = await run({
49
+ packageRoot,
50
+ packageName: packageManifest.name,
51
+ cliVersion: packageManifest.version,
52
+ homeDir,
53
+ workspaceRoot,
54
+ agents: options.adapters,
55
+ components: options.components,
56
+ noDefaultComponents: options.noDefaultComponents,
57
+ dryRun: options.dryRun
58
+ });
59
+
60
+ printInstallResult(result, { update, dryRun: options.dryRun });
61
+ return result;
62
+ }
63
+
64
+ export async function runGlobalSetup(options, packageManifest, packageRoot) {
65
+ const homeDir = resolveHomeDir();
66
+ const preReport = await buildStatusReport(homeDir, { packageRoot, workspaceRoot: options.cwd });
67
+ const checksBefore = buildCheckSnapshot(preReport.counts);
68
+
69
+ const outcome = await runHarnessSetup({
70
+ packageRoot,
71
+ packageName: packageManifest.name,
72
+ cliVersion: packageManifest.version,
73
+ homeDir,
74
+ workspaceRoot: options.cwd,
75
+ agents: options.adapters,
76
+ components: options.components,
77
+ noDefaultComponents: options.noDefaultComponents,
78
+ dryRun: options.dryRun,
79
+ yes: options.yes,
80
+ confirm: options.confirm,
81
+ preflight: options.preflight,
82
+ preflightExplicit: options.preflightExplicit,
83
+ yesExplicit: options.yesExplicit,
84
+ confirmExplicit: options.confirmExplicit,
85
+ json: options.json,
86
+ interactive: options.interactive,
87
+ simple: options.simple
88
+ });
89
+
90
+ await recordSetupHistory(homeDir, {
91
+ cliVersion: packageManifest.version,
92
+ options,
93
+ outcome,
94
+ checksBefore,
95
+ packageRoot,
96
+ workspaceRoot: options.cwd
97
+ });
98
+
99
+ if (outcome.cancelled) return outcome;
100
+
101
+ if (!outcome.usedWizard) {
102
+ printInstallResult(outcome.result, { update: false, dryRun: options.dryRun, command: "setup" });
103
+ }
104
+ return outcome;
105
+ }
106
+
107
+ export async function runGlobalStatus(packageRoot, {
108
+ workspaceRoot = process.cwd(),
109
+ setExitCode = true,
110
+ json = false,
111
+ cliVersion = null
112
+ } = {}) {
113
+ const homeDir = resolveHomeDir();
114
+ const report = await buildStatusReport(homeDir, { packageRoot, workspaceRoot });
115
+
116
+ if (json) {
117
+ printJson(buildControlPlaneJson(report, { cliVersion }));
118
+ } else {
119
+ printStatusReport(report);
120
+ }
121
+
122
+ if (setExitCode && !report.ok) process.exitCode = 1;
123
+ return report;
124
+ }
125
+
126
+ export async function runGlobalSync(options, packageManifest, packageRoot) {
127
+ const homeDir = resolveHomeDir();
128
+ const preReport = await buildStatusReport(homeDir, { packageRoot, workspaceRoot: options.cwd });
129
+ const checksBefore = buildCheckSnapshot(preReport.counts);
130
+
131
+ const outcome = await runHarnessSync({
132
+ packageRoot,
133
+ packageName: packageManifest.name,
134
+ cliVersion: packageManifest.version,
135
+ homeDir,
136
+ workspaceRoot: options.cwd,
137
+ dryRun: options.dryRun,
138
+ yes: options.yes,
139
+ confirm: options.confirm,
140
+ preflight: options.preflight,
141
+ preflightExplicit: options.preflightExplicit,
142
+ yesExplicit: options.yesExplicit,
143
+ confirmExplicit: options.confirmExplicit,
144
+ json: options.json,
145
+ interactive: options.interactive
146
+ });
147
+
148
+ await recordSyncHistory(homeDir, {
149
+ cliVersion: packageManifest.version,
150
+ options,
151
+ outcome,
152
+ checksBefore,
153
+ packageRoot,
154
+ workspaceRoot: options.cwd
155
+ });
156
+
157
+ if (options.json) {
158
+ printJson(buildControlPlaneJson(outcome.report, {
159
+ cliVersion: packageManifest.version,
160
+ extras: buildSyncJsonExtras(outcome)
161
+ }));
162
+ if (!outcome.report.ok) process.exitCode = 1;
163
+ return outcome;
164
+ }
165
+
166
+ console.log(commandHeader("sync — converge local AI ecosystem"));
167
+
168
+ switch (outcome.action) {
169
+ case "setup-required":
170
+ console.log(`No managed state found. Run "${formatCliCommand("setup")}" first.`);
171
+ if (options.dryRun) console.log("Dry run: nothing was written.");
172
+ break;
173
+ case "noop":
174
+ console.log("Ecosystem already in sync. No changes needed.");
175
+ if (options.dryRun) console.log("Dry run: nothing was written.");
176
+ break;
177
+ case "plan":
178
+ printSyncRepairSummary(outcome.result, { dryRun: true });
179
+ break;
180
+ case "repaired":
181
+ printSyncRepairSummary(outcome.result, { dryRun: false });
182
+ break;
183
+ case "cancelled":
184
+ console.log("Sync cancelled. No changes were written.");
185
+ break;
186
+ default: {
187
+ const _exhaustive = outcome.action;
188
+ throw new Error(`Unknown sync action: ${_exhaustive}`);
189
+ }
190
+ }
191
+
192
+ console.log("");
193
+ printStatusReport(outcome.report);
194
+ if (!outcome.report.ok) process.exitCode = 1;
195
+ return outcome;
196
+ }
197
+
198
+ export async function runGlobalUpgrade(options, packageManifest, packageRoot) {
199
+ const homeDir = resolveHomeDir();
200
+ const preReport = await buildStatusReport(homeDir, { packageRoot, workspaceRoot: options.cwd });
201
+ const checksBefore = buildCheckSnapshot(preReport.counts);
202
+
203
+ const outcome = await runHarnessUpgrade({
204
+ packageRoot,
205
+ packageName: packageManifest.name,
206
+ cliVersion: packageManifest.version,
207
+ homeDir,
208
+ workspaceRoot: options.cwd,
209
+ dryRun: options.dryRun,
210
+ yes: options.yes,
211
+ confirm: options.confirm,
212
+ preflight: options.preflight,
213
+ preflightExplicit: options.preflightExplicit,
214
+ yesExplicit: options.yesExplicit,
215
+ confirmExplicit: options.confirmExplicit,
216
+ json: options.json,
217
+ interactive: options.interactive
218
+ });
219
+
220
+ await recordUpgradeHistory(homeDir, {
221
+ cliVersion: packageManifest.version,
222
+ options,
223
+ outcome,
224
+ checksBefore,
225
+ packageRoot,
226
+ workspaceRoot: options.cwd
227
+ });
228
+
229
+ if (outcome.cancelled) {
230
+ console.log(commandHeader("upgrade — preview or apply managed ecosystem updates"));
231
+ console.log("Upgrade cancelled. No changes were written.");
232
+ return outcome;
233
+ }
234
+
235
+ console.log(commandHeader("upgrade — preview or apply managed ecosystem updates"));
236
+ console.log(`Installed CLI: ${outcome.installedVersion}`);
237
+ console.log(`Published latest: ${outcome.latestVersion}`);
238
+ console.log("");
239
+
240
+ if (outcome.dryRun) {
241
+ console.log("Preview only. No configs or ~/.harness state were modified.");
242
+ console.log(`Run latest package preview: ${outcome.previewCommand}`);
243
+ console.log(`Apply with latest package: ${outcome.latestCommand}`);
244
+ console.log("");
245
+ printInstallResult(outcome.result, { update: true, dryRun: true, command: "upgrade" });
246
+ return outcome;
247
+ }
248
+
249
+ console.log("Applied upgrade with the current CLI package.");
250
+ console.log(`To converge with npm latest, run: ${outcome.latestCommand}`);
251
+ console.log("");
252
+ printInstallResult(outcome.result, { update: true, dryRun: false, command: "upgrade" });
253
+ return outcome;
254
+ }
255
+
256
+ function buildSyncJsonExtras(outcome) {
257
+ const extras = {
258
+ action: outcome.action,
259
+ wrote: outcome.wrote
260
+ };
261
+
262
+ if (!outcome.result) return extras;
263
+
264
+ return {
265
+ ...extras,
266
+ driftDetected: outcome.result.driftDetected,
267
+ assetsRepaired: outcome.result.assetsRepaired,
268
+ assetsUnchanged: outcome.result.assetsUnchanged,
269
+ configsRepaired: outcome.result.configsRepaired,
270
+ repairs: outcome.result.repairs ?? []
271
+ };
272
+ }
273
+
274
+ function printStatusReport(report) {
275
+ console.log(commandHeader("status — local AI ecosystem"));
276
+ console.log(`Home: ${report.homeDir}`);
277
+ console.log(`State root: ${report.stateRoot}`);
278
+ console.log(
279
+ report.state
280
+ ? `State: installed (cliVersion=${report.state.cliVersion ?? "unknown"})`
281
+ : "State: missing"
282
+ );
283
+ console.log("");
284
+
285
+ console.log("Agents:");
286
+ for (const agent of report.agents) {
287
+ const detected = agent.detected ? "detected" : "not detected";
288
+ const managed = agent.managed ? "managed" : "unmanaged";
289
+ console.log(` ${agent.id.padEnd(10)} ${detected.padEnd(13)} ${managed}`);
290
+ }
291
+
292
+ console.log("");
293
+ console.log("Components:");
294
+ if (report.components.length === 0) {
295
+ console.log(" none");
296
+ } else {
297
+ for (const component of report.components) {
298
+ console.log(
299
+ ` ${component.id.padEnd(14)} ${String(component.version).padEnd(8)} ${component.status}`
300
+ );
301
+ }
302
+ }
303
+
304
+ console.log("");
305
+ console.log("Policy:");
306
+ console.log(` Source: ${formatPolicySourceLabel(report.policy)}`);
307
+ console.log(` Profile: ${formatPolicyProfileLabel(report.policy.profile)}`);
308
+ console.log(` Apply mode: ${report.policy.applyMode}`);
309
+ console.log(` Preflight: ${report.policy.preflight ? "enabled" : "disabled"}`);
310
+ console.log(` Agents: ${report.policy.agents}`);
311
+ console.log(` Components: ${report.policy.components.join(", ") || "none"}`);
312
+ console.log("");
313
+ console.log(`Checks: ok=${report.counts.ok} missing=${report.counts.missing} stale=${report.counts.stale} warning=${report.counts.warning}`);
314
+ console.log(`Backups: ${report.backups} snapshot(s)`);
315
+ console.log(`Overall: ${report.overall.toUpperCase()}`);
316
+ console.log(`Next: ${report.nextAction}`);
317
+ }
318
+
319
+ function printSyncRepairSummary(result, { dryRun = false } = {}) {
320
+ console.log(dryRun ? "Planned repairs:" : "Applied repairs:");
321
+ console.log(` Drift detected: ${result.driftDetected ? "yes" : "no"}`);
322
+ console.log(` Assets repaired: ${result.assetsRepaired.length}`);
323
+ console.log(` Assets unchanged: ${result.assetsUnchanged.length}`);
324
+ console.log(` Sections repaired: ${result.configsRepaired.length}`);
325
+ console.log(`${dryRun ? "Backups planned" : "Backups"}: ${result.backups.length}`);
326
+
327
+ if (dryRun && result.repairs?.length) {
328
+ for (const repair of result.repairs) {
329
+ console.log(` - [${repair.status.toUpperCase()}] ${repair.name}`);
330
+ }
331
+ }
332
+
333
+ if (dryRun) {
334
+ console.log("Dry run: nothing was written.");
335
+ }
336
+ }
337
+
338
+ function printInstallResult(result, { update = false, dryRun = false, command = null } = {}) {
339
+ const verb = update ? "update" : (command === "setup" ? "setup" : "install");
340
+ const pastLabel = update ? "updated" : (command === "setup" ? "configured" : "installed");
341
+ console.log(`${BRAND.displayName} global ${dryRun ? `${verb} plan` : pastLabel} (scope: agent-global)`);
342
+ console.log(`State root: ${result.stateRoot}`);
343
+ console.log(`Agents: ${result.agents.join(", ")}`);
344
+ console.log(`Components: ${result.components.join(", ") || "none (core plumbing only)"}`);
345
+ console.log(`Core files: ${result.coreFiles.join(", ") || "none"}`);
346
+
347
+ if (update) {
348
+ console.log(`Drift detected: ${result.driftDetected ? "yes" : "no"}`);
349
+ console.log(`Assets repaired: ${result.assetsRepaired.length}`);
350
+ console.log(`Assets unchanged: ${result.assetsUnchanged.length}`);
351
+ console.log(`Sections repaired: ${result.configsRepaired.length}`);
352
+ }
353
+
354
+ console.log(`Configs created: ${result.configsCreated.length}`);
355
+ console.log(`Configs updated: ${result.configsUpdated.length}`);
356
+ console.log(`Configs unchanged: ${result.configsUnchanged.length}`);
357
+ console.log(`${dryRun ? "Backups planned" : "Backups"}: ${result.backups.length}`);
358
+
359
+ if (dryRun) {
360
+ if (result.repairs?.length) {
361
+ console.log(`Planned repairs: ${result.repairs.length}`);
362
+ for (const repair of result.repairs) {
363
+ console.log(` - [${repair.status.toUpperCase()}] ${repair.name}`);
364
+ }
365
+ }
366
+ console.log("Dry run: nothing was written.");
367
+ return;
368
+ }
369
+
370
+ console.log(`State tracked in ~/.harness/state.json. Run "${formatCliCommand("status")}" or "${formatCliCommand("doctor")}" to verify.`);
371
+ }
372
+
373
+ export async function runGlobalUninstall(options, packageManifest) {
374
+ const homeDir = resolveHomeDir();
375
+ const result = await uninstallGlobalHarness({
376
+ homeDir,
377
+ dryRun: options.dryRun
378
+ });
379
+
380
+ await recordUninstallHistory(homeDir, {
381
+ cliVersion: packageManifest?.version ?? null,
382
+ options,
383
+ result
384
+ });
385
+
386
+ console.log(`${BRAND.displayName} global ${options.dryRun ? "uninstall plan" : "uninstalled"} (scope: agent-global)`);
387
+ console.log(`Configs cleaned: ${result.configsCleaned.join(", ") || "none"}`);
388
+ console.log(`Backups: ${result.backups.length}`);
389
+ console.log(`State removed: ${result.stateRemoved ? "yes" : "no state found"}`);
390
+ console.log("Backups under ~/.harness/backups were preserved.");
391
+ }
392
+
393
+ export async function runGlobalDoctor(packageRoot, {
394
+ workspaceRoot = process.cwd(),
395
+ json = false,
396
+ cliVersion = null
397
+ } = {}) {
398
+ const homeDir = resolveHomeDir();
399
+
400
+ if (json) {
401
+ const report = await buildStatusReport(homeDir, { packageRoot, workspaceRoot });
402
+ printJson(buildControlPlaneJson(report, { cliVersion }));
403
+ if (!report.ok) process.exitCode = 1;
404
+ return report;
405
+ }
406
+
407
+ const { checks, ok, hasDrift } = await runGlobalDoctorChecks(homeDir, { packageRoot, workspaceRoot });
408
+
409
+ console.log(`${BRAND.displayName} doctor (scope: agent-global)`);
410
+ console.log(`Home: ${homeDir}`);
411
+ console.log("");
412
+
413
+ for (const check of checks) {
414
+ const label = check.status.toUpperCase().padEnd(8);
415
+ const detail = check.detail ? ` — ${check.detail}` : "";
416
+ console.log(`[${label}] ${check.name}${detail}`);
417
+ }
418
+
419
+ console.log("");
420
+ if (ok) {
421
+ console.log("Status: OK");
422
+ } else if (hasDrift) {
423
+ console.log(`Status: DRIFT DETECTED — run "${formatCliCommand("sync")}" to auto-repair managed content`);
424
+ } else {
425
+ console.log("Status: FAILED (missing managed state or configs)");
426
+ }
427
+
428
+ if (!ok) process.exitCode = 1;
429
+ }
430
+
431
+ export async function runGlobalAdapters({ json = false, cliVersion = null } = {}) {
432
+ const homeDir = resolveHomeDir();
433
+ const report = await buildAdapterMatrixReport(homeDir);
434
+
435
+ if (json) {
436
+ printJson({
437
+ adapters: report.adapters,
438
+ managedCount: report.managedCount,
439
+ detectedCount: report.detectedCount,
440
+ supportedCount: report.supportedCount,
441
+ cliVersion
442
+ });
443
+ return report;
444
+ }
445
+
446
+ printAdapterMatrixReport(report);
447
+ return report;
448
+ }
449
+
450
+ export async function runGlobalExplain({ json = false, cliVersion = null } = {}) {
451
+ const homeDir = resolveHomeDir();
452
+ const report = await buildExplainReport(homeDir);
453
+
454
+ if (json) {
455
+ printJson(buildExplainJson(report, { cliVersion }));
456
+ return report;
457
+ }
458
+
459
+ printExplainReport(report);
460
+ return report;
461
+ }
462
+
463
+ function printExplainReport(report) {
464
+ console.log(commandHeader("explain — managed ecosystem audit (read-only)"));
465
+ console.log(`Home: ${report.homeDir}`);
466
+ console.log(`State root: ${report.stateRoot}`);
467
+ console.log("");
468
+
469
+ console.log("Managed markers:");
470
+ console.log(` start: ${report.markers.start}`);
471
+ console.log(` end: ${report.markers.end}`);
472
+ console.log("");
473
+
474
+ console.log("Policy:");
475
+ console.log(` Source: ${formatPolicySourceLabel(report.policy)}`);
476
+ console.log(` Profile: ${formatPolicyProfileLabel(report.policy.profile)}`);
477
+ console.log(` Apply mode: ${report.policy.applyMode}`);
478
+ console.log(` Preflight: ${report.policy.preflight ? "enabled" : "disabled"}`);
479
+ console.log(` Agents: ${report.policy.agents}`);
480
+ console.log(` Components: ${report.policy.components.join(", ") || "none"}`);
481
+ console.log(` File: ${report.policy.path}`);
482
+ console.log("");
483
+
484
+ console.log("Adapters:");
485
+ for (const adapter of report.adapters) {
486
+ const detected = adapter.detected ? "detected" : "not detected";
487
+ const managed = adapter.managed ? "managed" : "unmanaged";
488
+ console.log(` ${adapter.id.padEnd(10)} ${detected.padEnd(13)} ${managed}`);
489
+ }
490
+
491
+ console.log("");
492
+ console.log(`${BRAND.displayName} writes to:`);
493
+ for (const target of report.writesTo) {
494
+ console.log(` - ~/${target.replace(/^\//, "")}`);
495
+ }
496
+
497
+ console.log("");
498
+ console.log("Config files:");
499
+ if (report.configFiles.length === 0) {
500
+ console.log(" none (run setup to configure managed sections)");
501
+ } else {
502
+ for (const file of report.configFiles) {
503
+ const managedLabel = file.managed ? "managed" : "unmanaged";
504
+ const sectionLabel = file.hasManagedSection ? "has managed section" : "no managed section";
505
+ console.log(` ${file.path} — ${managedLabel}, ${sectionLabel}`);
506
+
507
+ if (file.hasPreservedUserContent) {
508
+ console.log(" user-owned preserved: yes");
509
+ } else if (file.exists && file.hasManagedSection) {
510
+ console.log(" user-owned preserved: no (managed markers only)");
511
+ }
512
+ }
513
+ }
514
+
515
+ console.log("");
516
+ console.log("Components:");
517
+ if (report.components.length === 0) {
518
+ console.log(" none");
519
+ } else {
520
+ for (const component of report.components) {
521
+ console.log(
522
+ ` ${component.id.padEnd(14)} ${String(component.version).padEnd(8)} ${component.source} -> ~/.harness/${component.assetDir}`
523
+ );
524
+ }
525
+ }
526
+
527
+ console.log("");
528
+ console.log("Backups:");
529
+ if (report.backups.length === 0) {
530
+ console.log(" none");
531
+ } else {
532
+ for (const snapshot of report.backups) {
533
+ console.log(` - ${snapshot.name} (${snapshot.fileCount} file${snapshot.fileCount === 1 ? "" : "s"})`);
534
+ }
535
+ }
536
+
537
+ console.log("");
538
+ console.log(`Next: ${report.nextAction}`);
539
+ }
540
+
541
+ export async function runGlobalReport({
542
+ packageManifest,
543
+ packageRoot,
544
+ json = false,
545
+ workspaceRoot = process.cwd(),
546
+ historyLimit = null,
547
+ outPath = null
548
+ } = {}) {
549
+ const homeDir = resolveHomeDir();
550
+ const limit = historyLimit ?? DEFAULT_HISTORY_LIMIT;
551
+ const report = await buildDiagnosticsReport(homeDir, {
552
+ packageRoot,
553
+ packageName: packageManifest.name,
554
+ cliVersion: packageManifest.version,
555
+ workspaceRoot,
556
+ historyLimit: limit
557
+ });
558
+
559
+ if (json) {
560
+ const payload = buildReportJson(report);
561
+ if (outPath) {
562
+ await writeReportFile(outPath, `${JSON.stringify(payload)}\n`);
563
+ console.log(`Diagnostics report written to: ${outPath}`);
564
+ } else {
565
+ printJson(payload);
566
+ }
567
+ if (!report.ok) process.exitCode = 1;
568
+ return report;
569
+ }
570
+
571
+ const text = formatDiagnosticsReport(report);
572
+ if (outPath) {
573
+ await writeReportFile(outPath, text);
574
+ console.log(`Diagnostics report written to: ${outPath}`);
575
+ } else {
576
+ console.log(text);
577
+ }
578
+
579
+ if (!report.ok) process.exitCode = 1;
580
+ return report;
581
+ }
582
+
583
+ function formatDiagnosticsReport(report) {
584
+ const lines = [];
585
+
586
+ lines.push(commandHeader("report — local diagnostics (read-only)"));
587
+ lines.push(`CLI version: ${report.cliVersion}`);
588
+ lines.push(`Home: ${report.homeDir}`);
589
+ lines.push("");
590
+
591
+ lines.push("Adapters:");
592
+ lines.push(
593
+ ` Supported: ${report.adapters.supportedCount} Detected: ${report.adapters.detectedCount} Managed: ${report.adapters.managedCount}`
594
+ );
595
+ for (const adapter of report.adapters.adapters) {
596
+ const detected = adapter.detected ? "detected" : "not detected";
597
+ const managed = adapter.managed ? "managed" : "unmanaged";
598
+ lines.push(` ${adapter.id.padEnd(10)} ${detected.padEnd(13)} ${managed}`);
599
+ }
600
+ lines.push("");
601
+
602
+ lines.push("Policy:");
603
+ lines.push(` Source: ${formatPolicySourceLabel(report.policy)}`);
604
+ lines.push(` Profile: ${formatPolicyProfileLabel(report.policy.profile)}`);
605
+ lines.push(` Apply mode: ${report.policy.applyMode}`);
606
+ lines.push(` Preflight: ${report.policy.preflight ? "enabled" : "disabled"}`);
607
+ lines.push(` Agents: ${report.policy.agents}`);
608
+ lines.push(` Components: ${report.policy.components.join(", ") || "none"}`);
609
+ lines.push("");
610
+
611
+ lines.push("Status:");
612
+ lines.push(` Overall: ${report.status.overall.toUpperCase()}`);
613
+ lines.push(
614
+ report.status.installed
615
+ ? ` State: installed (cliVersion=${report.status.stateCliVersion ?? "unknown"})`
616
+ : " State: missing"
617
+ );
618
+ lines.push(
619
+ ` Checks: ok=${report.status.counts.ok} missing=${report.status.counts.missing} stale=${report.status.counts.stale} warning=${report.status.counts.warning}`
620
+ );
621
+ lines.push(` Backups: ${report.status.backups} snapshot(s)`);
622
+ lines.push(` Next: ${report.status.nextAction}`);
623
+ lines.push("");
624
+
625
+ lines.push("Diff:");
626
+ lines.push(` Summary: ${report.diff.summary}`);
627
+ if (report.diff.hasChanges) {
628
+ lines.push(` Planned changes: ${report.diff.changeCount}`);
629
+ for (const change of report.diff.changes) {
630
+ lines.push(` [${change.status}] ${change.kind} ${change.action} -> ${change.target}`);
631
+ }
632
+ } else {
633
+ lines.push(" Drift: none");
634
+ }
635
+ lines.push(` Next: ${report.diff.nextAction}`);
636
+ lines.push("");
637
+
638
+ lines.push(`History (last ${report.history.limit} events):`);
639
+ lines.push(` File: ${report.history.path}`);
640
+ for (const warning of report.history.warnings) {
641
+ lines.push(` Warning: skipped invalid history line ${warning.line}: ${warning.message}`);
642
+ }
643
+ if (report.history.events.length === 0) {
644
+ lines.push(" No managed operations recorded yet.");
645
+ } else {
646
+ for (const event of report.history.events) {
647
+ lines.push(` ${formatHistoryEvent(event)}`);
648
+ }
649
+ }
650
+
651
+ return `${lines.join("\n")}\n`;
652
+ }
653
+
654
+ export async function runGlobalDiff({
655
+ packageManifest,
656
+ packageRoot,
657
+ json = false,
658
+ workspaceRoot = process.cwd()
659
+ } = {}) {
660
+ const homeDir = resolveHomeDir();
661
+ const report = await buildDiffReport(homeDir, {
662
+ packageRoot,
663
+ packageName: packageManifest.name,
664
+ cliVersion: packageManifest.version,
665
+ workspaceRoot
666
+ });
667
+
668
+ if (json) {
669
+ printJson(buildDiffJson(report, { cliVersion: packageManifest.version }));
670
+ return report;
671
+ }
672
+
673
+ printDiffReport(report);
674
+ return report;
675
+ }
676
+
677
+ function printDiffReport(report) {
678
+ console.log(commandHeader("diff — managed content preview (read-only)"));
679
+ console.log(`Home: ${report.homeDir}`);
680
+ console.log(`Summary: ${report.summary}`);
681
+ console.log("");
682
+
683
+ if (!report.installed) {
684
+ console.log(`Next: ${report.nextAction}`);
685
+ return;
686
+ }
687
+
688
+ if (!report.hasChanges) {
689
+ console.log("Managed changes: none");
690
+ console.log("");
691
+ if (report.preserved.length > 0) {
692
+ console.log("User-owned preserved content:");
693
+ for (const entry of report.preserved) {
694
+ console.log(` ${entry.path} — intact`);
695
+ }
696
+ console.log("");
697
+ }
698
+ console.log(`Next: ${report.nextAction}`);
699
+ return;
700
+ }
701
+
702
+ console.log("Planned managed changes:");
703
+ for (const change of report.changes) {
704
+ console.log(
705
+ ` [${change.status}] ${change.kind} ${change.action} -> ${change.target}`
706
+ );
707
+ console.log(` ${change.detail}`);
708
+ }
709
+
710
+ console.log("");
711
+ if (report.preserved.length > 0) {
712
+ console.log("User-owned preserved content (outside managed markers):");
713
+ for (const entry of report.preserved) {
714
+ console.log(` ${entry.path} — intact`);
715
+ }
716
+ console.log("");
717
+ } else {
718
+ console.log("User-owned preserved content: none detected in affected configs.");
719
+ console.log("");
720
+ }
721
+
722
+ console.log(`Next: ${report.nextAction}`);
723
+ }
724
+
725
+ function printAdapterMatrixReport(report) {
726
+ console.log(commandHeader("adapters — supported agent integrations"));
727
+ console.log(`Home: ${report.homeDir}`);
728
+ console.log("");
729
+ console.log(`${BRAND.displayName} does not install Cursor, Codex, OpenCode, or Claude Code.`);
730
+ console.log("It configures managed sections in each agent's config files.");
731
+ console.log("");
732
+ console.log(`Supported: ${report.supportedCount} Detected: ${report.detectedCount} Managed: ${report.managedCount}`);
733
+ console.log("");
734
+
735
+ for (const adapter of report.adapters) {
736
+ const detected = adapter.detected ? "detected" : "not detected";
737
+ const managed = adapter.managed ? "managed" : "unmanaged";
738
+ console.log(`${adapter.id.padEnd(10)} ${adapter.label.padEnd(12)} ${detected.padEnd(13)} ${managed}`);
739
+ console.log(` root: ~/${adapter.rootDir}`);
740
+ console.log(` config: ~/${adapter.configFile}`);
741
+ console.log(` targets: ${adapter.managedTargets.join(", ")}`);
742
+ console.log("");
743
+ }
744
+ }
745
+
746
+ export function printGlobalDetect() {
747
+ const homeDir = resolveHomeDir();
748
+ const detected = detectInstalledAdapters({ homeDir });
749
+
750
+ console.log("Global agents (scope: agent-global)");
751
+ console.log(`Home: ${homeDir}`);
752
+ console.log(`Detected: ${detected.join(", ") || "none"}`);
753
+ console.log(`Supported: ${GLOBAL_AGENT_IDS.join(", ")}`);
754
+ }
755
+
756
+ export function printGlobalComponents({ workspaceRoot = process.cwd() } = {}) {
757
+ const bundled = describeBundledComponentCatalog();
758
+ const workspace = describeWorkspaceComponentCatalog(workspaceRoot);
759
+
760
+ console.log(commandHeader("components (scope: agent-global)"));
761
+ console.log(`Bundled: ${bundled.length}`);
762
+
763
+ for (const component of bundled) {
764
+ printComponentEntry(component);
765
+ }
766
+
767
+ console.log("");
768
+ console.log(`Workspace: ${workspace.length}`);
769
+
770
+ if (workspace.length === 0) {
771
+ console.log("No workspace catalog at .harness/components/catalog.json");
772
+ return;
773
+ }
774
+
775
+ for (const component of workspace) {
776
+ printComponentEntry(component, { workspace: true });
777
+ }
778
+ }
779
+
780
+ function printComponentEntry(component, { workspace = false } = {}) {
781
+ const defaultLabel = workspace ? "workspace" : (component.defaultEnabled ? "default" : "optional");
782
+ console.log("");
783
+ console.log(`${component.id} (${component.version}) [${defaultLabel}]`);
784
+ console.log(` Label: ${component.label}`);
785
+ console.log(` Assets: ${component.assetFiles.join(", ")}`);
786
+
787
+ if (component.instructions) {
788
+ console.log(` Instructions: ${component.instructions}`);
789
+ }
790
+
791
+ if (component.adapterHints.length > 0) {
792
+ console.log(` Adapter hints: ${component.adapterHints.join(", ")}`);
793
+ }
794
+ }
795
+
796
+ export function runComponentsValidate({ workspaceRoot = process.cwd() } = {}) {
797
+ const result = validateWorkspaceComponentsCatalog(workspaceRoot);
798
+
799
+ console.log("Workspace component catalog is valid");
800
+ console.log(`Catalog: .harness/components/catalog.json`);
801
+ console.log(`Components: ${result.components.length}`);
802
+
803
+ for (const component of result.components) {
804
+ console.log(`- ${component.id} (${component.version}) — ${component.assetFiles.join(", ")}`);
805
+ }
806
+ }
807
+
808
+ export async function runComponentsInit(options) {
809
+ const result = await initWorkspaceComponent({
810
+ workspaceRoot: options.cwd,
811
+ id: options.componentId,
812
+ label: options.label
813
+ });
814
+
815
+ console.log("Workspace component created");
816
+ console.log(`Id: ${result.entry.id}`);
817
+ console.log(`Label: ${result.entry.label}`);
818
+ console.log(`Version: ${result.entry.version}`);
819
+ console.log(`Catalog: .harness/components/catalog.json`);
820
+ console.log(`Asset: .harness/components/${result.entry.id}/README.md`);
821
+ console.log("");
822
+ console.log("Next:");
823
+ console.log(` 1. Edit .harness/components/${result.entry.id}/README.md`);
824
+ console.log(` 2. ${formatCliCommand("components validate")}`);
825
+ console.log(` 3. ${formatCliCommand(`install --components ${result.entry.id}`)}`);
826
+ }
827
+
828
+ export async function runComponentsPack(options) {
829
+ const result = await packWorkspaceComponent({
830
+ workspaceRoot: options.cwd,
831
+ id: options.componentId,
832
+ outPath: options.outPath
833
+ });
834
+
835
+ console.log("Workspace component packed");
836
+ console.log(`Id: ${result.entry.id}`);
837
+ console.log(`Version: ${result.entry.version}`);
838
+ console.log(`Bundle: ${result.outPath}`);
839
+ console.log(`Assets: ${result.entry.assetFiles.join(", ")}`);
840
+ }
841
+
842
+ export async function runComponentsImport(options) {
843
+ const result = await importWorkspaceComponent({
844
+ workspaceRoot: options.cwd,
845
+ bundlePath: options.bundlePath
846
+ });
847
+
848
+ console.log("Workspace component imported");
849
+ console.log(`Id: ${result.entry.id}`);
850
+ console.log(`Label: ${result.entry.label}`);
851
+ console.log(`Version: ${result.entry.version}`);
852
+ console.log(`Catalog: .harness/components/catalog.json`);
853
+ console.log(`Assets: ${result.entry.assetFiles.map((asset) => `.harness/components/${result.entry.id}/${asset}`).join(", ")}`);
854
+ console.log("");
855
+ console.log("Next:");
856
+ console.log(` 1. ${formatCliCommand("components validate")}`);
857
+ console.log(` 2. ${formatCliCommand(`install --components ${result.entry.id}`)}`);
858
+ }
859
+
860
+ export async function runGlobalBackups() {
861
+ const homeDir = resolveHomeDir();
862
+ const { backupsDir } = harnessHomePaths(homeDir);
863
+ const snapshots = await describeBackupSnapshots(backupsDir);
864
+
865
+ console.log(commandHeader("backups"));
866
+ console.log("Directory: ~/.harness/backups");
867
+ console.log(`Snapshots: ${snapshots.length}`);
868
+
869
+ if (snapshots.length === 0) {
870
+ console.log("No snapshots yet. Backups are created before config changes.");
871
+ return;
872
+ }
873
+
874
+ for (const snapshot of snapshots) {
875
+ console.log(`- ${snapshot.name} (${snapshot.fileCount} file${snapshot.fileCount === 1 ? "" : "s"})`);
876
+ }
877
+ }
878
+
879
+ export async function runGlobalHistory(options, packageManifest) {
880
+ const homeDir = resolveHomeDir();
881
+ const historyPath = getHistoryPath(homeDir);
882
+ const query = {
883
+ command: options.historyCommand ?? null,
884
+ action: options.historyEventAction ?? null,
885
+ limit: options.limit
886
+ };
887
+
888
+ if (options.historyAction === "last") {
889
+ const { event, warnings } = await readLastHistoryEvent(homeDir, query);
890
+ printHistoryWarnings(warnings);
891
+
892
+ if (options.json) {
893
+ printJson({
894
+ path: historyPath,
895
+ event,
896
+ warnings,
897
+ cliVersion: packageManifest?.version ?? null
898
+ });
899
+ return { event, warnings };
900
+ }
901
+
902
+ console.log(commandHeader("history last — most recent managed operation"));
903
+ console.log(`Home: ${homeDir}`);
904
+ console.log(`File: ${historyPath}`);
905
+ printHistoryFiltersLabel(query);
906
+
907
+ if (!event) {
908
+ console.log("No managed operations recorded yet.");
909
+ return { event: null, warnings };
910
+ }
911
+
912
+ console.log("");
913
+ console.log(formatHistoryEvent(event));
914
+ printHistoryEventDetails(event);
915
+ return { event, warnings };
916
+ }
917
+
918
+ const { events, warnings } = await readHistoryEvents(homeDir, query);
919
+ printHistoryWarnings(warnings);
920
+
921
+ if (options.json) {
922
+ printJson({
923
+ path: historyPath,
924
+ events,
925
+ warnings,
926
+ filters: buildHistoryFiltersJson(query),
927
+ cliVersion: packageManifest?.version ?? null
928
+ });
929
+ return { events, warnings };
930
+ }
931
+
932
+ console.log(commandHeader("history — local operation audit log"));
933
+ console.log(`Home: ${homeDir}`);
934
+ console.log(`File: ${historyPath}`);
935
+ console.log(`Events: ${events.length}`);
936
+ printHistoryFiltersLabel(query);
937
+
938
+ if (events.length === 0) {
939
+ console.log("No managed operations recorded yet.");
940
+ return { events, warnings };
941
+ }
942
+
943
+ console.log("");
944
+ for (const event of events) {
945
+ console.log(formatHistoryEvent(event));
946
+ }
947
+
948
+ return { events, warnings };
949
+ }
950
+
951
+ function printHistoryWarnings(warnings) {
952
+ for (const warning of warnings) {
953
+ console.warn(`Warning: skipped invalid history line ${warning.line}: ${warning.message}`);
954
+ }
955
+ }
956
+
957
+ function buildHistoryFiltersJson({ command, action, limit }) {
958
+ const filters = {};
959
+ if (command) filters.command = command;
960
+ if (action) filters.action = action;
961
+ if (limit != null) filters.limit = limit;
962
+ return Object.keys(filters).length > 0 ? filters : null;
963
+ }
964
+
965
+ function printHistoryFiltersLabel({ command, action, limit }) {
966
+ const parts = [];
967
+ if (command) parts.push(`command=${command}`);
968
+ if (action) parts.push(`action=${action}`);
969
+ if (limit != null) parts.push(`limit=${limit}`);
970
+ if (parts.length > 0) {
971
+ console.log(`Filters: ${parts.join(", ")}`);
972
+ }
973
+ }
974
+
975
+ function printHistoryEventDetails(event) {
976
+ console.log(` wrote: ${event.wrote ? "yes" : "no"}`);
977
+ console.log(` cliVersion: ${event.cliVersion ?? "unknown"}`);
978
+
979
+ if (event.consentSource) {
980
+ console.log(` consent: ${event.consentSource}`);
981
+ }
982
+
983
+ if (Array.isArray(event.backupsCreated) && event.backupsCreated.length > 0) {
984
+ console.log(` backups: ${event.backupsCreated.join(", ")}`);
985
+ }
986
+
987
+ if (Array.isArray(event.snapshotsUsed) && event.snapshotsUsed.length > 0) {
988
+ console.log(` snapshots: ${event.snapshotsUsed.join(", ")}`);
989
+ }
990
+ }
991
+
992
+ export async function runGlobalRollback(options, packageManifest) {
993
+ if (!options.snapshot) {
994
+ throw new Error(`Missing snapshot. Use: ${formatCliCommand("rollback --to <snapshot>")}`);
995
+ }
996
+
997
+ const homeDir = resolveHomeDir();
998
+
999
+ if (options.apply) {
1000
+ const result = await applyRollback({ homeDir, snapshot: options.snapshot });
1001
+
1002
+ await recordRollbackHistory(homeDir, {
1003
+ cliVersion: packageManifest?.version ?? null,
1004
+ snapshot: options.snapshot,
1005
+ result
1006
+ });
1007
+
1008
+ console.log(commandHeader("rollback applied"));
1009
+ console.log(`Snapshot: ${result.snapshot}`);
1010
+ console.log(`Restored: ${result.restored.length}`);
1011
+
1012
+ if (result.noop) {
1013
+ console.log("No files to restore.");
1014
+ return;
1015
+ }
1016
+
1017
+ if (result.safetyBackup) {
1018
+ console.log(`Safety backup: ${result.safetyBackup}`);
1019
+ }
1020
+ return;
1021
+ }
1022
+
1023
+ const result = await previewRollback({ homeDir, snapshot: options.snapshot });
1024
+
1025
+ console.log(commandHeader("rollback preview"));
1026
+ console.log(`Snapshot: ${result.snapshot}`);
1027
+ console.log(`Files: ${result.plans.length}`);
1028
+
1029
+ if (result.noop) {
1030
+ console.log("No files to restore.");
1031
+ return;
1032
+ }
1033
+
1034
+ console.log("Would restore:");
1035
+ for (const plan of result.plans) {
1036
+ console.log(`- ${plan.displayPath}`);
1037
+ }
1038
+
1039
+ console.log("");
1040
+ console.log("Run with --apply to restore.");
1041
+ }
1042
+
1043
+ export async function runGlobalPolicy(options, packageManifest) {
1044
+ const homeDir = resolveHomeDir();
1045
+
1046
+ switch (options.policyAction) {
1047
+ case "show": {
1048
+ const rawPolicy = await loadPolicyFile(homeDir);
1049
+
1050
+ if (options.json) {
1051
+ printJson(buildPolicyJson(homeDir, rawPolicy));
1052
+ return;
1053
+ }
1054
+
1055
+ printPolicyReport(homeDir, rawPolicy);
1056
+ return;
1057
+ }
1058
+ case "set": {
1059
+ const resolved = await savePolicyField(homeDir, options.policyKey, options.policyValue);
1060
+
1061
+ await recordPolicyHistory(homeDir, {
1062
+ cliVersion: packageManifest?.version ?? null,
1063
+ action: "set"
1064
+ });
1065
+
1066
+ if (options.json) {
1067
+ printJson({
1068
+ ok: true,
1069
+ action: "set",
1070
+ key: options.policyKey,
1071
+ value: resolved[options.policyKey],
1072
+ policy: buildPolicyJson(homeDir, await loadPolicyFile(homeDir))
1073
+ });
1074
+ return;
1075
+ }
1076
+
1077
+ console.log(`Policy updated: ${options.policyKey}=${formatPolicyValue(resolved[options.policyKey])}`);
1078
+ printPolicyReport(homeDir, await loadPolicyFile(homeDir));
1079
+ return;
1080
+ }
1081
+ case "reset": {
1082
+ const removed = await resetPolicyFile(homeDir);
1083
+
1084
+ if (removed) {
1085
+ await recordPolicyHistory(homeDir, {
1086
+ cliVersion: packageManifest?.version ?? null,
1087
+ action: "reset"
1088
+ });
1089
+ }
1090
+
1091
+ if (options.json) {
1092
+ printJson({
1093
+ ok: true,
1094
+ action: "reset",
1095
+ removed,
1096
+ policy: buildPolicyJson(homeDir, null)
1097
+ });
1098
+ return;
1099
+ }
1100
+
1101
+ console.log(removed ? "Policy reset. Using CLI defaults." : "No policy file found.");
1102
+ if (removed) {
1103
+ printPolicyReport(homeDir, null);
1104
+ }
1105
+ return;
1106
+ }
1107
+ default: {
1108
+ const _exhaustive = options.policyAction;
1109
+ throw new Error(`Unknown policy action "${_exhaustive}".`);
1110
+ }
1111
+ }
1112
+ }
1113
+
1114
+ function printPolicyReport(homeDir, rawPolicy) {
1115
+ const resolved = resolvePolicy(rawPolicy ?? {});
1116
+ const policyPath = harnessHomePaths(homeDir).policyPath;
1117
+
1118
+ console.log(commandHeader("policy — local operation preferences"));
1119
+ console.log(`Home: ${homeDir}`);
1120
+ console.log(`File: ${rawPolicy ? policyPath : "(none — using CLI defaults)"}`);
1121
+ console.log("");
1122
+
1123
+ if (resolved.profile) {
1124
+ console.log(`Profile: ${resolved.profile}`);
1125
+ }
1126
+
1127
+ console.log(`Apply mode: ${resolved.applyMode}`);
1128
+ console.log(`Preflight: ${resolved.preflight ? "enabled" : "disabled"}`);
1129
+ console.log(`Agents: ${formatPolicyAgents(resolved.agents)}`);
1130
+ console.log(`Components: ${resolved.components.join(", ") || "none"}`);
1131
+ console.log("");
1132
+ console.log("Precedence: CLI flags > policy file > internal defaults.");
1133
+ console.log(`Commands: ${formatCliCommand("policy set <key> <value>")} | ${formatCliCommand("policy reset")}`);
1134
+ }
1135
+
1136
+ function formatPolicyAgents(agents) {
1137
+ if (agents === "detected") return "detected";
1138
+ if (agents === "all") return "all";
1139
+ return agents.join(", ");
1140
+ }
1141
+
1142
+ function formatPolicyValue(value) {
1143
+ if (Array.isArray(value)) return value.join(",");
1144
+ return String(value);
1145
+ }