@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,89 @@
1
+ import { loadComponentCatalog } from "./load-component-catalog.js";
2
+ import { loadWorkspaceComponentCatalog } from "./load-workspace-component-catalog.js";
3
+
4
+ const BUNDLED_COMPONENTS = loadComponentCatalog();
5
+
6
+ export const DEFAULT_COMPONENT_IDS = BUNDLED_COMPONENTS
7
+ .filter((component) => component.defaultEnabled)
8
+ .map((component) => component.id);
9
+
10
+ export const COMPONENT_IDS = BUNDLED_COMPONENTS.map((component) => component.id);
11
+
12
+ function loadWorkspaceComponents(workspaceRoot) {
13
+ if (!workspaceRoot) return [];
14
+
15
+ return loadWorkspaceComponentCatalog(workspaceRoot, { bundledIds: COMPONENT_IDS });
16
+ }
17
+
18
+ function mergeComponents(workspaceRoot) {
19
+ return [...BUNDLED_COMPONENTS, ...loadWorkspaceComponents(workspaceRoot)];
20
+ }
21
+
22
+ function formatCatalogEntry(component) {
23
+ return {
24
+ id: component.id,
25
+ label: component.label,
26
+ version: component.version,
27
+ source: component.source ?? "bundled",
28
+ defaultEnabled: component.defaultEnabled,
29
+ assetFiles: [...component.assetFiles],
30
+ adapterHints: Object.keys(component.adapterHints),
31
+ instructions: component.instructions ?? null
32
+ };
33
+ }
34
+
35
+ export function listComponents({ workspaceRoot = null } = {}) {
36
+ return mergeComponents(workspaceRoot);
37
+ }
38
+
39
+ export function describeComponentCatalog({ workspaceRoot = null } = {}) {
40
+ return listComponents({ workspaceRoot }).map(formatCatalogEntry);
41
+ }
42
+
43
+ export function describeBundledComponentCatalog() {
44
+ return BUNDLED_COMPONENTS.map(formatCatalogEntry);
45
+ }
46
+
47
+ export function describeWorkspaceComponentCatalog(workspaceRoot) {
48
+ return loadWorkspaceComponents(workspaceRoot).map(formatCatalogEntry);
49
+ }
50
+
51
+ export function resolveComponent(id, { workspaceRoot = null } = {}) {
52
+ const component = mergeComponents(workspaceRoot).find((candidate) => candidate.id === id);
53
+
54
+ if (!component) {
55
+ const available = mergeComponents(workspaceRoot).map((entry) => entry.id);
56
+ throw new Error(`Unknown component "${id}". Use ${available.join(", ")}.`);
57
+ }
58
+
59
+ return component;
60
+ }
61
+
62
+ export function validateComponentIds(ids, { workspaceRoot = null } = {}) {
63
+ return ids.map((id) => resolveComponent(id, { workspaceRoot }).id);
64
+ }
65
+
66
+ export function resolveTargetComponents({
67
+ components = null,
68
+ noDefaultComponents = false,
69
+ workspaceRoot = null
70
+ } = {}) {
71
+ if (components != null) {
72
+ return validateComponentIds(components, { workspaceRoot }).map((id) => resolveComponent(id, { workspaceRoot }));
73
+ }
74
+
75
+ if (noDefaultComponents) return [];
76
+
77
+ return DEFAULT_COMPONENT_IDS.map((id) => resolveComponent(id, { workspaceRoot }));
78
+ }
79
+
80
+ export function buildComponentStateEntries(components, adapters) {
81
+ const managedTargets = adapters.map((adapter) => adapter.assets.configFile);
82
+
83
+ return components.map((component) => ({
84
+ id: component.id,
85
+ version: component.version,
86
+ source: component.source ?? "bundled",
87
+ managedTargets: [...managedTargets]
88
+ }));
89
+ }
@@ -0,0 +1,14 @@
1
+ import { join } from "node:path";
2
+
3
+ export function buildOrchestratorManagedSection(context, adapter) {
4
+ const contractPath = join(context.componentsDir, "orchestrator", "orchestrator.md");
5
+
6
+ return [
7
+ "### Orchestrator",
8
+ "",
9
+ `- Contract: ${contractPath}`,
10
+ "- Coordinates cross-agent handoffs; does not replace any agent.",
11
+ `- Adapter target: ~/${adapter.assets.configFile}`,
12
+ "- Repository AGENTS.md governs when a repo harness is present."
13
+ ].join("\n");
14
+ }
@@ -0,0 +1,17 @@
1
+ import { join } from "node:path";
2
+
3
+ export function buildSddCoreManagedSection(context, adapter, catalogEntry) {
4
+ const baseDir = join(context.componentsDir, "sdd-core");
5
+ const adapterNote = catalogEntry?.adapterHints?.[adapter.id] ?? null;
6
+
7
+ return [
8
+ "### SDD Core",
9
+ "",
10
+ `- Workflow: ${join(baseDir, "workflow.md")}`,
11
+ `- Spec sizing: ${join(baseDir, "spec-sizing.md")}`,
12
+ `- Handoff rules: ${join(baseDir, "handoff.md")}`,
13
+ "- Classify work as basic, standard, or complex before implementing.",
14
+ "- No significant feature without a spec; no bug fix without a failing test first.",
15
+ adapterNote
16
+ ].filter(Boolean).join("\n");
17
+ }
@@ -0,0 +1,233 @@
1
+ import { existsSync } from "node:fs";
2
+ import { readFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { updateGlobalHarness } from "./global-installer.js";
5
+ import { harnessHomePaths } from "./paths.js";
6
+ import { readGlobalState } from "./state.js";
7
+ import { buildStatusReport } from "./status.js";
8
+ import { userOwnedContent } from "./managed-section.js";
9
+ import { formatCliCommand } from "./brand/cli.js";
10
+
11
+ export async function buildDiffReport(homeDir, {
12
+ packageRoot,
13
+ packageName,
14
+ cliVersion,
15
+ workspaceRoot = null
16
+ }) {
17
+ const paths = harnessHomePaths(homeDir);
18
+ const state = await readGlobalState(paths.statePath);
19
+
20
+ if (!state) {
21
+ return {
22
+ homeDir,
23
+ installed: false,
24
+ status: "setup-required",
25
+ hasChanges: false,
26
+ summary: "No managed state found.",
27
+ nextAction: `Run "${formatCliCommand("setup --dry-run")}" to preview the initial managed plan.`,
28
+ changes: [],
29
+ preserved: []
30
+ };
31
+ }
32
+
33
+ const statusReport = await buildStatusReport(homeDir, { packageRoot, workspaceRoot });
34
+ const needsRepair = statusReport.overall === "drift"
35
+ || statusReport.counts.missing > 0
36
+ || statusReport.counts.stale > 0;
37
+
38
+ if (!needsRepair) {
39
+ return {
40
+ homeDir,
41
+ installed: true,
42
+ status: "clean",
43
+ hasChanges: false,
44
+ summary: "No managed changes.",
45
+ nextAction: "Ecosystem in sync. No managed changes would be applied.",
46
+ changes: [],
47
+ preserved: await collectPreservedContent(homeDir, state)
48
+ };
49
+ }
50
+
51
+ const plan = await updateGlobalHarness({
52
+ packageRoot,
53
+ packageName,
54
+ cliVersion,
55
+ homeDir,
56
+ workspaceRoot,
57
+ dryRun: true
58
+ });
59
+
60
+ const changes = buildChangesFromPlan(plan);
61
+ const preserved = await collectPreservedForChanges(homeDir, plan);
62
+
63
+ return {
64
+ homeDir,
65
+ installed: true,
66
+ status: "drift",
67
+ hasChanges: true,
68
+ summary: `${changes.length} managed change(s) planned.`,
69
+ nextAction: `Run "${formatCliCommand("sync")}" to apply these managed repairs.`,
70
+ changes,
71
+ preserved
72
+ };
73
+ }
74
+
75
+ export async function summarizeInstallPreflight(homeDir, plan) {
76
+ const changes = buildChangesFromPlan({ ...plan, repairs: plan.repairs ?? [] });
77
+
78
+ for (const coreFile of plan.coreFiles ?? []) {
79
+ if (changes.some((change) => change.target === coreFile)) continue;
80
+ changes.push({
81
+ kind: "component_asset",
82
+ action: "create",
83
+ target: coreFile,
84
+ status: "planned",
85
+ detail: `Component asset would be written to ~/.harness/${coreFile}.`
86
+ });
87
+ }
88
+
89
+ const preserved = await collectPreservedForChanges(homeDir, plan);
90
+
91
+ return {
92
+ summary: changes.length > 0
93
+ ? `${changes.length} managed change(s) planned.`
94
+ : "No managed changes planned.",
95
+ changes,
96
+ preserved
97
+ };
98
+ }
99
+
100
+ export function buildChangesFromPlan(plan) {
101
+ const changes = [];
102
+
103
+ for (const repair of plan.repairs ?? []) {
104
+ changes.push({
105
+ kind: repair.category,
106
+ action: repairAction(repair),
107
+ target: repairTarget(repair),
108
+ status: repair.status,
109
+ detail: repair.detail
110
+ });
111
+ }
112
+
113
+ for (const configFile of plan.configsCreated ?? []) {
114
+ if (changes.some((change) => change.target === configFile)) continue;
115
+ changes.push({
116
+ kind: "config",
117
+ action: "create",
118
+ target: configFile,
119
+ status: "planned",
120
+ detail: `Managed config would be created at ~/${configFile}.`
121
+ });
122
+ }
123
+
124
+ for (const configFile of plan.configsUpdated ?? []) {
125
+ if (changes.some((change) => change.target === configFile)) continue;
126
+ changes.push({
127
+ kind: "config",
128
+ action: "update",
129
+ target: configFile,
130
+ status: "planned",
131
+ detail: `Managed config would be updated at ~/${configFile}.`
132
+ });
133
+ }
134
+
135
+ for (const configFile of plan.configsRepaired ?? []) {
136
+ if (changes.some((change) => change.target === configFile)) continue;
137
+ changes.push({
138
+ kind: "config",
139
+ action: "repair",
140
+ target: configFile,
141
+ status: "planned",
142
+ detail: `Managed section would be repaired at ~/${configFile}.`
143
+ });
144
+ }
145
+
146
+ return changes;
147
+ }
148
+
149
+ function repairAction(repair) {
150
+ if (repair.status === "missing") {
151
+ return repair.category === "managed_section" ? "create" : "repair";
152
+ }
153
+
154
+ if (repair.status === "stale") {
155
+ return repair.category === "managed_section" || repair.category === "component_section"
156
+ ? "replace"
157
+ : "repair";
158
+ }
159
+
160
+ return "repair";
161
+ }
162
+
163
+ function repairTarget(repair) {
164
+ if (repair.category === "component_asset") {
165
+ return repair.name.replace(/^~\//, "");
166
+ }
167
+
168
+ return repair.configFile ?? repair.name;
169
+ }
170
+
171
+ async function collectPreservedContent(homeDir, state) {
172
+ const preserved = [];
173
+ const configFiles = new Set(
174
+ (state.adapters ?? []).map((adapter) => adapter.configFile)
175
+ );
176
+
177
+ for (const configFile of configFiles) {
178
+ const entry = await readPreservedEntry(homeDir, configFile);
179
+ if (entry) preserved.push(entry);
180
+ }
181
+
182
+ return preserved;
183
+ }
184
+
185
+ async function collectPreservedForChanges(homeDir, plan) {
186
+ const configFiles = new Set([
187
+ ...(plan.configsCreated ?? []),
188
+ ...(plan.configsUpdated ?? []),
189
+ ...(plan.configsRepaired ?? []),
190
+ ...(plan.repairs ?? [])
191
+ .filter((repair) => repair.configFile)
192
+ .map((repair) => repair.configFile)
193
+ ]);
194
+
195
+ const preserved = [];
196
+
197
+ for (const configFile of configFiles) {
198
+ const entry = await readPreservedEntry(homeDir, configFile);
199
+ if (entry) preserved.push(entry);
200
+ }
201
+
202
+ return preserved;
203
+ }
204
+
205
+ async function readPreservedEntry(homeDir, configFile) {
206
+ const configPath = join(homeDir, configFile);
207
+ if (!existsSync(configPath)) return null;
208
+
209
+ const content = await readFile(configPath, "utf8");
210
+ const preserved = userOwnedContent(content).trim();
211
+
212
+ if (preserved.length === 0) return null;
213
+
214
+ return {
215
+ path: configFile,
216
+ preservedUserContent: preserved,
217
+ intact: true
218
+ };
219
+ }
220
+
221
+ export function buildDiffJson(report, { cliVersion = null } = {}) {
222
+ return {
223
+ ok: true,
224
+ installed: report.installed,
225
+ status: report.status,
226
+ hasChanges: report.hasChanges,
227
+ cliVersion,
228
+ summary: report.summary,
229
+ nextAction: report.nextAction,
230
+ changes: report.changes,
231
+ preserved: report.preserved
232
+ };
233
+ }
@@ -0,0 +1,264 @@
1
+ import { existsSync } from "node:fs";
2
+ import { readFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { hashBuffer } from "../hash.js";
5
+ import { buildManagedBody } from "./managed-body.js";
6
+ import { hasManagedSection, upsertManagedSection } from "./managed-section.js";
7
+ import { resolveComponent } from "./component-registry.js";
8
+ import { resolveComponentTemplateDir } from "./component-paths.js";
9
+ import { listAdapters } from "./registry.js";
10
+ import { formatCliCommand } from "./brand/cli.js";
11
+
12
+ export async function detectGlobalDrift({ homeDir, paths, state, packageRoot, workspaceRoot = null, context }) {
13
+ if (!state) {
14
+ return [{
15
+ name: "~/.harness/state.json",
16
+ status: "missing",
17
+ category: "state",
18
+ detail: `Not found. Run "${formatCliCommand("install")}" first.`
19
+ }];
20
+ }
21
+
22
+ const checks = [
23
+ stateMetadataCheck(state),
24
+ ...await componentAssetDrift({ paths, state, packageRoot, workspaceRoot, context }),
25
+ ...await managedSectionDrift({ homeDir, state, context }),
26
+ ...await componentSectionDrift({ homeDir, state, workspaceRoot, context }),
27
+ ...await adapterConfigDrift({ homeDir, state, context })
28
+ ];
29
+
30
+ return checks;
31
+ }
32
+
33
+ export function hasRepairableDrift(checks) {
34
+ return checks.some((check) => check.status === "missing" || check.status === "stale");
35
+ }
36
+
37
+ export function driftChecksToDoctor(checks) {
38
+ return checks;
39
+ }
40
+
41
+ function stateMetadataCheck(state) {
42
+ return {
43
+ name: "~/.harness/state.json",
44
+ status: "ok",
45
+ category: "state",
46
+ detail: `cliVersion=${state.cliVersion ?? "unknown"}, adapters=${state.adapters?.length ?? 0}, components=${state.components?.length ?? 0}`
47
+ };
48
+ }
49
+
50
+ async function componentAssetDrift({ paths, state, packageRoot, workspaceRoot, context }) {
51
+ const checks = [];
52
+ const installedComponents = context.components;
53
+
54
+ for (const component of installedComponents) {
55
+ const templateDir = resolveComponentTemplateDir(component, { packageRoot, workspaceRoot });
56
+ if (!existsSync(templateDir)) continue;
57
+
58
+ for (const assetFile of component.assetFiles) {
59
+ const relativePath = `components/${component.id}/${assetFile}`;
60
+ const templatePath = join(templateDir, assetFile);
61
+ const destinationPath = join(paths.root, relativePath);
62
+ const templateContent = await readFile(templatePath);
63
+ const expectedHash = hashBuffer(templateContent);
64
+
65
+ if (!existsSync(destinationPath)) {
66
+ checks.push({
67
+ name: `~/.harness/${relativePath}`,
68
+ status: "missing",
69
+ category: "component_asset",
70
+ componentId: component.id,
71
+ detail: "Component asset missing on disk."
72
+ });
73
+ continue;
74
+ }
75
+
76
+ const diskContent = await readFile(destinationPath);
77
+ const diskHash = hashBuffer(diskContent);
78
+ const trackedHash = state.coreFiles?.[relativePath];
79
+
80
+ if (diskHash !== expectedHash) {
81
+ checks.push({
82
+ name: `~/.harness/${relativePath}`,
83
+ status: "stale",
84
+ category: "component_asset",
85
+ componentId: component.id,
86
+ detail: `Asset hash drift (disk ${diskHash.slice(0, 8)} vs template ${expectedHash.slice(0, 8)}).`
87
+ });
88
+ } else if (trackedHash && trackedHash !== expectedHash) {
89
+ checks.push({
90
+ name: `~/.harness/${relativePath}`,
91
+ status: "stale",
92
+ category: "component_asset",
93
+ componentId: component.id,
94
+ detail: `State hash drift. Run ${formatCliCommand("sync")} to refresh metadata.`
95
+ });
96
+ } else {
97
+ checks.push({
98
+ name: `~/.harness/${relativePath}`,
99
+ status: "ok",
100
+ category: "component_asset",
101
+ componentId: component.id,
102
+ detail: `hash=${expectedHash.slice(0, 8)}`
103
+ });
104
+ }
105
+ }
106
+ }
107
+
108
+ return checks;
109
+ }
110
+
111
+ async function managedSectionDrift({ homeDir, state, context }) {
112
+ const checks = [];
113
+ const installedAdapterIds = new Set(state.adapters?.map((entry) => entry.id) ?? []);
114
+
115
+ for (const adapter of listAdapters()) {
116
+ if (!installedAdapterIds.has(adapter.id)) continue;
117
+
118
+ const configFile = adapter.assets.configFile;
119
+ const configPath = join(homeDir, configFile);
120
+ const checkName = `managed-section:${configFile}`;
121
+
122
+ if (!existsSync(configPath)) {
123
+ checks.push({
124
+ name: checkName,
125
+ status: "missing",
126
+ category: "managed_section",
127
+ adapterId: adapter.id,
128
+ configFile,
129
+ detail: `Installed adapter config missing: ~/${configFile}`
130
+ });
131
+ continue;
132
+ }
133
+
134
+ const content = await readFile(configPath, "utf8");
135
+ const expectedBody = buildManagedBody(context, { id: adapter.id, assets: adapter.assets });
136
+ const sectionStatus = classifyManagedSection(content, expectedBody);
137
+
138
+ checks.push({
139
+ name: checkName,
140
+ status: sectionStatus,
141
+ category: "managed_section",
142
+ adapterId: adapter.id,
143
+ configFile,
144
+ detail: managedSectionDetail(sectionStatus, configFile)
145
+ });
146
+ }
147
+
148
+ return checks;
149
+ }
150
+
151
+ async function componentSectionDrift({ homeDir, state, workspaceRoot, context }) {
152
+ const checks = [];
153
+
154
+ for (const stateEntry of state.components ?? []) {
155
+ const component = resolveComponent(stateEntry.id, { workspaceRoot });
156
+ const heading = componentSectionHeading(component);
157
+
158
+ for (const configFile of stateEntry.managedTargets ?? []) {
159
+ const configPath = join(homeDir, configFile);
160
+ const checkName = `component-section:${component.id}:${configFile}`;
161
+
162
+ if (!existsSync(configPath)) {
163
+ checks.push({
164
+ name: checkName,
165
+ status: "missing",
166
+ category: "component_section",
167
+ componentId: component.id,
168
+ configFile,
169
+ detail: `Managed target missing: ~/${configFile}`
170
+ });
171
+ continue;
172
+ }
173
+
174
+ const content = await readFile(configPath, "utf8");
175
+ let status = "ok";
176
+
177
+ if (!hasManagedSection(content)) {
178
+ status = "missing";
179
+ } else if (!content.includes(heading)) {
180
+ status = "stale";
181
+ }
182
+
183
+ checks.push({
184
+ name: checkName,
185
+ status,
186
+ category: "component_section",
187
+ componentId: component.id,
188
+ configFile,
189
+ detail: componentSectionDetail(status, component.id, configFile)
190
+ });
191
+ }
192
+ }
193
+
194
+ return checks;
195
+ }
196
+
197
+ async function adapterConfigDrift({ homeDir, state, context }) {
198
+ const checks = [];
199
+
200
+ for (const adapter of listAdapters()) {
201
+ const stateEntry = state.adapters?.find((entry) => entry.id === adapter.id);
202
+ const detected = adapter.detect(context);
203
+ const isRelevant = detected || Boolean(stateEntry);
204
+
205
+ if (!isRelevant) {
206
+ checks.push({
207
+ name: `agent:${adapter.id}`,
208
+ status: "warning",
209
+ category: "adapter",
210
+ adapterId: adapter.id,
211
+ detail: "Not detected on this machine."
212
+ });
213
+ continue;
214
+ }
215
+
216
+ if (!stateEntry) continue;
217
+
218
+ const configPath = join(homeDir, adapter.assets.configFile);
219
+ if (!existsSync(configPath)) {
220
+ checks.push({
221
+ name: `agent:${adapter.id}`,
222
+ status: "missing",
223
+ category: "adapter",
224
+ adapterId: adapter.id,
225
+ detail: `Installed in state but config missing: ~/${adapter.assets.configFile}`
226
+ });
227
+ }
228
+ }
229
+
230
+ return checks;
231
+ }
232
+
233
+ function classifyManagedSection(content, expectedBody) {
234
+ if (!hasManagedSection(content)) return "missing";
235
+
236
+ const { changed } = upsertManagedSection(content, expectedBody);
237
+ return changed ? "stale" : "ok";
238
+ }
239
+
240
+ function managedSectionDetail(status, configFile) {
241
+ switch (status) {
242
+ case "missing":
243
+ return `No managed section in ~/${configFile}. Run "${formatCliCommand("sync")}".`;
244
+ case "stale":
245
+ return `Stale managed section in ~/${configFile}. Run "${formatCliCommand("sync")}".`;
246
+ default:
247
+ return `Managed section in sync at ~/${configFile}`;
248
+ }
249
+ }
250
+
251
+ function componentSectionDetail(status, componentId, configFile) {
252
+ switch (status) {
253
+ case "missing":
254
+ return `Missing managed section for ${componentId} in ~/${configFile}`;
255
+ case "stale":
256
+ return `Stale managed section for ${componentId} in ~/${configFile}`;
257
+ default:
258
+ return `Component section in sync for ${componentId} in ~/${configFile}`;
259
+ }
260
+ }
261
+
262
+ function componentSectionHeading(component) {
263
+ return `### ${component.label}`;
264
+ }