@kal-elsam/kairo-runtime 0.2.1 → 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,18 +1,30 @@
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";
18
30
 
@@ -35,25 +47,36 @@ export function OrchestratorApp({
35
47
  const { exit } = useApp();
36
48
  const [view, setView] = useState(ORCHESTRATOR_VIEWS.HOME);
37
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);
38
55
  const [loading, setLoading] = useState(true);
56
+ const [busy, setBusy] = useState(false);
39
57
  const [error, setError] = useState(null);
58
+ const [dashboard, setDashboard] = useState(null);
40
59
  const [diagnostics, setDiagnostics] = useState(null);
41
- const [profileJson, setProfileJson] = useState(null);
42
- 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
+ };
43
72
 
44
73
  useEffect(() => {
45
74
  let cancelled = false;
46
75
 
47
76
  async function load() {
48
77
  try {
49
- const [diag, profileResolved] = await Promise.all([
50
- buildReadOnlyDiagnostics({ homeDir, workspaceRoot, packageName, packageRoot, cliVersion }),
51
- resolveProfile({ homeDir, workspaceRoot })
52
- ]);
53
-
78
+ await reload();
54
79
  if (cancelled) return;
55
- setDiagnostics(diag);
56
- setProfileJson(buildProfileJson(profileResolved));
57
80
  setLoading(false);
58
81
  } catch (loadError) {
59
82
  if (cancelled) return;
@@ -73,6 +96,81 @@ export function OrchestratorApp({
73
96
  exit();
74
97
  };
75
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
+
76
174
  useInput((inputKey, key) => {
77
175
  if (key.escape) {
78
176
  if (view === ORCHESTRATOR_VIEWS.HOME) {
@@ -80,24 +178,148 @@ export function OrchestratorApp({
80
178
  return;
81
179
  }
82
180
  setView(ORCHESTRATOR_VIEWS.HOME);
83
- setPlan(null);
181
+ setSelectedRun(null);
182
+ setListIndex(0);
84
183
  return;
85
184
  }
86
185
 
87
- if (loading || error) return;
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
+ }
88
213
 
89
- if (view === ORCHESTRATOR_VIEWS.CONFIRM) {
90
- if (inputKey.toLowerCase() === "y") {
91
- finish({ cancelled: false, action: plan?.action ?? PLAN_ACTIONS.SETUP, confirmed: true, plan });
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;
92
231
  }
93
- if (inputKey.toLowerCase() === "n") {
94
- setView(ORCHESTRATOR_VIEWS.HOME);
95
- setPlan(null);
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
+ });
96
277
  }
97
278
  return;
98
279
  }
99
280
 
100
- if (view !== ORCHESTRATOR_VIEWS.HOME) 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
+ }
304
+
305
+ if (view === ORCHESTRATOR_VIEWS.RUN_DETAIL) {
306
+ if (inputKey.toLowerCase() === "c" && isRunCancellable(selectedRun)) {
307
+ handleCancelRun();
308
+ }
309
+ if (inputKey.toLowerCase() === "r") {
310
+ openRunDetail(selectedRun);
311
+ }
312
+ return;
313
+ }
314
+
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
+ }
101
323
 
102
324
  if (key.upArrow) {
103
325
  setMenuIndex((index) => shiftMenuIndex(index, "up"));
@@ -112,55 +334,73 @@ export function OrchestratorApp({
112
334
  if (!key.return) return;
113
335
 
114
336
  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
- });
337
+ if (item?.action === "launch") {
338
+ resetLaunchWizard();
339
+ setView(ORCHESTRATOR_VIEWS.LAUNCH);
128
340
  return;
129
341
  }
130
342
 
131
343
  setView(resolveMenuItemView(menuIndex));
344
+ setListIndex(0);
132
345
  });
133
346
 
134
347
  if (loading) {
135
348
  return React.createElement(Box, { flexDirection: "column" },
136
349
  React.createElement(Text, { bold: true, color: COLORS.accent }, BRAND.displayName),
137
- React.createElement(Text, { color: COLORS.muted }, "Loading agent capabilities…")
350
+ React.createElement(Text, { color: COLORS.muted }, "Loading runtime dashboard…")
138
351
  );
139
352
  }
140
353
 
141
354
  if (error) {
142
355
  return React.createElement(Box, { flexDirection: "column" },
143
- React.createElement(Text, { bold: true, color: COLORS.danger }, "Orchestrator error"),
356
+ React.createElement(Text, { bold: true, color: COLORS.danger }, "Runtime error"),
144
357
  React.createElement(Text, null, error),
145
358
  React.createElement(Text, { dimColor: true }, "Esc to exit")
146
359
  );
147
360
  }
148
361
 
149
362
  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"),
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),
152
366
  React.createElement(Text, null, ""),
153
- 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
+ }),
154
381
  React.createElement(Text, null, ""),
155
- React.createElement(Text, { dimColor: true }, footerHint(view))
382
+ React.createElement(Text, { dimColor: true }, footerHint(view, selectedRun, launchStep))
156
383
  );
157
384
  }
158
385
 
159
- 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
+ }) {
160
400
  switch (view) {
161
401
  case ORCHESTRATOR_VIEWS.HOME:
162
402
  return React.createElement(Box, { flexDirection: "column" },
163
- React.createElement(Text, { bold: true }, "Menu"),
403
+ React.createElement(Text, { bold: true }, "Operations"),
164
404
  ORCHESTRATOR_MENU.map((item, index) =>
165
405
  React.createElement(Text, {
166
406
  key: item.id,
@@ -170,55 +410,74 @@ function renderView({ view, diagnostics, profileJson, plan, menuIndex }) {
170
410
  ),
171
411
  React.createElement(Text, null, ""),
172
412
  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
- )
413
+ formatDashboardSnapshot(dashboard)
414
+ .map((line) => React.createElement(Text, { key: line }, line))
180
415
  );
181
- case ORCHESTRATOR_VIEWS.DIAGNOSTICS:
416
+ case ORCHESTRATOR_VIEWS.ACTIVE_RUNS:
182
417
  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))
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}`))
186
435
  );
187
- case ORCHESTRATOR_VIEWS.AGENTS:
436
+ case ORCHESTRATOR_VIEWS.PROVIDERS:
188
437
  return React.createElement(Box, { flexDirection: "column" },
189
- React.createElement(Text, { bold: true }, "Agent capabilities"),
190
- formatAgentStatusLines(diagnostics.capabilities)
438
+ React.createElement(Text, { bold: true }, "Providers"),
439
+ formatProviderLines(dashboard?.providers ?? [])
191
440
  .map((line) => React.createElement(Text, { key: line }, line))
192
441
  );
193
- 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
+ }
194
450
  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")
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))
200
459
  );
201
- case ORCHESTRATOR_VIEWS.PROFILE:
460
+ case ORCHESTRATOR_VIEWS.RUN_DETAIL:
202
461
  return React.createElement(Box, { flexDirection: "column" },
203
- React.createElement(Text, { bold: true }, "Profile"),
204
- formatProfileLines(profileJson)
462
+ React.createElement(Text, { bold: true }, "Run detail"),
463
+ formatRunDetailLines(selectedRun, selectedEvents)
205
464
  .map((line) => React.createElement(Text, { key: line }, line))
206
465
  );
207
- case ORCHESTRATOR_VIEWS.PLAN:
208
- case ORCHESTRATOR_VIEWS.CONFIRM:
466
+ case ORCHESTRATOR_VIEWS.DIAGNOSTICS:
209
467
  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")
468
+ React.createElement(Text, { bold: true }, "Diagnostics"),
469
+ formatDiagnosticsLines(diagnostics)
470
+ .map((line) => React.createElement(Text, { key: line }, line))
213
471
  );
214
472
  case ORCHESTRATOR_VIEWS.HELP:
215
473
  return React.createElement(Box, { flexDirection: "column" },
216
474
  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.")
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.")
222
481
  );
223
482
  default: {
224
483
  const _exhaustive = view;
@@ -227,8 +486,23 @@ function renderView({ view, diagnostics, profileJson, plan, menuIndex }) {
227
486
  }
228
487
  }
229
488
 
230
- function footerHint(view) {
489
+ function footerHint(view, selectedRun, launchStep) {
231
490
  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";
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";
234
508
  }