@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
package/src/cli.js ADDED
@@ -0,0 +1,625 @@
1
+ import { fileURLToPath } from "node:url";
2
+ import { readFile } from "node:fs/promises";
3
+ import { basename, dirname, resolve } from "node:path";
4
+ import { ADAPTERS } from "./harness-files.js";
5
+ import { GLOBAL_AGENT_IDS } from "./global/registry.js";
6
+ import { COMPONENT_IDS, DEFAULT_COMPONENT_IDS } from "./global/component-registry.js";
7
+ import {
8
+ printGlobalComponents,
9
+ printGlobalDetect,
10
+ runComponentsImport,
11
+ runComponentsInit,
12
+ runComponentsPack,
13
+ runComponentsValidate,
14
+ runGlobalAdapters,
15
+ runGlobalBackups,
16
+ runGlobalDoctor,
17
+ runGlobalInstall,
18
+ runGlobalRollback,
19
+ runGlobalSetup,
20
+ runGlobalStatus,
21
+ runGlobalSync,
22
+ runGlobalUninstall,
23
+ runGlobalUpgrade,
24
+ runGlobalExplain,
25
+ runGlobalDiff,
26
+ runGlobalPolicy,
27
+ runGlobalHistory,
28
+ runGlobalReport
29
+ } from "./global/global-cli.js";
30
+ import { applyPolicyToOptions, loadPolicyFile } from "./global/policy.js";
31
+ import { resolveHomeDir } from "./global/paths.js";
32
+ import { runWorkspaceDetect, runWorkspaceDoctor, runWorkspaceInit, runWorkspaceUpdate } from "./workspace-cli.js";
33
+ import {
34
+ ALL_CLI_NAMES,
35
+ LEGACY_PACKAGE_NAME,
36
+ PACKAGE_NAME,
37
+ PREFERRED_CLI,
38
+ formatCliCommand,
39
+ maybeWarnLegacyCli
40
+ } from "./global/brand/cli.js";
41
+ import { BRAND } from "./global/brand/index.js";
42
+
43
+ const __dirname = dirname(fileURLToPath(import.meta.url));
44
+ const packageRoot = resolve(__dirname, "..");
45
+ const SCOPES = new Set(["agent-global", "workspace"]);
46
+
47
+ export function resolveSuggestedInvocation(packageName, argv = process.argv) {
48
+ const invokedPath = argv[1] ?? PREFERRED_CLI;
49
+ const invokedBase = basename(invokedPath);
50
+
51
+ if (!invokedBase.endsWith(".js") && ALL_CLI_NAMES.has(invokedBase)) {
52
+ return invokedBase;
53
+ }
54
+
55
+ const packageManager = detectInvocationPackageManager();
56
+
57
+ switch (packageManager) {
58
+ case "pnpm":
59
+ return `pnpm dlx ${packageName}`;
60
+ case "yarn":
61
+ return `yarn dlx ${packageName}`;
62
+ case "bun":
63
+ return `bunx ${packageName}`;
64
+ default:
65
+ return `npx ${packageName}`;
66
+ }
67
+ }
68
+
69
+ function detectInvocationPackageManager() {
70
+ const execPath = process.env.npm_execpath ?? "";
71
+ const userAgent = process.env.npm_config_user_agent ?? "";
72
+
73
+ if (execPath.includes("pnpm") || userAgent.startsWith("pnpm/")) return "pnpm";
74
+ if (execPath.includes("yarn") || userAgent.startsWith("yarn/")) return "yarn";
75
+ if (execPath.includes("bun") || userAgent.startsWith("bun/")) return "bun";
76
+ return "npm";
77
+ }
78
+
79
+ export async function runCli(argv) {
80
+ const { command, options } = parseArgs(argv);
81
+ maybeWarnLegacyCli(process.argv, { json: options.json });
82
+
83
+ if (options.help || command === "help") {
84
+ printHelp();
85
+ return;
86
+ }
87
+
88
+ const packageManifest = await readPackageManifest();
89
+
90
+ if (options.version || command === "version") {
91
+ console.log(packageManifest.version);
92
+ return;
93
+ }
94
+
95
+ const optionsWithPolicy = await applyCommandPolicy(command, options);
96
+ const invoke = resolveSuggestedInvocation(packageManifest.name);
97
+
98
+ switch (command) {
99
+ case "setup":
100
+ await runGlobalSetup(optionsWithPolicy, packageManifest, packageRoot);
101
+ return;
102
+ case "status":
103
+ await runGlobalStatus(packageRoot, {
104
+ workspaceRoot: optionsWithPolicy.cwd,
105
+ json: optionsWithPolicy.json,
106
+ cliVersion: packageManifest.version
107
+ });
108
+ return;
109
+ case "sync":
110
+ await runGlobalSync(optionsWithPolicy, packageManifest, packageRoot);
111
+ return;
112
+ case "upgrade":
113
+ await runGlobalUpgrade(optionsWithPolicy, packageManifest, packageRoot);
114
+ return;
115
+ case "install":
116
+ await dispatchByScope(options, "agent-global", {
117
+ "agent-global": () => runGlobalInstall(options, packageManifest, packageRoot),
118
+ workspace: () => runWorkspaceInit(options, packageManifest, packageRoot, invoke)
119
+ });
120
+ return;
121
+ case "init":
122
+ await dispatchByScope(options, "workspace", {
123
+ "agent-global": () => runGlobalInstall(options, packageManifest, packageRoot),
124
+ workspace: () => runWorkspaceInit(options, packageManifest, packageRoot, invoke)
125
+ });
126
+ return;
127
+ case "update":
128
+ await dispatchByScope(options, "agent-global", {
129
+ "agent-global": () => runGlobalInstall(options, packageManifest, packageRoot, { update: true }),
130
+ workspace: () => runWorkspaceUpdate(options, packageManifest, packageRoot)
131
+ });
132
+ return;
133
+ case "doctor":
134
+ await dispatchByScope(options, "agent-global", {
135
+ "agent-global": () => runGlobalDoctor(packageRoot, {
136
+ workspaceRoot: options.cwd,
137
+ json: options.json,
138
+ cliVersion: packageManifest.version
139
+ }),
140
+ workspace: () => runWorkspaceDoctor(options)
141
+ });
142
+ return;
143
+ case "uninstall":
144
+ if (options.scope === "workspace") {
145
+ throw new Error('Workspace uninstall is not supported yet. Remove workspace files manually or via git.');
146
+ }
147
+ await runGlobalUninstall(options, packageManifest);
148
+ return;
149
+ case "detect":
150
+ printGlobalDetect();
151
+ console.log("");
152
+ await runWorkspaceDetect(options, invoke);
153
+ return;
154
+ case "adapters":
155
+ await runGlobalAdapters({
156
+ json: options.json,
157
+ cliVersion: packageManifest.version
158
+ });
159
+ return;
160
+ case "explain":
161
+ await runGlobalExplain({
162
+ json: options.json,
163
+ cliVersion: packageManifest.version
164
+ });
165
+ return;
166
+ case "diff":
167
+ await runGlobalDiff({
168
+ packageManifest,
169
+ packageRoot,
170
+ json: options.json,
171
+ workspaceRoot: options.cwd
172
+ });
173
+ return;
174
+ case "backups":
175
+ await runGlobalBackups();
176
+ return;
177
+ case "history":
178
+ await runGlobalHistory(options, packageManifest);
179
+ return;
180
+ case "rollback":
181
+ await runGlobalRollback(options, packageManifest);
182
+ return;
183
+ case "components":
184
+ await dispatchComponentsCommand(options, invoke);
185
+ return;
186
+ case "policy":
187
+ await runGlobalPolicy(options, packageManifest);
188
+ return;
189
+ case "report":
190
+ await runGlobalReport({
191
+ packageManifest,
192
+ packageRoot,
193
+ json: options.json,
194
+ workspaceRoot: options.cwd,
195
+ historyLimit: options.limit,
196
+ outPath: options.outPath
197
+ });
198
+ return;
199
+ default:
200
+ throw new Error(`Unknown command "${command}". Run "${invoke} help".`);
201
+ }
202
+ }
203
+
204
+ async function dispatchByScope(options, defaultScope, handlers) {
205
+ const scope = options.scope ?? defaultScope;
206
+ const handler = handlers[scope];
207
+ await handler();
208
+ }
209
+
210
+ async function dispatchComponentsCommand(options, invoke) {
211
+ switch (options.componentsAction) {
212
+ case null:
213
+ printGlobalComponents({ workspaceRoot: options.cwd });
214
+ return;
215
+ case "validate":
216
+ runComponentsValidate({ workspaceRoot: options.cwd });
217
+ return;
218
+ case "init":
219
+ await runComponentsInit(options);
220
+ return;
221
+ case "pack":
222
+ await runComponentsPack(options);
223
+ return;
224
+ case "import":
225
+ await runComponentsImport(options);
226
+ return;
227
+ default:
228
+ throw new Error(
229
+ `Unknown components action "${options.componentsAction}". Run "${invoke} help".`
230
+ );
231
+ }
232
+ }
233
+
234
+ async function applyCommandPolicy(command, options) {
235
+ if (!new Set(["setup", "sync", "upgrade"]).has(command)) {
236
+ return options;
237
+ }
238
+
239
+ const homeDir = resolveHomeDir();
240
+ const rawPolicy = await loadPolicyFile(homeDir);
241
+ return applyPolicyToOptions(options, rawPolicy);
242
+ }
243
+
244
+ async function readPackageManifest() {
245
+ return JSON.parse(await readFile(resolve(packageRoot, "package.json"), "utf8"));
246
+ }
247
+
248
+ function resolveImplicitCommand(args) {
249
+ if (argsWantsWorkspaceScope(args)) {
250
+ return "init";
251
+ }
252
+ return "setup";
253
+ }
254
+
255
+ function argsWantsWorkspaceScope(args) {
256
+ for (let index = 0; index < args.length; index += 1) {
257
+ const arg = args[index];
258
+ if (arg === "--scope=workspace") return true;
259
+ if (arg === "--scope" && args[index + 1] === "workspace") return true;
260
+ }
261
+ return false;
262
+ }
263
+
264
+ export function parseArgs(argv) {
265
+ const args = [...argv];
266
+ const firstArg = args[0];
267
+ const implicitCommand = !firstArg || firstArg.startsWith("-");
268
+ const rawCommand = implicitCommand ? resolveImplicitCommand(args) : args.shift();
269
+ const command = normalizeCommand(rawCommand);
270
+ const options = {
271
+ cwd: process.cwd(),
272
+ scope: null,
273
+ mode: "standard",
274
+ modeExplicit: false,
275
+ detect: implicitCommand,
276
+ adapters: null,
277
+ allAdapters: false,
278
+ components: null,
279
+ componentsAction: null,
280
+ componentId: null,
281
+ label: null,
282
+ outPath: null,
283
+ bundlePath: null,
284
+ noDefaultComponents: false,
285
+ force: false,
286
+ dryRun: false,
287
+ yes: false,
288
+ confirm: false,
289
+ preflight: true,
290
+ preflightExplicit: false,
291
+ yesExplicit: false,
292
+ confirmExplicit: false,
293
+ adaptersExplicit: false,
294
+ componentsExplicit: false,
295
+ json: false,
296
+ apply: false,
297
+ snapshot: null,
298
+ policyAction: null,
299
+ policyKey: null,
300
+ policyValue: null,
301
+ historyAction: null,
302
+ historyCommand: null,
303
+ historyEventAction: null,
304
+ limit: null,
305
+ simple: false,
306
+ help: false,
307
+ version: false,
308
+ interactive: Boolean(process.stdin.isTTY && process.stdout.isTTY)
309
+ };
310
+
311
+ if (command === "components") {
312
+ parseComponentsAction(args, options);
313
+ }
314
+
315
+ if (command === "policy") {
316
+ parsePolicyAction(args, options);
317
+ }
318
+
319
+ if (command === "history") {
320
+ parseHistoryAction(args, options);
321
+ }
322
+
323
+ for (let index = 0; index < args.length; index += 1) {
324
+ const arg = args[index];
325
+
326
+ if (arg === "--cwd") options.cwd = resolve(args[++index]);
327
+ else if (arg === "--scope") options.scope = parseScope(args[++index]);
328
+ else if (arg.startsWith("--scope=")) options.scope = parseScope(arg.slice("--scope=".length));
329
+ else if (arg === "--mode") {
330
+ options.mode = args[++index];
331
+ options.modeExplicit = true;
332
+ } else if (arg.startsWith("--mode=")) {
333
+ options.mode = arg.slice("--mode=".length);
334
+ options.modeExplicit = true;
335
+ } else if (arg === "--detect") options.detect = true;
336
+ else if (arg === "--all-adapters") {
337
+ options.allAdapters = true;
338
+ options.adapters = null;
339
+ options.adaptersExplicit = true;
340
+ } else if (arg === "--adapters" || arg === "--agents") {
341
+ options.adapters = parseAdapters(args[++index]);
342
+ options.adaptersExplicit = true;
343
+ } else if (arg.startsWith("--adapters=")) {
344
+ options.adapters = parseAdapters(arg.slice("--adapters=".length));
345
+ options.adaptersExplicit = true;
346
+ } else if (arg.startsWith("--agents=")) {
347
+ options.adapters = parseAdapters(arg.slice("--agents=".length));
348
+ options.adaptersExplicit = true;
349
+ } else if (arg === "--components") {
350
+ options.components = parseAdapters(args[++index]);
351
+ options.componentsExplicit = true;
352
+ } else if (arg.startsWith("--components=")) {
353
+ options.components = parseAdapters(arg.slice("--components=".length));
354
+ options.componentsExplicit = true;
355
+ } else if (arg === "--no-default-components") {
356
+ options.noDefaultComponents = true;
357
+ options.componentsExplicit = true;
358
+ } else if (arg === "--force") options.force = true;
359
+ else if (arg === "--dry-run") options.dryRun = true;
360
+ else if (arg === "--json") options.json = true;
361
+ else if (arg === "--yes" || arg === "-y") {
362
+ options.yes = true;
363
+ options.yesExplicit = true;
364
+ } else if (arg === "--confirm") {
365
+ options.confirm = true;
366
+ options.confirmExplicit = true;
367
+ } else if (arg === "--no-preflight") {
368
+ options.preflight = false;
369
+ options.preflightExplicit = true;
370
+ } else if (arg === "--apply") options.apply = true;
371
+ else if (arg === "--to") options.snapshot = args[++index];
372
+ else if (arg.startsWith("--to=")) options.snapshot = arg.slice("--to=".length);
373
+ else if (arg === "--limit") options.limit = parsePositiveInt(args[++index], "limit");
374
+ else if (arg.startsWith("--limit=")) options.limit = parsePositiveInt(arg.slice("--limit=".length), "limit");
375
+ else if (arg === "--command") options.historyCommand = args[++index];
376
+ else if (arg.startsWith("--command=")) options.historyCommand = arg.slice("--command=".length);
377
+ else if (arg === "--action") options.historyEventAction = args[++index];
378
+ else if (arg.startsWith("--action=")) options.historyEventAction = arg.slice("--action=".length);
379
+ else if (arg === "--label") options.label = args[++index];
380
+ else if (arg.startsWith("--label=")) options.label = arg.slice("--label=".length);
381
+ else if (arg === "--out") options.outPath = resolve(args[++index]);
382
+ else if (arg.startsWith("--out=")) options.outPath = resolve(arg.slice("--out=".length));
383
+ else if (arg === "--simple") options.simple = true;
384
+ else if (arg === "--help" || arg === "-h") options.help = true;
385
+ else if (arg === "--version" || arg === "-v") options.version = true;
386
+ else throw new Error(`Unknown option "${arg}".`);
387
+ }
388
+
389
+ return { command, options };
390
+ }
391
+
392
+ function parseComponentsAction(args, options) {
393
+ const action = args[0];
394
+ if (!action || action.startsWith("-")) return;
395
+
396
+ args.shift();
397
+ options.componentsAction = action;
398
+
399
+ if (action === "init" || action === "pack") {
400
+ const componentId = args[0];
401
+ if (!componentId || componentId.startsWith("-")) {
402
+ const usage = action === "init"
403
+ ? `${formatCliCommand("components init <id> --label \"My Label\"")}`
404
+ : formatCliCommand("components pack <id> --out <file>");
405
+ throw new Error(`Missing component id. Use: ${usage}`);
406
+ }
407
+ options.componentId = args.shift();
408
+ return;
409
+ }
410
+
411
+ if (action === "import") {
412
+ const bundlePath = args[0];
413
+ if (!bundlePath || bundlePath.startsWith("-")) {
414
+ throw new Error(`Missing bundle path. Use: ${formatCliCommand("components import <file>")}`);
415
+ }
416
+ options.bundlePath = resolve(args.shift());
417
+ return;
418
+ }
419
+
420
+ if (action === "validate") return;
421
+
422
+ throw new Error(`Unknown components action "${action}". Use validate, init, pack, or import.`);
423
+ }
424
+
425
+ function parsePolicyAction(args, options) {
426
+ const action = args[0];
427
+
428
+ if (!action || action.startsWith("-")) {
429
+ options.policyAction = "show";
430
+ return;
431
+ }
432
+
433
+ args.shift();
434
+
435
+ if (action === "set") {
436
+ options.policyAction = "set";
437
+ const key = args[0];
438
+ const value = args[1];
439
+
440
+ if (!key || key.startsWith("-") || !value || value.startsWith("-")) {
441
+ throw new Error(`Missing policy key or value. Use: ${formatCliCommand("policy set <key> <value>")}`);
442
+ }
443
+
444
+ options.policyKey = args.shift();
445
+ options.policyValue = args.shift();
446
+ return;
447
+ }
448
+
449
+ if (action === "reset") {
450
+ options.policyAction = "reset";
451
+ return;
452
+ }
453
+
454
+ throw new Error(`Unknown policy action "${action}". Use set or reset.`);
455
+ }
456
+
457
+ function parseHistoryAction(args, options) {
458
+ const action = args[0];
459
+
460
+ if (!action || action.startsWith("-")) {
461
+ options.historyAction = "list";
462
+ return;
463
+ }
464
+
465
+ if (action === "last") {
466
+ args.shift();
467
+ options.historyAction = "last";
468
+ return;
469
+ }
470
+
471
+ throw new Error(`Unknown history action "${action}". Use last or omit for the full log.`);
472
+ }
473
+
474
+ function parsePositiveInt(value, label) {
475
+ const parsed = Number.parseInt(value, 10);
476
+ if (!Number.isFinite(parsed) || parsed < 1) {
477
+ throw new Error(`Invalid --${label} value "${value}". Use a positive integer.`);
478
+ }
479
+ return parsed;
480
+ }
481
+
482
+ function parseScope(value) {
483
+ if (!SCOPES.has(value)) {
484
+ throw new Error(`Invalid scope "${value}". Use agent-global or workspace.`);
485
+ }
486
+
487
+ return value;
488
+ }
489
+
490
+ function normalizeCommand(command) {
491
+ if (!command) return "install";
492
+
493
+ if (command === "install" || command === "i") return "install";
494
+ if (command === "setup") return "setup";
495
+ if (command === "status") return "status";
496
+ if (command === "sync") return "sync";
497
+ if (command === "upgrade") return "upgrade";
498
+ if (command === "init") return "init";
499
+ if (command === "update" || command === "u") return "update";
500
+ if (command === "doctor") return "doctor";
501
+ if (command === "uninstall") return "uninstall";
502
+ if (command === "detect" || command === "d") return "detect";
503
+ if (command === "adapters") return "adapters";
504
+ if (command === "explain") return "explain";
505
+ if (command === "diff") return "diff";
506
+ if (command === "backups") return "backups";
507
+ if (command === "history") return "history";
508
+ if (command === "rollback") return "rollback";
509
+ if (command === "components") return "components";
510
+ if (command === "policy") return "policy";
511
+ if (command === "report") return "report";
512
+ if (command === "help") return "help";
513
+ if (command === "version") return "version";
514
+
515
+ return command;
516
+ }
517
+
518
+ function parseAdapters(value) {
519
+ if (!value) return [];
520
+
521
+ const items = [...new Set(
522
+ value
523
+ .split(",")
524
+ .map((item) => item.trim().toLowerCase())
525
+ .filter(Boolean)
526
+ )];
527
+
528
+ if (items.length === 1 && items[0] === "all") {
529
+ return ["all"];
530
+ }
531
+
532
+ if (items.includes("all")) {
533
+ throw new Error('Use --agents all alone to target all supported agents, not mixed with other ids.');
534
+ }
535
+
536
+ return items;
537
+ }
538
+
539
+ function printHelp() {
540
+ const cli = PREFERRED_CLI;
541
+ console.log(`${BRAND.displayName} (${PACKAGE_NAME})
542
+
543
+ ${BRAND.tagline}. ${BRAND.displayName} does not install AI apps — it powers and
544
+ coordinates agents you already have (Cursor, Codex, OpenCode, Claude) with managed
545
+ sections, components, backups, and drift repair under ~/.harness.
546
+
547
+ Bootstrap: see README.md (curl install.sh or npx ${PACKAGE_NAME}).
548
+
549
+ Usage:
550
+ ${cli} [--dry-run] [--yes] [--confirm] [--agents <list|all>] [--components <list>]
551
+ ${cli} --version
552
+ ${cli} setup [--dry-run] [--yes] [--confirm] [--simple] [--no-preflight] [--agents <list|all>] [--components <list>]
553
+ ${cli} status [--json]
554
+ ${cli} sync [--dry-run] [--yes] [--confirm] [--json] [--no-preflight]
555
+ ${cli} upgrade [--dry-run] [--yes] [--confirm] [--no-preflight]
556
+ ${cli} install [--agents <list|all>] [--components <list>] [--dry-run]
557
+ ${cli} install --no-default-components
558
+ ${cli} doctor [--json]
559
+ ${cli} adapters [--json]
560
+ ${cli} explain [--json]
561
+ ${cli} diff [--json]
562
+ ${cli} update [--dry-run]
563
+ ${cli} install --scope=workspace [--mode minimal|standard|enterprise] (opt-in/legacy)
564
+ ${cli} init [--mode minimal|standard|enterprise] (workspace alias)
565
+ ${cli} detect
566
+ ${cli} backups
567
+ ${cli} history [--json] [--limit <n>] [--command <name>] [--action <name>]
568
+ ${cli} history last [--json] [--command <name>] [--action <name>]
569
+ ${cli} rollback --to <snapshot> [--apply]
570
+ ${cli} policy [--json]
571
+ ${cli} policy set <key> <value>
572
+ ${cli} policy reset
573
+ ${cli} report [--json] [--out <file>] [--limit <n>]
574
+ ${cli} components
575
+ ${cli} components validate|init|pack|import ...
576
+ ${cli} uninstall [--dry-run]
577
+
578
+ Scopes:
579
+ agent-global (default) Configure local agent roots and managed sections.
580
+ Primary product path. Writes ~/.harness state.
581
+ workspace (opt-in) Legacy repo scaffolding into the current project.
582
+ Explicit --scope=workspace only.
583
+
584
+ Commands:
585
+ setup Interactive Ink UI (TTY). Use --simple for Clack prompts.
586
+ status Control panel: agents, components, drift, backups, next action.
587
+ sync Converge managed content (repair drift), then show status.
588
+ upgrade Preview or apply ecosystem updates (apply requires --yes).
589
+ install Non-interactive configure (agent-global) or legacy workspace scaffold.
590
+ doctor Detailed health checks for managed state and configs.
591
+ update Technical repair alias (prefer sync for day-to-day use).
592
+ detect Inspect global agents and the current project. Read-only.
593
+ adapters Official adapter matrix: roots, config files, detected/managed.
594
+ explain Read-only audit of managed adapters, configs, markers, and backups.
595
+ diff Read-only preview of managed content changes (sync/setup plan).
596
+ backups List config snapshots under ~/.harness/backups.
597
+ history Local audit log of managed operations under ~/.harness/history.jsonl.
598
+ Use "history last" for the most recent event. Read-only.
599
+ rollback Preview or restore a prior config snapshot (--apply to write).
600
+ policy View or edit local operation preferences under ~/.harness/policy.json.
601
+ report Read-only diagnostics bundle: status, policy, adapters, diff, history.
602
+ components List, validate, scaffold, pack, or import workspace components.
603
+ uninstall Remove managed sections and global state. Backups are preserved.
604
+ init Alias for install --scope=workspace (legacy).
605
+
606
+ JSON output (--json on supported commands):
607
+ status, sync, doctor, adapters, explain, diff, history, history last,
608
+ policy (show/set/reset), report
609
+ Human text remains the default. See README.md for examples and field notes.
610
+
611
+ Version:
612
+ ${cli} --version Installed CLI version
613
+ npm view ${PACKAGE_NAME} version Latest published version
614
+ npx ${PACKAGE_NAME}@latest sync Converge with latest package
615
+
616
+ More examples: README.md
617
+
618
+ Preferred CLI: kairo, kairo-runtime
619
+ Legacy aliases: harness, agentic-harness, sgs-harness, harness-sgs (prefer kairo)
620
+ Legacy package: ${LEGACY_PACKAGE_NAME}
621
+ Global agents: ${GLOBAL_AGENT_IDS.join(", ")}
622
+ Global components: ${COMPONENT_IDS.join(", ")} (default: ${DEFAULT_COMPONENT_IDS.join(", ")})
623
+ Workspace adapters: ${[...ADAPTERS].join(", ")}
624
+ `);
625
+ }
package/src/doctor.js ADDED
@@ -0,0 +1,68 @@
1
+ import { existsSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import { readManifest } from "./manifest.js";
4
+ import { formatCliCommand } from "./global/brand/cli.js";
5
+
6
+ const REQUIRED_FILES = ["AGENTS.md", "docs/ai/harness.md", "docs/ai/memory.md"];
7
+
8
+ const RECOMMENDED_FILES = [
9
+ "docs/ai/context-graph.md",
10
+ "docs/ai/architecture.md",
11
+ ".github/copilot-instructions.md",
12
+ ".cursor/rules/core.mdc"
13
+ ];
14
+
15
+ const DRIFT_PREVIEW_LIMIT = 5;
16
+
17
+ export async function runDoctorChecks(project) {
18
+ const checks = [
19
+ ...REQUIRED_FILES.map((relativePath) => fileCheck(project.root, relativePath, "required")),
20
+ ...RECOMMENDED_FILES.map((relativePath) => fileCheck(project.root, relativePath, "recommended"))
21
+ ];
22
+
23
+ checks.push(...await manifestChecks(project.root));
24
+
25
+ const hasMissingRequired = checks.some((check) => check.status === "missing");
26
+ return { checks, ok: !hasMissingRequired };
27
+ }
28
+
29
+ function fileCheck(root, relativePath, severity) {
30
+ const exists = existsSync(resolve(root, relativePath));
31
+ if (exists) return { name: relativePath, status: "ok" };
32
+ return { name: relativePath, status: severity === "required" ? "missing" : "warning" };
33
+ }
34
+
35
+ async function manifestChecks(root) {
36
+ const manifest = await readManifest(root);
37
+
38
+ if (!manifest) {
39
+ return [{
40
+ name: ".harness/manifest.json",
41
+ status: "warning",
42
+ detail: `Not found. Run "${formatCliCommand("init")}" to enable "${formatCliCommand("update")}".`
43
+ }];
44
+ }
45
+
46
+ const checks = [{
47
+ name: ".harness/manifest.json",
48
+ status: "ok",
49
+ detail: `mode=${manifest.mode}, cliVersion=${manifest.cliVersion ?? "unknown"}`
50
+ }];
51
+
52
+ const drifted = Object.keys(manifest.files ?? {}).filter(
53
+ (relativePath) => !existsSync(resolve(root, relativePath))
54
+ );
55
+
56
+ if (drifted.length > 0) {
57
+ const preview = drifted.slice(0, DRIFT_PREVIEW_LIMIT).join(", ");
58
+ const suffix = drifted.length > DRIFT_PREVIEW_LIMIT ? ", ..." : "";
59
+
60
+ checks.push({
61
+ name: "manifest drift",
62
+ status: "warning",
63
+ detail: `${drifted.length} tracked file(s) missing on disk: ${preview}${suffix}`
64
+ });
65
+ }
66
+
67
+ return checks;
68
+ }