@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,5 +1,6 @@
|
|
|
1
1
|
import { stdin as input, stdout as output } from "node:process";
|
|
2
2
|
import { canUseSetupInk } from "./terminal.js";
|
|
3
|
+
import { isActiveRunState, formatTaskLabel } from "../runtime/run-types.js";
|
|
3
4
|
|
|
4
5
|
export function canUseOrchestratorShell({
|
|
5
6
|
interactive = Boolean(input.isTTY && output.isTTY),
|
|
@@ -12,24 +13,137 @@ export function canUseOrchestratorShell({
|
|
|
12
13
|
|
|
13
14
|
export const ORCHESTRATOR_VIEWS = {
|
|
14
15
|
HOME: "home",
|
|
16
|
+
ACTIVE_RUNS: "active-runs",
|
|
17
|
+
RECENT_RUNS: "recent-runs",
|
|
18
|
+
RUN_DETAIL: "run-detail",
|
|
19
|
+
PROVIDERS: "providers",
|
|
20
|
+
LAUNCH: "launch",
|
|
15
21
|
DIAGNOSTICS: "diagnostics",
|
|
16
|
-
|
|
17
|
-
PROFILE: "profile",
|
|
18
|
-
PLAN: "plan",
|
|
19
|
-
CONFIRM: "confirm",
|
|
20
|
-
HELP: "help",
|
|
21
|
-
INTELLIGENCE: "intelligence"
|
|
22
|
+
HELP: "help"
|
|
22
23
|
};
|
|
23
24
|
|
|
24
25
|
export const ORCHESTRATOR_MENU = [
|
|
25
|
-
{ id: "
|
|
26
|
-
{ id: "
|
|
27
|
-
{ id: "
|
|
28
|
-
{ id: "
|
|
29
|
-
{ id: "
|
|
26
|
+
{ id: "active", label: "Active runs", view: ORCHESTRATOR_VIEWS.ACTIVE_RUNS },
|
|
27
|
+
{ id: "recent", label: "Recent runs", view: ORCHESTRATOR_VIEWS.RECENT_RUNS },
|
|
28
|
+
{ id: "providers", label: "Providers", view: ORCHESTRATOR_VIEWS.PROVIDERS },
|
|
29
|
+
{ id: "launch", label: "Launch run", view: ORCHESTRATOR_VIEWS.LAUNCH, action: "launch" },
|
|
30
|
+
{ id: "diagnostics", label: "Diagnostics", view: ORCHESTRATOR_VIEWS.DIAGNOSTICS },
|
|
30
31
|
{ id: "help", label: "Help", view: ORCHESTRATOR_VIEWS.HELP }
|
|
31
32
|
];
|
|
32
33
|
|
|
34
|
+
export const LAUNCH_WIZARD_STEPS = {
|
|
35
|
+
AGENT: "agent",
|
|
36
|
+
TASK: "task",
|
|
37
|
+
MODEL: "model",
|
|
38
|
+
PERMISSIONS: "permissions",
|
|
39
|
+
CONFIRM: "confirm"
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const LAUNCH_PERMISSION_OPTIONS = [
|
|
43
|
+
{ id: "default", label: "Default (agent prompts)", permissions: [] },
|
|
44
|
+
{ id: "force", label: "Force / auto-approve", permissions: ["force"] },
|
|
45
|
+
{ id: "yolo", label: "YOLO / skip permissions", permissions: ["yolo"] }
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
export function resolveLaunchableAgents(providers = []) {
|
|
49
|
+
return providers
|
|
50
|
+
.filter((provider) => provider.launchable)
|
|
51
|
+
.map((provider) => provider.id);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function createLaunchDraft() {
|
|
55
|
+
return {
|
|
56
|
+
agentId: null,
|
|
57
|
+
task: "",
|
|
58
|
+
model: "",
|
|
59
|
+
permissionIndex: 0
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function resolveLaunchPermissions(draft) {
|
|
64
|
+
return LAUNCH_PERMISSION_OPTIONS[draft.permissionIndex]?.permissions ?? [];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function advanceLaunchWizardStep(currentStep) {
|
|
68
|
+
switch (currentStep) {
|
|
69
|
+
case LAUNCH_WIZARD_STEPS.AGENT:
|
|
70
|
+
return LAUNCH_WIZARD_STEPS.TASK;
|
|
71
|
+
case LAUNCH_WIZARD_STEPS.TASK:
|
|
72
|
+
return LAUNCH_WIZARD_STEPS.MODEL;
|
|
73
|
+
case LAUNCH_WIZARD_STEPS.MODEL:
|
|
74
|
+
return LAUNCH_WIZARD_STEPS.PERMISSIONS;
|
|
75
|
+
case LAUNCH_WIZARD_STEPS.PERMISSIONS:
|
|
76
|
+
return LAUNCH_WIZARD_STEPS.CONFIRM;
|
|
77
|
+
default:
|
|
78
|
+
return LAUNCH_WIZARD_STEPS.CONFIRM;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function retreatLaunchWizardStep(currentStep) {
|
|
83
|
+
switch (currentStep) {
|
|
84
|
+
case LAUNCH_WIZARD_STEPS.CONFIRM:
|
|
85
|
+
return LAUNCH_WIZARD_STEPS.PERMISSIONS;
|
|
86
|
+
case LAUNCH_WIZARD_STEPS.PERMISSIONS:
|
|
87
|
+
return LAUNCH_WIZARD_STEPS.MODEL;
|
|
88
|
+
case LAUNCH_WIZARD_STEPS.MODEL:
|
|
89
|
+
return LAUNCH_WIZARD_STEPS.TASK;
|
|
90
|
+
case LAUNCH_WIZARD_STEPS.TASK:
|
|
91
|
+
return LAUNCH_WIZARD_STEPS.AGENT;
|
|
92
|
+
default:
|
|
93
|
+
return LAUNCH_WIZARD_STEPS.AGENT;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function formatLaunchWizardLines({
|
|
98
|
+
step,
|
|
99
|
+
draft,
|
|
100
|
+
launchableAgents,
|
|
101
|
+
agentIndex,
|
|
102
|
+
permissionIndex
|
|
103
|
+
}) {
|
|
104
|
+
const lines = [`Step: ${step}`];
|
|
105
|
+
|
|
106
|
+
if (step === LAUNCH_WIZARD_STEPS.AGENT) {
|
|
107
|
+
lines.push("Select agent:");
|
|
108
|
+
for (const [index, agentId] of launchableAgents.entries()) {
|
|
109
|
+
const marker = index === agentIndex ? "›" : " ";
|
|
110
|
+
lines.push(`${marker} ${agentId}`);
|
|
111
|
+
}
|
|
112
|
+
return lines;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (step === LAUNCH_WIZARD_STEPS.TASK) {
|
|
116
|
+
lines.push(`Agent: ${draft.agentId ?? "—"}`);
|
|
117
|
+
lines.push(`Task: ${draft.task || "(type your task)"}`);
|
|
118
|
+
lines.push("Enter to continue · Backspace to edit");
|
|
119
|
+
return lines;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (step === LAUNCH_WIZARD_STEPS.MODEL) {
|
|
123
|
+
lines.push(`Agent: ${draft.agentId ?? "—"}`);
|
|
124
|
+
lines.push(`Task length: ${draft.task.length} chars`);
|
|
125
|
+
lines.push(`Model: ${draft.model || "(default — press Enter)"}`);
|
|
126
|
+
lines.push("Type model alias or Enter for default");
|
|
127
|
+
return lines;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (step === LAUNCH_WIZARD_STEPS.PERMISSIONS) {
|
|
131
|
+
lines.push("Permissions:");
|
|
132
|
+
for (const [index, option] of LAUNCH_PERMISSION_OPTIONS.entries()) {
|
|
133
|
+
const marker = index === permissionIndex ? "›" : " ";
|
|
134
|
+
lines.push(`${marker} ${option.label}`);
|
|
135
|
+
}
|
|
136
|
+
return lines;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
lines.push(`Agent: ${draft.agentId ?? "—"}`);
|
|
140
|
+
lines.push(`Task length: ${draft.task.length} chars (content not stored)`);
|
|
141
|
+
lines.push(`Model: ${draft.model || "default"}`);
|
|
142
|
+
lines.push(`Permissions: ${LAUNCH_PERMISSION_OPTIONS[permissionIndex]?.label ?? "default"}`);
|
|
143
|
+
lines.push("Enter to launch · Esc to go back");
|
|
144
|
+
return lines;
|
|
145
|
+
}
|
|
146
|
+
|
|
33
147
|
export function resolveMenuItem(menuIndex) {
|
|
34
148
|
return ORCHESTRATOR_MENU[menuIndex] ?? null;
|
|
35
149
|
}
|
|
@@ -43,6 +157,29 @@ export function shiftMenuIndex(currentIndex, direction, menuLength = ORCHESTRATO
|
|
|
43
157
|
return Math.min(menuLength - 1, Math.max(0, currentIndex + delta));
|
|
44
158
|
}
|
|
45
159
|
|
|
160
|
+
export function formatRunLines(runs, { emptyMessage = "No runs." } = {}) {
|
|
161
|
+
if (!runs || runs.length === 0) return [emptyMessage];
|
|
162
|
+
|
|
163
|
+
return runs.map((run) => {
|
|
164
|
+
const state = run.state.padEnd(12);
|
|
165
|
+
const agent = run.agentId.padEnd(10);
|
|
166
|
+
return `${run.runId} ${state} ${agent} ${formatTaskLabel(run)}`;
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function formatProviderLines(providers) {
|
|
171
|
+
return providers.map((provider) => {
|
|
172
|
+
const status = provider.launchable
|
|
173
|
+
? "launchable"
|
|
174
|
+
: provider.compatible
|
|
175
|
+
? "auditable"
|
|
176
|
+
: provider.available
|
|
177
|
+
? "limited"
|
|
178
|
+
: "missing";
|
|
179
|
+
return `${provider.label.padEnd(14)} ${status.padEnd(12)} ${provider.reason ?? ""}`.trimEnd();
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
46
183
|
export function formatDiagnosticsLines(diagnostics) {
|
|
47
184
|
const summary = diagnostics?.diagnostics;
|
|
48
185
|
const lines = [
|
|
@@ -53,9 +190,6 @@ export function formatDiagnosticsLines(diagnostics) {
|
|
|
53
190
|
`Unknown: ${summary?.unknown ?? 0}`,
|
|
54
191
|
`Errors: ${summary?.errors ?? 0}`,
|
|
55
192
|
"",
|
|
56
|
-
"Intelligence availability",
|
|
57
|
-
...formatIntelligenceLines(diagnostics),
|
|
58
|
-
"",
|
|
59
193
|
"Agent capabilities",
|
|
60
194
|
...formatAgentStatusLines(diagnostics?.capabilities ?? [])
|
|
61
195
|
];
|
|
@@ -79,71 +213,68 @@ export function formatAgentStatusLines(capabilities) {
|
|
|
79
213
|
});
|
|
80
214
|
}
|
|
81
215
|
|
|
82
|
-
export function
|
|
216
|
+
export function formatRunDetailLines(run, events = []) {
|
|
217
|
+
if (!run) return ["Run not found."];
|
|
218
|
+
|
|
83
219
|
const lines = [
|
|
84
|
-
`
|
|
85
|
-
`
|
|
86
|
-
`
|
|
87
|
-
`
|
|
88
|
-
`
|
|
89
|
-
`
|
|
90
|
-
`
|
|
220
|
+
`Run: ${run.runId}`,
|
|
221
|
+
`Agent: ${run.agentId} (${run.provider})`,
|
|
222
|
+
`State: ${run.state}`,
|
|
223
|
+
`Model: ${run.model ?? "default"}`,
|
|
224
|
+
`Cwd: ${run.cwd}`,
|
|
225
|
+
`Started: ${run.startedAt}`,
|
|
226
|
+
`Updated: ${run.updatedAt}`
|
|
91
227
|
];
|
|
92
228
|
|
|
93
|
-
if (
|
|
94
|
-
|
|
95
|
-
}
|
|
229
|
+
if (run.completedAt) lines.push(`Completed: ${run.completedAt}`);
|
|
230
|
+
if (run.tokenUsage) lines.push(`Tokens: ${JSON.stringify(run.tokenUsage)}`);
|
|
231
|
+
if (run.error) lines.push(`Error: ${run.error}`);
|
|
232
|
+
if (run.tools?.length) lines.push(`Tools: ${run.tools.join(", ")}`);
|
|
96
233
|
|
|
97
|
-
if (
|
|
98
|
-
lines.push(
|
|
234
|
+
if (events.length > 0) {
|
|
235
|
+
lines.push("", "Recent events");
|
|
236
|
+
for (const event of events.slice(-8)) {
|
|
237
|
+
if (event.parseError) continue;
|
|
238
|
+
lines.push(` ${event.type} ${summarizeEvent(event)}`);
|
|
239
|
+
}
|
|
99
240
|
}
|
|
100
241
|
|
|
101
|
-
lines.push(`Precedence: ${profileJson.sources.precedence}`);
|
|
102
242
|
return lines;
|
|
103
243
|
}
|
|
104
244
|
|
|
105
|
-
export function
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
`
|
|
113
|
-
`Cloud authenticated: ${intelligence.summary.cloudAuthenticated ? "yes" : "no"}`,
|
|
114
|
-
`Routing: ${intelligence.routingPreview?.reason ?? "n/a"}`,
|
|
115
|
-
`Can invoke: ${intelligence.routingPreview?.canInvoke ? "yes" : "no"}`,
|
|
116
|
-
""
|
|
245
|
+
export function formatDashboardSnapshot(dashboard) {
|
|
246
|
+
const active = dashboard?.activeRuns?.length ?? 0;
|
|
247
|
+
const recent = dashboard?.recentRuns?.length ?? 0;
|
|
248
|
+
const auditable = (dashboard?.providers ?? []).filter((entry) => entry.compatible).length;
|
|
249
|
+
return [
|
|
250
|
+
`Active runs: ${active}`,
|
|
251
|
+
`Recent runs: ${recent}`,
|
|
252
|
+
`Auditable providers: ${auditable}/${dashboard?.providers?.length ?? 0}`
|
|
117
253
|
];
|
|
118
|
-
|
|
119
|
-
for (const backend of intelligence.backends ?? []) {
|
|
120
|
-
lines.push(
|
|
121
|
-
`${backend.label.padEnd(14)} ${backend.state.padEnd(14)} models=${backend.models?.length ?? 0}`
|
|
122
|
-
);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return lines;
|
|
126
254
|
}
|
|
127
255
|
|
|
128
|
-
export function
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
lines.push(` • ${step}`);
|
|
132
|
-
}
|
|
256
|
+
export function selectRunFromList(runs, index) {
|
|
257
|
+
return runs[index] ?? null;
|
|
258
|
+
}
|
|
133
259
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
lines.push(` ! ${warning}`);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
260
|
+
export function filterInspectableRuns(runs) {
|
|
261
|
+
return runs ?? [];
|
|
262
|
+
}
|
|
140
263
|
|
|
141
|
-
|
|
264
|
+
export function isRunCancellable(run) {
|
|
265
|
+
return run && isActiveRunState(run.state);
|
|
142
266
|
}
|
|
143
267
|
|
|
144
|
-
function
|
|
145
|
-
if (
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
268
|
+
function summarizeEvent(event) {
|
|
269
|
+
if (event.type === "agent.tool_call") {
|
|
270
|
+
return event.data?.tool_name ?? event.data?.name ?? "tool";
|
|
271
|
+
}
|
|
272
|
+
if (event.type === "process.stdout" || event.type === "process.stderr") {
|
|
273
|
+
const line = event.data?.line ?? "";
|
|
274
|
+
return line.length > 60 ? `${line.slice(0, 59)}…` : line;
|
|
275
|
+
}
|
|
276
|
+
if (event.type === "run.completed" || event.type === "run.failed") {
|
|
277
|
+
return `exit=${event.data?.exitCode ?? "n/a"}`;
|
|
278
|
+
}
|
|
279
|
+
return "";
|
|
149
280
|
}
|
|
@@ -8,6 +8,7 @@ export async function runOrchestratorInk({
|
|
|
8
8
|
packageRoot,
|
|
9
9
|
packageName,
|
|
10
10
|
cliVersion,
|
|
11
|
+
hasGlobalState = false,
|
|
11
12
|
renderImpl = render
|
|
12
13
|
}) {
|
|
13
14
|
return new Promise((resolve) => {
|
|
@@ -18,6 +19,7 @@ export async function runOrchestratorInk({
|
|
|
18
19
|
packageRoot,
|
|
19
20
|
packageName,
|
|
20
21
|
cliVersion,
|
|
22
|
+
hasGlobalState,
|
|
21
23
|
onComplete: resolve
|
|
22
24
|
})
|
|
23
25
|
);
|
|
@@ -15,6 +15,7 @@ export async function runSetupInk({
|
|
|
15
15
|
packageName,
|
|
16
16
|
cliVersion,
|
|
17
17
|
dryRun = false,
|
|
18
|
+
onboarding = false,
|
|
18
19
|
preflight = true,
|
|
19
20
|
yes = false,
|
|
20
21
|
confirm = false,
|
|
@@ -33,6 +34,7 @@ export async function runSetupInk({
|
|
|
33
34
|
packageName,
|
|
34
35
|
cliVersion,
|
|
35
36
|
dryRun,
|
|
37
|
+
onboarding,
|
|
36
38
|
onComplete: resolve
|
|
37
39
|
})
|
|
38
40
|
);
|
|
@@ -56,8 +56,8 @@ function Footer({ children }) {
|
|
|
56
56
|
return React.createElement(Text, { dimColor: true }, children);
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
function Splash({ compact }) {
|
|
60
|
-
const lines = formatInkSplashLines({ compact });
|
|
59
|
+
function Splash({ compact, onboarding = false }) {
|
|
60
|
+
const lines = formatInkSplashLines({ compact, onboarding });
|
|
61
61
|
const logoLineCount = compact ? BRAND.compactLogo.length : BRAND.asciiLogo.length;
|
|
62
62
|
|
|
63
63
|
return React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
|
|
@@ -71,7 +71,7 @@ function Splash({ compact }) {
|
|
|
71
71
|
if (line === BRAND.tagline) {
|
|
72
72
|
return React.createElement(Text, { key: `line-${index}`, color: INK_COLORS.muted }, line);
|
|
73
73
|
}
|
|
74
|
-
if (line === BRAND.splashHint) {
|
|
74
|
+
if (line === BRAND.splashHint || line.includes("Esc to exit") || line.includes("Press Enter")) {
|
|
75
75
|
return React.createElement(Text, { key: `line-${index}`, dimColor: true }, line);
|
|
76
76
|
}
|
|
77
77
|
if (line === "") {
|
|
@@ -89,6 +89,7 @@ export function SetupApp({
|
|
|
89
89
|
packageName,
|
|
90
90
|
cliVersion,
|
|
91
91
|
dryRun = false,
|
|
92
|
+
onboarding = false,
|
|
92
93
|
onComplete
|
|
93
94
|
}) {
|
|
94
95
|
const { exit } = useApp();
|
|
@@ -243,7 +244,10 @@ export function SetupApp({
|
|
|
243
244
|
const detectPanel = formatInkDetectPanel({ adapters, detected });
|
|
244
245
|
|
|
245
246
|
return React.createElement(Box, { flexDirection: "column" },
|
|
246
|
-
step === SETUP_STEPS.SPLASH && React.createElement(Splash, {
|
|
247
|
+
step === SETUP_STEPS.SPLASH && React.createElement(Splash, {
|
|
248
|
+
compact: useCompactSplash,
|
|
249
|
+
onboarding
|
|
250
|
+
}),
|
|
247
251
|
step !== SETUP_STEPS.SPLASH && React.createElement(Header),
|
|
248
252
|
step === SETUP_STEPS.DETECT && React.createElement(Panel, { title: WIZARD_COPY.detectTitle },
|
|
249
253
|
detectPanel.split("\n")
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
AGENT_HINTS,
|
|
3
|
+
BRAND,
|
|
4
|
+
ONBOARDING_COPY,
|
|
5
|
+
formatCliCommand,
|
|
6
|
+
getAgentLabel,
|
|
7
|
+
PREFERRED_CLI,
|
|
8
|
+
WIZARD_COPY
|
|
9
|
+
} from "../brand/index.js";
|
|
2
10
|
import { formatAgentMultiselectHint } from "../clack/theme.js";
|
|
3
11
|
|
|
4
12
|
export const SETUP_STEPS = {
|
|
@@ -16,8 +24,22 @@ export function shouldUseCompactSplashLogo(columns) {
|
|
|
16
24
|
return columns < fullWidth + 4;
|
|
17
25
|
}
|
|
18
26
|
|
|
19
|
-
export function formatInkSplashLines({ compact = false } = {}) {
|
|
27
|
+
export function formatInkSplashLines({ compact = false, onboarding = false } = {}) {
|
|
20
28
|
const logo = compact ? BRAND.compactLogo : BRAND.asciiLogo;
|
|
29
|
+
if (onboarding) {
|
|
30
|
+
return [
|
|
31
|
+
...logo,
|
|
32
|
+
"",
|
|
33
|
+
BRAND.name,
|
|
34
|
+
BRAND.tagline,
|
|
35
|
+
"",
|
|
36
|
+
ONBOARDING_COPY.purpose,
|
|
37
|
+
ONBOARDING_COPY.safety,
|
|
38
|
+
"",
|
|
39
|
+
ONBOARDING_COPY.continueHint
|
|
40
|
+
];
|
|
41
|
+
}
|
|
42
|
+
|
|
21
43
|
return [
|
|
22
44
|
...logo,
|
|
23
45
|
"",
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { stdin as input, stdout as output } from "node:process";
|
|
2
2
|
import { resolveHomeDir } from "./paths.js";
|
|
3
|
-
import { runGlobalSetup } from "./global-cli.js";
|
|
4
|
-
import { PLAN_ACTIONS, buildReadOnlyDiagnostics, shouldExecutePlan } from "./action-planner.js";
|
|
5
3
|
import { canUseOrchestratorShell } from "./ink/orchestrator-state.js";
|
|
6
4
|
import { runOrchestratorInk as defaultRunOrchestratorInk } from "./ink/run-orchestrator-ink.js";
|
|
7
5
|
import { formatCliCommand } from "./brand/cli.js";
|
|
8
6
|
import { BRAND } from "./brand/index.js";
|
|
7
|
+
import { buildReadOnlyDiagnostics, shouldExecutePlan } from "./action-planner.js";
|
|
8
|
+
import { runHarnessSetup as defaultRunHarnessSetup } from "./setup.js";
|
|
9
|
+
import {
|
|
10
|
+
INITIAL_EXPERIENCE,
|
|
11
|
+
hasConfiguredGlobalState
|
|
12
|
+
} from "./initial-experience.js";
|
|
9
13
|
|
|
10
14
|
export { canUseOrchestratorShell };
|
|
11
15
|
|
|
@@ -24,68 +28,68 @@ export async function runOrchestratorShell({
|
|
|
24
28
|
packageManifest,
|
|
25
29
|
workspaceRoot,
|
|
26
30
|
interactive = Boolean(input.isTTY && output.isTTY),
|
|
27
|
-
|
|
31
|
+
initialMode = INITIAL_EXPERIENCE.DASHBOARD,
|
|
32
|
+
shellCapable = canUseOrchestratorShell({ interactive }),
|
|
33
|
+
runOrchestratorInkImpl = defaultRunOrchestratorInk,
|
|
34
|
+
runHarnessSetupImpl = defaultRunHarnessSetup
|
|
28
35
|
}) {
|
|
29
36
|
if (!interactive) {
|
|
30
37
|
throw new Error(
|
|
31
|
-
`Non-interactive shell requires an explicit command. Try ${formatCliCommand("help")} or ${formatCliCommand("
|
|
38
|
+
`Non-interactive shell requires an explicit command. Try ${formatCliCommand("help")} or ${formatCliCommand("runs list")}.`
|
|
32
39
|
);
|
|
33
40
|
}
|
|
34
41
|
|
|
35
|
-
if (!
|
|
42
|
+
if (!shellCapable) {
|
|
36
43
|
throw new Error(
|
|
37
|
-
`Interactive shell requires a capable TTY. Use ${formatCliCommand("
|
|
44
|
+
`Interactive shell requires a capable TTY. Use ${formatCliCommand("runs list")} or explicit commands.`
|
|
38
45
|
);
|
|
39
46
|
}
|
|
40
47
|
|
|
41
48
|
const homeDir = resolveHomeDir();
|
|
49
|
+
let setupOutcome = null;
|
|
50
|
+
|
|
51
|
+
if (initialMode === INITIAL_EXPERIENCE.ONBOARDING) {
|
|
52
|
+
setupOutcome = await runHarnessSetupImpl({
|
|
53
|
+
packageRoot,
|
|
54
|
+
packageName: packageManifest.name,
|
|
55
|
+
cliVersion: packageManifest.version,
|
|
56
|
+
homeDir,
|
|
57
|
+
workspaceRoot,
|
|
58
|
+
onboarding: true,
|
|
59
|
+
interactive: true
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
if (setupOutcome?.cancelled) {
|
|
63
|
+
return {
|
|
64
|
+
cancelled: true,
|
|
65
|
+
wrote: false,
|
|
66
|
+
action: null,
|
|
67
|
+
initialMode,
|
|
68
|
+
setup: setupOutcome
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
42
73
|
const outcome = await runOrchestratorInkImpl({
|
|
43
74
|
homeDir,
|
|
44
75
|
workspaceRoot,
|
|
45
76
|
packageRoot,
|
|
46
77
|
packageName: packageManifest.name,
|
|
47
|
-
cliVersion: packageManifest.version
|
|
78
|
+
cliVersion: packageManifest.version,
|
|
79
|
+
hasGlobalState: hasConfiguredGlobalState(homeDir)
|
|
48
80
|
});
|
|
49
81
|
|
|
50
82
|
if (outcome.error) {
|
|
51
83
|
throw outcome.error;
|
|
52
84
|
}
|
|
53
85
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
cwd: workspaceRoot,
|
|
62
|
-
adapters: null,
|
|
63
|
-
components: null,
|
|
64
|
-
noDefaultComponents: false,
|
|
65
|
-
dryRun: false,
|
|
66
|
-
yes: false,
|
|
67
|
-
confirm: false,
|
|
68
|
-
preflight: true,
|
|
69
|
-
preflightExplicit: false,
|
|
70
|
-
yesExplicit: false,
|
|
71
|
-
confirmExplicit: false,
|
|
72
|
-
json: false,
|
|
73
|
-
interactive: true,
|
|
74
|
-
simple: false
|
|
75
|
-
},
|
|
76
|
-
packageManifest,
|
|
77
|
-
packageRoot
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
return {
|
|
81
|
-
cancelled: Boolean(setupOutcome.cancelled),
|
|
82
|
-
wrote: !setupOutcome.cancelled && !setupOutcome.result?.dryRun,
|
|
83
|
-
action: PLAN_ACTIONS.SETUP,
|
|
84
|
-
setupOutcome
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
return { cancelled: false, wrote: false, action: outcome.action ?? null };
|
|
86
|
+
return {
|
|
87
|
+
cancelled: Boolean(outcome.cancelled),
|
|
88
|
+
wrote: Boolean(setupOutcome && !setupOutcome.cancelled),
|
|
89
|
+
action: outcome.action ?? null,
|
|
90
|
+
initialMode,
|
|
91
|
+
setup: setupOutcome
|
|
92
|
+
};
|
|
89
93
|
}
|
|
90
94
|
|
|
91
95
|
export async function runOrchestratorDiagnostics({
|
package/src/global/paths.js
CHANGED
|
@@ -17,7 +17,20 @@ export function harnessHomePaths(homeDir) {
|
|
|
17
17
|
policyPath: join(root, "policy.json"),
|
|
18
18
|
profilePath: join(root, "profile.json"),
|
|
19
19
|
historyPath: join(root, "history.jsonl"),
|
|
20
|
+
runsDir: join(root, "runs"),
|
|
20
21
|
coreDir: join(root, "core"),
|
|
21
22
|
backupsDir: join(root, "backups")
|
|
22
23
|
};
|
|
23
24
|
}
|
|
25
|
+
|
|
26
|
+
export function runPaths(homeDir, runId) {
|
|
27
|
+
const { runsDir } = harnessHomePaths(homeDir);
|
|
28
|
+
const runDir = join(runsDir, runId);
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
runDir,
|
|
32
|
+
statePath: join(runDir, "state.json"),
|
|
33
|
+
eventsPath: join(runDir, "events.jsonl"),
|
|
34
|
+
transcriptPath: join(runDir, "transcript.jsonl")
|
|
35
|
+
};
|
|
36
|
+
}
|
package/src/global/profile.js
CHANGED
|
@@ -4,6 +4,7 @@ import { join } from "node:path";
|
|
|
4
4
|
import { harnessHomePaths } from "./paths.js";
|
|
5
5
|
import { AGENT_CAPABILITY_IDS } from "./agent-capabilities/index.js";
|
|
6
6
|
import { classifyCustomBaseUrl, isValidEnvironmentName } from "./intelligence/custom-url.js";
|
|
7
|
+
import { validateRuntimeProfile, RUNTIME_PROFILE_KEYS } from "./runtime/run-profile.js";
|
|
7
8
|
|
|
8
9
|
export const PROFILE_KEYS = new Set([
|
|
9
10
|
"coordinator",
|
|
@@ -16,7 +17,8 @@ export const PROFILE_KEYS = new Set([
|
|
|
16
17
|
"tokenBudget",
|
|
17
18
|
"stableContextBudget",
|
|
18
19
|
"requestContextBudget",
|
|
19
|
-
"customProviders"
|
|
20
|
+
"customProviders",
|
|
21
|
+
...RUNTIME_PROFILE_KEYS
|
|
20
22
|
]);
|
|
21
23
|
|
|
22
24
|
export const DEFAULT_PROFILE = {
|
|
@@ -30,7 +32,13 @@ export const DEFAULT_PROFILE = {
|
|
|
30
32
|
tokenBudget: null,
|
|
31
33
|
stableContextBudget: null,
|
|
32
34
|
requestContextBudget: null,
|
|
33
|
-
customProviders: []
|
|
35
|
+
customProviders: [],
|
|
36
|
+
agentAliases: {},
|
|
37
|
+
modelAliases: {},
|
|
38
|
+
defaultPermissions: [],
|
|
39
|
+
defaultRuntimeAgent: null,
|
|
40
|
+
defaultRuntimeModel: null,
|
|
41
|
+
captureTranscript: false
|
|
34
42
|
};
|
|
35
43
|
|
|
36
44
|
const APPLY_MODES = new Set(["prompt", "confirm"]);
|
|
@@ -105,6 +113,12 @@ export function buildProfileJson(resolved) {
|
|
|
105
113
|
stableContextBudget: profile.stableContextBudget,
|
|
106
114
|
requestContextBudget: profile.requestContextBudget,
|
|
107
115
|
customProviders: sanitizeCustomProviders(profile.customProviders),
|
|
116
|
+
agentAliases: profile.agentAliases ?? {},
|
|
117
|
+
modelAliases: profile.modelAliases ?? {},
|
|
118
|
+
defaultPermissions: profile.defaultPermissions ?? [],
|
|
119
|
+
defaultRuntimeAgent: profile.defaultRuntimeAgent ?? null,
|
|
120
|
+
defaultRuntimeModel: profile.defaultRuntimeModel ?? null,
|
|
121
|
+
captureTranscript: profile.captureTranscript ?? false,
|
|
108
122
|
sources: {
|
|
109
123
|
global: sources.global,
|
|
110
124
|
project: sources.project,
|
|
@@ -187,6 +201,7 @@ function validateProfile(profile) {
|
|
|
187
201
|
|
|
188
202
|
validateNoSecrets(profile);
|
|
189
203
|
validateCustomProviders(profile.customProviders);
|
|
204
|
+
validateRuntimeProfile(profile);
|
|
190
205
|
}
|
|
191
206
|
|
|
192
207
|
/**
|