@kal-elsam/kairo-runtime 0.7.0 → 0.9.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 (42) hide show
  1. package/README.md +43 -11
  2. package/global-template/components/catalog.json +4 -1
  3. package/global-template/components/orchestrator/extensions/pi/kairo-minion.js +604 -0
  4. package/package.json +1 -1
  5. package/scripts/cockpit-smoke.mjs +4 -4
  6. package/src/cli.js +34 -2
  7. package/src/global/adapters/pi.js +1 -1
  8. package/src/global/global-doctor.js +2 -0
  9. package/src/global/ink/cockpit/primitives.js +96 -31
  10. package/src/global/ink/cockpit-alerts.js +36 -0
  11. package/src/global/ink/cockpit-changes.js +59 -35
  12. package/src/global/ink/cockpit-control-center.js +129 -51
  13. package/src/global/ink/cockpit-controller.js +58 -11
  14. package/src/global/ink/cockpit-focus.js +4 -2
  15. package/src/global/ink/cockpit-models.js +89 -47
  16. package/src/global/ink/cockpit-palette.js +98 -0
  17. package/src/global/ink/cockpit-path-label.js +19 -0
  18. package/src/global/ink/cockpit-recovery.js +78 -15
  19. package/src/global/ink/cockpit-reviews.js +14 -10
  20. package/src/global/ink/cockpit-runs.js +13 -4
  21. package/src/global/ink/cockpit-settings.js +194 -0
  22. package/src/global/ink/cockpit-views.js +88 -57
  23. package/src/global/ink/orchestrator-app.js +137 -46
  24. package/src/global/ink/orchestrator-state.js +24 -14
  25. package/src/global/ink/use-orchestrator-data.js +58 -0
  26. package/src/global/paths.js +3 -0
  27. package/src/global/runtime/alerts/alert-store.js +216 -0
  28. package/src/global/runtime/alerts/alert-types.js +59 -0
  29. package/src/global/runtime/alerts/alert-validate.js +117 -0
  30. package/src/global/runtime/execution-adapters/pi.js +12 -2
  31. package/src/global/runtime/monitor/monitor-cli.js +62 -0
  32. package/src/global/runtime/monitor/monitor-platform.js +95 -0
  33. package/src/global/runtime/monitor/monitor.js +249 -0
  34. package/src/global/runtime/orchestration/index.js +23 -0
  35. package/src/global/runtime/orchestration/orch-receipts.js +234 -0
  36. package/src/global/runtime/orchestration/orch-types.js +173 -0
  37. package/src/global/runtime/orchestration/orch-validate.js +63 -0
  38. package/src/global/runtime/run-cli.js +1 -0
  39. package/src/global/runtime/run-manager.js +59 -4
  40. package/src/global/runtime/run-strategy.js +71 -0
  41. package/src/global/runtime/run-supervisor.js +22 -2
  42. package/src/global/runtime/run-types.js +5 -1
@@ -17,46 +17,58 @@ import { formatRunsHubLines, RUNS_HUB_ITEMS } from "./cockpit-runs.js";
17
17
  import { formatReviewDetailLines, formatReviewListLines } from "./cockpit-reviews.js";
18
18
  import { formatChangesActionLines } from "./cockpit-changes.js";
19
19
  import { formatRecoveryLines } from "./cockpit-recovery.js";
20
+ import { formatUsageLines } from "./cockpit-control-center.js";
21
+ import { formatOrchestrationStatus } from "./cockpit-runs.js";
22
+ import { formatAlertListLines } from "./cockpit-alerts.js";
23
+ import { formatSettingsLines } from "./cockpit-settings.js";
24
+
25
+ export function PalettePanel({ model, colorEnabled = true }) {
26
+ return React.createElement(Box, { flexDirection: "column" },
27
+ React.createElement(Text, {
28
+ bold: true,
29
+ color: colorEnabled ? COCKPIT_COLORS.secondary : undefined
30
+ }, model.title),
31
+ React.createElement(Text, { color: COCKPIT_COLORS.muted }, model.hint),
32
+ React.createElement(Text, null, ""),
33
+ ...(model.items ?? []).map((item) => React.createElement(Text, {
34
+ key: item.id,
35
+ bold: item.selected,
36
+ color: item.selected && colorEnabled ? COCKPIT_COLORS.primary : undefined
37
+ }, `${item.marker} ${item.label}`))
38
+ );
39
+ }
20
40
 
21
41
  export function ControlCenterPanel({ model, colorEnabled = true }) {
22
- const health = model.health;
42
+ const status = model.status ?? model.health;
43
+ const next = model.nextAction ?? model.cta;
23
44
  return React.createElement(Box, { flexDirection: "column" },
24
45
  React.createElement(Text, {
25
46
  bold: true,
26
47
  color: colorEnabled ? COCKPIT_COLORS.secondary : undefined
27
48
  }, model.title),
28
- React.createElement(Text, null, model.purpose),
29
49
  React.createElement(Text, null, ""),
30
50
  React.createElement(Text, {
31
51
  bold: true,
32
52
  color: colorEnabled ? COCKPIT_COLORS.primary : undefined
33
- }, health.label),
34
- React.createElement(Text, null, health.summaryLine),
35
- ...(model.coverageLines ?? []).map((line) =>
36
- React.createElement(Text, { key: line, color: COCKPIT_COLORS.muted }, line)
37
- ),
53
+ }, status?.label),
54
+ React.createElement(Text, null, status?.summaryLine),
38
55
  React.createElement(Text, null, ""),
39
- React.createElement(Text, { bold: true }, model.cta.title),
56
+ React.createElement(Text, { bold: true }, next?.title ?? "NEXT"),
40
57
  React.createElement(Text, {
41
58
  bold: true,
42
59
  color: colorEnabled ? COCKPIT_COLORS.primary : undefined
43
- }, model.cta.actionTitle),
44
- React.createElement(Text, null, model.cta.actionDetail),
45
- React.createElement(Text, { color: COCKPIT_COLORS.muted }, model.cta.enterHint),
46
- model.notes?.length > 0 && React.createElement(Box, { flexDirection: "column", marginTop: 1 },
47
- React.createElement(Text, { bold: true }, "NOTES"),
48
- model.notes.map((line) =>
49
- React.createElement(Text, { key: line, color: COCKPIT_COLORS.muted }, line)
50
- )
51
- ),
52
- model.proposalLines?.length > 0 && React.createElement(Box, { flexDirection: "column", marginTop: 1 },
53
- React.createElement(Text, { bold: true }, "PROPOSALS"),
54
- model.proposalLines.map((line) =>
55
- React.createElement(Text, { key: line, color: COCKPIT_COLORS.muted }, line)
56
- )
57
- ),
60
+ }, next?.actionTitle),
61
+ next?.actionDetail ? React.createElement(Text, null, next.actionDetail) : null,
62
+ React.createElement(Text, { color: COCKPIT_COLORS.muted }, next?.enterHint),
63
+ React.createElement(Text, null, ""),
64
+ React.createElement(Text, { bold: true }, "ACTIVITY"),
65
+ React.createElement(Text, null, model.activity?.headline ?? "Idle"),
58
66
  React.createElement(Text, null, ""),
59
- React.createElement(Text, { color: COCKPIT_COLORS.muted }, model.runsSecondaryHint)
67
+ React.createElement(Text, { bold: true }, "ALERTS"),
68
+ React.createElement(Text, null, model.alerts?.headline ?? "Alert data unavailable"),
69
+ React.createElement(Text, null, ""),
70
+ React.createElement(Text, { bold: true }, "TOKENS"),
71
+ React.createElement(Text, null, model.tokens?.headline ?? "Data unavailable")
60
72
  );
61
73
  }
62
74
 
@@ -72,18 +84,32 @@ export function renderCockpitView({
72
84
  launchPermissionIndex,
73
85
  launchableAgents,
74
86
  controlCenter,
87
+ palette = null,
75
88
  layoutMode = LAYOUT_MODES.COMPACT,
76
89
  selectedRun,
77
90
  selectedEvents,
78
91
  reviews = [],
79
92
  selectedReview = null,
93
+ alerts = [],
80
94
  changesAction = null,
81
95
  recoveryAction = null,
82
- colorEnabled = true
96
+ settingsAction = null,
97
+ colorEnabled = true,
98
+ homeDir = null
83
99
  }) {
100
+ if (palette) {
101
+ return React.createElement(PalettePanel, { model: palette, colorEnabled });
102
+ }
84
103
  switch (view) {
85
104
  case ORCHESTRATOR_VIEWS.HOME:
86
105
  return React.createElement(ControlCenterPanel, { model: controlCenter, colorEnabled });
106
+ case ORCHESTRATOR_VIEWS.USAGE:
107
+ return governanceList(
108
+ "Usage",
109
+ formatUsageLines({ snapshot, dashboard }),
110
+ layoutMode,
111
+ colorEnabled
112
+ );
87
113
  case ORCHESTRATOR_VIEWS.IDES:
88
114
  case ORCHESTRATOR_VIEWS.PROVIDERS:
89
115
  return governanceList("IDEs & models", [
@@ -95,23 +121,37 @@ export function renderCockpitView({
95
121
  return governanceList("Harness modules", formatModuleLines(snapshot), layoutMode, colorEnabled);
96
122
  case ORCHESTRATOR_VIEWS.CHANGES:
97
123
  return governanceList(
98
- "Changes",
99
- formatChangeLines(snapshot, changesAction, layoutMode),
124
+ "Governance",
125
+ formatChangeLines(snapshot, changesAction, layoutMode, homeDir),
100
126
  layoutMode,
101
127
  colorEnabled
102
128
  );
103
129
  case ORCHESTRATOR_VIEWS.ACTIVITY:
104
130
  return governanceList(
105
- "Activity & recovery",
106
- formatRecoveryLines({ snapshot, recoveryAction, listIndex }),
131
+ "Activity",
132
+ formatRecoveryLines({ snapshot, recoveryAction, listIndex, dashboard, homeDir }),
107
133
  layoutMode,
108
134
  colorEnabled
109
135
  );
110
136
  case ORCHESTRATOR_VIEWS.PROFILE:
111
- return governanceList("Profile & policy", formatProfileLines(snapshot, diagnostics), layoutMode, colorEnabled);
137
+ return governanceList(
138
+ "Settings",
139
+ formatSettingsLines({
140
+ listIndex,
141
+ settingsAction,
142
+ snapshot,
143
+ diagnostics
144
+ }),
145
+ layoutMode,
146
+ colorEnabled
147
+ );
112
148
  case ORCHESTRATOR_VIEWS.RUNS:
113
149
  return listBlock(
114
- "Runs",
150
+ `Orchestration · ${formatOrchestrationStatus({
151
+ active: (dashboard?.activeRuns ?? []).length,
152
+ recent: (dashboard?.recentRuns ?? []).length,
153
+ reviews: (reviews ?? []).length
154
+ })}`,
115
155
  formatRunsHubLines(RUNS_HUB_ITEMS),
116
156
  listIndex,
117
157
  colorEnabled,
@@ -126,7 +166,7 @@ export function renderCockpitView({
126
166
  }),
127
167
  listIndex,
128
168
  colorEnabled,
129
- "Runs are secondary. Prefer Control center Actions when drift or setup remains."
169
+ "Enter opens detail · Esc back to Orchestration"
130
170
  );
131
171
  case ORCHESTRATOR_VIEWS.RECENT_RUNS:
132
172
  return listBlock(
@@ -137,7 +177,7 @@ export function renderCockpitView({
137
177
  }),
138
178
  listIndex,
139
179
  colorEnabled,
140
- "Open Runs after governance is healthy."
180
+ "Enter opens detail · Esc back to Orchestration"
141
181
  );
142
182
  case ORCHESTRATOR_VIEWS.REVIEWS:
143
183
  return listBlock(
@@ -173,7 +213,7 @@ export function renderCockpitView({
173
213
  case ORCHESTRATOR_VIEWS.RUN_DETAIL:
174
214
  return React.createElement(Box, { flexDirection: "column" },
175
215
  React.createElement(Text, { bold: true }, "Run detail"),
176
- formatRunDetailLines(selectedRun, selectedEvents)
216
+ formatRunDetailLines(selectedRun, selectedEvents, { homeDir })
177
217
  .map((line) => React.createElement(Text, { key: line }, line))
178
218
  );
179
219
  case ORCHESTRATOR_VIEWS.REVIEW_DETAIL:
@@ -182,6 +222,14 @@ export function renderCockpitView({
182
222
  formatReviewDetailLines(selectedReview)
183
223
  .map((line) => React.createElement(Text, { key: line }, line))
184
224
  );
225
+ case ORCHESTRATOR_VIEWS.ALERTS:
226
+ return listBlock(
227
+ "Alerts",
228
+ formatAlertListLines(alerts),
229
+ listIndex,
230
+ colorEnabled,
231
+ "Enter resolves · D dismisses · Esc back · / Alerts"
232
+ );
185
233
  case ORCHESTRATOR_VIEWS.DIAGNOSTICS:
186
234
  return governanceList(
187
235
  "System health",
@@ -194,8 +242,8 @@ export function renderCockpitView({
194
242
  React.createElement(Text, { bold: true }, "Help"),
195
243
  React.createElement(Text, null, "Kairo keeps IDEs and agents aligned with project architecture and workflows."),
196
244
  React.createElement(Text, null, "Primary flow: scan → findings → preview → confirm → apply → re-scan."),
197
- React.createElement(Text, null, "↑↓ navigate · Enter open · Esc back/exit · R refresh/retry · ? help"),
198
- React.createElement(Text, null, "Runs are secondary after setup and repairs. Reviews are read-only receipts.")
245
+ React.createElement(Text, null, "↑↓ navigate · Enter open/activate · / actions · Esc back · R refresh · ? help"),
246
+ React.createElement(Text, null, "Overview hides raw diagnostics Enter opens detail destinations.")
199
247
  );
200
248
  default: {
201
249
  const _exhaustive = view;
@@ -213,8 +261,8 @@ function governanceList(title, lines, layoutMode, colorEnabled) {
213
261
  message: "No data yet from the read-only scan.",
214
262
  hint: "Press R to rescan."
215
263
  })
216
- : windowed.items.map((line) => React.createElement(Text, {
217
- key: line,
264
+ : windowed.items.map((line, index) => React.createElement(Text, {
265
+ key: `${index}-${line}`,
218
266
  color: colorEnabled ? undefined : undefined
219
267
  }, line)),
220
268
  windowed.moreLine && React.createElement(Text, {
@@ -239,25 +287,8 @@ function formatModuleLines(snapshot) {
239
287
  ];
240
288
  }
241
289
 
242
- function formatChangeLines(snapshot, changesAction, layoutMode = LAYOUT_MODES.COMPACT) {
243
- return formatChangesActionLines({ snapshot, changesAction, layoutMode });
244
- }
245
-
246
- function formatProfileLines(snapshot, diagnostics) {
247
- const policy = snapshot?.policy;
248
- const sources = diagnostics?.profile?.sources;
249
- const sourceLabel = sources?.global || sources?.project
250
- ? [sources.global ? "global" : null, sources.project ? "project" : null].filter(Boolean).join(", ")
251
- : "none";
252
- return [
253
- `Policy profile: ${policy?.profile ?? "none"}`,
254
- `Apply mode: ${policy?.applyMode ?? "n/a"}`,
255
- `Preflight: ${policy?.preflight ?? "n/a"}`,
256
- `Policy source: ${policy?.source ?? "none"}`,
257
- `Kairo profile sources: ${sourceLabel}`,
258
- "",
259
- "Project overrides global overrides defaults. Consent remains explicit for writes."
260
- ];
290
+ function formatChangeLines(snapshot, changesAction, layoutMode = LAYOUT_MODES.COMPACT, homeDir = null) {
291
+ return formatChangesActionLines({ snapshot, changesAction, layoutMode, homeDir });
261
292
  }
262
293
 
263
294
  function listBlock(title, lines, listIndex, colorEnabled, emptyHint) {
@@ -13,19 +13,26 @@ import {
13
13
  isContentInteractiveView
14
14
  } from "./cockpit-controller.js";
15
15
  import {
16
- COCKPIT_NAV,
17
16
  COCKPIT_REGIONS,
18
17
  buildFooterModel,
19
18
  buildNavModel,
20
- buildSystemStripModel,
21
19
  buildTopBarModel,
22
20
  navIndexForView,
23
21
  resolveProjectName
24
22
  } from "./cockpit-models.js";
25
23
  import { buildControlCenterModel } from "./cockpit-control-center.js";
24
+ import {
25
+ buildPaletteActions,
26
+ buildPaletteModel,
27
+ canOpenPalette,
28
+ PALETTE_KINDS,
29
+ resolvePaletteDestination
30
+ } from "./cockpit-palette.js";
26
31
  import { resolveEnterNavIntent } from "./cockpit-enter.js";
27
32
  import { resolveRunsHubItem, RUNS_HUB_ITEMS } from "./cockpit-runs.js";
28
33
  import { selectReviewFromList } from "./cockpit-reviews.js";
34
+ import { selectAlertFromList } from "./cockpit-alerts.js";
35
+ import { ALERT_STATES } from "../runtime/alerts/alert-types.js";
29
36
  import { resolveProjectReadiness } from "../dashboard-guidance.js";
30
37
  import { CONTROL_PLANE_HEALTH } from "../control-plane-snapshot.js";
31
38
  import { CockpitShell } from "./cockpit/primitives.js";
@@ -38,6 +45,7 @@ import { COCKPIT_COLORS } from "./theme.js";
38
45
  import { LAYOUT_MODES } from "./layout.js";
39
46
  import { CHANGES_PHASE } from "./cockpit-changes.js";
40
47
  import { RECOVERY_PHASE, listRecoverySnapshots } from "./cockpit-recovery.js";
48
+ import { SETTINGS_PHASE } from "./cockpit-settings.js";
41
49
 
42
50
  export function OrchestratorApp({
43
51
  homeDir,
@@ -76,7 +84,7 @@ export function OrchestratorApp({
76
84
  };
77
85
 
78
86
  const openDestination = (destinationKey) => {
79
- const view = resolveCtaDestinationView(destinationKey);
87
+ const view = resolvePaletteDestination(destinationKey);
80
88
  if (!view) return false;
81
89
  dispatch({
82
90
  type: "set-view",
@@ -86,6 +94,15 @@ export function OrchestratorApp({
86
94
  return true;
87
95
  };
88
96
 
97
+ const confirming = data.changesAction?.phase === CHANGES_PHASE.CONFIRMING
98
+ || data.recoveryAction?.phase === RECOVERY_PHASE.CONFIRMING
99
+ || data.settingsAction?.phase === SETTINGS_PHASE.CONFIRMING;
100
+ const paletteActions = buildPaletteActions({
101
+ ctaDestination: data.snapshot?.cta?.destination ?? null,
102
+ ctaTitle: data.snapshot?.cta?.title ?? null,
103
+ ctaDetail: data.snapshot?.cta?.detail ?? null
104
+ });
105
+
89
106
  useInput((inputKey, key) => {
90
107
  if (data.loading) return;
91
108
 
@@ -104,6 +121,46 @@ export function OrchestratorApp({
104
121
 
105
122
  if (data.busy) return;
106
123
 
124
+ if (ui.paletteOpen) {
125
+ if (key.escape) {
126
+ dispatch({ type: "close-palette" });
127
+ return;
128
+ }
129
+ if (inputKey === "/") {
130
+ dispatch({ type: "toggle-palette" });
131
+ return;
132
+ }
133
+ if (key.upArrow || key.downArrow) {
134
+ dispatch({
135
+ type: "palette-arrow",
136
+ direction: key.upArrow ? "up" : "down",
137
+ listLength: paletteActions.length
138
+ });
139
+ return;
140
+ }
141
+ if (key.return) {
142
+ const selected = paletteActions[ui.paletteIndex] ?? null;
143
+ if (!selected) return;
144
+ if (selected.kind === PALETTE_KINDS.REFRESH) {
145
+ dispatch({ type: "run-palette", kind: selected.kind });
146
+ data.reload().catch(() => {});
147
+ return;
148
+ }
149
+ dispatch({
150
+ type: "run-palette",
151
+ kind: selected.kind,
152
+ view: selected.view
153
+ });
154
+ }
155
+ return;
156
+ }
157
+
158
+ if (inputKey === "/"
159
+ && canOpenPalette({ loading: data.loading, busy: data.busy, confirming })) {
160
+ dispatch({ type: "toggle-palette" });
161
+ return;
162
+ }
163
+
107
164
  if (key.escape) {
108
165
  if (ui.view === ORCHESTRATOR_VIEWS.CHANGES
109
166
  && data.changesAction?.phase === CHANGES_PHASE.CONFIRMING) {
@@ -115,6 +172,18 @@ export function OrchestratorApp({
115
172
  data.cancelRecovery();
116
173
  return;
117
174
  }
175
+ if (ui.view === ORCHESTRATOR_VIEWS.PROFILE) {
176
+ const settingsPhase = data.settingsAction?.phase;
177
+ if (settingsPhase === SETTINGS_PHASE.CONFIRMING) {
178
+ data.cancelSettings();
179
+ return;
180
+ }
181
+ if (settingsPhase === SETTINGS_PHASE.PREVIEW
182
+ || settingsPhase === SETTINGS_PHASE.COMPLETED) {
183
+ data.resetSettings();
184
+ return;
185
+ }
186
+ }
118
187
 
119
188
  if (ui.view === ORCHESTRATOR_VIEWS.LAUNCH && data.launchableAgents.length > 0) {
120
189
  const retreated = handleLaunchInput({
@@ -162,9 +231,15 @@ export function OrchestratorApp({
162
231
  ? (data.dashboard?.recentRuns ?? []).length
163
232
  : ui.view === ORCHESTRATOR_VIEWS.REVIEWS
164
233
  ? (data.reviews ?? []).length
165
- : ui.view === ORCHESTRATOR_VIEWS.ACTIVITY
166
- ? listRecoverySnapshots(data.snapshot).length
167
- : 0;
234
+ : ui.view === ORCHESTRATOR_VIEWS.ALERTS
235
+ ? (Array.isArray(data.alerts) ? data.alerts : [])
236
+ .filter((alert) => alert.state === ALERT_STATES.OPEN).length
237
+ : ui.view === ORCHESTRATOR_VIEWS.ACTIVITY
238
+ ? listRecoverySnapshots(data.snapshot).length
239
+ : ui.view === ORCHESTRATOR_VIEWS.PROFILE
240
+ && data.settingsAction?.phase === SETTINGS_PHASE.BROWSE
241
+ ? data.curatedIntegrations.length
242
+ : 0;
168
243
 
169
244
  let routed = null;
170
245
  if (key.tab) {
@@ -261,6 +336,19 @@ export function OrchestratorApp({
261
336
  return;
262
337
  }
263
338
 
339
+ if (ui.region === COCKPIT_REGIONS.CONTENT
340
+ && ui.view === ORCHESTRATOR_VIEWS.ALERTS) {
341
+ const selected = selectAlertFromList(data.alerts, ui.listIndex);
342
+ if (key.return) {
343
+ data.handleAlertTransition(selected, "resolve").catch(() => {});
344
+ return;
345
+ }
346
+ if (inputKey.toLowerCase() === "d") {
347
+ data.handleAlertTransition(selected, "dismiss").catch(() => {});
348
+ return;
349
+ }
350
+ }
351
+
264
352
  if (ui.view === ORCHESTRATOR_VIEWS.RUN_DETAIL) {
265
353
  if (inputKey.toLowerCase() === "c" && isRunCancellable(data.selectedRun)) {
266
354
  data.handleCancelRun();
@@ -317,6 +405,30 @@ export function OrchestratorApp({
317
405
  }
318
406
  }
319
407
 
408
+ if (ui.view === ORCHESTRATOR_VIEWS.PROFILE) {
409
+ const keyName = inputKey.toLowerCase();
410
+ const phase = data.settingsAction?.phase ?? SETTINGS_PHASE.BROWSE;
411
+ if (key.return && ui.region === COCKPIT_REGIONS.CONTENT) {
412
+ if (phase === SETTINGS_PHASE.BROWSE) {
413
+ const entry = data.curatedIntegrations[ui.listIndex];
414
+ if (entry?.id) data.previewSettings(entry.id);
415
+ return;
416
+ }
417
+ if (phase === SETTINGS_PHASE.PREVIEW) {
418
+ data.promptConfirmSettings();
419
+ return;
420
+ }
421
+ }
422
+ if (keyName === "y" && phase === SETTINGS_PHASE.CONFIRMING) {
423
+ data.confirmSettings();
424
+ return;
425
+ }
426
+ if (keyName === "n" && phase === SETTINGS_PHASE.CONFIRMING) {
427
+ data.cancelSettings();
428
+ return;
429
+ }
430
+ }
431
+
320
432
  if (inputKey.toLowerCase() === "r" && ui.view !== ORCHESTRATOR_VIEWS.LAUNCH) {
321
433
  if (ui.view === ORCHESTRATOR_VIEWS.REVIEWS || ui.view === ORCHESTRATOR_VIEWS.REVIEW_DETAIL) {
322
434
  data.loadReviews().catch(() => {});
@@ -354,7 +466,9 @@ export function OrchestratorApp({
354
466
  const controlCenter = buildControlCenterModel({
355
467
  projectName,
356
468
  snapshot: data.snapshot,
357
- layoutMode: mode
469
+ dashboard: data.dashboard,
470
+ layoutMode: mode,
471
+ alerts: data.alerts
358
472
  });
359
473
  const systemOnline = data.snapshot
360
474
  ? data.snapshot.health !== CONTROL_PLANE_HEALTH.NOT_CONFIGURED
@@ -376,12 +490,16 @@ export function OrchestratorApp({
376
490
  region: ui.region,
377
491
  navIndex: ui.navIndex,
378
492
  helpOpen: ui.helpOpen,
493
+ paletteOpen: ui.paletteOpen,
379
494
  canCancel: isRunCancellable(data.selectedRun),
380
495
  unicode,
381
496
  changesPhase: data.changesAction?.phase ?? null,
382
- recoveryPhase: data.recoveryAction?.phase ?? null
497
+ recoveryPhase: data.recoveryAction?.phase ?? null,
498
+ settingsPhase: data.settingsAction?.phase ?? null,
499
+ columns
383
500
  }),
384
501
  layoutMode: mode,
502
+ columns,
385
503
  nav: buildNavModel({
386
504
  navIndex: ui.navIndex,
387
505
  currentView: ui.view,
@@ -391,24 +509,8 @@ export function OrchestratorApp({
391
509
  diagnostics: data.diagnostics,
392
510
  snapshot: data.snapshot
393
511
  }),
394
- system: buildSystemStripModel({
395
- dashboard: data.dashboard,
396
- diagnostics: data.diagnostics,
397
- readiness: data.snapshot
398
- ? {
399
- kind: data.snapshot.health.toLowerCase(),
400
- label: controlCenter.health.label,
401
- healthKind: data.snapshot.health === CONTROL_PLANE_HEALTH.HEALTHY
402
- ? "ready"
403
- : data.snapshot.health === CONTROL_PLANE_HEALTH.CHECK_FAILED
404
- ? "error"
405
- : "warn"
406
- }
407
- : readiness
408
- }),
409
512
  navFocused: ui.region === COCKPIT_REGIONS.NAV,
410
513
  contentFocused: ui.region === COCKPIT_REGIONS.CONTENT,
411
- systemFocused: ui.region === COCKPIT_REGIONS.SYSTEM,
412
514
  colorEnabled
413
515
  },
414
516
  renderCockpitView({
@@ -426,33 +528,22 @@ export function OrchestratorApp({
426
528
  selectedEvents: data.selectedEvents,
427
529
  reviews: data.reviews,
428
530
  selectedReview: data.selectedReview,
531
+ alerts: data.alerts,
429
532
  changesAction: data.changesAction,
430
533
  recoveryAction: data.recoveryAction,
534
+ settingsAction: data.settingsAction,
431
535
  controlCenter,
536
+ palette: ui.paletteOpen
537
+ ? buildPaletteModel({
538
+ actions: paletteActions,
539
+ index: ui.paletteIndex,
540
+ unicode
541
+ })
542
+ : null,
432
543
  layoutMode: mode,
433
- colorEnabled
544
+ colorEnabled,
545
+ homeDir
434
546
  })
435
547
  )
436
548
  );
437
549
  }
438
-
439
- function resolveCtaDestinationView(destinationKey) {
440
- switch (destinationKey) {
441
- case "changes":
442
- return ORCHESTRATOR_VIEWS.CHANGES;
443
- case "control-center":
444
- return ORCHESTRATOR_VIEWS.HOME;
445
- case "ides":
446
- return ORCHESTRATOR_VIEWS.IDES;
447
- case "modules":
448
- return ORCHESTRATOR_VIEWS.MODULES;
449
- case "activity":
450
- return ORCHESTRATOR_VIEWS.ACTIVITY;
451
- case "profile":
452
- return ORCHESTRATOR_VIEWS.PROFILE;
453
- case "runs":
454
- return ORCHESTRATOR_VIEWS.RUNS;
455
- default:
456
- return null;
457
- }
458
- }
@@ -1,6 +1,7 @@
1
1
  import { stdin as input, stdout as output } from "node:process";
2
2
  import { canUseSetupInk } from "./terminal.js";
3
3
  import { isActiveRunState, formatTaskLabel } from "../runtime/run-types.js";
4
+ import { formatConfirmPath } from "./cockpit-path-label.js";
4
5
 
5
6
  export function canUseOrchestratorShell({
6
7
  interactive = Boolean(input.isTTY && output.isTTY),
@@ -27,7 +28,9 @@ export const ORCHESTRATOR_VIEWS = {
27
28
  PROVIDERS: "providers",
28
29
  LAUNCH: "launch",
29
30
  DIAGNOSTICS: "diagnostics",
30
- HELP: "help"
31
+ HELP: "help",
32
+ USAGE: "usage",
33
+ ALERTS: "alerts"
31
34
  };
32
35
 
33
36
  export const ORCHESTRATOR_MENU = [
@@ -175,8 +178,9 @@ export function formatRunLines(runs, {
175
178
  const agent = humanizeToken(run.agentId);
176
179
  const state = humanizeRunState(run.state);
177
180
  const task = formatTaskLabel(run);
181
+ const strategy = run.strategy ? ` · ${run.strategy}` : "";
178
182
  if (readable) {
179
- return `${agent} · ${state} · ${task}`;
183
+ return `${agent} · ${state}${strategy} · ${task}`;
180
184
  }
181
185
  const statePad = run.state.padEnd(12);
182
186
  const agentPad = run.agentId.padEnd(10);
@@ -270,23 +274,29 @@ export function formatAgentStatusLines(capabilities) {
270
274
  });
271
275
  }
272
276
 
273
- export function formatRunDetailLines(run, events = []) {
277
+ export function formatRunDetailLines(run, events = [], { homeDir = null } = {}) {
274
278
  if (!run) return ["Run not found."];
275
279
 
276
280
  const lines = [
277
- `Run: ${run.runId}`,
278
- `Agent: ${run.agentId} (${run.provider})`,
279
- `State: ${run.state}`,
280
- `Model: ${run.model ?? "default"}`,
281
- `Cwd: ${run.cwd}`,
282
- `Started: ${run.startedAt}`,
283
- `Updated: ${run.updatedAt}`
281
+ "SUMMARY",
282
+ `${humanizeToken(run.agentId)} · ${humanizeRunState(run.state)}${run.strategy ? ` · ${run.strategy}` : ""}`,
283
+ `Model · ${run.model ?? "default"}`,
284
+ `Started · ${run.startedAt ?? "n/a"}`
284
285
  ];
286
+ if (run.completedAt) lines.push(`Completed · ${run.completedAt}`);
287
+ if (run.tokenUsage && typeof run.tokenUsage === "object") {
288
+ const parts = [];
289
+ if (Number.isFinite(run.tokenUsage.input)) parts.push(`in ${run.tokenUsage.input}`);
290
+ if (Number.isFinite(run.tokenUsage.output)) parts.push(`out ${run.tokenUsage.output}`);
291
+ if (Number.isFinite(run.tokenUsage.total)) parts.push(`total ${run.tokenUsage.total}`);
292
+ if (parts.length > 0) lines.push(`Tokens · ${parts.join(" · ")}`);
293
+ }
294
+ if (run.error) lines.push(`Error · ${run.error}`);
285
295
 
286
- if (run.completedAt) lines.push(`Completed: ${run.completedAt}`);
287
- if (run.tokenUsage) lines.push(`Tokens: ${JSON.stringify(run.tokenUsage)}`);
288
- if (run.error) lines.push(`Error: ${run.error}`);
289
- if (run.tools?.length) lines.push(`Tools: ${run.tools.join(", ")}`);
296
+ lines.push("", "DETAILS");
297
+ lines.push(`Run id · ${run.runId}`);
298
+ if (run.cwd) lines.push(`Cwd · ${formatConfirmPath(run.cwd, homeDir)}`);
299
+ if (run.tools?.length) lines.push(`Tools · ${run.tools.join(", ")}`);
290
300
 
291
301
  if (events.length > 0) {
292
302
  lines.push("", "Recent events");