@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.
- package/README.md +13 -2
- package/package.json +1 -1
- package/scripts/runtime-mvp-smoke.sh +152 -0
- package/src/cli.js +97 -9
- package/src/global/brand/index.js +10 -0
- package/src/global/dashboard-guidance.js +66 -0
- package/src/global/initial-experience.js +34 -0
- package/src/global/ink/orchestrator-app.js +372 -82
- package/src/global/ink/orchestrator-state.js +196 -65
- package/src/global/ink/run-orchestrator-ink.js +2 -0
- package/src/global/ink/run-setup-ink.js +2 -0
- package/src/global/ink/setup-app.js +8 -4
- package/src/global/ink/setup-state.js +24 -2
- package/src/global/orchestrator.js +46 -42
- package/src/global/paths.js +13 -0
- package/src/global/profile.js +17 -2
- package/src/global/runtime/execution-adapters/claude.js +65 -0
- package/src/global/runtime/execution-adapters/codex.js +78 -0
- package/src/global/runtime/execution-adapters/create-execution-adapter.js +92 -0
- package/src/global/runtime/execution-adapters/cursor.js +104 -0
- package/src/global/runtime/execution-adapters/index.js +36 -0
- package/src/global/runtime/execution-adapters/opencode.js +38 -0
- package/src/global/runtime/run-cancel-signal.js +29 -0
- package/src/global/runtime/run-cli.js +221 -0
- package/src/global/runtime/run-events.js +144 -0
- package/src/global/runtime/run-handoff.js +71 -0
- package/src/global/runtime/run-liveness.js +28 -0
- package/src/global/runtime/run-manager.js +271 -0
- package/src/global/runtime/run-profile.js +93 -0
- package/src/global/runtime/run-redact.js +66 -0
- package/src/global/runtime/run-starting.js +13 -0
- package/src/global/runtime/run-store.js +159 -0
- package/src/global/runtime/run-supervisor-lock.js +37 -0
- package/src/global/runtime/run-supervisor-worker.js +12 -0
- package/src/global/runtime/run-supervisor.js +289 -0
- package/src/global/runtime/run-types.js +117 -0
- 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 {
|
|
5
|
-
import {
|
|
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
|
-
|
|
12
|
+
LAUNCH_WIZARD_STEPS,
|
|
13
|
+
LAUNCH_PERMISSION_OPTIONS,
|
|
14
|
+
createLaunchDraft,
|
|
15
|
+
formatDashboardSnapshot,
|
|
10
16
|
formatDiagnosticsLines,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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 [
|
|
42
|
-
const [
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
|
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 === "
|
|
116
|
-
|
|
117
|
-
|
|
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
|
|
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 }, "
|
|
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}
|
|
151
|
-
React.createElement(Text, { color: COLORS.muted },
|
|
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({
|
|
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({
|
|
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 }, "
|
|
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
|
-
|
|
174
|
-
|
|
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
|
-
|
|
431
|
+
}
|
|
432
|
+
case ORCHESTRATOR_VIEWS.ACTIVE_RUNS:
|
|
182
433
|
return React.createElement(Box, { flexDirection: "column" },
|
|
183
|
-
React.createElement(Text, { bold: true }, "
|
|
184
|
-
|
|
185
|
-
.map((line) => React.createElement(Text, {
|
|
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.
|
|
442
|
+
case ORCHESTRATOR_VIEWS.RECENT_RUNS:
|
|
188
443
|
return React.createElement(Box, { flexDirection: "column" },
|
|
189
|
-
React.createElement(Text, { bold: true }, "
|
|
190
|
-
|
|
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.
|
|
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 }, "
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
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.
|
|
476
|
+
case ORCHESTRATOR_VIEWS.RUN_DETAIL:
|
|
202
477
|
return React.createElement(Box, { flexDirection: "column" },
|
|
203
|
-
React.createElement(Text, { bold: true }, "
|
|
204
|
-
|
|
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.
|
|
208
|
-
case ORCHESTRATOR_VIEWS.CONFIRM:
|
|
482
|
+
case ORCHESTRATOR_VIEWS.DIAGNOSTICS:
|
|
209
483
|
return React.createElement(Box, { flexDirection: "column" },
|
|
210
|
-
React.createElement(Text, { bold: true },
|
|
211
|
-
|
|
212
|
-
|
|
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
|
|
218
|
-
React.createElement(Text, null, "
|
|
219
|
-
React.createElement(Text, null, "
|
|
220
|
-
React.createElement(Text, null, "
|
|
221
|
-
React.createElement(Text, null, "
|
|
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.
|
|
233
|
-
|
|
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
|
}
|