@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,77 @@
1
+ import React from "react";
2
+ import { render } from "ink";
3
+ import { WIZARD_COPY } from "../brand/index.js";
4
+ import { loadConsentAudit } from "../policy.js";
5
+ import { formatResultNote } from "../clack/theme.js";
6
+ import { SetupWizardCancelledError } from "../clack/setup-wizard-constants.js";
7
+ import { SetupApp } from "./setup-app.js";
8
+
9
+ export { SetupWizardCancelledError };
10
+
11
+ export async function runSetupInk({
12
+ homeDir,
13
+ workspaceRoot,
14
+ packageRoot,
15
+ packageName,
16
+ cliVersion,
17
+ dryRun = false,
18
+ preflight = true,
19
+ yes = false,
20
+ confirm = false,
21
+ preflightExplicit = false,
22
+ yesExplicit = false,
23
+ confirmExplicit = false,
24
+ interactive = true,
25
+ renderImpl = render
26
+ }) {
27
+ const outcome = await new Promise((resolve) => {
28
+ const { waitUntilExit } = renderImpl(
29
+ React.createElement(SetupApp, {
30
+ homeDir,
31
+ workspaceRoot,
32
+ packageRoot,
33
+ packageName,
34
+ cliVersion,
35
+ dryRun,
36
+ onComplete: resolve
37
+ })
38
+ );
39
+
40
+ waitUntilExit().catch((error) => {
41
+ resolve({ cancelled: true, usedWizard: true, error });
42
+ });
43
+ });
44
+
45
+ if (outcome.error) {
46
+ throw outcome.error;
47
+ }
48
+
49
+ if (outcome.cancelled) {
50
+ return outcome;
51
+ }
52
+
53
+ const consent = preflight
54
+ ? await loadConsentAudit(homeDir, {
55
+ yes,
56
+ confirm,
57
+ yesExplicit,
58
+ confirmExplicit,
59
+ preflight,
60
+ preflightExplicit,
61
+ interactive,
62
+ applying: !dryRun,
63
+ dryRun,
64
+ json: false
65
+ })
66
+ : null;
67
+
68
+ return { ...outcome, consent };
69
+ }
70
+
71
+ export function renderSetupInkResult(result, { dryRun = false } = {}) {
72
+ const title = dryRun ? WIZARD_COPY.resultDryRunTitle : WIZARD_COPY.resultSuccessTitle;
73
+ const outro = dryRun ? WIZARD_COPY.outroDryRun : WIZARD_COPY.outroSuccess;
74
+ console.log(`\n${title}\n`);
75
+ console.log(formatResultNote(result, { dryRun }));
76
+ console.log(`\n${outro}\n`);
77
+ }
@@ -0,0 +1,278 @@
1
+ import React, { useEffect, useState } from "react";
2
+ import { Box, Text, useApp, useInput } from "ink";
3
+ import { stdout as output } from "node:process";
4
+ import { BRAND, WIZARD_COPY } from "../brand/index.js";
5
+ import { DEFAULT_COMPONENT_IDS, describeComponentCatalog } from "../component-registry.js";
6
+ import { GLOBAL_AGENT_IDS, detectInstalledAdapters, listAdapters } from "../registry.js";
7
+ import { buildSetupPreview, resolveComponentSelection } from "../clack/setup-preview.js";
8
+ import {
9
+ SETUP_STEPS,
10
+ buildAgentOptions,
11
+ buildComponentOptions,
12
+ formatInkDetectPanel,
13
+ formatInkHeaderLines,
14
+ formatInkPreviewLines,
15
+ formatInkSelectList,
16
+ formatInkSplashLines,
17
+ INITIAL_SETUP_STEP,
18
+ shouldStartPreviewLoad,
19
+ shouldUseCompactSplashLogo,
20
+ toggleComponentSelection,
21
+ toggleSelection,
22
+ transitionFromSplash
23
+ } from "./setup-state.js";
24
+
25
+ const INK_COLORS = {
26
+ accent: "cyan",
27
+ success: "green",
28
+ warning: "yellow",
29
+ danger: "red",
30
+ muted: "gray"
31
+ };
32
+
33
+ function Header() {
34
+ const lines = formatInkHeaderLines();
35
+ return React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
36
+ React.createElement(Text, { bold: true, color: INK_COLORS.accent }, lines[0]),
37
+ React.createElement(Text, { color: INK_COLORS.muted }, lines[1]),
38
+ React.createElement(Text, { dimColor: true }, lines[2])
39
+ );
40
+ }
41
+
42
+ function Panel({ title, children }) {
43
+ return React.createElement(Box, {
44
+ flexDirection: "column",
45
+ borderStyle: "round",
46
+ borderColor: INK_COLORS.accent,
47
+ paddingX: 1,
48
+ marginBottom: 1
49
+ },
50
+ React.createElement(Text, { bold: true, color: INK_COLORS.accent }, title),
51
+ children
52
+ );
53
+ }
54
+
55
+ function Footer({ children }) {
56
+ return React.createElement(Text, { dimColor: true }, children);
57
+ }
58
+
59
+ function Splash({ compact }) {
60
+ const lines = formatInkSplashLines({ compact });
61
+ const logoLineCount = compact ? BRAND.compactLogo.length : BRAND.asciiLogo.length;
62
+
63
+ return React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
64
+ lines.map((line, index) => {
65
+ if (index < logoLineCount) {
66
+ return React.createElement(Text, { key: `logo-${index}`, bold: true, color: INK_COLORS.accent }, line);
67
+ }
68
+ if (line === BRAND.name) {
69
+ return React.createElement(Text, { key: `line-${index}`, bold: true, color: INK_COLORS.accent }, line);
70
+ }
71
+ if (line === BRAND.tagline) {
72
+ return React.createElement(Text, { key: `line-${index}`, color: INK_COLORS.muted }, line);
73
+ }
74
+ if (line === BRAND.splashHint) {
75
+ return React.createElement(Text, { key: `line-${index}`, dimColor: true }, line);
76
+ }
77
+ if (line === "") {
78
+ return React.createElement(Text, { key: `line-${index}` }, "");
79
+ }
80
+ return React.createElement(Text, { key: `line-${index}` }, line);
81
+ })
82
+ );
83
+ }
84
+
85
+ export function SetupApp({
86
+ homeDir,
87
+ workspaceRoot,
88
+ packageRoot,
89
+ packageName,
90
+ cliVersion,
91
+ dryRun = false,
92
+ onComplete
93
+ }) {
94
+ const { exit } = useApp();
95
+ const adapters = listAdapters();
96
+ const detected = detectInstalledAdapters({ homeDir });
97
+ const componentCatalog = describeComponentCatalog({ workspaceRoot });
98
+ const agentOptions = buildAgentOptions(adapters, detected);
99
+ const componentOptions = buildComponentOptions(componentCatalog);
100
+ const defaultAgents = detected.length > 0 ? detected : [...GLOBAL_AGENT_IDS];
101
+
102
+ const [step, setStep] = useState(INITIAL_SETUP_STEP);
103
+ const useCompactSplash = shouldUseCompactSplashLogo(output.columns);
104
+ const [activeIndex, setActiveIndex] = useState(0);
105
+ const [selectedAgents, setSelectedAgents] = useState(defaultAgents);
106
+ const [selectedComponents, setSelectedComponents] = useState([...DEFAULT_COMPONENT_IDS]);
107
+ const [preview, setPreview] = useState(null);
108
+ const [previewError, setPreviewError] = useState(null);
109
+ const [previewLoading, setPreviewLoading] = useState(false);
110
+
111
+ useEffect(() => {
112
+ if (!shouldStartPreviewLoad({ step, preview, previewError })) return;
113
+
114
+ let cancelled = false;
115
+ setPreviewLoading(true);
116
+
117
+ const { noDefaults, selected } = resolveComponentSelection(selectedComponents, { workspaceRoot });
118
+
119
+ buildSetupPreview({
120
+ homeDir,
121
+ workspaceRoot,
122
+ packageRoot,
123
+ packageName,
124
+ cliVersion,
125
+ agents: selectedAgents,
126
+ components: selected,
127
+ noDefaultComponents: noDefaults
128
+ }).then((built) => {
129
+ if (cancelled) return;
130
+ setPreview(built);
131
+ setPreviewLoading(false);
132
+ }).catch((error) => {
133
+ if (cancelled) return;
134
+ setPreviewError(error instanceof Error ? error.message : String(error));
135
+ setPreviewLoading(false);
136
+ });
137
+
138
+ return () => {
139
+ cancelled = true;
140
+ setPreviewLoading(false);
141
+ };
142
+ }, [step, preview, previewError, homeDir, workspaceRoot, packageRoot, packageName, cliVersion, selectedAgents, selectedComponents]);
143
+
144
+ const finish = (outcome) => {
145
+ onComplete(outcome);
146
+ exit();
147
+ };
148
+
149
+ useInput((inputKey, key) => {
150
+ if (key.escape) {
151
+ finish({ cancelled: true, usedWizard: true });
152
+ return;
153
+ }
154
+
155
+ if (step === SETUP_STEPS.SPLASH) {
156
+ const splashTransition = transitionFromSplash({
157
+ escape: key.escape,
158
+ enter: key.return
159
+ });
160
+
161
+ if (splashTransition.kind === "cancel") {
162
+ finish({ cancelled: true, usedWizard: true });
163
+ return;
164
+ }
165
+ if (splashTransition.kind === "advance") {
166
+ setStep(splashTransition.step);
167
+ }
168
+ return;
169
+ }
170
+
171
+ if (step === SETUP_STEPS.DETECT && key.return) {
172
+ setStep(SETUP_STEPS.AGENTS);
173
+ setActiveIndex(0);
174
+ return;
175
+ }
176
+
177
+ if (step === SETUP_STEPS.AGENTS) {
178
+ if (key.upArrow) {
179
+ setActiveIndex((index) => Math.max(0, index - 1));
180
+ return;
181
+ }
182
+ if (key.downArrow) {
183
+ setActiveIndex((index) => Math.min(agentOptions.length - 1, index + 1));
184
+ return;
185
+ }
186
+ if (inputKey === " ") {
187
+ const id = agentOptions[activeIndex].id;
188
+ setSelectedAgents((current) => toggleSelection(current, id));
189
+ return;
190
+ }
191
+ if (key.return && selectedAgents.length > 0) {
192
+ setStep(SETUP_STEPS.COMPONENTS);
193
+ setActiveIndex(0);
194
+ }
195
+ return;
196
+ }
197
+
198
+ if (step === SETUP_STEPS.COMPONENTS) {
199
+ if (key.upArrow) {
200
+ setActiveIndex((index) => Math.max(0, index - 1));
201
+ return;
202
+ }
203
+ if (key.downArrow) {
204
+ setActiveIndex((index) => Math.min(componentOptions.length - 1, index + 1));
205
+ return;
206
+ }
207
+ if (inputKey === " ") {
208
+ const id = componentOptions[activeIndex].id;
209
+ setSelectedComponents((current) => toggleComponentSelection(current, id));
210
+ return;
211
+ }
212
+ if (key.return) {
213
+ setStep(SETUP_STEPS.PREVIEW);
214
+ setPreview(null);
215
+ setPreviewError(null);
216
+ }
217
+ return;
218
+ }
219
+
220
+ if (step === SETUP_STEPS.PREVIEW && key.return && preview && !previewLoading) {
221
+ setStep(SETUP_STEPS.CONFIRM);
222
+ return;
223
+ }
224
+
225
+ if (step === SETUP_STEPS.CONFIRM) {
226
+ if (inputKey.toLowerCase() === "y") {
227
+ const { noDefaults, selected } = resolveComponentSelection(selectedComponents, { workspaceRoot });
228
+ finish({
229
+ cancelled: false,
230
+ usedWizard: true,
231
+ agents: selectedAgents,
232
+ components: selected,
233
+ noDefaultComponents: noDefaults,
234
+ preview
235
+ });
236
+ }
237
+ if (inputKey.toLowerCase() === "n") {
238
+ finish({ cancelled: true, usedWizard: true });
239
+ }
240
+ }
241
+ });
242
+
243
+ const detectPanel = formatInkDetectPanel({ adapters, detected });
244
+
245
+ return React.createElement(Box, { flexDirection: "column" },
246
+ step === SETUP_STEPS.SPLASH && React.createElement(Splash, { compact: useCompactSplash }),
247
+ step !== SETUP_STEPS.SPLASH && React.createElement(Header),
248
+ step === SETUP_STEPS.DETECT && React.createElement(Panel, { title: WIZARD_COPY.detectTitle },
249
+ detectPanel.split("\n")
250
+ .map((line) => React.createElement(Text, { key: line }, line))
251
+ ),
252
+ step === SETUP_STEPS.AGENTS && React.createElement(Panel, { title: WIZARD_COPY.agentsPrompt },
253
+ formatInkSelectList({ options: agentOptions, selected: selectedAgents, activeIndex })
254
+ .map((line) => React.createElement(Text, { key: line }, line))
255
+ ),
256
+ step === SETUP_STEPS.COMPONENTS && React.createElement(Panel, { title: WIZARD_COPY.componentsPrompt },
257
+ formatInkSelectList({ options: componentOptions, selected: selectedComponents, activeIndex })
258
+ .map((line) => React.createElement(Text, { key: line }, line))
259
+ ),
260
+ step === SETUP_STEPS.PREVIEW && React.createElement(Panel, { title: WIZARD_COPY.previewTitle },
261
+ previewLoading && React.createElement(Text, { color: INK_COLORS.warning }, "Building preview…"),
262
+ previewError && React.createElement(Text, { color: INK_COLORS.danger }, previewError),
263
+ preview && formatInkPreviewLines({ preview, componentCatalog })
264
+ .map((line) => React.createElement(Text, { key: line }, line))
265
+ ),
266
+ step === SETUP_STEPS.CONFIRM && React.createElement(Panel, { title: "Confirm" },
267
+ React.createElement(Text, null, dryRun ? WIZARD_COPY.confirmDryRun : WIZARD_COPY.confirmApply)
268
+ ),
269
+ React.createElement(Footer, null,
270
+ step === SETUP_STEPS.SPLASH && `${BRAND.splashHint} · Esc cancel`,
271
+ step === SETUP_STEPS.DETECT && "Enter continue · Esc cancel",
272
+ step === SETUP_STEPS.AGENTS && "↑↓ move · Space toggle · Enter continue · Esc cancel",
273
+ step === SETUP_STEPS.COMPONENTS && "↑↓ move · Space toggle · Enter continue · Esc cancel",
274
+ step === SETUP_STEPS.PREVIEW && preview && !previewLoading && "Enter continue · Esc cancel",
275
+ step === SETUP_STEPS.CONFIRM && "Y apply · N cancel · Esc cancel"
276
+ )
277
+ );
278
+ }
@@ -0,0 +1,51 @@
1
+ import { canUseSetupInk } from "./terminal.js";
2
+
3
+ const BARE_SETUP_FLAGS = [
4
+ "interactive",
5
+ "dryRun",
6
+ "yes",
7
+ "confirm",
8
+ "json",
9
+ "agents",
10
+ "components",
11
+ "noDefaultComponents"
12
+ ];
13
+
14
+ function isBareInteractiveSetup({
15
+ interactive,
16
+ yes = false,
17
+ confirm = false,
18
+ json = false,
19
+ agents = null,
20
+ components = null,
21
+ noDefaultComponents = false
22
+ } = {}) {
23
+ if (!interactive || json) return false;
24
+ if (yes || confirm) return false;
25
+ if (agents != null || components != null || noDefaultComponents) return false;
26
+ return true;
27
+ }
28
+
29
+ export function shouldUseSetupInk({
30
+ interactive,
31
+ simple = false,
32
+ inkCapable = canUseSetupInk({ interactive }),
33
+ ...flags
34
+ } = {}) {
35
+ if (simple) return false;
36
+ if (!isBareInteractiveSetup({ interactive, ...flags })) return false;
37
+ return inkCapable;
38
+ }
39
+
40
+ export function shouldUseClackWizard({
41
+ interactive,
42
+ simple = false,
43
+ inkCapable = canUseSetupInk({ interactive }),
44
+ ...flags
45
+ } = {}) {
46
+ if (!isBareInteractiveSetup({ interactive, ...flags })) return false;
47
+ if (!simple && inkCapable) return false;
48
+ return true;
49
+ }
50
+
51
+ export { BARE_SETUP_FLAGS, isBareInteractiveSetup };
@@ -0,0 +1,180 @@
1
+ import { AGENT_HINTS, BRAND, PREFERRED_CLI, formatCliCommand, getAgentLabel, WIZARD_COPY } from "../brand/index.js";
2
+ import { formatAgentMultiselectHint } from "../clack/theme.js";
3
+
4
+ export const SETUP_STEPS = {
5
+ SPLASH: "splash",
6
+ DETECT: "detect",
7
+ AGENTS: "agents",
8
+ COMPONENTS: "components",
9
+ PREVIEW: "preview",
10
+ CONFIRM: "confirm"
11
+ };
12
+
13
+ export function shouldUseCompactSplashLogo(columns) {
14
+ if (!columns || columns <= 0) return false;
15
+ const fullWidth = Math.max(...BRAND.asciiLogo.map((line) => line.length));
16
+ return columns < fullWidth + 4;
17
+ }
18
+
19
+ export function formatInkSplashLines({ compact = false } = {}) {
20
+ const logo = compact ? BRAND.compactLogo : BRAND.asciiLogo;
21
+ return [
22
+ ...logo,
23
+ "",
24
+ BRAND.name,
25
+ BRAND.tagline,
26
+ "",
27
+ BRAND.splashHint
28
+ ];
29
+ }
30
+
31
+ export const INITIAL_SETUP_STEP = SETUP_STEPS.SPLASH;
32
+
33
+ export function shouldStartPreviewLoad({ step, preview, previewError }) {
34
+ if (step !== SETUP_STEPS.PREVIEW) return false;
35
+ if (preview || previewError) return false;
36
+ return true;
37
+ }
38
+
39
+ export function transitionFromSplash({ escape = false, enter = false } = {}) {
40
+ if (escape) {
41
+ return { kind: "cancel" };
42
+ }
43
+ if (enter) {
44
+ return { kind: "advance", step: SETUP_STEPS.DETECT };
45
+ }
46
+ return { kind: "noop" };
47
+ }
48
+
49
+ export function toggleSelection(selected, id) {
50
+ if (selected.includes(id)) {
51
+ return selected.filter((entry) => entry !== id);
52
+ }
53
+ return [...selected, id];
54
+ }
55
+
56
+ export function toggleComponentSelection(selected, id) {
57
+ if (id === "__none__") {
58
+ return selected.includes("__none__") ? [] : ["__none__"];
59
+ }
60
+
61
+ const withoutNone = selected.filter((entry) => entry !== "__none__");
62
+ return toggleSelection(withoutNone, id);
63
+ }
64
+
65
+ export function buildAgentOptions(adapters, detected) {
66
+ return adapters.map((adapter) => ({
67
+ id: adapter.id,
68
+ label: getAgentLabel(adapter.id),
69
+ hint: formatAgentMultiselectHint(adapter.id, detected)
70
+ }));
71
+ }
72
+
73
+ export function buildComponentOptions(components) {
74
+ return [
75
+ ...components.map((component) => ({
76
+ id: component.id,
77
+ label: component.label,
78
+ hint: component.defaultEnabled ? "recommended" : undefined
79
+ })),
80
+ {
81
+ id: "__none__",
82
+ label: WIZARD_COPY.coreOnlyLabel,
83
+ hint: undefined
84
+ }
85
+ ];
86
+ }
87
+
88
+ export function formatInkHeaderLines() {
89
+ return [
90
+ BRAND.name,
91
+ BRAND.tagline,
92
+ BRAND.splashLine
93
+ ];
94
+ }
95
+
96
+ export function formatInkDetectPanel({ adapters, detected }) {
97
+ const readyCount = detected.length;
98
+ const lines = [
99
+ `Your agents · ${readyCount}/${adapters.length} roots found`,
100
+ ""
101
+ ];
102
+
103
+ for (const adapter of adapters) {
104
+ const isReady = detected.includes(adapter.id);
105
+ const status = isReady ? AGENT_HINTS.ready : AGENT_HINTS.notDetected;
106
+ lines.push(`${getAgentLabel(adapter.id)} · ${status}`);
107
+ }
108
+
109
+ return lines.join("\n");
110
+ }
111
+
112
+ export function formatInkSelectList({ options, selected, activeIndex }) {
113
+ return options.map((option, index) => {
114
+ const checked = selected.includes(option.id) ? "[x]" : "[ ]";
115
+ const pointer = index === activeIndex ? "›" : " ";
116
+ const hint = option.hint ? ` (${option.hint})` : "";
117
+ return `${pointer} ${checked} ${option.label}${hint}`;
118
+ });
119
+ }
120
+
121
+ export function formatInkPreviewLines({ preview, componentCatalog }) {
122
+ const labelById = new Map(componentCatalog.map((entry) => [entry.id, entry.label]));
123
+ const agentLine = preview.agents.map((id) => getAgentLabel(id)).join(", ") || "none";
124
+ const componentLine = preview.components.length > 0
125
+ ? preview.components.map((id) => labelById.get(id) ?? id).join(", ")
126
+ : WIZARD_COPY.coreOnlyLabel;
127
+
128
+ const lines = [
129
+ "Agents",
130
+ ` ${agentLine}`,
131
+ "",
132
+ "Components",
133
+ ` ${componentLine}`,
134
+ "",
135
+ "Managed writes"
136
+ ];
137
+
138
+ if (preview.preflight.changes.length === 0) {
139
+ lines.push(" none — already in sync");
140
+ } else {
141
+ for (const change of preview.preflight.changes) {
142
+ const verb = change.action === "create" ? "+" : change.action === "repair" ? "~" : "↻";
143
+ lines.push(` ${verb} ${change.target}`);
144
+ }
145
+ }
146
+
147
+ lines.push("", "Preserved content");
148
+ if (preview.preflight.preserved.length === 0) {
149
+ lines.push(" none");
150
+ } else {
151
+ for (const entry of preview.preflight.preserved) {
152
+ lines.push(` ${entry.path}`);
153
+ }
154
+ }
155
+
156
+ return lines;
157
+ }
158
+
159
+ export function formatInkSuccessLines(result, { dryRun = false, cliName = PREFERRED_CLI } = {}) {
160
+ const agentLine = result.agents.map((id) => getAgentLabel(id)).join(", ");
161
+ const componentLine = result.components.length > 0
162
+ ? result.components.join(", ")
163
+ : WIZARD_COPY.coreOnlyLabel;
164
+
165
+ return [
166
+ dryRun ? WIZARD_COPY.resultDryRunTitle : WIZARD_COPY.resultSuccessTitle,
167
+ "",
168
+ `State ${result.stateRoot}`,
169
+ `Agents ${agentLine}`,
170
+ `Comps ${componentLine}`,
171
+ "",
172
+ "Next steps",
173
+ dryRun
174
+ ? ` ${formatCliCommand("setup --confirm", cliName)}`
175
+ : ` ${formatCliCommand("status", cliName)}`,
176
+ dryRun
177
+ ? ` ${formatCliCommand("setup --dry-run", cliName)}`
178
+ : ` ${formatCliCommand("doctor", cliName)}`
179
+ ];
180
+ }
@@ -0,0 +1,13 @@
1
+ import { stdin as input, stdout as output } from "node:process";
2
+
3
+ export function canUseSetupInk({
4
+ interactive = Boolean(input.isTTY && output.isTTY),
5
+ term = process.env.TERM ?? "",
6
+ columns = output.columns ?? 80,
7
+ forceInk = process.env.HARNESS_INK !== "0"
8
+ } = {}) {
9
+ if (!interactive || !forceInk) return false;
10
+ if (term === "dumb") return false;
11
+ if (columns > 0 && columns < 60) return false;
12
+ return true;
13
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Stable control-plane JSON envelope for CI, tooling, and debugging.
3
+ * Field order and names are part of the public contract.
4
+ */
5
+ export function buildControlPlaneJson(report, { cliVersion, extras = {} } = {}) {
6
+ return {
7
+ ok: report.ok,
8
+ overall: report.overall,
9
+ agents: report.agents,
10
+ components: report.components,
11
+ checks: report.checks,
12
+ backups: report.backups,
13
+ nextAction: report.nextAction,
14
+ policy: report.policy,
15
+ cliVersion,
16
+ ...extras
17
+ };
18
+ }
19
+
20
+ export function printJson(payload) {
21
+ console.log(JSON.stringify(payload));
22
+ }
@@ -0,0 +1,41 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { createManagedSectionBuilder } from "./component-builders.js";
3
+
4
+ const defaultCatalogUrl = new URL("../../global-template/components/catalog.json", import.meta.url);
5
+
6
+ function validateCatalogEntry(entry) {
7
+ const required = ["id", "label", "version", "defaultEnabled", "assetFiles"];
8
+
9
+ for (const field of required) {
10
+ if (entry[field] === undefined) {
11
+ throw new Error(`Component catalog entry is missing "${field}".`);
12
+ }
13
+ }
14
+
15
+ if (!Array.isArray(entry.assetFiles) || entry.assetFiles.length === 0) {
16
+ throw new Error(`Component "${entry.id}" must declare at least one asset file.`);
17
+ }
18
+ }
19
+
20
+ export function readComponentCatalogDocument(catalogUrl = defaultCatalogUrl) {
21
+ return JSON.parse(readFileSync(catalogUrl, "utf8"));
22
+ }
23
+
24
+ export function loadComponentCatalog(catalogUrl = defaultCatalogUrl) {
25
+ const catalog = readComponentCatalogDocument(catalogUrl);
26
+
27
+ return catalog.components.map((entry) => {
28
+ validateCatalogEntry(entry);
29
+
30
+ return {
31
+ id: entry.id,
32
+ label: entry.label,
33
+ version: entry.version,
34
+ source: "bundled",
35
+ defaultEnabled: entry.defaultEnabled,
36
+ assetFiles: [...entry.assetFiles],
37
+ adapterHints: { ...(entry.adapterHints ?? {}) },
38
+ buildManagedSection: createManagedSectionBuilder(entry.id, entry)
39
+ };
40
+ });
41
+ }