@kal-elsam/kairo-runtime 0.2.1 → 0.2.3

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 (37) hide show
  1. package/README.md +13 -2
  2. package/package.json +1 -1
  3. package/scripts/runtime-mvp-smoke.sh +152 -0
  4. package/src/cli.js +97 -9
  5. package/src/global/brand/index.js +10 -0
  6. package/src/global/dashboard-guidance.js +66 -0
  7. package/src/global/initial-experience.js +34 -0
  8. package/src/global/ink/orchestrator-app.js +372 -82
  9. package/src/global/ink/orchestrator-state.js +196 -65
  10. package/src/global/ink/run-orchestrator-ink.js +2 -0
  11. package/src/global/ink/run-setup-ink.js +2 -0
  12. package/src/global/ink/setup-app.js +8 -4
  13. package/src/global/ink/setup-state.js +24 -2
  14. package/src/global/orchestrator.js +46 -42
  15. package/src/global/paths.js +13 -0
  16. package/src/global/profile.js +17 -2
  17. package/src/global/runtime/execution-adapters/claude.js +65 -0
  18. package/src/global/runtime/execution-adapters/codex.js +78 -0
  19. package/src/global/runtime/execution-adapters/create-execution-adapter.js +92 -0
  20. package/src/global/runtime/execution-adapters/cursor.js +104 -0
  21. package/src/global/runtime/execution-adapters/index.js +36 -0
  22. package/src/global/runtime/execution-adapters/opencode.js +38 -0
  23. package/src/global/runtime/run-cancel-signal.js +29 -0
  24. package/src/global/runtime/run-cli.js +221 -0
  25. package/src/global/runtime/run-events.js +144 -0
  26. package/src/global/runtime/run-handoff.js +71 -0
  27. package/src/global/runtime/run-liveness.js +28 -0
  28. package/src/global/runtime/run-manager.js +271 -0
  29. package/src/global/runtime/run-profile.js +93 -0
  30. package/src/global/runtime/run-redact.js +66 -0
  31. package/src/global/runtime/run-starting.js +13 -0
  32. package/src/global/runtime/run-store.js +159 -0
  33. package/src/global/runtime/run-supervisor-lock.js +37 -0
  34. package/src/global/runtime/run-supervisor-worker.js +12 -0
  35. package/src/global/runtime/run-supervisor.js +289 -0
  36. package/src/global/runtime/run-types.js +117 -0
  37. package/src/global/setup.js +13 -5
@@ -1,20 +1,36 @@
1
1
  import React, { useEffect, useState } from "react";
2
2
  import { Box, Text, useApp, useInput } from "ink";
3
3
  import { BRAND } from "../brand/index.js";
4
- import { PLAN_ACTIONS, buildActionPlan, buildReadOnlyDiagnostics } from "../action-planner.js";
5
- import { buildProfileJson, resolveProfile } from "../profile.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";
6
9
  import {
7
10
  ORCHESTRATOR_MENU,
8
11
  ORCHESTRATOR_VIEWS,
9
- formatAgentStatusLines,
12
+ LAUNCH_WIZARD_STEPS,
13
+ LAUNCH_PERMISSION_OPTIONS,
14
+ createLaunchDraft,
15
+ formatDashboardSnapshot,
10
16
  formatDiagnosticsLines,
11
- formatIntelligenceLines,
12
- formatPlanLines,
13
- formatProfileLines,
17
+ formatLaunchWizardLines,
18
+ formatProviderLines,
19
+ formatRunDetailLines,
20
+ formatRunLines,
21
+ isRunCancellable,
22
+ resolveLaunchPermissions,
23
+ resolveLaunchableAgents,
14
24
  resolveMenuItem,
15
25
  resolveMenuItemView,
26
+ retreatLaunchWizardStep,
27
+ selectRunFromList,
16
28
  shiftMenuIndex
17
29
  } from "./orchestrator-state.js";
30
+ import {
31
+ formatDashboardPurpose,
32
+ resolveDashboardRecommendation
33
+ } from "../dashboard-guidance.js";
18
34
 
19
35
  const COLORS = {
20
36
  accent: "cyan",
@@ -30,30 +46,42 @@ export function OrchestratorApp({
30
46
  packageName,
31
47
  packageRoot,
32
48
  cliVersion,
49
+ hasGlobalState = false,
33
50
  onComplete
34
51
  }) {
35
52
  const { exit } = useApp();
36
53
  const [view, setView] = useState(ORCHESTRATOR_VIEWS.HOME);
37
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);
38
60
  const [loading, setLoading] = useState(true);
61
+ const [busy, setBusy] = useState(false);
39
62
  const [error, setError] = useState(null);
63
+ const [dashboard, setDashboard] = useState(null);
40
64
  const [diagnostics, setDiagnostics] = useState(null);
41
- const [profileJson, setProfileJson] = useState(null);
42
- const [plan, setPlan] = 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
+ };
43
77
 
44
78
  useEffect(() => {
45
79
  let cancelled = false;
46
80
 
47
81
  async function load() {
48
82
  try {
49
- const [diag, profileResolved] = await Promise.all([
50
- buildReadOnlyDiagnostics({ homeDir, workspaceRoot, packageName, packageRoot, cliVersion }),
51
- resolveProfile({ homeDir, workspaceRoot })
52
- ]);
53
-
83
+ await reload();
54
84
  if (cancelled) return;
55
- setDiagnostics(diag);
56
- setProfileJson(buildProfileJson(profileResolved));
57
85
  setLoading(false);
58
86
  } catch (loadError) {
59
87
  if (cancelled) return;
@@ -73,6 +101,81 @@ export function OrchestratorApp({
73
101
  exit();
74
102
  };
75
103
 
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
+
76
179
  useInput((inputKey, key) => {
77
180
  if (key.escape) {
78
181
  if (view === ORCHESTRATOR_VIEWS.HOME) {
@@ -80,24 +183,148 @@ export function OrchestratorApp({
80
183
  return;
81
184
  }
82
185
  setView(ORCHESTRATOR_VIEWS.HOME);
83
- setPlan(null);
186
+ setSelectedRun(null);
187
+ setListIndex(0);
84
188
  return;
85
189
  }
86
190
 
87
- if (loading || error) return;
191
+ if (loading || error || busy) return;
192
+
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
+ }
201
+
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
+ }
216
+ return;
217
+ }
218
+
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
+ }
235
+ return;
236
+ }
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
+ }
250
+ return;
251
+ }
252
+
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
+ }
265
+ return;
266
+ }
88
267
 
89
- if (view === ORCHESTRATOR_VIEWS.CONFIRM) {
90
- if (inputKey.toLowerCase() === "y") {
91
- finish({ cancelled: false, action: plan?.action ?? PLAN_ACTIONS.SETUP, confirmed: true, plan });
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
+ }
275
+ return;
92
276
  }
93
- if (inputKey.toLowerCase() === "n") {
94
- setView(ORCHESTRATOR_VIEWS.HOME);
95
- setPlan(null);
277
+
278
+ if (inputKey.toLowerCase() === "r") {
279
+ reload().catch((reloadError) => {
280
+ setError(reloadError instanceof Error ? reloadError.message : String(reloadError));
281
+ });
96
282
  }
97
283
  return;
98
284
  }
99
285
 
100
- if (view !== ORCHESTRATOR_VIEWS.HOME) return;
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));
297
+ return;
298
+ }
299
+ 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);
316
+ }
317
+ return;
318
+ }
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
+ }
101
328
 
102
329
  if (key.upArrow) {
103
330
  setMenuIndex((index) => shiftMenuIndex(index, "up"));
@@ -112,55 +339,83 @@ export function OrchestratorApp({
112
339
  if (!key.return) return;
113
340
 
114
341
  const item = resolveMenuItem(menuIndex);
115
- if (item?.action === "setup") {
116
- buildActionPlan({
117
- action: PLAN_ACTIONS.SETUP,
118
- homeDir,
119
- workspaceRoot,
120
- packageName,
121
- options: { packageRoot, cliVersion }
122
- }).then((builtPlan) => {
123
- setPlan(builtPlan);
124
- setView(ORCHESTRATOR_VIEWS.CONFIRM);
125
- }).catch((planError) => {
126
- setError(planError instanceof Error ? planError.message : String(planError));
127
- });
342
+ if (item?.action === "launch") {
343
+ resetLaunchWizard();
344
+ setView(ORCHESTRATOR_VIEWS.LAUNCH);
128
345
  return;
129
346
  }
130
347
 
131
348
  setView(resolveMenuItemView(menuIndex));
349
+ setListIndex(0);
132
350
  });
133
351
 
134
352
  if (loading) {
135
353
  return React.createElement(Box, { flexDirection: "column" },
136
354
  React.createElement(Text, { bold: true, color: COLORS.accent }, BRAND.displayName),
137
- React.createElement(Text, { color: COLORS.muted }, "Loading agent capabilities…")
355
+ React.createElement(Text, { color: COLORS.muted }, "Loading runtime dashboard…")
138
356
  );
139
357
  }
140
358
 
141
359
  if (error) {
142
360
  return React.createElement(Box, { flexDirection: "column" },
143
- React.createElement(Text, { bold: true, color: COLORS.danger }, "Orchestrator error"),
361
+ React.createElement(Text, { bold: true, color: COLORS.danger }, "Runtime error"),
144
362
  React.createElement(Text, null, error),
145
363
  React.createElement(Text, { dimColor: true }, "Esc to exit")
146
364
  );
147
365
  }
148
366
 
149
367
  return React.createElement(Box, { flexDirection: "column" },
150
- React.createElement(Text, { bold: true, color: COLORS.accent }, `${BRAND.displayName} orchestrator`),
151
- React.createElement(Text, { color: COLORS.muted }, "Harness Engineering · local-first · cloud opt-in"),
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),
152
371
  React.createElement(Text, null, ""),
153
- renderView({ view, diagnostics, profileJson, plan, menuIndex }),
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
+ }),
154
387
  React.createElement(Text, null, ""),
155
- React.createElement(Text, { dimColor: true }, footerHint(view))
388
+ React.createElement(Text, { dimColor: true }, footerHint(view, selectedRun, launchStep))
156
389
  );
157
390
  }
158
391
 
159
- function renderView({ view, diagnostics, profileJson, plan, menuIndex }) {
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
+ }) {
160
407
  switch (view) {
161
- case ORCHESTRATOR_VIEWS.HOME:
408
+ case ORCHESTRATOR_VIEWS.HOME: {
409
+ const nextStep = resolveDashboardRecommendation({
410
+ hasGlobalState,
411
+ diagnostics,
412
+ dashboard
413
+ });
162
414
  return React.createElement(Box, { flexDirection: "column" },
163
- React.createElement(Text, { bold: true }, "Menu"),
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"),
164
419
  ORCHESTRATOR_MENU.map((item, index) =>
165
420
  React.createElement(Text, {
166
421
  key: item.id,
@@ -170,55 +425,75 @@ function renderView({ view, diagnostics, profileJson, plan, menuIndex }) {
170
425
  ),
171
426
  React.createElement(Text, null, ""),
172
427
  React.createElement(Text, { bold: true }, "Snapshot"),
173
- React.createElement(Text, null, `Agents detected: ${diagnostics.diagnostics.detected}/${diagnostics.capabilities.length}`),
174
- React.createElement(Text, null, `Available: ${diagnostics.diagnostics.available}`),
175
- diagnostics.intelligence && React.createElement(
176
- Text,
177
- null,
178
- `Intelligence: local=${diagnostics.intelligence.summary.localAvailable ? "yes" : "no"} cloud=${diagnostics.intelligence.summary.cloudAuthenticated ? "yes" : "no"}`
179
- )
428
+ formatDashboardSnapshot(dashboard)
429
+ .map((line) => React.createElement(Text, { key: line }, line))
180
430
  );
181
- case ORCHESTRATOR_VIEWS.DIAGNOSTICS:
431
+ }
432
+ case ORCHESTRATOR_VIEWS.ACTIVE_RUNS:
182
433
  return React.createElement(Box, { flexDirection: "column" },
183
- React.createElement(Text, { bold: true }, "Diagnostics"),
184
- formatDiagnosticsLines(diagnostics)
185
- .map((line) => React.createElement(Text, { key: line }, line))
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}`))
186
441
  );
187
- case ORCHESTRATOR_VIEWS.AGENTS:
442
+ case ORCHESTRATOR_VIEWS.RECENT_RUNS:
188
443
  return React.createElement(Box, { flexDirection: "column" },
189
- React.createElement(Text, { bold: true }, "Agent capabilities"),
190
- formatAgentStatusLines(diagnostics.capabilities)
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 ?? [])
191
456
  .map((line) => React.createElement(Text, { key: line }, line))
192
457
  );
193
- case ORCHESTRATOR_VIEWS.INTELLIGENCE:
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
+ }
194
466
  return React.createElement(Box, { flexDirection: "column" },
195
- React.createElement(Text, { bold: true }, "Intelligence backends"),
196
- formatIntelligenceLines(diagnostics)
197
- .map((line) => React.createElement(Text, { key: line }, line)),
198
- React.createElement(Text, null, ""),
199
- React.createElement(Text, { dimColor: true }, "CLI: kairo intelligence status|models|context|route|ask")
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))
200
475
  );
201
- case ORCHESTRATOR_VIEWS.PROFILE:
476
+ case ORCHESTRATOR_VIEWS.RUN_DETAIL:
202
477
  return React.createElement(Box, { flexDirection: "column" },
203
- React.createElement(Text, { bold: true }, "Profile"),
204
- formatProfileLines(profileJson)
478
+ React.createElement(Text, { bold: true }, "Run detail"),
479
+ formatRunDetailLines(selectedRun, selectedEvents)
205
480
  .map((line) => React.createElement(Text, { key: line }, line))
206
481
  );
207
- case ORCHESTRATOR_VIEWS.PLAN:
208
- case ORCHESTRATOR_VIEWS.CONFIRM:
482
+ case ORCHESTRATOR_VIEWS.DIAGNOSTICS:
209
483
  return React.createElement(Box, { flexDirection: "column" },
210
- React.createElement(Text, { bold: true }, view === ORCHESTRATOR_VIEWS.CONFIRM ? "Confirm plan" : "Plan"),
211
- plan && formatPlanLines(plan).map((line) => React.createElement(Text, { key: line }, line)),
212
- view === ORCHESTRATOR_VIEWS.CONFIRM && React.createElement(Text, { color: COLORS.warning }, "Y confirm · N decline")
484
+ React.createElement(Text, { bold: true }, "Diagnostics"),
485
+ formatDiagnosticsLines(diagnostics)
486
+ .map((line) => React.createElement(Text, { key: line }, line))
213
487
  );
214
488
  case ORCHESTRATOR_VIEWS.HELP:
215
489
  return React.createElement(Box, { flexDirection: "column" },
216
490
  React.createElement(Text, { bold: true }, "Help"),
217
- React.createElement(Text, null, "Kairo coordinates installed agent CLIs and governs project intelligence."),
218
- React.createElement(Text, null, "Local-first: Ollama when available. Cloud (OpenRouter/free) needs consent."),
219
- React.createElement(Text, null, "Use: intelligence status|models|context|route|ask"),
220
- React.createElement(Text, null, "Profiles: ~/.harness/profile.json and .harness/kairo.json (project wins)."),
221
- React.createElement(Text, null, "Credentials are never stored by Kairo — use environment variables.")
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.")
222
497
  );
223
498
  default: {
224
499
  const _exhaustive = view;
@@ -227,8 +502,23 @@ function renderView({ view, diagnostics, profileJson, plan, menuIndex }) {
227
502
  }
228
503
  }
229
504
 
230
- function footerHint(view) {
505
+ function footerHint(view, selectedRun, launchStep) {
231
506
  if (view === ORCHESTRATOR_VIEWS.HOME) return "↑↓ navigate · Enter select · Esc quit";
232
- if (view === ORCHESTRATOR_VIEWS.CONFIRM) return "Y confirm · N decline · Esc back";
233
- return "Esc back to menu";
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";
234
524
  }