@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,126 @@
1
+ import { existsSync } from "node:fs";
2
+ import { copyFile, mkdir, readdir } from "node:fs/promises";
3
+ import { dirname, join, relative, sep } from "node:path";
4
+ import {
5
+ backupFileBeforeChange,
6
+ backupTimestamp,
7
+ listBackupSnapshots,
8
+ resolveSnapshotDir
9
+ } from "./backups.js";
10
+ import { harnessHomePaths } from "./paths.js";
11
+
12
+ const BLOCKED_RELATIVE_PATHS = new Set([".harness/state.json"]);
13
+
14
+ export function backupNameToRelativePath(backupName) {
15
+ return backupName.split("__").join("/");
16
+ }
17
+
18
+ export function resolveBackupTarget(backupName, homeDir) {
19
+ if (!backupName || backupName.includes("..")) return null;
20
+
21
+ const relativePath = backupNameToRelativePath(backupName);
22
+ if (relativePath.includes("..")) return null;
23
+
24
+ const normalizedRelative = relativePath.split("/").join(sep);
25
+ if (BLOCKED_RELATIVE_PATHS.has(relativePath.replace(/\\/g, "/"))) return null;
26
+
27
+ const targetPath = join(homeDir, normalizedRelative);
28
+ const withinHome = relative(homeDir, targetPath);
29
+
30
+ if (withinHome.startsWith("..") || withinHome === "") return null;
31
+
32
+ return targetPath;
33
+ }
34
+
35
+ export function formatHomePath(homeDir, filePath) {
36
+ const rel = relative(homeDir, filePath);
37
+ return `~/${rel.split(sep).join("/")}`;
38
+ }
39
+
40
+ export async function listSnapshotFiles(snapshotDir) {
41
+ if (!existsSync(snapshotDir)) return [];
42
+
43
+ const entries = await readdir(snapshotDir, { withFileTypes: true });
44
+
45
+ return entries
46
+ .filter((entry) => entry.isFile())
47
+ .map((entry) => entry.name)
48
+ .sort();
49
+ }
50
+
51
+ export async function describeBackupSnapshots(backupsDir) {
52
+ const names = await listBackupSnapshots(backupsDir);
53
+ const snapshots = [];
54
+
55
+ for (const name of names) {
56
+ const files = await listSnapshotFiles(join(backupsDir, name));
57
+ snapshots.push({ name, fileCount: files.length });
58
+ }
59
+
60
+ return snapshots;
61
+ }
62
+
63
+ function buildRestorePlans(snapshotDir, homeDir) {
64
+ return listSnapshotFiles(snapshotDir).then((files) =>
65
+ files
66
+ .map((backupName) => {
67
+ const targetPath = resolveBackupTarget(backupName, homeDir);
68
+ if (!targetPath) return null;
69
+
70
+ return {
71
+ backupName,
72
+ targetPath,
73
+ displayPath: formatHomePath(homeDir, targetPath),
74
+ backupPath: join(snapshotDir, backupName)
75
+ };
76
+ })
77
+ .filter(Boolean)
78
+ );
79
+ }
80
+
81
+ export async function previewRollback({ homeDir, snapshot }) {
82
+ const paths = harnessHomePaths(homeDir);
83
+ const snapshotDir = resolveSnapshotDir(paths.backupsDir, snapshot);
84
+ const plans = await buildRestorePlans(snapshotDir, homeDir);
85
+
86
+ return {
87
+ snapshot,
88
+ plans,
89
+ noop: plans.length === 0
90
+ };
91
+ }
92
+
93
+ export async function applyRollback({ homeDir, snapshot }) {
94
+ const paths = harnessHomePaths(homeDir);
95
+ const snapshotDir = resolveSnapshotDir(paths.backupsDir, snapshot);
96
+ const plans = await buildRestorePlans(snapshotDir, homeDir);
97
+
98
+ if (plans.length === 0) {
99
+ return { snapshot, restored: [], safetyBackup: null, noop: true };
100
+ }
101
+
102
+ const safetyTimestamp = backupTimestamp();
103
+ let safetyBackup = null;
104
+
105
+ for (const plan of plans) {
106
+ if (existsSync(plan.targetPath)) {
107
+ await backupFileBeforeChange({
108
+ backupsDir: paths.backupsDir,
109
+ homeDir,
110
+ filePath: plan.targetPath,
111
+ timestamp: safetyTimestamp
112
+ });
113
+ safetyBackup ??= safetyTimestamp;
114
+ }
115
+
116
+ await mkdir(dirname(plan.targetPath), { recursive: true });
117
+ await copyFile(plan.backupPath, plan.targetPath);
118
+ }
119
+
120
+ return {
121
+ snapshot,
122
+ restored: plans.map((plan) => plan.displayPath),
123
+ safetyBackup,
124
+ noop: false
125
+ };
126
+ }
@@ -0,0 +1,284 @@
1
+ import { stdin as input, stdout as output } from "node:process";
2
+ import { BRAND } from "./brand/index.js";
3
+ import { installGlobalHarness } from "./global-installer.js";
4
+ import {
5
+ assertExplicitApplyConsent,
6
+ createReadlinePrompt,
7
+ promptApplyConfirmation,
8
+ shouldPromptApplyConfirmation
9
+ } from "./apply-confirmation.js";
10
+ import { summarizeInstallPreflight } from "./diff.js";
11
+ import {
12
+ COMPONENT_IDS,
13
+ DEFAULT_COMPONENT_IDS,
14
+ validateComponentIds
15
+ } from "./component-registry.js";
16
+ import {
17
+ GLOBAL_AGENT_IDS,
18
+ detectInstalledAdapters,
19
+ isAllAgentsSelection,
20
+ resolveAgentIds,
21
+ validateAdapterIds
22
+ } from "./registry.js";
23
+ import { printManagedPreflight, shouldShowPreflight } from "./preflight.js";
24
+ import { loadConsentAudit } from "./policy.js";
25
+ import {
26
+ renderSetupWizardResult,
27
+ runSetupWizard as defaultRunSetupWizard,
28
+ SetupWizardCancelledError,
29
+ shouldUseSetupWizard as evaluateClackWizard
30
+ } from "./clack/setup-wizard.js";
31
+ import {
32
+ renderSetupInkResult,
33
+ runSetupInk as defaultRunSetupInk,
34
+ SetupWizardCancelledError as SetupInkCancelledError
35
+ } from "./ink/run-setup-ink.js";
36
+ import { canUseSetupInk } from "./ink/terminal.js";
37
+ import { shouldUseSetupInk as evaluateSetupInk } from "./ink/setup-routing.js";
38
+
39
+ export { shouldUseSetupInk } from "./ink/setup-routing.js";
40
+ export { shouldUseSetupWizard } from "./clack/setup-wizard.js";
41
+ /** @deprecated Use shouldUseSetupWizard */
42
+ export { shouldUseSetupTui } from "./clack/setup-wizard.js";
43
+
44
+ export async function runHarnessSetup({
45
+ packageRoot,
46
+ packageName,
47
+ cliVersion,
48
+ homeDir,
49
+ workspaceRoot = null,
50
+ agents = null,
51
+ components = null,
52
+ noDefaultComponents = false,
53
+ dryRun = false,
54
+ yes = false,
55
+ confirm = false,
56
+ preflight = true,
57
+ preflightExplicit = false,
58
+ yesExplicit = false,
59
+ confirmExplicit = false,
60
+ json = false,
61
+ simple = false,
62
+ interactive = Boolean(input.isTTY && output.isTTY),
63
+ createPrompt = createReadlinePrompt,
64
+ runSetupInkImpl = defaultRunSetupInk,
65
+ runSetupWizardImpl = defaultRunSetupWizard,
66
+ inkCapable = canUseSetupInk({ interactive })
67
+ }) {
68
+ const routing = { interactive, simple, inkCapable, dryRun, yes, confirm, json, agents, components, noDefaultComponents };
69
+ const useInk = evaluateSetupInk(routing);
70
+ const useWizard = !useInk && evaluateClackWizard({ ...routing, inkCapable });
71
+
72
+ let selectedAgents = agents;
73
+ let selectedComponents = components;
74
+ let selectedNoDefaults = noDefaultComponents;
75
+ let usedWizard = false;
76
+ let usedInk = false;
77
+
78
+ if (!useInk && !useWizard) {
79
+ printSetupIntro({ homeDir });
80
+ }
81
+
82
+ const setupUiArgs = {
83
+ homeDir,
84
+ workspaceRoot,
85
+ packageRoot,
86
+ packageName,
87
+ cliVersion,
88
+ dryRun,
89
+ preflight,
90
+ yes,
91
+ confirm,
92
+ preflightExplicit,
93
+ yesExplicit,
94
+ confirmExplicit,
95
+ interactive
96
+ };
97
+
98
+ if (useInk) {
99
+ try {
100
+ const inkOutcome = await runSetupInkImpl(setupUiArgs);
101
+
102
+ if (inkOutcome.cancelled) {
103
+ return { cancelled: true, usedWizard: true, usedInk: true };
104
+ }
105
+
106
+ selectedAgents = inkOutcome.agents;
107
+ selectedComponents = inkOutcome.components;
108
+ selectedNoDefaults = inkOutcome.noDefaultComponents;
109
+ usedWizard = true;
110
+ usedInk = true;
111
+ } catch (error) {
112
+ if (error instanceof SetupInkCancelledError) {
113
+ return { cancelled: true, usedWizard: true, usedInk: true };
114
+ }
115
+ throw error;
116
+ }
117
+ } else if (useWizard) {
118
+ try {
119
+ const wizardOutcome = await runSetupWizardImpl(setupUiArgs);
120
+
121
+ if (wizardOutcome.cancelled) {
122
+ return { cancelled: true, usedWizard: true };
123
+ }
124
+
125
+ selectedAgents = wizardOutcome.agents;
126
+ selectedComponents = wizardOutcome.components;
127
+ selectedNoDefaults = wizardOutcome.noDefaultComponents;
128
+ usedWizard = true;
129
+ } catch (error) {
130
+ if (error instanceof SetupWizardCancelledError) {
131
+ return { cancelled: true, usedWizard: true };
132
+ }
133
+ throw error;
134
+ }
135
+ } else if (
136
+ interactive && !dryRun && !yes && !confirm
137
+ && agents == null
138
+ && components == null
139
+ && !noDefaultComponents
140
+ ) {
141
+ const prompt = createPrompt();
142
+ const detected = detectInstalledAdapters({ homeDir });
143
+ const defaultAgentsLabel = detected.length > 0 ? detected.join(",") : GLOBAL_AGENT_IDS.join(",");
144
+
145
+ try {
146
+ const agentsAnswer = (await prompt(`Agents to configure [${defaultAgentsLabel}]: `)).trim();
147
+ if (agentsAnswer.length > 0) {
148
+ selectedAgents = parseList(agentsAnswer);
149
+ if (!isAllAgentsSelection(selectedAgents)) {
150
+ validateAdapterIds(selectedAgents);
151
+ }
152
+ }
153
+
154
+ const componentsAnswer = (await prompt(
155
+ `Components to install [${DEFAULT_COMPONENT_IDS.join(",")}] (or "none"): `
156
+ )).trim();
157
+
158
+ if (componentsAnswer.toLowerCase() === "none") {
159
+ selectedNoDefaults = true;
160
+ selectedComponents = null;
161
+ } else if (componentsAnswer.length > 0) {
162
+ selectedComponents = parseList(componentsAnswer);
163
+ validateComponentIds(selectedComponents, { workspaceRoot });
164
+ }
165
+
166
+ console.log("");
167
+ printSetupPlanPreview({
168
+ agents: resolveAgentIds(selectedAgents, { homeDir }),
169
+ components: selectedNoDefaults
170
+ ? []
171
+ : (selectedComponents ?? [...DEFAULT_COMPONENT_IDS])
172
+ });
173
+
174
+ const confirmAnswer = (await prompt("Apply this plan? [Y/n]: ")).trim().toLowerCase();
175
+ if (confirmAnswer === "n" || confirmAnswer === "no") {
176
+ console.log("Setup cancelled.");
177
+ return { cancelled: true };
178
+ }
179
+ } finally {
180
+ await prompt.close?.();
181
+ }
182
+ } else if (!useInk && !useWizard) {
183
+ printSetupPlanPreview({
184
+ agents: resolveAgentIds(selectedAgents, { homeDir }),
185
+ components: selectedNoDefaults
186
+ ? []
187
+ : (selectedComponents ?? [...DEFAULT_COMPONENT_IDS])
188
+ });
189
+ }
190
+
191
+ const installArgs = {
192
+ packageRoot,
193
+ packageName,
194
+ cliVersion,
195
+ homeDir,
196
+ workspaceRoot,
197
+ agents: selectedAgents,
198
+ components: selectedComponents,
199
+ noDefaultComponents: selectedNoDefaults
200
+ };
201
+
202
+ const applying = !dryRun;
203
+
204
+ assertExplicitApplyConsent({
205
+ applying,
206
+ dryRun,
207
+ json,
208
+ yes,
209
+ confirm,
210
+ noPreflight: !preflight,
211
+ interactive,
212
+ command: "setup"
213
+ });
214
+
215
+ if (!usedWizard && shouldShowPreflight({ preflight, dryRun, json, applying })) {
216
+ const preview = await installGlobalHarness({ ...installArgs, dryRun: true });
217
+ const summary = await summarizeInstallPreflight(homeDir, preview);
218
+ const consent = await loadConsentAudit(homeDir, {
219
+ yes,
220
+ confirm,
221
+ yesExplicit,
222
+ confirmExplicit,
223
+ preflight,
224
+ preflightExplicit,
225
+ interactive,
226
+ applying,
227
+ dryRun,
228
+ json
229
+ });
230
+ printManagedPreflight({
231
+ command: "setup",
232
+ ...summary,
233
+ consentSource: consent.consentSource,
234
+ policyProfile: consent.policyProfile
235
+ });
236
+ }
237
+
238
+ if (!usedWizard && shouldPromptApplyConfirmation({ applying, dryRun, json, confirm, interactive })) {
239
+ const approved = await promptApplyConfirmation({ command: "setup", createPrompt });
240
+ if (!approved) {
241
+ console.log("Setup cancelled.");
242
+ return { cancelled: true };
243
+ }
244
+ }
245
+
246
+ const result = await installGlobalHarness({ ...installArgs, dryRun });
247
+
248
+ if (usedInk) {
249
+ renderSetupInkResult(result, { dryRun });
250
+ } else if (usedWizard) {
251
+ renderSetupWizardResult(result, { dryRun });
252
+ }
253
+
254
+ return { cancelled: false, result, usedWizard, usedInk };
255
+ }
256
+
257
+ function printSetupIntro({ homeDir }) {
258
+ const detected = detectInstalledAdapters({ homeDir });
259
+
260
+ console.log(`${BRAND.displayName} setup — local AI ecosystem configurator`);
261
+ console.log("Configures and coordinates local agents. Does not install the AI apps themselves.");
262
+ console.log("");
263
+ console.log(`Detected agents: ${detected.join(", ") || "none"}`);
264
+ console.log(`Supported agents: ${GLOBAL_AGENT_IDS.join(", ")}`);
265
+ console.log(`Default components: ${DEFAULT_COMPONENT_IDS.join(", ")}`);
266
+ console.log("");
267
+ }
268
+
269
+ function printSetupPlanPreview({ agents, components }) {
270
+ console.log("Plan:");
271
+ console.log(` Agents: ${agents.join(", ")}`);
272
+ console.log(` Components: ${components.join(", ") || "none (core plumbing only)"}`);
273
+ console.log(` Available components: ${COMPONENT_IDS.join(", ")}`);
274
+ console.log("");
275
+ }
276
+
277
+ function parseList(value) {
278
+ return [...new Set(
279
+ value
280
+ .split(",")
281
+ .map((item) => item.trim().toLowerCase())
282
+ .filter(Boolean)
283
+ )];
284
+ }
@@ -0,0 +1,65 @@
1
+ import { resolveAdapter } from "./registry.js";
2
+ import { resolveComponent } from "./component-registry.js";
3
+
4
+ const LEGACY_ORCHESTRATOR_COMPONENT = {
5
+ id: "orchestrator",
6
+ version: resolveComponent("orchestrator").version,
7
+ managedTargets: []
8
+ };
9
+
10
+ export function normalizeGlobalState(state) {
11
+ if (!state) return null;
12
+
13
+ const adapters = state.adapters ?? migrateLegacyAgents(state.agents ?? []);
14
+ const components = state.components ?? migrateLegacyComponents(state, adapters);
15
+
16
+ return {
17
+ ...state,
18
+ adapters,
19
+ agents: toLegacyAgents(adapters),
20
+ components
21
+ };
22
+ }
23
+
24
+ export function getInstalledAdapterIds(state) {
25
+ const normalized = normalizeGlobalState(state);
26
+ return normalized?.adapters?.map((entry) => entry.id) ?? [];
27
+ }
28
+
29
+ export function getInstalledComponentIds(state) {
30
+ const normalized = normalizeGlobalState(state);
31
+ return normalized?.components?.map((entry) => entry.id) ?? [];
32
+ }
33
+
34
+ function migrateLegacyAgents(agents) {
35
+ return agents.map((entry) => {
36
+ const adapter = resolveAdapter(entry.id);
37
+
38
+ return {
39
+ id: adapter.id,
40
+ label: adapter.label,
41
+ rootDir: adapter.assets.rootDir,
42
+ configFile: entry.configFile ?? adapter.assets.configFile,
43
+ managedTargets: [...adapter.assets.managedTargets],
44
+ present: entry.present ?? false
45
+ };
46
+ });
47
+ }
48
+
49
+ function migrateLegacyComponents(state, adapters) {
50
+ if (Array.isArray(state.components)) return state.components;
51
+
52
+ const managedTargets = adapters.map((adapter) => adapter.configFile);
53
+ const hasLegacyOrchestrator = Boolean(state.coreFiles?.["core/orchestrator.md"]);
54
+
55
+ if (!hasLegacyOrchestrator && managedTargets.length === 0) return [];
56
+
57
+ return [{
58
+ ...LEGACY_ORCHESTRATOR_COMPONENT,
59
+ managedTargets
60
+ }];
61
+ }
62
+
63
+ function toLegacyAgents(adapters) {
64
+ return adapters.map(({ id, configFile, present }) => ({ id, configFile, present }));
65
+ }
@@ -0,0 +1,50 @@
1
+ import { existsSync } from "node:fs";
2
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
3
+ import { dirname } from "node:path";
4
+ import { normalizeGlobalState } from "./state-migration.js";
5
+
6
+ export const STATE_VERSION = 3;
7
+
8
+ export async function readGlobalState(statePath) {
9
+ if (!existsSync(statePath)) return null;
10
+
11
+ try {
12
+ const raw = JSON.parse(await readFile(statePath, "utf8"));
13
+ return normalizeGlobalState(raw);
14
+ } catch {
15
+ return null;
16
+ }
17
+ }
18
+
19
+ export async function writeGlobalState(statePath, state) {
20
+ await mkdir(dirname(statePath), { recursive: true });
21
+ await writeFile(statePath, `${JSON.stringify(state, null, 2)}\n`, "utf8");
22
+ }
23
+
24
+ export function createGlobalState({
25
+ packageName,
26
+ cliVersion,
27
+ adapters,
28
+ components = [],
29
+ coreFiles,
30
+ backups,
31
+ installedAt
32
+ }) {
33
+ const now = new Date().toISOString();
34
+ const normalizedAdapters = adapters.map((entry) => ({ ...entry }));
35
+ const normalizedComponents = components.map((entry) => ({ ...entry }));
36
+
37
+ return {
38
+ stateVersion: STATE_VERSION,
39
+ packageName,
40
+ cliVersion,
41
+ scope: "agent-global",
42
+ installedAt: installedAt ?? now,
43
+ updatedAt: now,
44
+ adapters: normalizedAdapters,
45
+ agents: normalizedAdapters.map(({ id, configFile, present }) => ({ id, configFile, present })),
46
+ components: normalizedComponents,
47
+ coreFiles,
48
+ backups
49
+ };
50
+ }
@@ -0,0 +1,94 @@
1
+ import { listBackupSnapshots } from "./backups.js";
2
+ import { runGlobalDoctorChecks } from "./global-doctor.js";
3
+ import { buildEffectivePolicy } from "./policy.js";
4
+ import { harnessHomePaths } from "./paths.js";
5
+ import { GLOBAL_AGENT_IDS, detectInstalledAdapters } from "./registry.js";
6
+ import { readGlobalState } from "./state.js";
7
+ import { formatCliCommand } from "./brand/cli.js";
8
+
9
+ export async function buildStatusReport(homeDir, { packageRoot, workspaceRoot = null } = {}) {
10
+ const paths = harnessHomePaths(homeDir);
11
+ const state = await readGlobalState(paths.statePath);
12
+ const detected = detectInstalledAdapters({ homeDir });
13
+ const doctor = await runGlobalDoctorChecks(homeDir, { packageRoot, workspaceRoot });
14
+ const backups = await listBackupSnapshots(paths.backupsDir);
15
+
16
+ const installedAgentIds = new Set((state?.adapters ?? state?.agents ?? []).map((entry) => entry.id));
17
+ const agents = GLOBAL_AGENT_IDS.map((id) => ({
18
+ id,
19
+ detected: detected.includes(id),
20
+ managed: installedAgentIds.has(id)
21
+ }));
22
+
23
+ const components = (state?.components ?? []).map((entry) => {
24
+ const related = doctor.checks.filter((check) => check.componentId === entry.id);
25
+ const status = summarizeCheckStatuses(related);
26
+ return {
27
+ id: entry.id,
28
+ version: entry.version,
29
+ source: entry.source ?? "bundled",
30
+ status
31
+ };
32
+ });
33
+
34
+ const counts = {
35
+ ok: doctor.checks.filter((check) => check.status === "ok").length,
36
+ stale: doctor.checks.filter((check) => check.status === "stale").length,
37
+ missing: doctor.checks.filter((check) => check.status === "missing").length,
38
+ warning: doctor.checks.filter((check) => check.status === "warning").length
39
+ };
40
+
41
+ const overall = resolveOverallStatus({ state, doctor });
42
+ const nextAction = resolveNextAction(overall, { backups: backups.length });
43
+ const policy = await buildEffectivePolicy(homeDir);
44
+
45
+ return {
46
+ homeDir,
47
+ stateRoot: paths.root,
48
+ state,
49
+ agents,
50
+ components,
51
+ checks: doctor.checks,
52
+ backups: backups.length,
53
+ counts,
54
+ overall,
55
+ nextAction,
56
+ policy,
57
+ ok: overall === "ok"
58
+ };
59
+ }
60
+
61
+ function summarizeCheckStatuses(checks) {
62
+ if (checks.length === 0) return "ok";
63
+ if (checks.some((check) => check.status === "missing")) return "missing";
64
+ if (checks.some((check) => check.status === "stale")) return "stale";
65
+ return "ok";
66
+ }
67
+
68
+ function resolveOverallStatus({ state, doctor }) {
69
+ if (!state) return "missing";
70
+ if (doctor.hasDrift) return "drift";
71
+ if (!doctor.ok) return "failed";
72
+ return "ok";
73
+ }
74
+
75
+ function resolveNextAction(overall, { backups = 0 } = {}) {
76
+ switch (overall) {
77
+ case "missing":
78
+ return `Run "${formatCliCommand("setup")}" (or "${formatCliCommand("install")}") to configure the local ecosystem.`;
79
+ case "drift":
80
+ return backups > 0
81
+ ? `Run "${formatCliCommand("sync")}" to repair managed content. Use "${formatCliCommand("rollback")}" to restore a prior snapshot.`
82
+ : `Run "${formatCliCommand("sync")}" to repair managed content.`;
83
+ case "failed":
84
+ return `Run "${formatCliCommand("doctor")}" for details, then "${formatCliCommand("sync")}" or "${formatCliCommand("setup")}".`;
85
+ case "ok":
86
+ return backups > 0
87
+ ? `Ecosystem healthy. Use "${formatCliCommand("rollback")}" if you need a prior snapshot.`
88
+ : "Ecosystem healthy. No action required.";
89
+ default: {
90
+ const _exhaustive = overall;
91
+ return _exhaustive;
92
+ }
93
+ }
94
+ }