@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.
- package/package.json +1 -1
- package/scripts/runtime-mvp-smoke.sh +152 -0
- package/src/cli.js +77 -4
- package/src/global/ink/orchestrator-app.js +355 -81
- package/src/global/ink/orchestrator-state.js +196 -65
- package/src/global/orchestrator.js +8 -39
- 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
|
@@ -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
|
}
|
|
@@ -1,11 +1,10 @@
|
|
|
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";
|
|
9
8
|
|
|
10
9
|
export { canUseOrchestratorShell };
|
|
11
10
|
|
|
@@ -28,13 +27,13 @@ export async function runOrchestratorShell({
|
|
|
28
27
|
}) {
|
|
29
28
|
if (!interactive) {
|
|
30
29
|
throw new Error(
|
|
31
|
-
`Non-interactive shell requires an explicit command. Try ${formatCliCommand("help")} or ${formatCliCommand("
|
|
30
|
+
`Non-interactive shell requires an explicit command. Try ${formatCliCommand("help")} or ${formatCliCommand("runs list")}.`
|
|
32
31
|
);
|
|
33
32
|
}
|
|
34
33
|
|
|
35
34
|
if (!canUseOrchestratorShell({ interactive })) {
|
|
36
35
|
throw new Error(
|
|
37
|
-
`Interactive shell requires a capable TTY. Use ${formatCliCommand("
|
|
36
|
+
`Interactive shell requires a capable TTY. Use ${formatCliCommand("runs list")} or explicit commands.`
|
|
38
37
|
);
|
|
39
38
|
}
|
|
40
39
|
|
|
@@ -51,41 +50,11 @@ export async function runOrchestratorShell({
|
|
|
51
50
|
throw outcome.error;
|
|
52
51
|
}
|
|
53
52
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const setupOutcome = await runGlobalSetup(
|
|
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 };
|
|
53
|
+
return {
|
|
54
|
+
cancelled: Boolean(outcome.cancelled),
|
|
55
|
+
wrote: false,
|
|
56
|
+
action: outcome.action ?? null
|
|
57
|
+
};
|
|
89
58
|
}
|
|
90
59
|
|
|
91
60
|
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
|
/**
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { createExecutionAdapter, parseNdjsonLine, buildPermissionsArgs } from "./create-execution-adapter.js";
|
|
2
|
+
|
|
3
|
+
const EXECUTABLE = "claude";
|
|
4
|
+
|
|
5
|
+
function buildClaudeLaunch({ task, cwd, model, permissions = [] }) {
|
|
6
|
+
const args = [
|
|
7
|
+
"-p",
|
|
8
|
+
"--output-format",
|
|
9
|
+
"stream-json",
|
|
10
|
+
...buildPermissionsArgs(permissions),
|
|
11
|
+
task
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
if (model) {
|
|
15
|
+
args.unshift("--model", model);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
command: EXECUTABLE,
|
|
20
|
+
args,
|
|
21
|
+
cwd,
|
|
22
|
+
env: process.env
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function parseClaudeEventLine(line) {
|
|
27
|
+
const parsed = parseNdjsonLine(line);
|
|
28
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
29
|
+
|
|
30
|
+
if (parsed.type === "tool_use" || parsed.type === "tool_call") {
|
|
31
|
+
return {
|
|
32
|
+
type: "tool_call",
|
|
33
|
+
tool_name: parsed.name ?? parsed.tool ?? "unknown",
|
|
34
|
+
status: parsed.status ?? "started"
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (parsed.type === "usage" || parsed.usage) {
|
|
39
|
+
const usage = parsed.usage ?? parsed;
|
|
40
|
+
return {
|
|
41
|
+
type: "usage",
|
|
42
|
+
inputTokens: usage.input_tokens ?? usage.input ?? null,
|
|
43
|
+
outputTokens: usage.output_tokens ?? usage.output ?? null,
|
|
44
|
+
totalTokens: usage.total_tokens ?? usage.total ?? null,
|
|
45
|
+
cost: usage.cost ?? null
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return parsed;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export default createExecutionAdapter({
|
|
53
|
+
id: "claude",
|
|
54
|
+
label: "Claude Code",
|
|
55
|
+
executable: EXECUTABLE,
|
|
56
|
+
capabilities: {
|
|
57
|
+
structuredEvents: true,
|
|
58
|
+
tokens: true,
|
|
59
|
+
diff: false,
|
|
60
|
+
cancel: true,
|
|
61
|
+
transcript: true
|
|
62
|
+
},
|
|
63
|
+
buildLaunch: buildClaudeLaunch,
|
|
64
|
+
parseEventLine: parseClaudeEventLine
|
|
65
|
+
});
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { createExecutionAdapter, parseNdjsonLine } from "./create-execution-adapter.js";
|
|
2
|
+
|
|
3
|
+
const EXECUTABLE = "codex";
|
|
4
|
+
|
|
5
|
+
function buildCodexPermissionsArgs(permissions = []) {
|
|
6
|
+
const normalized = new Set(permissions.map((entry) => String(entry).toLowerCase()));
|
|
7
|
+
|
|
8
|
+
if (
|
|
9
|
+
normalized.has("yolo")
|
|
10
|
+
|| normalized.has("dangerously-skip-permissions")
|
|
11
|
+
|| normalized.has("dangerously-bypass-approvals-and-sandbox")
|
|
12
|
+
) {
|
|
13
|
+
return ["--dangerously-bypass-approvals-and-sandbox"];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return [];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function buildCodexLaunch({ task, cwd, model, permissions = [] }) {
|
|
20
|
+
const args = [
|
|
21
|
+
"exec",
|
|
22
|
+
"--json",
|
|
23
|
+
...buildCodexPermissionsArgs(permissions),
|
|
24
|
+
task
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
if (model) {
|
|
28
|
+
args.unshift("--model", model);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
command: EXECUTABLE,
|
|
33
|
+
args,
|
|
34
|
+
cwd,
|
|
35
|
+
env: process.env
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function parseCodexEventLine(line) {
|
|
40
|
+
const parsed = parseNdjsonLine(line);
|
|
41
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
42
|
+
|
|
43
|
+
if (parsed.type === "tool" || parsed.type === "tool_call") {
|
|
44
|
+
return {
|
|
45
|
+
type: "tool_call",
|
|
46
|
+
tool_name: parsed.tool ?? parsed.name ?? "unknown",
|
|
47
|
+
status: parsed.status ?? "started"
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (parsed.usage || parsed.token_usage) {
|
|
52
|
+
const usage = parsed.usage ?? parsed.token_usage;
|
|
53
|
+
return {
|
|
54
|
+
type: "usage",
|
|
55
|
+
inputTokens: usage.input_tokens ?? usage.input ?? null,
|
|
56
|
+
outputTokens: usage.output_tokens ?? usage.output ?? null,
|
|
57
|
+
totalTokens: usage.total_tokens ?? usage.total ?? null,
|
|
58
|
+
cost: usage.cost ?? null
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return parsed;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export default createExecutionAdapter({
|
|
66
|
+
id: "codex",
|
|
67
|
+
label: "Codex",
|
|
68
|
+
executable: EXECUTABLE,
|
|
69
|
+
capabilities: {
|
|
70
|
+
structuredEvents: true,
|
|
71
|
+
tokens: true,
|
|
72
|
+
diff: false,
|
|
73
|
+
cancel: true,
|
|
74
|
+
transcript: true
|
|
75
|
+
},
|
|
76
|
+
buildLaunch: buildCodexLaunch,
|
|
77
|
+
parseEventLine: parseCodexEventLine
|
|
78
|
+
});
|