@kal-elsam/kairo-runtime 0.13.1 → 0.15.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 (53) hide show
  1. package/CHANGELOG.md +107 -0
  2. package/README.md +12 -10
  3. package/bin/kairo-runtime.js +0 -0
  4. package/bin/kairo.js +0 -0
  5. package/package.json +5 -1
  6. package/scripts/cockpit-smoke.mjs +14 -10
  7. package/src/cli.js +182 -11
  8. package/src/global/check-resolutions.js +31 -0
  9. package/src/global/cli-help.js +23 -4
  10. package/src/global/component-ecosystem-checks.js +2 -0
  11. package/src/global/component-integration-cli.js +29 -10
  12. package/src/global/components-resolve-cli.js +246 -0
  13. package/src/global/connection-actions.js +147 -0
  14. package/src/global/connections.js +269 -0
  15. package/src/global/fleet-configure-plan.js +123 -0
  16. package/src/global/fleet-configure.js +303 -0
  17. package/src/global/fleet-models.js +188 -0
  18. package/src/global/fleet-set.js +219 -0
  19. package/src/global/fleet-shared.js +38 -0
  20. package/src/global/ink/cockpit-controller.js +2 -4
  21. package/src/global/ink/cockpit-enter.js +3 -1
  22. package/src/global/ink/cockpit-focus.js +7 -1
  23. package/src/global/ink/cockpit-models.js +33 -21
  24. package/src/global/ink/cockpit-palette.js +8 -3
  25. package/src/global/ink/cockpit-views.js +9 -2
  26. package/src/global/ink/orchestrator-app.js +42 -4
  27. package/src/global/ink/ux/live-overview.js +53 -26
  28. package/src/global/ink/ux/overview-actions.js +80 -0
  29. package/src/global/ink/ux/overview-needs.js +1 -1
  30. package/src/global/integrations/engram-evidence.js +7 -2
  31. package/src/global/integrations/sdd-apply.js +17 -7
  32. package/src/global/integrations/sdd-evidence.js +22 -3
  33. package/src/global/integrations/sdd-plan.js +21 -3
  34. package/src/global/integrations/sdd-resolutions.js +73 -0
  35. package/src/global/integrations/sdd-state.js +69 -0
  36. package/src/global/integrations/sdd-verify.js +9 -4
  37. package/src/global/mcp/kairo-mcp.js +56 -5
  38. package/src/global/mcp/resolve-mcp-workspace.js +51 -0
  39. package/src/global/mcp/work-snapshot-rule.js +89 -0
  40. package/src/global/mcp/work-snapshot-tool.js +49 -0
  41. package/src/global/mcp-install.js +239 -0
  42. package/src/global/next/next-cli.js +35 -0
  43. package/src/global/next/next-report.js +145 -0
  44. package/src/global/next/project-key.js +36 -0
  45. package/src/global/next/publish-work-snapshot.js +116 -0
  46. package/src/global/next/work-enroll.js +91 -0
  47. package/src/global/next/work-snapshot.js +216 -0
  48. package/src/global/observability/fleet-activity.js +197 -0
  49. package/src/global/observability/fleet-models-catalog.js +137 -0
  50. package/src/global/observability/fleet-platforms.js +166 -0
  51. package/src/global/observability/fleet-probe.js +229 -0
  52. package/src/global/paths.js +2 -1
  53. package/src/global/self-update.js +216 -0
package/CHANGELOG.md CHANGED
@@ -5,6 +5,113 @@ Historical entries below may reference the legacy `@kal-elsam/harness` package n
5
5
 
6
6
  ## Unreleased
7
7
 
8
+ ## 0.15.0 — 2026-08-12 (Kairo Runtime)
9
+
10
+ Minor release. Declared Fleet board + model configure, and the Cursor
11
+ observable companion (work snapshots, MCP publish, `kairo next`, managed
12
+ rule, honest panel). Publish tag: `kairo-runtime-v0.15.0`. Extension
13
+ marketplace delivery stays out of this unit.
14
+
15
+ ### Added
16
+
17
+ - Contract `kairo.work-snapshot/v1` and MCP tool `kairo_publish_work_snapshot`
18
+ to enroll the current Cursor conversation with Goal / Progress / Now /
19
+ Constraints / Next.
20
+ - `kairo next` / `kairo.next/v1`: selected work snapshot plus integration
21
+ state (`active` / `enrolled` / `showRepair`) for the IDE panel.
22
+ - `kairo mcp install [--yes]`: consent-gated registration of Kairo MCP in
23
+ `~/.cursor/mcp.json` (plan first; atomic write + backup) and managed
24
+ Cursor rule `~/.cursor/rules/kairo-work-snapshot.mdc` (`alwaysApply`).
25
+ - Panel **0.7.0**: honest companion surface — Repair only when integration
26
+ is broken; otherwise active/enrolled without false prompts.
27
+ - MCP workspace binding: prefer Cursor env (`VSCODE_CWD` /
28
+ `WORKSPACE_FOLDER_PATHS`) over process cwd; canonicalize macOS `/tmp` vs
29
+ `/private/tmp` before hashing `projectKey`.
30
+ - Panel **0.6.5**: One **Configure all** for multi-agent (Claude + OpenCode +
31
+ Cursor agents). **Codex aparte** (`--codex-model`). `kairo fleet models`
32
+ shows available vs enabled per tool. Cursor desk: open agents/skills/rules.
33
+ Profile at `~/.harness/fleet-models.json` (seeded from disk; preserves
34
+ tuned OpenCode). `--from gentle` remaps OpenCode tiers when you want that.
35
+ - Panel **0.6.4**: Fleet Details puts configure buttons first (Edit per
36
+ minion on Claude/OpenCode; Cursor offers Claude/OpenCode configure +
37
+ optional Pixel Agents). `fleet configure` defaults to Claude only (no
38
+ surprise OpenCode overwrite).
39
+ - `kairo fleet configure`: Gentle-style model assignments across OpenCode +
40
+ Claude (+ Codex when `codex_default` set). Plan / `--yes` + backups. Panel
41
+ **Models** button. Cursor Auto remains IDE-managed.
42
+ - Panel **0.6.2**: Fleet floor (compact platform desks). Working floor only
43
+ shows live agents — no idle OpenCode wall. CLI `kairo fleet` compact by
44
+ default (`--verbose` for full minion list).
45
+ - Panel **0.6.3**: Configure models toolbar + desk actions for sync/set.
46
+ - `kairo fleet [--json]`: declared orchestrator→minion fleet topology from
47
+ OpenCode config (Gentle + SDD models); Cursor Auto marked opaque.
48
+ MCP tool `kairo_fleet`; `kairo connections --json` includes `fleets`.
49
+ - Panel **0.5.0**: Fleet tree under connections (platform · orchestrator ·
50
+ model, indented minions). Details note: declared config, not live tokens.
51
+ - `kairo connections [--json]`: Gentle / Hermes / Engram / Graphify / Agent
52
+ connection chips for the IDE panel (companion probes + MCP registration).
53
+ - VS Code / Cursor panel **0.3.0**: connection chips, Connect Agent button,
54
+ Entries + Details webview. Docs: `docs/mcp.md`.
55
+ - Panel **0.3.1**: soften "not installed / unconfigured" entries to `note`;
56
+ fix false Engram conflict when Claude uses `~/.claude/mcp/engram.json`
57
+ without `mcpServers.engram` in settings.json.
58
+ - Panel **0.3.2**: **Setup** button + per-connection actions (Configure /
59
+ How to install / Update graph). Optional tools labeled; Kairo never
60
+ auto-installs Gentle/Hermes/Graphify.
61
+ - Panel **0.3.3**: every Entry shows resolve buttons in Details (Fix SDD,
62
+ Repair, Update graph, Why optional?). Hermes chip offers **Start Hermes
63
+ gateway**. Conflicts sort first so buttons are visible immediately.
64
+ - Panel **0.3.4**: Hermes tip documents `API_SERVER_ENABLED=true` — gateway
65
+ alone without API Server does not expose :8642.
66
+ - Check **resolutions[]** contract + panel **0.4.0**: status checks can declare
67
+ clickable fix buttons. For `sdd-core:skills` conflicts:
68
+ - `kairo components diff sdd-core` (read-only)
69
+ - `kairo components adopt sdd-core` (keep disk; record adopted hashes)
70
+ - `kairo components configure sdd-core --overwrite-conflicts` (backup + replace)
71
+ Destructive overwrite asks for a modal confirm in the IDE panel.
72
+ - Panel **0.4.1**: adopt/overwrite buttons apply with `--yes` (click = consent).
73
+ Previous `--dry-run` left CONFLICT unchanged after clicking Conservar el mío.
74
+ - Panel **0.4.2**: status/connections/terminal use the open workspace folder as
75
+ `cwd`, so graphify-out/ is detected (was falsely "not found" from IDE cwd).
76
+
77
+ ### Fixed
78
+
79
+ - Cockpit Home opened with focus on the tab bar, so the two Home buttons never
80
+ showed a selection mark and the arrow keys moved between tabs instead. Home
81
+ now starts on the buttons.
82
+
83
+ ### Changed
84
+
85
+ - Home buttons render as `› [1] Label` with `← Press Enter` on the focused
86
+ option; press `1` / `2` to run a button without arrow navigation.
87
+ - Home footer names each key (`1·2 Select · Enter Run · ? Help · Esc Exit`)
88
+ instead of listing bare keys.
89
+ - Home shows at most two plain-language needs; the rest collapse into the
90
+ `More info (n)` disclosure, which absorbs the duplicated "n more" line.
91
+
92
+ ## 0.14.0 — 2026-08-07 (Kairo Runtime)
93
+
94
+ Minor release. Simpler Cockpit, one-command CLI self-update, pnpm for
95
+ contributors, and a minimal IDE status panel. Publish tag:
96
+ `kairo-runtime-v0.14.0`.
97
+
98
+ ### Added
99
+
100
+ - Cockpit Home with three tabs (Home · Settings · History) and two clear
101
+ actions (prepare/repair + Configure). Secondary destinations stay in `/`.
102
+ - `kairo update`: update the Kairo CLI from npm (`--yes` applies). Workspace
103
+ template refresh stays at `kairo update --scope=workspace`.
104
+ - VS Code / Cursor extension scaffold in `packages/kairo-vscode`: status bar +
105
+ explorer tree from `kairo status --json`; sync/doctor/cockpit open a terminal
106
+ (no silent writes). Local VSIX via `npm run package`.
107
+
108
+ ### Changed
109
+
110
+ - Local development and CI use **pnpm 10.x** (`packageManager` pinned). End-user
111
+ installs and `npm publish` (OIDC Trusted Publishing) stay on npm.
112
+ - Install scripts blocked by default (`pnpm.onlyBuiltDependencies: []`);
113
+ `.npmrc` sets `strict-dep-builds` and `minimum-release-age=1440`.
114
+
8
115
  ## 0.13.1 — 2026-08-07 (Kairo Runtime)
9
116
 
10
117
  Patch release. Docs/UX/license polish for npm adoption. Publish tag:
package/README.md CHANGED
@@ -24,25 +24,23 @@ KAIRO
24
24
  Needs attention · 4/4 agents · drift pending
25
25
  Kairo coordinates installed AI agents for this project.
26
26
 
27
- Fix drift
28
- Run "kairo sync" to repair managed content.
29
- Enter → preview in Governance
30
-
31
- Last activity · codex · failed
32
- Obsidian not connected · open Settings to choose your vault
33
- Update available · run kairo updates check
34
- 9 more in Details · Space
27
+ Repair 3 changes
28
+ You will see the exact plan before anything is written.
29
+
30
+ Configure
31
+ Agents, Obsidian vault, integrations.
35
32
  ```
36
33
 
37
- `↑↓` move · `Enter` open · `Space` details · `R` refresh · `Esc` back · `?` help
34
+ `↑↓` move · `Enter` open · `Tab` nav · `Space` details · `R` refresh · `Esc` back · `?` help
38
35
 
39
- ## The four commands
36
+ ## Day-to-day commands
40
37
 
41
38
  | Command | What it does |
42
39
  |---|---|
43
40
  | `kairo` | Open the cockpit |
44
41
  | `kairo status` | See how your setup is doing |
45
42
  | `kairo sync` | Repair what drifted |
43
+ | `kairo update` | Update Kairo itself from npm |
46
44
  | `kairo doctor` | Deeper health checks |
47
45
 
48
46
  Run `kairo help --all` for everything else, or read the
@@ -70,6 +68,10 @@ npx @kal-elsam/kairo-runtime
70
68
  # Install globally
71
69
  npm i -g @kal-elsam/kairo-runtime && kairo
72
70
 
71
+ # Later: update the CLI itself
72
+ kairo update
73
+ kairo update --yes
74
+
73
75
  # Preview the setup plan, write nothing
74
76
  npx @kal-elsam/kairo-runtime --dry-run
75
77
  ```
File without changes
package/bin/kairo.js CHANGED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kal-elsam/kairo-runtime",
3
- "version": "0.13.1",
3
+ "version": "0.15.0",
4
4
  "description": "Kairo Runtime — local agent operating system for Codex, Cursor, Claude, Pi, Engram, and Graphify.",
5
5
  "type": "module",
6
6
  "homepage": "https://github.com/Kal-elSam/harness#readme",
@@ -62,6 +62,10 @@
62
62
  "engines": {
63
63
  "node": ">=20.12.0"
64
64
  },
65
+ "packageManager": "pnpm@10.34.5",
66
+ "pnpm": {
67
+ "onlyBuiltDependencies": []
68
+ },
65
69
  "dependencies": {
66
70
  "@clack/prompts": "^1.7.0",
67
71
  "@modelcontextprotocol/server": "2.0.0",
@@ -86,7 +86,7 @@ const asciiNav = buildNavModel({
86
86
  assert.equal(asciiNav.items[1].marker, ">");
87
87
  assert.equal(asciiNav.items[0].current, true);
88
88
  assert.equal(asciiNav.items[1].selected, true);
89
- assert.match(asciiNav.explanation, /Repair|Govern|Activity|Usage|Settings|Overview/i);
89
+ assert.match(asciiNav.explanation, /agents|Obsidian|integrations/i);
90
90
 
91
91
  function applyKey(state, keyAction) {
92
92
  const routed = routeCockpitKey(state, keyAction);
@@ -99,25 +99,29 @@ function smokeNavigation(layoutMode) {
99
99
  layoutMode,
100
100
  region: layoutMode === LAYOUT_MODES.MINIMAL ? COCKPIT_REGIONS.CONTENT : COCKPIT_REGIONS.NAV
101
101
  });
102
- const diagnosticsIndex = COCKPIT_NAV.findIndex((item) => item.id === "governance");
103
- while (state.navIndex < diagnosticsIndex) {
102
+ const settingsIndex = COCKPIT_NAV.findIndex((item) => item.id === "settings");
103
+ while (state.navIndex < settingsIndex) {
104
104
  state = applyKey(state, { type: "arrow", direction: "down" });
105
105
  }
106
106
  state = applyKey(state, { type: "enter" });
107
- assert.equal(state.view, ORCHESTRATOR_VIEWS.CHANGES);
108
- assert.equal(state.region, COCKPIT_REGIONS.NAV);
107
+ assert.equal(state.view, ORCHESTRATOR_VIEWS.PROFILE);
108
+ assert.equal(state.region, COCKPIT_REGIONS.CONTENT);
109
109
 
110
- state = applyKey(state, { type: "arrow", direction: "up" });
110
+ state = applyKey(state, { type: "tab" });
111
+ assert.equal(state.region, COCKPIT_REGIONS.NAV);
112
+ while (state.navIndex > 0) {
113
+ state = applyKey(state, { type: "arrow", direction: "up" });
114
+ }
111
115
  state = applyKey(state, { type: "enter" });
112
116
  assert.equal(state.view, ORCHESTRATOR_VIEWS.HOME);
113
- assert.equal(state.region, COCKPIT_REGIONS.NAV);
117
+ assert.equal(state.region, COCKPIT_REGIONS.CONTENT);
114
118
 
115
119
  const footer = buildFooterModel({
116
- view: ORCHESTRATOR_VIEWS.CHANGES,
117
- region: COCKPIT_REGIONS.NAV,
120
+ view: ORCHESTRATOR_VIEWS.HOME,
121
+ region: COCKPIT_REGIONS.CONTENT,
118
122
  unicode: false
119
123
  });
120
- assert.doesNotMatch(footer.text, /Tab/);
124
+ assert.match(footer.text, /Tab/);
121
125
 
122
126
  state = applyKey(state, { type: "escape" });
123
127
  assert.equal(state.view, ORCHESTRATOR_VIEWS.HOME);
package/src/cli.js CHANGED
@@ -6,6 +6,10 @@ import {
6
6
  runComponentsRollback,
7
7
  runComponentsVerify
8
8
  } from "./global/component-integration-cli.js";
9
+ import {
10
+ runComponentsAdopt,
11
+ runComponentsDiff
12
+ } from "./global/components-resolve-cli.js";
9
13
  import {
10
14
  printGlobalComponents,
11
15
  printGlobalDetect,
@@ -30,6 +34,7 @@ import {
30
34
  runGlobalReport
31
35
  } from "./global/global-cli.js";
32
36
  import { runEcosystemUpdatesCheck } from "./global/updates-cli.js";
37
+ import { runSelfUpdate } from "./global/self-update.js";
33
38
  import { applyPolicyToOptions, loadPolicyFile } from "./global/policy.js";
34
39
  import { resolveHomeDir } from "./global/paths.js";
35
40
  import { runWorkspaceDetect, runWorkspaceDoctor, runWorkspaceInit, runWorkspaceUpdate } from "./workspace-cli.js";
@@ -127,17 +132,100 @@ export async function runCli(argv) {
127
132
  await runGraphifyCli(optionsWithPolicy, packageManifest);
128
133
  return;
129
134
  case "mcp": {
130
- // Lazy-load: MCP SDK is heavy and optional for day-to-day CLI (help/status/sync).
131
- const { runKairoMcp } = await import("./global/mcp/kairo-mcp.js");
132
- // stdout reserved for MCP protocol — no banners/logs here
133
- await runKairoMcp({
135
+ const { runMcpCli } = await import("./global/mcp-install.js");
136
+ await runMcpCli({
137
+ mcpAction: optionsWithPolicy.mcpAction ?? "serve",
138
+ mcpClient: optionsWithPolicy.mcpClient ?? "cursor",
139
+ yes: optionsWithPolicy.yes === true,
140
+ json: optionsWithPolicy.json === true,
134
141
  cwd: optionsWithPolicy.cwd,
142
+ cwdExplicit: optionsWithPolicy.cwdExplicit,
135
143
  packageRoot,
136
144
  packageName: packageManifest.name,
137
145
  version: packageManifest.version
138
146
  });
139
147
  return;
140
148
  }
149
+ case "connections": {
150
+ const { buildConnectionsReport } = await import("./global/connections.js");
151
+ const { printJson } = await import("./global/json-output.js");
152
+ const { commandHeader } = await import("./global/brand/index.js");
153
+ const report = await buildConnectionsReport({
154
+ workspaceRoot: optionsWithPolicy.cwd,
155
+ packageRoot,
156
+ packageName: packageManifest.name,
157
+ cliVersion: packageManifest.version,
158
+ client: optionsWithPolicy.mcpClient ?? "cursor"
159
+ });
160
+ if (optionsWithPolicy.json) {
161
+ printJson(report);
162
+ } else {
163
+ console.log(commandHeader("Connections"));
164
+ for (const c of report.connections) {
165
+ console.log(`${c.label} · ${c.state}`);
166
+ console.log(` ${c.access}`);
167
+ if (c.detail) console.log(` ${c.detail}`);
168
+ }
169
+ }
170
+ return;
171
+ }
172
+ case "next": {
173
+ const { runNextCli } = await import("./global/next/next-cli.js");
174
+ await runNextCli({
175
+ cwd: optionsWithPolicy.cwd,
176
+ json: optionsWithPolicy.json === true,
177
+ mcpClient: optionsWithPolicy.mcpClient ?? "cursor"
178
+ });
179
+ return;
180
+ }
181
+ case "fleet": {
182
+ const fleetAction = optionsWithPolicy.fleetAction ?? "show";
183
+ if (fleetAction === "set") {
184
+ const { runFleetSet } = await import("./global/fleet-set.js");
185
+ await runFleetSet({
186
+ platform: optionsWithPolicy.fleetPlatform,
187
+ agent: optionsWithPolicy.fleetAgent ?? optionsWithPolicy.agent,
188
+ model: optionsWithPolicy.model,
189
+ yes: optionsWithPolicy.yes === true,
190
+ dryRun: optionsWithPolicy.dryRun === true,
191
+ json: optionsWithPolicy.json === true
192
+ });
193
+ return;
194
+ }
195
+ if (fleetAction === "configure") {
196
+ const { runFleetConfigure } = await import("./global/fleet-configure.js");
197
+ await runFleetConfigure({
198
+ yes: optionsWithPolicy.yes === true,
199
+ json: optionsWithPolicy.json === true,
200
+ platforms: optionsWithPolicy.fleetPlatforms ?? null,
201
+ from: optionsWithPolicy.fleetFrom ?? "profile",
202
+ assignmentsRaw: optionsWithPolicy.fleetAssignments ?? null,
203
+ codexModel: optionsWithPolicy.fleetCodexModel ?? null
204
+ });
205
+ return;
206
+ }
207
+ if (fleetAction === "models") {
208
+ const { runFleetModels } = await import("./global/fleet-configure.js");
209
+ await runFleetModels({
210
+ json: optionsWithPolicy.json === true,
211
+ profile: optionsWithPolicy.fleetProfile === true
212
+ });
213
+ return;
214
+ }
215
+ const { buildFleetReport, formatFleetText } = await import("./global/observability/fleet-probe.js");
216
+ const { printJson } = await import("./global/json-output.js");
217
+ const report = await buildFleetReport({
218
+ includeVariants: optionsWithPolicy.includeVariants === true
219
+ });
220
+ if (optionsWithPolicy.json) {
221
+ printJson(report);
222
+ } else {
223
+ console.log(formatFleetText(report, {
224
+ verbose: optionsWithPolicy.verbose === true || optionsWithPolicy.includeVariants === true
225
+ }));
226
+ }
227
+ return;
228
+ }
141
229
  case "intelligence":
142
230
  await runIntelligenceCli(optionsWithPolicy, packageManifest);
143
231
  return;
@@ -173,9 +261,15 @@ export async function runCli(argv) {
173
261
  });
174
262
  return;
175
263
  case "update":
176
- await dispatchByScope(options, "agent-global", {
177
- "agent-global": () => runGlobalInstall(options, packageManifest, packageRoot, { update: true }),
178
- workspace: () => runWorkspaceUpdate(options, packageManifest, packageRoot)
264
+ if (options.scope === "workspace") {
265
+ await runWorkspaceUpdate(options, packageManifest, packageRoot);
266
+ return;
267
+ }
268
+ await runSelfUpdate({
269
+ packageName: packageManifest.name,
270
+ cliVersion: packageManifest.version,
271
+ yes: optionsWithPolicy.yes === true,
272
+ json: optionsWithPolicy.json === true
179
273
  });
180
274
  return;
181
275
  case "doctor":
@@ -278,6 +372,12 @@ async function dispatchComponentsCommand(options, invoke) {
278
372
  case "verify":
279
373
  await runComponentsVerify({ ...options, packageRoot });
280
374
  return;
375
+ case "adopt":
376
+ await runComponentsAdopt({ ...options, packageRoot });
377
+ return;
378
+ case "diff":
379
+ await runComponentsDiff({ ...options, packageRoot });
380
+ return;
281
381
  case "rollback":
282
382
  await runComponentsRollback(options);
283
383
  return;
@@ -356,6 +456,7 @@ export function parseArgs(argv) {
356
456
  const command = normalizeCommand(rawCommand);
357
457
  const options = {
358
458
  cwd: process.cwd(),
459
+ cwdExplicit: false,
359
460
  scope: null,
360
461
  mode: "standard",
361
462
  modeExplicit: false,
@@ -375,6 +476,7 @@ export function parseArgs(argv) {
375
476
  dryRun: false,
376
477
  yes: false,
377
478
  confirm: false,
479
+ overwriteConflicts: false,
378
480
  preflight: true,
379
481
  preflightExplicit: false,
380
482
  yesExplicit: false,
@@ -412,6 +514,18 @@ export function parseArgs(argv) {
412
514
  confirmDismiss: false,
413
515
  graphifyAction: null, graphifyArgs: [], graphifyBudget: null, graphPath: null,
414
516
  updatesAction: "check",
517
+ mcpAction: "serve",
518
+ mcpClient: "cursor",
519
+ fleetAction: "show",
520
+ fleetPlatform: null,
521
+ fleetAgent: null,
522
+ fleetPlatforms: null,
523
+ fleetFrom: "profile",
524
+ fleetAssignments: null,
525
+ fleetCodexModel: null,
526
+ fleetProfile: false,
527
+ includeVariants: false,
528
+ verbose: false,
415
529
  base: null,
416
530
  commit: null,
417
531
  staged: false,
@@ -466,6 +580,8 @@ export function parseArgs(argv) {
466
580
 
467
581
  if (command === "graphify") parseGraphifyAction(args, options);
468
582
  if (command === "updates") parseUpdatesAction(args, options);
583
+ if (command === "mcp") parseMcpAction(args, options);
584
+ if (command === "fleet") parseFleetAction(args, options);
469
585
 
470
586
  if (command === "help") {
471
587
  while (args[0] === "all" || args[0] === "--all") {
@@ -477,7 +593,10 @@ export function parseArgs(argv) {
477
593
  for (let index = 0; index < args.length; index += 1) {
478
594
  const arg = args[index];
479
595
 
480
- if (arg === "--cwd") options.cwd = resolve(args[++index]);
596
+ if (arg === "--cwd") {
597
+ options.cwd = resolve(args[++index]);
598
+ options.cwdExplicit = true;
599
+ }
481
600
  else if (arg === "--scope") options.scope = parseScope(args[++index]);
482
601
  else if (arg.startsWith("--scope=")) options.scope = parseScope(arg.slice("--scope=".length));
483
602
  else if (arg === "--mode") {
@@ -511,8 +630,26 @@ export function parseArgs(argv) {
511
630
  options.componentsExplicit = true;
512
631
  } else if (arg === "--force") options.force = true;
513
632
  else if (arg === "--dry-run") options.dryRun = true;
633
+ else if (arg === "--overwrite-conflicts") options.overwriteConflicts = true;
514
634
  else if (arg === "--json") options.json = true;
515
- else if (arg === "--yes" || arg === "-y") {
635
+ else if (arg === "--include-variants") options.includeVariants = true;
636
+ else if (arg === "--platforms") options.fleetPlatforms = args[++index];
637
+ else if (arg.startsWith("--platforms=")) options.fleetPlatforms = arg.slice("--platforms=".length);
638
+ else if (arg === "--from") options.fleetFrom = args[++index];
639
+ else if (arg.startsWith("--from=")) options.fleetFrom = arg.slice("--from=".length);
640
+ else if (arg === "--assignments") options.fleetAssignments = args[++index];
641
+ else if (arg.startsWith("--assignments=")) options.fleetAssignments = arg.slice("--assignments=".length);
642
+ else if (arg === "--codex-model") options.fleetCodexModel = args[++index];
643
+ else if (arg.startsWith("--codex-model=")) options.fleetCodexModel = arg.slice("--codex-model=".length);
644
+ else if (arg === "--profile") options.fleetProfile = true;
645
+ else if (arg === "--verbose") options.verbose = true;
646
+ else if (arg === "--platform") options.fleetPlatform = args[++index];
647
+ else if (arg.startsWith("--platform=")) options.fleetPlatform = arg.slice("--platform=".length);
648
+ else if (arg === "--client") {
649
+ options.mcpClient = args[++index];
650
+ } else if (arg.startsWith("--client=")) {
651
+ options.mcpClient = arg.slice("--client=".length);
652
+ } else if (arg === "--yes" || arg === "-y") {
516
653
  options.yes = true;
517
654
  options.yesExplicit = true;
518
655
  } else if (arg === "--confirm") {
@@ -644,7 +781,8 @@ function parseComponentsAction(args, options) {
644
781
 
645
782
  if (action === "validate") return;
646
783
 
647
- if (action === "configure" || action === "verify" || action === "rollback") {
784
+ if (action === "configure" || action === "verify" || action === "rollback"
785
+ || action === "adopt" || action === "diff") {
648
786
  const componentId = args[0];
649
787
  if (!componentId || componentId.startsWith("-")) {
650
788
  throw new Error(
@@ -655,7 +793,7 @@ function parseComponentsAction(args, options) {
655
793
  return;
656
794
  }
657
795
 
658
- throw new Error(`Unknown components action "${action}". Use validate, init, pack, import, configure, verify, or rollback.`);
796
+ throw new Error(`Unknown components action "${action}". Use validate, init, pack, import, configure, verify, adopt, diff, or rollback.`);
659
797
  }
660
798
 
661
799
  function parsePolicyAction(args, options) {
@@ -835,6 +973,36 @@ function parseUpdatesAction(args, options) {
835
973
  options.updatesAction = "check";
836
974
  }
837
975
 
976
+ function parseMcpAction(args, options) {
977
+ const action = args[0];
978
+ if (!action || action.startsWith("-")) {
979
+ options.mcpAction = "serve";
980
+ return;
981
+ }
982
+ if (!new Set(["serve", "install"]).has(action)) {
983
+ throw new Error(
984
+ `Unknown mcp action "${action}". Use: ${formatCliCommand("mcp")} or ${formatCliCommand("mcp install [--yes]")}`
985
+ );
986
+ }
987
+ args.shift();
988
+ options.mcpAction = action;
989
+ }
990
+
991
+ function parseFleetAction(args, options) {
992
+ const action = args[0];
993
+ if (!action || action.startsWith("-")) {
994
+ options.fleetAction = "show";
995
+ return;
996
+ }
997
+ if (!new Set(["show", "set", "activity", "configure", "models"]).has(action)) {
998
+ throw new Error(
999
+ `Unknown fleet action "${action}". Use: ${formatCliCommand("fleet")}, ${formatCliCommand("fleet models")}, ${formatCliCommand("fleet configure")}, or ${formatCliCommand("fleet set --platform opencode --agent <id> --model <id>")}`
1000
+ );
1001
+ }
1002
+ args.shift();
1003
+ options.fleetAction = action === "activity" ? "show" : action;
1004
+ }
1005
+
838
1006
  function parsePathList(value) {
839
1007
  if (!value) return [];
840
1008
  return [...new Set(
@@ -882,6 +1050,9 @@ function normalizeCommand(command) {
882
1050
  if (command === "alerts") return "alerts";
883
1051
  if (command === "graphify") return "graphify";
884
1052
  if (command === "mcp") return "mcp";
1053
+ if (command === "connections") return "connections";
1054
+ if (command === "next") return "next";
1055
+ if (command === "fleet") return "fleet";
885
1056
  if (command === "intelligence" || command === "intel") return "intelligence";
886
1057
  if (command === "setup") return "setup";
887
1058
  if (command === "status") return "status";
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Stable resolution contract for doctor/status checks.
3
+ * Panels render these as buttons; commands stay consent-gated in the CLI.
4
+ */
5
+ export function resolution(id, label, command, {
6
+ kind = "run",
7
+ safety = "consent",
8
+ detail = ""
9
+ } = {}) {
10
+ return {
11
+ id: String(id),
12
+ label: String(label),
13
+ command: command == null ? null : String(command),
14
+ kind: String(kind),
15
+ safety: String(safety),
16
+ detail: detail == null ? "" : String(detail)
17
+ };
18
+ }
19
+
20
+ export const RESOLUTION_SAFETY = Object.freeze({
21
+ READ_ONLY: "read-only",
22
+ CONSENT: "consent",
23
+ DESTRUCTIVE: "destructive"
24
+ });
25
+
26
+ export const RESOLUTION_KIND = Object.freeze({
27
+ RUN: "run",
28
+ CONFIGURE: "configure",
29
+ GUIDE: "guide",
30
+ REFRESH: "refresh"
31
+ });
@@ -29,6 +29,7 @@ Usage:
29
29
  ${cli} Open the cockpit (setup on first run)
30
30
  ${cli} status See how your setup is doing
31
31
  ${cli} sync Repair what drifted
32
+ ${cli} update Update Kairo itself (npm)
32
33
  ${cli} doctor Deeper health checks
33
34
 
34
35
  ${cli} help --all Every command and flag
@@ -63,7 +64,8 @@ Bootstrap: see README.md and docs/install.md (curl install.sh or npx ${PACKAGE_N
63
64
  ${cli} updates check [--json] [--force]
64
65
  ${cli} install [--agents <list|all>] [--components <list>] [--dry-run]
65
66
  ${cli} install --no-default-components
66
- ${cli} update [--dry-run] Technical repair alias (prefer sync)
67
+ ${cli} update [--yes] [--json] Update the Kairo CLI from npm
68
+ ${cli} update --scope=workspace [--dry-run] Refresh workspace template files
67
69
  ${cli} uninstall [--dry-run]
68
70
 
69
71
  ## Agents & runs
@@ -107,10 +109,19 @@ Bootstrap: see README.md and docs/install.md (curl install.sh or npx ${PACKAGE_N
107
109
  ${cli} components
108
110
  ${cli} components validate|init|pack|import ...
109
111
  ${cli} components configure engram-memory [--agents <list>] [--dry-run|--yes] [--json]
110
- ${cli} components configure sdd-core [--agents <list>] [--persona off|teaching] [--dry-run|--yes] [--json]
112
+ ${cli} components configure sdd-core [--agents <list>] [--persona off|teaching] [--overwrite-conflicts] [--dry-run|--yes] [--json]
111
113
  ${cli} components verify sdd-core [--agents <list>] [--json]
114
+ ${cli} components adopt sdd-core [--agents <list>] [--dry-run|--yes] [--json]
115
+ ${cli} components diff sdd-core [--agents <list>] [--json]
112
116
  ${cli} components rollback engram-memory|sdd-core --receipt <id> [--dry-run|--yes] [--json]
117
+ ${cli} connections [--json] [--client cursor]
118
+ ${cli} next [--json] [--client cursor]
119
+ ${cli} fleet [--json] [--verbose] [--include-variants]
120
+ ${cli} fleet models [--profile] [--json]
121
+ ${cli} fleet configure [--platforms claude,opencode,cursor|codex] [--from profile|gentle] [--codex-model <id>] [--assignments a=b,...] [--yes] [--json]
122
+ ${cli} fleet set --platform opencode|claude|codex --agent <id> --model <id> [--yes] [--json]
113
123
  ${cli} mcp
124
+ ${cli} mcp install [--yes] [--json] [--client cursor]
114
125
  ${cli} install --scope=workspace [--mode minimal|standard|enterprise] (opt-in/legacy)
115
126
  ${cli} init [--mode minimal|standard|enterprise] (workspace alias)
116
127
 
@@ -143,7 +154,7 @@ Commands:
143
154
  updates Read-only ecosystem update check (kairo/hermes/gentle/skills). Never applies.
144
155
  install Non-interactive configure (agent-global) or legacy workspace scaffold.
145
156
  doctor Detailed health checks for managed state and configs.
146
- update Technical repair alias (prefer sync for day-to-day use).
157
+ update Update the Kairo CLI from npm (--yes applies). Workspace templates: --scope=workspace.
147
158
  detect Inspect global agents and the current project. Read-only.
148
159
  adapters Official adapter matrix: roots, config files, detected/managed.
149
160
  explain Read-only audit of managed adapters, configs, markers, and backups.
@@ -155,12 +166,20 @@ Commands:
155
166
  policy View or edit local operation preferences under ~/.harness/policy.json.
156
167
  report Read-only diagnostics bundle: status, policy, adapters, diff, history.
157
168
  components List, validate, scaffold, pack, import, or configure integrations (Engram, SDD).
169
+ connections Companion chips + MCP registration (IDE panel).
170
+ next Selected work snapshot + integration state (panel contract).
171
+ fleet Declared fleet floor + working activity; configure/set models across CLIs.
172
+ fleet models [--profile] available vs enabled per tool
173
+ fleet configure one plan for Claude+OpenCode+Cursor (profile)
174
+ fleet configure --codex-model <id> Codex only (single-default)
175
+ fleet set --platform opencode|claude|codex --agent <id> --model <id> [--yes]
176
+ mcp Serve or install MCP for agents (mcp install writes entry + snapshot rule).
158
177
  uninstall Remove managed sections and global state. Backups are preserved.
159
178
  init Alias for install --scope=workspace (legacy).
160
179
 
161
180
  JSON output (--json on supported commands):
162
181
  status, sync, doctor, adapters, explain, diff, history, history last,
163
- policy (show/set/reset), report, monitor
182
+ policy (show/set/reset), report, monitor, connections, fleet
164
183
  Human text remains the default. See docs/cli-reference.md for examples and field notes.
165
184
 
166
185
  Version:
@@ -9,6 +9,7 @@ import { requireIntegrationProvider } from "./integrations/provider-registry.js"
9
9
  import { buildEngramIntegrationChecks, buildSddIntegrationChecks } from "./component-integration-cli.js";
10
10
  import { KAIRO_ENGRAM_AGENT_IDS } from "./integrations/engram-evidence.js";
11
11
  import { SDD_MANAGED_AGENT_IDS } from "./integrations/sdd-destinations.js";
12
+ import { adoptedHashesFromState } from "./integrations/sdd-state.js";
12
13
  import { harnessHomePaths } from "./paths.js";
13
14
  import { readGlobalState } from "./state.js";
14
15
 
@@ -78,6 +79,7 @@ async function buildSddChecks({ homeDir }) {
78
79
  requestedAgentIds: installedAgents.length ? installedAgents : [],
79
80
  detectedAgentIds: installedAgents,
80
81
  trackedFiles,
82
+ adoptedFiles: adoptedHashesFromState(state?.sdd),
81
83
  personaAgentIds: state?.sdd?.personaAgentIds ?? [],
82
84
  packageRoot: PACKAGE_ROOT
83
85
  });