@kal-elsam/kairo-runtime 0.2.3 → 0.3.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.
@@ -1,44 +1,32 @@
1
- import React, { useEffect, useState } from "react";
1
+ import React, { useEffect, useReducer } from "react";
2
2
  import { Box, Text, useApp, useInput } from "ink";
3
- import { BRAND } from "../brand/index.js";
4
- import { buildReadOnlyDiagnostics } from "../action-planner.js";
5
- import { buildRuntimeDashboardData } from "../runtime/run-cli.js";
6
- import { readRunEvents } from "../runtime/run-store.js";
7
- import { stopRun } from "../runtime/run-manager.js";
8
- import { startRun } from "../runtime/run-manager.js";
9
3
  import {
10
- ORCHESTRATOR_MENU,
11
4
  ORCHESTRATOR_VIEWS,
12
- LAUNCH_WIZARD_STEPS,
13
- LAUNCH_PERMISSION_OPTIONS,
14
- createLaunchDraft,
15
- formatDashboardSnapshot,
16
- formatDiagnosticsLines,
17
- formatLaunchWizardLines,
18
- formatProviderLines,
19
- formatRunDetailLines,
20
- formatRunLines,
21
5
  isRunCancellable,
22
- resolveLaunchPermissions,
23
- resolveLaunchableAgents,
24
- resolveMenuItem,
25
- resolveMenuItemView,
26
- retreatLaunchWizardStep,
27
- selectRunFromList,
28
- shiftMenuIndex
6
+ selectRunFromList
29
7
  } from "./orchestrator-state.js";
30
8
  import {
31
- formatDashboardPurpose,
32
- resolveDashboardRecommendation
33
- } from "../dashboard-guidance.js";
34
-
35
- const COLORS = {
36
- accent: "cyan",
37
- success: "green",
38
- warning: "yellow",
39
- danger: "red",
40
- muted: "gray"
41
- };
9
+ createCockpitUiState,
10
+ reduceCockpitUi,
11
+ resolveNavAction
12
+ } from "./cockpit-controller.js";
13
+ import {
14
+ COCKPIT_REGIONS,
15
+ buildFooterModel,
16
+ buildHomeMissionModel,
17
+ buildNavModel,
18
+ buildSystemStripModel,
19
+ buildTopBarModel,
20
+ resolveProjectName
21
+ } from "./cockpit-models.js";
22
+ import { CockpitShell } from "./cockpit/primitives.js";
23
+ import { renderCockpitView } from "./cockpit-views.js";
24
+ import { handleLaunchInput } from "./launch-input.js";
25
+ import { useTerminalSize } from "./use-terminal-size.js";
26
+ import { useOrchestratorData } from "./use-orchestrator-data.js";
27
+ import { resolveTerminalCapabilities } from "./terminal-capabilities.js";
28
+ import { COCKPIT_COLORS } from "./theme.js";
29
+ import { LAYOUT_MODES } from "./layout.js";
42
30
 
43
31
  export function OrchestratorApp({
44
32
  homeDir,
@@ -50,475 +38,205 @@ export function OrchestratorApp({
50
38
  onComplete
51
39
  }) {
52
40
  const { exit } = useApp();
53
- const [view, setView] = useState(ORCHESTRATOR_VIEWS.HOME);
54
- const [menuIndex, setMenuIndex] = useState(0);
55
- const [listIndex, setListIndex] = useState(0);
56
- const [launchAgentIndex, setLaunchAgentIndex] = useState(0);
57
- const [launchStep, setLaunchStep] = useState(LAUNCH_WIZARD_STEPS.AGENT);
58
- const [launchDraft, setLaunchDraft] = useState(createLaunchDraft);
59
- const [launchPermissionIndex, setLaunchPermissionIndex] = useState(0);
60
- const [loading, setLoading] = useState(true);
61
- const [busy, setBusy] = useState(false);
62
- const [error, setError] = useState(null);
63
- const [dashboard, setDashboard] = useState(null);
64
- const [diagnostics, setDiagnostics] = useState(null);
65
- const [selectedRun, setSelectedRun] = useState(null);
66
- const [selectedEvents, setSelectedEvents] = useState([]);
67
- const [statusMessage, setStatusMessage] = useState(null);
68
-
69
- const reload = async () => {
70
- const [dash, diag] = await Promise.all([
71
- buildRuntimeDashboardData({ homeDir, workspaceRoot, cliVersion }),
72
- buildReadOnlyDiagnostics({ homeDir, workspaceRoot, packageName, packageRoot, cliVersion })
73
- ]);
74
- setDashboard(dash);
75
- setDiagnostics(diag);
76
- };
41
+ const { columns, rows, layoutMode } = useTerminalSize();
42
+ const caps = resolveTerminalCapabilities({ columns, rows, isTTY: true });
43
+ const [ui, dispatch] = useReducer(
44
+ reduceCockpitUi,
45
+ createCockpitUiState({
46
+ layoutMode: layoutMode ?? LAYOUT_MODES.COMPACT,
47
+ region: COCKPIT_REGIONS.NAV
48
+ })
49
+ );
50
+ const data = useOrchestratorData({
51
+ homeDir,
52
+ workspaceRoot,
53
+ packageName,
54
+ packageRoot,
55
+ cliVersion
56
+ });
77
57
 
78
58
  useEffect(() => {
79
- let cancelled = false;
80
-
81
- async function load() {
82
- try {
83
- await reload();
84
- if (cancelled) return;
85
- setLoading(false);
86
- } catch (loadError) {
87
- if (cancelled) return;
88
- setError(loadError instanceof Error ? loadError.message : String(loadError));
89
- setLoading(false);
90
- }
91
- }
92
-
93
- load();
94
- return () => {
95
- cancelled = true;
96
- };
97
- }, [homeDir, workspaceRoot, packageName, packageRoot, cliVersion]);
59
+ if (layoutMode) dispatch({ type: "resize", layoutMode });
60
+ }, [layoutMode]);
98
61
 
99
62
  const finish = (outcome) => {
100
63
  onComplete(outcome);
101
64
  exit();
102
65
  };
103
66
 
104
- const openRunDetail = async (run) => {
105
- if (!run) return;
106
- const events = await readRunEvents(homeDir, run.runId, { limit: 20 });
107
- setSelectedRun(run);
108
- setSelectedEvents(events);
109
- setView(ORCHESTRATOR_VIEWS.RUN_DETAIL);
110
- };
111
-
112
- const launchableAgents = resolveLaunchableAgents(dashboard?.providers ?? []);
113
-
114
- const resetLaunchWizard = () => {
115
- setLaunchStep(LAUNCH_WIZARD_STEPS.AGENT);
116
- setLaunchDraft(createLaunchDraft());
117
- setLaunchAgentIndex(0);
118
- setLaunchPermissionIndex(0);
119
- };
120
-
121
- const handleLaunch = async (draft) => {
122
- if (!draft.agentId || !draft.task.trim()) {
123
- setError("Agent and task are required.");
124
- return;
125
- }
126
-
127
- setBusy(true);
128
- setStatusMessage(`Launching ${draft.agentId}…`);
129
- try {
130
- const permissions = resolveLaunchPermissions({
131
- ...draft,
132
- permissionIndex: launchPermissionIndex
133
- });
134
- const { runId } = await startRun({
135
- homeDir,
136
- agentId: draft.agentId,
137
- task: draft.task.trim(),
138
- cwd: workspaceRoot,
139
- model: draft.model.trim() || null,
140
- permissions,
141
- cliVersion,
142
- profile: dashboard?.profile ?? null,
143
- follow: false,
144
- wait: false
145
- });
146
- await reload();
147
- const run = (await buildRuntimeDashboardData({ homeDir, workspaceRoot, cliVersion }))
148
- .runs.find((entry) => entry.runId === runId);
149
- setStatusMessage(`Run started: ${runId}`);
150
- resetLaunchWizard();
151
- setView(ORCHESTRATOR_VIEWS.HOME);
152
- if (run) await openRunDetail(run);
153
- } catch (launchError) {
154
- setError(launchError instanceof Error ? launchError.message : String(launchError));
155
- } finally {
156
- setBusy(false);
157
- }
158
- };
159
-
160
- const handleCancelRun = async () => {
161
- if (!selectedRun || !isRunCancellable(selectedRun)) return;
162
- setBusy(true);
163
- try {
164
- await stopRun(homeDir, selectedRun.runId);
165
- await reload();
166
- const refreshed = await buildRuntimeDashboardData({ homeDir, workspaceRoot, cliVersion });
167
- const run = refreshed.runs.find((entry) => entry.runId === selectedRun.runId);
168
- const events = await readRunEvents(homeDir, selectedRun.runId, { limit: 20 });
169
- setSelectedRun(run ?? selectedRun);
170
- setSelectedEvents(events);
171
- setStatusMessage(`Cancelled ${selectedRun.runId}`);
172
- } catch (cancelError) {
173
- setError(cancelError instanceof Error ? cancelError.message : String(cancelError));
174
- } finally {
175
- setBusy(false);
176
- }
177
- };
178
-
179
67
  useInput((inputKey, key) => {
180
68
  if (key.escape) {
181
- if (view === ORCHESTRATOR_VIEWS.HOME) {
69
+ const next = reduceCockpitUi(ui, { type: "escape" });
70
+ if (next.shouldExit) {
182
71
  finish({ cancelled: true });
183
72
  return;
184
73
  }
185
- setView(ORCHESTRATOR_VIEWS.HOME);
186
- setSelectedRun(null);
187
- setListIndex(0);
74
+ data.setSelectedRun(null);
75
+ data.resetLaunchWizard();
76
+ dispatch({ type: "escape" });
188
77
  return;
189
78
  }
190
79
 
191
- if (loading || error || busy) return;
80
+ if (data.loading || data.error || data.busy) return;
192
81
 
193
- if (view === ORCHESTRATOR_VIEWS.LAUNCH) {
194
- if (launchableAgents.length === 0) {
195
- if (key.escape) {
196
- resetLaunchWizard();
197
- setView(ORCHESTRATOR_VIEWS.HOME);
198
- }
199
- return;
200
- }
82
+ if (inputKey === "?") {
83
+ dispatch({ type: "toggle-help" });
84
+ return;
85
+ }
86
+ if (key.tab) {
87
+ dispatch({ type: "tab" });
88
+ return;
89
+ }
201
90
 
202
- if (launchStep === LAUNCH_WIZARD_STEPS.AGENT) {
203
- if (key.upArrow) {
204
- setLaunchAgentIndex((index) => Math.max(0, index - 1));
205
- return;
206
- }
207
- if (key.downArrow) {
208
- setLaunchAgentIndex((index) => Math.min(launchableAgents.length - 1, index + 1));
209
- return;
210
- }
211
- if (key.return) {
212
- const agentId = launchableAgents[launchAgentIndex];
213
- setLaunchDraft((draft) => ({ ...draft, agentId }));
214
- setLaunchStep(LAUNCH_WIZARD_STEPS.TASK);
215
- }
91
+ if (ui.view === ORCHESTRATOR_VIEWS.LAUNCH && data.launchableAgents.length > 0) {
92
+ if (handleLaunchInput({
93
+ key,
94
+ inputKey,
95
+ launchStep: data.launchStep,
96
+ launchDraft: data.launchDraft,
97
+ launchableAgents: data.launchableAgents,
98
+ launchAgentIndex: data.launchAgentIndex,
99
+ launchPermissionIndex: data.launchPermissionIndex,
100
+ setLaunchAgentIndex: data.setLaunchAgentIndex,
101
+ setLaunchDraft: data.setLaunchDraft,
102
+ setLaunchStep: data.setLaunchStep,
103
+ setLaunchPermissionIndex: data.setLaunchPermissionIndex,
104
+ setError: data.setError,
105
+ handleLaunch: (draft) => data.handleLaunch(draft, data.dashboard?.profile, dispatch),
106
+ reload: data.reload
107
+ })) {
216
108
  return;
217
109
  }
110
+ }
218
111
 
219
- if (launchStep === LAUNCH_WIZARD_STEPS.TASK) {
220
- if (key.return) {
221
- if (!launchDraft.task.trim()) {
222
- setError("Task cannot be empty.");
223
- return;
224
- }
225
- setLaunchStep(LAUNCH_WIZARD_STEPS.MODEL);
226
- return;
227
- }
228
- if (key.backspace || key.delete) {
229
- setLaunchDraft((draft) => ({ ...draft, task: draft.task.slice(0, -1) }));
230
- return;
231
- }
232
- if (inputKey && inputKey.length === 1 && !key.ctrl && !key.meta) {
233
- setLaunchDraft((draft) => ({ ...draft, task: `${draft.task}${inputKey}` }));
234
- }
112
+ if (ui.view === ORCHESTRATOR_VIEWS.ACTIVE_RUNS || ui.view === ORCHESTRATOR_VIEWS.RECENT_RUNS) {
113
+ const runs = ui.view === ORCHESTRATOR_VIEWS.ACTIVE_RUNS
114
+ ? data.dashboard?.activeRuns ?? []
115
+ : data.dashboard?.recentRuns ?? [];
116
+ if (key.upArrow || key.downArrow) {
117
+ dispatch({
118
+ type: "arrow",
119
+ direction: key.upArrow ? "up" : "down",
120
+ listLength: runs.length
121
+ });
235
122
  return;
236
123
  }
237
-
238
- if (launchStep === LAUNCH_WIZARD_STEPS.MODEL) {
239
- if (key.return) {
240
- setLaunchStep(LAUNCH_WIZARD_STEPS.PERMISSIONS);
241
- return;
242
- }
243
- if (key.backspace || key.delete) {
244
- setLaunchDraft((draft) => ({ ...draft, model: draft.model.slice(0, -1) }));
245
- return;
246
- }
247
- if (inputKey && inputKey.length === 1 && !key.ctrl && !key.meta) {
248
- setLaunchDraft((draft) => ({ ...draft, model: `${draft.model}${inputKey}` }));
249
- }
124
+ if (key.return) {
125
+ data.openRunDetail(selectRunFromList(runs, ui.listIndex), dispatch);
250
126
  return;
251
127
  }
128
+ }
252
129
 
253
- if (launchStep === LAUNCH_WIZARD_STEPS.PERMISSIONS) {
254
- if (key.upArrow) {
255
- setLaunchPermissionIndex((index) => Math.max(0, index - 1));
256
- return;
257
- }
258
- if (key.downArrow) {
259
- setLaunchPermissionIndex((index) => Math.min(LAUNCH_PERMISSION_OPTIONS.length - 1, index + 1));
260
- return;
261
- }
262
- if (key.return) {
263
- setLaunchStep(LAUNCH_WIZARD_STEPS.CONFIRM);
264
- }
130
+ if (ui.view === ORCHESTRATOR_VIEWS.RUN_DETAIL) {
131
+ if (inputKey.toLowerCase() === "c" && isRunCancellable(data.selectedRun)) {
132
+ data.handleCancelRun();
265
133
  return;
266
134
  }
267
-
268
- if (launchStep === LAUNCH_WIZARD_STEPS.CONFIRM) {
269
- if (key.return) {
270
- handleLaunch({ ...launchDraft, permissionIndex: launchPermissionIndex });
271
- }
272
- if (key.escape) {
273
- setLaunchStep(retreatLaunchWizardStep(launchStep));
274
- }
135
+ if (inputKey.toLowerCase() === "r") {
136
+ data.openRunDetail(data.selectedRun, dispatch);
275
137
  return;
276
138
  }
139
+ }
277
140
 
278
- if (inputKey.toLowerCase() === "r") {
279
- reload().catch((reloadError) => {
280
- setError(reloadError instanceof Error ? reloadError.message : String(reloadError));
281
- });
282
- }
141
+ if (inputKey.toLowerCase() === "r" && ui.view !== ORCHESTRATOR_VIEWS.LAUNCH) {
142
+ data.reload().catch((reloadError) => {
143
+ data.setError(reloadError instanceof Error ? reloadError.message : String(reloadError));
144
+ });
283
145
  return;
284
146
  }
285
147
 
286
- if (view === ORCHESTRATOR_VIEWS.ACTIVE_RUNS || view === ORCHESTRATOR_VIEWS.RECENT_RUNS) {
287
- const runs = view === ORCHESTRATOR_VIEWS.ACTIVE_RUNS
288
- ? dashboard?.activeRuns ?? []
289
- : dashboard?.recentRuns ?? [];
290
-
291
- if (key.upArrow) {
292
- setListIndex((index) => Math.max(0, index - 1));
293
- return;
294
- }
295
- if (key.downArrow) {
296
- setListIndex((index) => Math.min(Math.max(runs.length - 1, 0), index + 1));
148
+ if (ui.view === ORCHESTRATOR_VIEWS.HOME || ui.region === COCKPIT_REGIONS.NAV) {
149
+ if (key.upArrow || key.downArrow) {
150
+ dispatch({ type: "arrow", direction: key.upArrow ? "up" : "down" });
297
151
  return;
298
152
  }
299
153
  if (key.return) {
300
- openRunDetail(selectRunFromList(runs, listIndex));
301
- }
302
- if (inputKey.toLowerCase() === "r") {
303
- reload().catch((reloadError) => {
304
- setError(reloadError instanceof Error ? reloadError.message : String(reloadError));
305
- });
306
- }
307
- return;
308
- }
309
-
310
- if (view === ORCHESTRATOR_VIEWS.RUN_DETAIL) {
311
- if (inputKey.toLowerCase() === "c" && isRunCancellable(selectedRun)) {
312
- handleCancelRun();
313
- }
314
- if (inputKey.toLowerCase() === "r") {
315
- openRunDetail(selectedRun);
154
+ const item = resolveNavAction(ui.navIndex);
155
+ if (item?.action === "launch") {
156
+ data.resetLaunchWizard();
157
+ dispatch({ type: "set-view", view: ORCHESTRATOR_VIEWS.LAUNCH });
158
+ return;
159
+ }
160
+ dispatch({ type: "enter-nav" });
316
161
  }
317
- return;
318
162
  }
319
-
320
- if (view !== ORCHESTRATOR_VIEWS.HOME) {
321
- if (inputKey.toLowerCase() === "r") {
322
- reload().catch((reloadError) => {
323
- setError(reloadError instanceof Error ? reloadError.message : String(reloadError));
324
- });
325
- }
326
- return;
327
- }
328
-
329
- if (key.upArrow) {
330
- setMenuIndex((index) => shiftMenuIndex(index, "up"));
331
- return;
332
- }
333
-
334
- if (key.downArrow) {
335
- setMenuIndex((index) => shiftMenuIndex(index, "down"));
336
- return;
337
- }
338
-
339
- if (!key.return) return;
340
-
341
- const item = resolveMenuItem(menuIndex);
342
- if (item?.action === "launch") {
343
- resetLaunchWizard();
344
- setView(ORCHESTRATOR_VIEWS.LAUNCH);
345
- return;
346
- }
347
-
348
- setView(resolveMenuItemView(menuIndex));
349
- setListIndex(0);
350
163
  });
351
164
 
352
- if (loading) {
165
+ if (data.loading) {
353
166
  return React.createElement(Box, { flexDirection: "column" },
354
- React.createElement(Text, { bold: true, color: COLORS.accent }, BRAND.displayName),
355
- React.createElement(Text, { color: COLORS.muted }, "Loading runtime dashboard…")
167
+ React.createElement(Text, { bold: true, color: COCKPIT_COLORS.primary }, "KAIRO"),
168
+ React.createElement(Text, { color: COCKPIT_COLORS.muted }, "Loading cockpit…")
356
169
  );
357
170
  }
358
171
 
359
- if (error) {
172
+ if (data.error) {
360
173
  return React.createElement(Box, { flexDirection: "column" },
361
- React.createElement(Text, { bold: true, color: COLORS.danger }, "Runtime error"),
362
- React.createElement(Text, null, error),
174
+ React.createElement(Text, { bold: true, color: COCKPIT_COLORS.danger }, "Runtime error"),
175
+ React.createElement(Text, null, data.error),
363
176
  React.createElement(Text, { dimColor: true }, "Esc to exit")
364
177
  );
365
178
  }
366
179
 
180
+ const mode = ui.layoutMode ?? LAYOUT_MODES.COMPACT;
181
+ const colorEnabled = caps.color;
182
+ const unicode = caps.unicode;
183
+
367
184
  return React.createElement(Box, { flexDirection: "column" },
368
- React.createElement(Text, { bold: true, color: COLORS.accent }, `${BRAND.displayName} runtime`),
369
- React.createElement(Text, { color: COLORS.muted }, formatDashboardPurpose()),
370
- statusMessage && React.createElement(Text, { color: COLORS.success }, statusMessage),
371
- React.createElement(Text, null, ""),
372
- renderView({
373
- view,
374
- dashboard,
375
- diagnostics,
376
- hasGlobalState,
377
- menuIndex,
378
- listIndex,
379
- launchStep,
380
- launchDraft,
381
- launchAgentIndex,
382
- launchPermissionIndex,
383
- launchableAgents,
384
- selectedRun,
385
- selectedEvents
386
- }),
387
- React.createElement(Text, null, ""),
388
- React.createElement(Text, { dimColor: true }, footerHint(view, selectedRun, launchStep))
185
+ data.statusMessage && React.createElement(Text, {
186
+ color: COCKPIT_COLORS.success
187
+ }, data.statusMessage),
188
+ React.createElement(CockpitShell, {
189
+ topBar: buildTopBarModel({
190
+ projectName: resolveProjectName(workspaceRoot),
191
+ systemOnline: true,
192
+ unicode
193
+ }),
194
+ footer: buildFooterModel({
195
+ view: ui.view,
196
+ region: ui.region,
197
+ helpOpen: ui.helpOpen,
198
+ canCancel: isRunCancellable(data.selectedRun),
199
+ unicode
200
+ }),
201
+ layoutMode: mode,
202
+ nav: buildNavModel({
203
+ navIndex: ui.navIndex,
204
+ focused: ui.region === COCKPIT_REGIONS.NAV,
205
+ unicode
206
+ }),
207
+ system: buildSystemStripModel({
208
+ dashboard: data.dashboard,
209
+ diagnostics: data.diagnostics,
210
+ healthKind: "ready"
211
+ }),
212
+ navFocused: ui.region === COCKPIT_REGIONS.NAV,
213
+ contentFocused: ui.region === COCKPIT_REGIONS.CONTENT,
214
+ systemFocused: ui.region === COCKPIT_REGIONS.SYSTEM,
215
+ colorEnabled
216
+ },
217
+ renderCockpitView({
218
+ view: ui.view,
219
+ dashboard: data.dashboard,
220
+ diagnostics: data.diagnostics,
221
+ listIndex: ui.listIndex,
222
+ launchStep: data.launchStep,
223
+ launchDraft: data.launchDraft,
224
+ launchAgentIndex: data.launchAgentIndex,
225
+ launchPermissionIndex: data.launchPermissionIndex,
226
+ launchableAgents: data.launchableAgents,
227
+ selectedRun: data.selectedRun,
228
+ selectedEvents: data.selectedEvents,
229
+ homeMission: buildHomeMissionModel({
230
+ hasGlobalState,
231
+ diagnostics: data.diagnostics,
232
+ dashboard: data.dashboard,
233
+ layoutMode: mode,
234
+ activityLines: (data.dashboard?.recentRuns ?? []).map((run) =>
235
+ `${run.runId} ${run.state} ${run.agentId}`
236
+ )
237
+ }),
238
+ colorEnabled
239
+ })
240
+ )
389
241
  );
390
242
  }
391
-
392
- function renderView({
393
- view,
394
- dashboard,
395
- diagnostics,
396
- hasGlobalState,
397
- menuIndex,
398
- listIndex,
399
- launchStep,
400
- launchDraft,
401
- launchAgentIndex,
402
- launchPermissionIndex,
403
- launchableAgents,
404
- selectedRun,
405
- selectedEvents
406
- }) {
407
- switch (view) {
408
- case ORCHESTRATOR_VIEWS.HOME: {
409
- const nextStep = resolveDashboardRecommendation({
410
- hasGlobalState,
411
- diagnostics,
412
- dashboard
413
- });
414
- return React.createElement(Box, { flexDirection: "column" },
415
- React.createElement(Text, { bold: true }, "Next"),
416
- React.createElement(Text, { color: COLORS.accent }, nextStep.message),
417
- React.createElement(Text, null, ""),
418
- React.createElement(Text, { bold: true }, "Operations"),
419
- ORCHESTRATOR_MENU.map((item, index) =>
420
- React.createElement(Text, {
421
- key: item.id,
422
- color: index === menuIndex ? COLORS.accent : undefined,
423
- bold: index === menuIndex
424
- }, `${index === menuIndex ? "› " : " "}${item.label}`)
425
- ),
426
- React.createElement(Text, null, ""),
427
- React.createElement(Text, { bold: true }, "Snapshot"),
428
- formatDashboardSnapshot(dashboard)
429
- .map((line) => React.createElement(Text, { key: line }, line))
430
- );
431
- }
432
- case ORCHESTRATOR_VIEWS.ACTIVE_RUNS:
433
- return React.createElement(Box, { flexDirection: "column" },
434
- React.createElement(Text, { bold: true }, "Active runs"),
435
- formatRunLines(dashboard?.activeRuns ?? [], { emptyMessage: "No active runs." })
436
- .map((line, index) => React.createElement(Text, {
437
- key: line,
438
- color: index === listIndex ? COLORS.accent : undefined,
439
- bold: index === listIndex
440
- }, `${index === listIndex ? "› " : " "}${line}`))
441
- );
442
- case ORCHESTRATOR_VIEWS.RECENT_RUNS:
443
- return React.createElement(Box, { flexDirection: "column" },
444
- React.createElement(Text, { bold: true }, "Recent runs"),
445
- formatRunLines(dashboard?.recentRuns ?? [], { emptyMessage: "No completed runs yet." })
446
- .map((line, index) => React.createElement(Text, {
447
- key: line,
448
- color: index === listIndex ? COLORS.accent : undefined,
449
- bold: index === listIndex
450
- }, `${index === listIndex ? "› " : " "}${line}`))
451
- );
452
- case ORCHESTRATOR_VIEWS.PROVIDERS:
453
- return React.createElement(Box, { flexDirection: "column" },
454
- React.createElement(Text, { bold: true }, "Providers"),
455
- formatProviderLines(dashboard?.providers ?? [])
456
- .map((line) => React.createElement(Text, { key: line }, line))
457
- );
458
- case ORCHESTRATOR_VIEWS.LAUNCH:
459
- if (launchableAgents.length === 0) {
460
- return React.createElement(Box, { flexDirection: "column" },
461
- React.createElement(Text, { bold: true }, "Launch run"),
462
- React.createElement(Text, { color: COLORS.warning }, "No launchable agents detected."),
463
- React.createElement(Text, { dimColor: true }, "Esc to return")
464
- );
465
- }
466
- return React.createElement(Box, { flexDirection: "column" },
467
- React.createElement(Text, { bold: true }, "Launch run"),
468
- formatLaunchWizardLines({
469
- step: launchStep,
470
- draft: launchDraft,
471
- launchableAgents,
472
- agentIndex: launchAgentIndex,
473
- permissionIndex: launchPermissionIndex
474
- }).map((line) => React.createElement(Text, { key: line, color: line.startsWith("›") ? COLORS.accent : undefined }, line))
475
- );
476
- case ORCHESTRATOR_VIEWS.RUN_DETAIL:
477
- return React.createElement(Box, { flexDirection: "column" },
478
- React.createElement(Text, { bold: true }, "Run detail"),
479
- formatRunDetailLines(selectedRun, selectedEvents)
480
- .map((line) => React.createElement(Text, { key: line }, line))
481
- );
482
- case ORCHESTRATOR_VIEWS.DIAGNOSTICS:
483
- return React.createElement(Box, { flexDirection: "column" },
484
- React.createElement(Text, { bold: true }, "Diagnostics"),
485
- formatDiagnosticsLines(diagnostics)
486
- .map((line) => React.createElement(Text, { key: line }, line))
487
- );
488
- case ORCHESTRATOR_VIEWS.HELP:
489
- return React.createElement(Box, { flexDirection: "column" },
490
- React.createElement(Text, { bold: true }, "Help"),
491
- React.createElement(Text, null, "Kairo runtime launches and audits agent CLIs you manage."),
492
- React.createElement(Text, null, "CLI: kairo run --agent <id> --task \"...\""),
493
- React.createElement(Text, null, "CLI: kairo runs list|show|stop"),
494
- React.createElement(Text, null, "Audit trail: ~/.harness/runs/<runId>/"),
495
- React.createElement(Text, null, "Transcripts are opt-in via --capture-transcript."),
496
- React.createElement(Text, null, "Credentials stay in environment variables — never in profiles.")
497
- );
498
- default: {
499
- const _exhaustive = view;
500
- return React.createElement(Text, null, `Unknown view: ${_exhaustive}`);
501
- }
502
- }
503
- }
504
-
505
- function footerHint(view, selectedRun, launchStep) {
506
- if (view === ORCHESTRATOR_VIEWS.HOME) return "↑↓ navigate · Enter select · Esc quit";
507
- if (view === ORCHESTRATOR_VIEWS.ACTIVE_RUNS || view === ORCHESTRATOR_VIEWS.RECENT_RUNS) {
508
- return "↑↓ select run · Enter inspect · R refresh · Esc menu";
509
- }
510
- if (view === ORCHESTRATOR_VIEWS.LAUNCH) {
511
- if (launchStep === LAUNCH_WIZARD_STEPS.TASK || launchStep === LAUNCH_WIZARD_STEPS.MODEL) {
512
- return "Type · Enter next · Esc menu";
513
- }
514
- if (launchStep === LAUNCH_WIZARD_STEPS.CONFIRM) {
515
- return "Enter launch · Esc back · R refresh";
516
- }
517
- return "↑↓ navigate · Enter select · Esc menu";
518
- }
519
- if (view === ORCHESTRATOR_VIEWS.RUN_DETAIL) {
520
- if (isRunCancellable(selectedRun)) return "C cancel · R refresh · Esc menu";
521
- return "R refresh · Esc menu";
522
- }
523
- return "R refresh · Esc menu";
524
- }