@kal-elsam/kairo-runtime 0.2.0 → 0.2.2

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,15 +1,31 @@
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,
10
- formatIntelligenceLines,
11
- formatPlanLines,
12
- formatProfileLines
12
+ LAUNCH_WIZARD_STEPS,
13
+ LAUNCH_PERMISSION_OPTIONS,
14
+ createLaunchDraft,
15
+ formatDashboardSnapshot,
16
+ formatDiagnosticsLines,
17
+ formatLaunchWizardLines,
18
+ formatProviderLines,
19
+ formatRunDetailLines,
20
+ formatRunLines,
21
+ isRunCancellable,
22
+ resolveLaunchPermissions,
23
+ resolveLaunchableAgents,
24
+ resolveMenuItem,
25
+ resolveMenuItemView,
26
+ retreatLaunchWizardStep,
27
+ selectRunFromList,
28
+ shiftMenuIndex
13
29
  } from "./orchestrator-state.js";
14
30
 
15
31
  const COLORS = {
@@ -31,25 +47,36 @@ export function OrchestratorApp({
31
47
  const { exit } = useApp();
32
48
  const [view, setView] = useState(ORCHESTRATOR_VIEWS.HOME);
33
49
  const [menuIndex, setMenuIndex] = useState(0);
50
+ const [listIndex, setListIndex] = useState(0);
51
+ const [launchAgentIndex, setLaunchAgentIndex] = useState(0);
52
+ const [launchStep, setLaunchStep] = useState(LAUNCH_WIZARD_STEPS.AGENT);
53
+ const [launchDraft, setLaunchDraft] = useState(createLaunchDraft);
54
+ const [launchPermissionIndex, setLaunchPermissionIndex] = useState(0);
34
55
  const [loading, setLoading] = useState(true);
56
+ const [busy, setBusy] = useState(false);
35
57
  const [error, setError] = useState(null);
58
+ const [dashboard, setDashboard] = useState(null);
36
59
  const [diagnostics, setDiagnostics] = useState(null);
37
- const [profileJson, setProfileJson] = useState(null);
38
- const [plan, setPlan] = useState(null);
60
+ const [selectedRun, setSelectedRun] = useState(null);
61
+ const [selectedEvents, setSelectedEvents] = useState([]);
62
+ const [statusMessage, setStatusMessage] = useState(null);
63
+
64
+ const reload = async () => {
65
+ const [dash, diag] = await Promise.all([
66
+ buildRuntimeDashboardData({ homeDir, workspaceRoot, cliVersion }),
67
+ buildReadOnlyDiagnostics({ homeDir, workspaceRoot, packageName, packageRoot, cliVersion })
68
+ ]);
69
+ setDashboard(dash);
70
+ setDiagnostics(diag);
71
+ };
39
72
 
40
73
  useEffect(() => {
41
74
  let cancelled = false;
42
75
 
43
76
  async function load() {
44
77
  try {
45
- const [diag, profileResolved] = await Promise.all([
46
- buildReadOnlyDiagnostics({ homeDir, workspaceRoot, packageName, packageRoot, cliVersion }),
47
- resolveProfile({ homeDir, workspaceRoot })
48
- ]);
49
-
78
+ await reload();
50
79
  if (cancelled) return;
51
- setDiagnostics(diag);
52
- setProfileJson(buildProfileJson(profileResolved));
53
80
  setLoading(false);
54
81
  } catch (loadError) {
55
82
  if (cancelled) return;
@@ -69,6 +96,81 @@ export function OrchestratorApp({
69
96
  exit();
70
97
  };
71
98
 
99
+ const openRunDetail = async (run) => {
100
+ if (!run) return;
101
+ const events = await readRunEvents(homeDir, run.runId, { limit: 20 });
102
+ setSelectedRun(run);
103
+ setSelectedEvents(events);
104
+ setView(ORCHESTRATOR_VIEWS.RUN_DETAIL);
105
+ };
106
+
107
+ const launchableAgents = resolveLaunchableAgents(dashboard?.providers ?? []);
108
+
109
+ const resetLaunchWizard = () => {
110
+ setLaunchStep(LAUNCH_WIZARD_STEPS.AGENT);
111
+ setLaunchDraft(createLaunchDraft());
112
+ setLaunchAgentIndex(0);
113
+ setLaunchPermissionIndex(0);
114
+ };
115
+
116
+ const handleLaunch = async (draft) => {
117
+ if (!draft.agentId || !draft.task.trim()) {
118
+ setError("Agent and task are required.");
119
+ return;
120
+ }
121
+
122
+ setBusy(true);
123
+ setStatusMessage(`Launching ${draft.agentId}…`);
124
+ try {
125
+ const permissions = resolveLaunchPermissions({
126
+ ...draft,
127
+ permissionIndex: launchPermissionIndex
128
+ });
129
+ const { runId } = await startRun({
130
+ homeDir,
131
+ agentId: draft.agentId,
132
+ task: draft.task.trim(),
133
+ cwd: workspaceRoot,
134
+ model: draft.model.trim() || null,
135
+ permissions,
136
+ cliVersion,
137
+ profile: dashboard?.profile ?? null,
138
+ follow: false,
139
+ wait: false
140
+ });
141
+ await reload();
142
+ const run = (await buildRuntimeDashboardData({ homeDir, workspaceRoot, cliVersion }))
143
+ .runs.find((entry) => entry.runId === runId);
144
+ setStatusMessage(`Run started: ${runId}`);
145
+ resetLaunchWizard();
146
+ setView(ORCHESTRATOR_VIEWS.HOME);
147
+ if (run) await openRunDetail(run);
148
+ } catch (launchError) {
149
+ setError(launchError instanceof Error ? launchError.message : String(launchError));
150
+ } finally {
151
+ setBusy(false);
152
+ }
153
+ };
154
+
155
+ const handleCancelRun = async () => {
156
+ if (!selectedRun || !isRunCancellable(selectedRun)) return;
157
+ setBusy(true);
158
+ try {
159
+ await stopRun(homeDir, selectedRun.runId);
160
+ await reload();
161
+ const refreshed = await buildRuntimeDashboardData({ homeDir, workspaceRoot, cliVersion });
162
+ const run = refreshed.runs.find((entry) => entry.runId === selectedRun.runId);
163
+ const events = await readRunEvents(homeDir, selectedRun.runId, { limit: 20 });
164
+ setSelectedRun(run ?? selectedRun);
165
+ setSelectedEvents(events);
166
+ setStatusMessage(`Cancelled ${selectedRun.runId}`);
167
+ } catch (cancelError) {
168
+ setError(cancelError instanceof Error ? cancelError.message : String(cancelError));
169
+ } finally {
170
+ setBusy(false);
171
+ }
172
+ };
173
+
72
174
  useInput((inputKey, key) => {
73
175
  if (key.escape) {
74
176
  if (view === ORCHESTRATOR_VIEWS.HOME) {
@@ -76,87 +178,229 @@ export function OrchestratorApp({
76
178
  return;
77
179
  }
78
180
  setView(ORCHESTRATOR_VIEWS.HOME);
79
- setPlan(null);
181
+ setSelectedRun(null);
182
+ setListIndex(0);
183
+ return;
184
+ }
185
+
186
+ if (loading || error || busy) return;
187
+
188
+ if (view === ORCHESTRATOR_VIEWS.LAUNCH) {
189
+ if (launchableAgents.length === 0) {
190
+ if (key.escape) {
191
+ resetLaunchWizard();
192
+ setView(ORCHESTRATOR_VIEWS.HOME);
193
+ }
194
+ return;
195
+ }
196
+
197
+ if (launchStep === LAUNCH_WIZARD_STEPS.AGENT) {
198
+ if (key.upArrow) {
199
+ setLaunchAgentIndex((index) => Math.max(0, index - 1));
200
+ return;
201
+ }
202
+ if (key.downArrow) {
203
+ setLaunchAgentIndex((index) => Math.min(launchableAgents.length - 1, index + 1));
204
+ return;
205
+ }
206
+ if (key.return) {
207
+ const agentId = launchableAgents[launchAgentIndex];
208
+ setLaunchDraft((draft) => ({ ...draft, agentId }));
209
+ setLaunchStep(LAUNCH_WIZARD_STEPS.TASK);
210
+ }
211
+ return;
212
+ }
213
+
214
+ if (launchStep === LAUNCH_WIZARD_STEPS.TASK) {
215
+ if (key.return) {
216
+ if (!launchDraft.task.trim()) {
217
+ setError("Task cannot be empty.");
218
+ return;
219
+ }
220
+ setLaunchStep(LAUNCH_WIZARD_STEPS.MODEL);
221
+ return;
222
+ }
223
+ if (key.backspace || key.delete) {
224
+ setLaunchDraft((draft) => ({ ...draft, task: draft.task.slice(0, -1) }));
225
+ return;
226
+ }
227
+ if (inputKey && inputKey.length === 1 && !key.ctrl && !key.meta) {
228
+ setLaunchDraft((draft) => ({ ...draft, task: `${draft.task}${inputKey}` }));
229
+ }
230
+ return;
231
+ }
232
+
233
+ if (launchStep === LAUNCH_WIZARD_STEPS.MODEL) {
234
+ if (key.return) {
235
+ setLaunchStep(LAUNCH_WIZARD_STEPS.PERMISSIONS);
236
+ return;
237
+ }
238
+ if (key.backspace || key.delete) {
239
+ setLaunchDraft((draft) => ({ ...draft, model: draft.model.slice(0, -1) }));
240
+ return;
241
+ }
242
+ if (inputKey && inputKey.length === 1 && !key.ctrl && !key.meta) {
243
+ setLaunchDraft((draft) => ({ ...draft, model: `${draft.model}${inputKey}` }));
244
+ }
245
+ return;
246
+ }
247
+
248
+ if (launchStep === LAUNCH_WIZARD_STEPS.PERMISSIONS) {
249
+ if (key.upArrow) {
250
+ setLaunchPermissionIndex((index) => Math.max(0, index - 1));
251
+ return;
252
+ }
253
+ if (key.downArrow) {
254
+ setLaunchPermissionIndex((index) => Math.min(LAUNCH_PERMISSION_OPTIONS.length - 1, index + 1));
255
+ return;
256
+ }
257
+ if (key.return) {
258
+ setLaunchStep(LAUNCH_WIZARD_STEPS.CONFIRM);
259
+ }
260
+ return;
261
+ }
262
+
263
+ if (launchStep === LAUNCH_WIZARD_STEPS.CONFIRM) {
264
+ if (key.return) {
265
+ handleLaunch({ ...launchDraft, permissionIndex: launchPermissionIndex });
266
+ }
267
+ if (key.escape) {
268
+ setLaunchStep(retreatLaunchWizardStep(launchStep));
269
+ }
270
+ return;
271
+ }
272
+
273
+ if (inputKey.toLowerCase() === "r") {
274
+ reload().catch((reloadError) => {
275
+ setError(reloadError instanceof Error ? reloadError.message : String(reloadError));
276
+ });
277
+ }
80
278
  return;
81
279
  }
82
280
 
83
- if (loading || error) return;
281
+ if (view === ORCHESTRATOR_VIEWS.ACTIVE_RUNS || view === ORCHESTRATOR_VIEWS.RECENT_RUNS) {
282
+ const runs = view === ORCHESTRATOR_VIEWS.ACTIVE_RUNS
283
+ ? dashboard?.activeRuns ?? []
284
+ : dashboard?.recentRuns ?? [];
285
+
286
+ if (key.upArrow) {
287
+ setListIndex((index) => Math.max(0, index - 1));
288
+ return;
289
+ }
290
+ if (key.downArrow) {
291
+ setListIndex((index) => Math.min(Math.max(runs.length - 1, 0), index + 1));
292
+ return;
293
+ }
294
+ if (key.return) {
295
+ openRunDetail(selectRunFromList(runs, listIndex));
296
+ }
297
+ if (inputKey.toLowerCase() === "r") {
298
+ reload().catch((reloadError) => {
299
+ setError(reloadError instanceof Error ? reloadError.message : String(reloadError));
300
+ });
301
+ }
302
+ return;
303
+ }
84
304
 
85
- if (view === ORCHESTRATOR_VIEWS.CONFIRM) {
86
- if (inputKey.toLowerCase() === "y") {
87
- finish({ cancelled: false, action: plan?.action ?? PLAN_ACTIONS.SETUP, confirmed: true, plan });
305
+ if (view === ORCHESTRATOR_VIEWS.RUN_DETAIL) {
306
+ if (inputKey.toLowerCase() === "c" && isRunCancellable(selectedRun)) {
307
+ handleCancelRun();
88
308
  }
89
- if (inputKey.toLowerCase() === "n") {
90
- setView(ORCHESTRATOR_VIEWS.HOME);
91
- setPlan(null);
309
+ if (inputKey.toLowerCase() === "r") {
310
+ openRunDetail(selectedRun);
92
311
  }
93
312
  return;
94
313
  }
95
314
 
96
- if (view !== ORCHESTRATOR_VIEWS.HOME) return;
315
+ if (view !== ORCHESTRATOR_VIEWS.HOME) {
316
+ if (inputKey.toLowerCase() === "r") {
317
+ reload().catch((reloadError) => {
318
+ setError(reloadError instanceof Error ? reloadError.message : String(reloadError));
319
+ });
320
+ }
321
+ return;
322
+ }
97
323
 
98
324
  if (key.upArrow) {
99
- setMenuIndex((index) => Math.max(0, index - 1));
325
+ setMenuIndex((index) => shiftMenuIndex(index, "up"));
100
326
  return;
101
327
  }
102
328
 
103
329
  if (key.downArrow) {
104
- setMenuIndex((index) => Math.min(ORCHESTRATOR_MENU.length - 1, index + 1));
330
+ setMenuIndex((index) => shiftMenuIndex(index, "down"));
105
331
  return;
106
332
  }
107
333
 
108
334
  if (!key.return) return;
109
335
 
110
- const item = ORCHESTRATOR_MENU[menuIndex];
111
- if (item.action === "setup") {
112
- buildActionPlan({
113
- action: PLAN_ACTIONS.SETUP,
114
- homeDir,
115
- workspaceRoot,
116
- packageName,
117
- options: { packageRoot, cliVersion }
118
- }).then((builtPlan) => {
119
- setPlan(builtPlan);
120
- setView(ORCHESTRATOR_VIEWS.CONFIRM);
121
- }).catch((planError) => {
122
- setError(planError instanceof Error ? planError.message : String(planError));
123
- });
336
+ const item = resolveMenuItem(menuIndex);
337
+ if (item?.action === "launch") {
338
+ resetLaunchWizard();
339
+ setView(ORCHESTRATOR_VIEWS.LAUNCH);
124
340
  return;
125
341
  }
126
342
 
127
- setView(item.view);
343
+ setView(resolveMenuItemView(menuIndex));
344
+ setListIndex(0);
128
345
  });
129
346
 
130
347
  if (loading) {
131
348
  return React.createElement(Box, { flexDirection: "column" },
132
349
  React.createElement(Text, { bold: true, color: COLORS.accent }, BRAND.displayName),
133
- React.createElement(Text, { color: COLORS.muted }, "Loading agent capabilities…")
350
+ React.createElement(Text, { color: COLORS.muted }, "Loading runtime dashboard…")
134
351
  );
135
352
  }
136
353
 
137
354
  if (error) {
138
355
  return React.createElement(Box, { flexDirection: "column" },
139
- React.createElement(Text, { bold: true, color: COLORS.danger }, "Orchestrator error"),
356
+ React.createElement(Text, { bold: true, color: COLORS.danger }, "Runtime error"),
140
357
  React.createElement(Text, null, error),
141
358
  React.createElement(Text, { dimColor: true }, "Esc to exit")
142
359
  );
143
360
  }
144
361
 
145
362
  return React.createElement(Box, { flexDirection: "column" },
146
- React.createElement(Text, { bold: true, color: COLORS.accent }, `${BRAND.displayName} orchestrator`),
147
- React.createElement(Text, { color: COLORS.muted }, "Harness Engineering · local-first · cloud opt-in"),
363
+ React.createElement(Text, { bold: true, color: COLORS.accent }, `${BRAND.displayName} runtime`),
364
+ React.createElement(Text, { color: COLORS.muted }, "Launch · supervise · audit agent runs"),
365
+ statusMessage && React.createElement(Text, { color: COLORS.success }, statusMessage),
148
366
  React.createElement(Text, null, ""),
149
- renderView({ view, diagnostics, profileJson, plan, menuIndex }),
367
+ renderView({
368
+ view,
369
+ dashboard,
370
+ diagnostics,
371
+ menuIndex,
372
+ listIndex,
373
+ launchStep,
374
+ launchDraft,
375
+ launchAgentIndex,
376
+ launchPermissionIndex,
377
+ launchableAgents,
378
+ selectedRun,
379
+ selectedEvents
380
+ }),
150
381
  React.createElement(Text, null, ""),
151
- React.createElement(Text, { dimColor: true }, footerHint(view))
382
+ React.createElement(Text, { dimColor: true }, footerHint(view, selectedRun, launchStep))
152
383
  );
153
384
  }
154
385
 
155
- function renderView({ view, diagnostics, profileJson, plan, menuIndex }) {
386
+ function renderView({
387
+ view,
388
+ dashboard,
389
+ diagnostics,
390
+ menuIndex,
391
+ listIndex,
392
+ launchStep,
393
+ launchDraft,
394
+ launchAgentIndex,
395
+ launchPermissionIndex,
396
+ launchableAgents,
397
+ selectedRun,
398
+ selectedEvents
399
+ }) {
156
400
  switch (view) {
157
401
  case ORCHESTRATOR_VIEWS.HOME:
158
402
  return React.createElement(Box, { flexDirection: "column" },
159
- React.createElement(Text, { bold: true }, "Menu"),
403
+ React.createElement(Text, { bold: true }, "Operations"),
160
404
  ORCHESTRATOR_MENU.map((item, index) =>
161
405
  React.createElement(Text, {
162
406
  key: item.id,
@@ -166,49 +410,74 @@ function renderView({ view, diagnostics, profileJson, plan, menuIndex }) {
166
410
  ),
167
411
  React.createElement(Text, null, ""),
168
412
  React.createElement(Text, { bold: true }, "Snapshot"),
169
- React.createElement(Text, null, `Agents detected: ${diagnostics.diagnostics.detected}/${diagnostics.capabilities.length}`),
170
- React.createElement(Text, null, `Available: ${diagnostics.diagnostics.available}`),
171
- diagnostics.intelligence && React.createElement(
172
- Text,
173
- null,
174
- `Intelligence: local=${diagnostics.intelligence.summary.localAvailable ? "yes" : "no"} cloud=${diagnostics.intelligence.summary.cloudAuthenticated ? "yes" : "no"}`
175
- )
413
+ formatDashboardSnapshot(dashboard)
414
+ .map((line) => React.createElement(Text, { key: line }, line))
415
+ );
416
+ case ORCHESTRATOR_VIEWS.ACTIVE_RUNS:
417
+ return React.createElement(Box, { flexDirection: "column" },
418
+ React.createElement(Text, { bold: true }, "Active runs"),
419
+ formatRunLines(dashboard?.activeRuns ?? [], { emptyMessage: "No active runs." })
420
+ .map((line, index) => React.createElement(Text, {
421
+ key: line,
422
+ color: index === listIndex ? COLORS.accent : undefined,
423
+ bold: index === listIndex
424
+ }, `${index === listIndex ? "› " : " "}${line}`))
425
+ );
426
+ case ORCHESTRATOR_VIEWS.RECENT_RUNS:
427
+ return React.createElement(Box, { flexDirection: "column" },
428
+ React.createElement(Text, { bold: true }, "Recent runs"),
429
+ formatRunLines(dashboard?.recentRuns ?? [], { emptyMessage: "No completed runs yet." })
430
+ .map((line, index) => React.createElement(Text, {
431
+ key: line,
432
+ color: index === listIndex ? COLORS.accent : undefined,
433
+ bold: index === listIndex
434
+ }, `${index === listIndex ? "› " : " "}${line}`))
176
435
  );
177
- case ORCHESTRATOR_VIEWS.AGENTS:
436
+ case ORCHESTRATOR_VIEWS.PROVIDERS:
178
437
  return React.createElement(Box, { flexDirection: "column" },
179
- React.createElement(Text, { bold: true }, "Agent capabilities"),
180
- formatAgentStatusLines(diagnostics.capabilities)
438
+ React.createElement(Text, { bold: true }, "Providers"),
439
+ formatProviderLines(dashboard?.providers ?? [])
181
440
  .map((line) => React.createElement(Text, { key: line }, line))
182
441
  );
183
- case ORCHESTRATOR_VIEWS.INTELLIGENCE:
442
+ case ORCHESTRATOR_VIEWS.LAUNCH:
443
+ if (launchableAgents.length === 0) {
444
+ return React.createElement(Box, { flexDirection: "column" },
445
+ React.createElement(Text, { bold: true }, "Launch run"),
446
+ React.createElement(Text, { color: COLORS.warning }, "No launchable agents detected."),
447
+ React.createElement(Text, { dimColor: true }, "Esc to return")
448
+ );
449
+ }
184
450
  return React.createElement(Box, { flexDirection: "column" },
185
- React.createElement(Text, { bold: true }, "Intelligence backends"),
186
- formatIntelligenceLines(diagnostics)
187
- .map((line) => React.createElement(Text, { key: line }, line)),
188
- React.createElement(Text, null, ""),
189
- React.createElement(Text, { dimColor: true }, "CLI: kairo intelligence status|models|context|route|ask")
451
+ React.createElement(Text, { bold: true }, "Launch run"),
452
+ formatLaunchWizardLines({
453
+ step: launchStep,
454
+ draft: launchDraft,
455
+ launchableAgents,
456
+ agentIndex: launchAgentIndex,
457
+ permissionIndex: launchPermissionIndex
458
+ }).map((line) => React.createElement(Text, { key: line, color: line.startsWith("›") ? COLORS.accent : undefined }, line))
190
459
  );
191
- case ORCHESTRATOR_VIEWS.PROFILE:
460
+ case ORCHESTRATOR_VIEWS.RUN_DETAIL:
192
461
  return React.createElement(Box, { flexDirection: "column" },
193
- React.createElement(Text, { bold: true }, "Profile"),
194
- formatProfileLines(profileJson)
462
+ React.createElement(Text, { bold: true }, "Run detail"),
463
+ formatRunDetailLines(selectedRun, selectedEvents)
195
464
  .map((line) => React.createElement(Text, { key: line }, line))
196
465
  );
197
- case ORCHESTRATOR_VIEWS.PLAN:
198
- case ORCHESTRATOR_VIEWS.CONFIRM:
466
+ case ORCHESTRATOR_VIEWS.DIAGNOSTICS:
199
467
  return React.createElement(Box, { flexDirection: "column" },
200
- React.createElement(Text, { bold: true }, view === ORCHESTRATOR_VIEWS.CONFIRM ? "Confirm plan" : "Plan"),
201
- plan && formatPlanLines(plan).map((line) => React.createElement(Text, { key: line }, line)),
202
- view === ORCHESTRATOR_VIEWS.CONFIRM && React.createElement(Text, { color: COLORS.warning }, "Y confirm · N decline")
468
+ React.createElement(Text, { bold: true }, "Diagnostics"),
469
+ formatDiagnosticsLines(diagnostics)
470
+ .map((line) => React.createElement(Text, { key: line }, line))
203
471
  );
204
472
  case ORCHESTRATOR_VIEWS.HELP:
205
473
  return React.createElement(Box, { flexDirection: "column" },
206
474
  React.createElement(Text, { bold: true }, "Help"),
207
- React.createElement(Text, null, "Kairo coordinates installed agent CLIs and governs project intelligence."),
208
- React.createElement(Text, null, "Local-first: Ollama when available. Cloud (OpenRouter/free) needs consent."),
209
- React.createElement(Text, null, "Use: intelligence status|models|context|route|ask"),
210
- React.createElement(Text, null, "Profiles: ~/.harness/profile.json and .harness/kairo.json (project wins)."),
211
- React.createElement(Text, null, "Credentials are never stored by Kairo — use environment variables.")
475
+ React.createElement(Text, null, "Kairo runtime launches and audits agent CLIs you manage."),
476
+ React.createElement(Text, null, "CLI: kairo run --agent <id> --task \"...\""),
477
+ React.createElement(Text, null, "CLI: kairo runs list|show|stop"),
478
+ React.createElement(Text, null, "Audit trail: ~/.harness/runs/<runId>/"),
479
+ React.createElement(Text, null, "Transcripts are opt-in via --capture-transcript."),
480
+ React.createElement(Text, null, "Credentials stay in environment variables — never in profiles.")
212
481
  );
213
482
  default: {
214
483
  const _exhaustive = view;
@@ -217,8 +486,23 @@ function renderView({ view, diagnostics, profileJson, plan, menuIndex }) {
217
486
  }
218
487
  }
219
488
 
220
- function footerHint(view) {
489
+ function footerHint(view, selectedRun, launchStep) {
221
490
  if (view === ORCHESTRATOR_VIEWS.HOME) return "↑↓ navigate · Enter select · Esc quit";
222
- if (view === ORCHESTRATOR_VIEWS.CONFIRM) return "Y confirm · N decline · Esc back";
223
- return "Esc back to menu";
491
+ if (view === ORCHESTRATOR_VIEWS.ACTIVE_RUNS || view === ORCHESTRATOR_VIEWS.RECENT_RUNS) {
492
+ return "↑↓ select run · Enter inspect · R refresh · Esc menu";
493
+ }
494
+ if (view === ORCHESTRATOR_VIEWS.LAUNCH) {
495
+ if (launchStep === LAUNCH_WIZARD_STEPS.TASK || launchStep === LAUNCH_WIZARD_STEPS.MODEL) {
496
+ return "Type · Enter next · Esc menu";
497
+ }
498
+ if (launchStep === LAUNCH_WIZARD_STEPS.CONFIRM) {
499
+ return "Enter launch · Esc back · R refresh";
500
+ }
501
+ return "↑↓ navigate · Enter select · Esc menu";
502
+ }
503
+ if (view === ORCHESTRATOR_VIEWS.RUN_DETAIL) {
504
+ if (isRunCancellable(selectedRun)) return "C cancel · R refresh · Esc menu";
505
+ return "R refresh · Esc menu";
506
+ }
507
+ return "R refresh · Esc menu";
224
508
  }