@heyditto/cli 2.0.1 → 2.2.0
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 +167 -1
- package/dist/agents/claude.d.ts +11 -0
- package/dist/agents/claude.js +48 -0
- package/dist/agents/claude.js.map +1 -0
- package/dist/agents/codex.d.ts +13 -0
- package/dist/agents/codex.js +48 -0
- package/dist/agents/codex.js.map +1 -0
- package/dist/agents/launch.d.ts +25 -0
- package/dist/agents/launch.js +376 -0
- package/dist/agents/launch.js.map +1 -0
- package/dist/agents/sessions.d.ts +28 -0
- package/dist/agents/sessions.js +63 -0
- package/dist/agents/sessions.js.map +1 -0
- package/dist/agents/types.d.ts +50 -0
- package/dist/agents/types.js +44 -0
- package/dist/agents/types.js.map +1 -0
- package/dist/agents/worktree.d.ts +19 -0
- package/dist/agents/worktree.js +72 -0
- package/dist/agents/worktree.js.map +1 -0
- package/dist/api.d.ts +178 -0
- package/dist/api.js +163 -0
- package/dist/api.js.map +1 -0
- package/dist/browser.d.ts +2 -0
- package/dist/browser.js +17 -0
- package/dist/browser.js.map +1 -0
- package/dist/cli.js +107 -24
- package/dist/cli.js.map +1 -1
- package/dist/commands.d.ts +77 -0
- package/dist/commands.js +638 -0
- package/dist/commands.js.map +1 -0
- package/dist/config.d.ts +8 -0
- package/dist/config.js +18 -1
- package/dist/config.js.map +1 -1
- package/dist/device-login.d.ts +28 -0
- package/dist/device-login.js +43 -0
- package/dist/device-login.js.map +1 -0
- package/dist/endpoint-format.d.ts +9 -0
- package/dist/endpoint-format.js +21 -0
- package/dist/endpoint-format.js.map +1 -0
- package/dist/mcp-session.d.ts +40 -0
- package/dist/mcp-session.js +133 -0
- package/dist/mcp-session.js.map +1 -0
- package/dist/store.d.ts +26 -0
- package/dist/store.js +61 -0
- package/dist/store.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import { createInterface } from "node:readline/promises";
|
|
5
|
+
import { ApiError, createEndpoint, createKey, findEndpoint, isEndpointPending, listEndpoints, revokeKey, } from "../api.js";
|
|
6
|
+
import { openInBrowser } from "../browser.js";
|
|
7
|
+
import { endpointURL, resolveApiKey } from "../config.js";
|
|
8
|
+
import { deviceLogin } from "../device-login.js";
|
|
9
|
+
import { formatActivation } from "../endpoint-format.js";
|
|
10
|
+
import { readStoredAuth, saveLogin, updateStoredAuth } from "../store.js";
|
|
11
|
+
import { planClaude } from "./claude.js";
|
|
12
|
+
import { planCodex } from "./codex.js";
|
|
13
|
+
import { latestSession, readSession, writeSession } from "./sessions.js";
|
|
14
|
+
import { KEY_EXPIRIES, childEnv, maskKey, stripSeparator, } from "./types.js";
|
|
15
|
+
import { defaultWorktreeName, ensureWorktree } from "./worktree.js";
|
|
16
|
+
const DRY_RUN_KEY = "ditto_inf_<minted-at-launch>";
|
|
17
|
+
function log(line) {
|
|
18
|
+
process.stderr.write(`ditto: ${line}\n`);
|
|
19
|
+
}
|
|
20
|
+
function planFor(harness, input) {
|
|
21
|
+
return harness === "claude" ? planClaude(input) : planCodex(input);
|
|
22
|
+
}
|
|
23
|
+
function binaryAvailable(command) {
|
|
24
|
+
const probe = process.platform === "win32" ? "where" : "which";
|
|
25
|
+
return spawnSync(probe, [command], { stdio: "ignore" }).status === 0;
|
|
26
|
+
}
|
|
27
|
+
function parseBudget(raw) {
|
|
28
|
+
if (raw === undefined)
|
|
29
|
+
return undefined;
|
|
30
|
+
const n = Number(raw.replace(/[_,]/g, ""));
|
|
31
|
+
if (!Number.isInteger(n) || n <= 0)
|
|
32
|
+
throw new Error(`--budget must be a positive integer token count, got "${raw}"`);
|
|
33
|
+
return n;
|
|
34
|
+
}
|
|
35
|
+
function parseExpiry(raw) {
|
|
36
|
+
const value = (raw ?? "1d").trim();
|
|
37
|
+
if (KEY_EXPIRIES.includes(value))
|
|
38
|
+
return value;
|
|
39
|
+
throw new Error(`--expires must be one of: ${KEY_EXPIRIES.join(", ")}`);
|
|
40
|
+
}
|
|
41
|
+
function formatSpend(e) {
|
|
42
|
+
const used = e.spentTokens ?? 0;
|
|
43
|
+
if (e.spendLimitTokens == null || e.spendLimitTokens < 0)
|
|
44
|
+
return `${used.toLocaleString()} tokens used, no limit`;
|
|
45
|
+
return `${used.toLocaleString()} / ${e.spendLimitTokens.toLocaleString()} tokens${e.spendPeriod && e.spendPeriod !== "never" ? ` per ${e.spendPeriod.replace(/ly$/, "")}` : ""}`;
|
|
46
|
+
}
|
|
47
|
+
function interactive() {
|
|
48
|
+
return Boolean(process.stdin.isTTY && process.stderr.isTTY);
|
|
49
|
+
}
|
|
50
|
+
async function ask(question) {
|
|
51
|
+
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
52
|
+
try {
|
|
53
|
+
return (await rl.question(question)).trim();
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
rl.close();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/** Yes/no prompt with Enter defaulting to yes. */
|
|
60
|
+
async function confirmYes(question) {
|
|
61
|
+
const answer = (await ask(`${question} [Y/n] `)).toLowerCase();
|
|
62
|
+
return answer === "" || answer === "y" || answer === "yes";
|
|
63
|
+
}
|
|
64
|
+
/** Interactive numbered picker; also accepts a slug or id. Exported for `heyditto endpoints pick`. */
|
|
65
|
+
export async function pickEndpoint(endpoints, defaultSlug) {
|
|
66
|
+
if (!interactive()) {
|
|
67
|
+
throw new Error("no endpoint selected. Pass --endpoint <slug>, or set a default with `heyditto endpoints use <slug>`.");
|
|
68
|
+
}
|
|
69
|
+
process.stderr.write("Ditto inference endpoints:\n\n");
|
|
70
|
+
endpoints.forEach((e, i) => {
|
|
71
|
+
const marks = [
|
|
72
|
+
e.slug === defaultSlug ? "default" : "",
|
|
73
|
+
isEndpointPending(e) ? "inactive" : "",
|
|
74
|
+
].filter(Boolean);
|
|
75
|
+
process.stderr.write(` ${i + 1}) ${e.slug} ${e.name !== e.slug ? `(${e.name}) ` : ""}model=${e.model}${marks.length ? ` [${marks.join(", ")}]` : ""}\n`);
|
|
76
|
+
process.stderr.write(` ${formatSpend(e)}${e.recordTrace ? " · traces on" : " · traces off"}\n`);
|
|
77
|
+
});
|
|
78
|
+
process.stderr.write("\n");
|
|
79
|
+
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
80
|
+
try {
|
|
81
|
+
for (;;) {
|
|
82
|
+
const answer = (await rl.question(`Connect to which endpoint? [1-${endpoints.length}, or a slug] `)).trim();
|
|
83
|
+
const idx = Number(answer);
|
|
84
|
+
if (Number.isInteger(idx) && idx >= 1 && idx <= endpoints.length)
|
|
85
|
+
return endpoints[idx - 1];
|
|
86
|
+
const bySlug = findEndpoint(endpoints, answer);
|
|
87
|
+
if (bySlug)
|
|
88
|
+
return bySlug;
|
|
89
|
+
process.stderr.write(`Pick a number from 1 to ${endpoints.length}, or type an endpoint slug.\n`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
finally {
|
|
93
|
+
rl.close();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/** Refuses to launch against an endpoint the backend marked inactive (e.g. awaiting the user's plan). */
|
|
97
|
+
export async function assertEndpointActive(endpoint) {
|
|
98
|
+
if (!isEndpointPending(endpoint))
|
|
99
|
+
return;
|
|
100
|
+
const stored = await readStoredAuth();
|
|
101
|
+
const details = formatActivation(endpoint, stored?.claimURL);
|
|
102
|
+
throw new Error(`endpoint "${endpoint.slug}" is not active yet (${endpoint.status}).\n\n${details}`);
|
|
103
|
+
}
|
|
104
|
+
async function resolveEndpoint(wanted, endpoints, selected) {
|
|
105
|
+
if (endpoints.length === 0) {
|
|
106
|
+
if (interactive() && (await confirmYes("You have no inference endpoints yet. Create your first one now?"))) {
|
|
107
|
+
const created = await createEndpoint({});
|
|
108
|
+
log(`created endpoint ${created.slug} (model ${created.model})`);
|
|
109
|
+
await updateStoredAuth({ defaultEndpoint: created.slug });
|
|
110
|
+
return created;
|
|
111
|
+
}
|
|
112
|
+
throw new Error(`you have no inference endpoints yet. Create one with \`heyditto endpoints create\`, or at ${endpointURL()}.`);
|
|
113
|
+
}
|
|
114
|
+
const stored = (await readStoredAuth())?.defaultEndpoint;
|
|
115
|
+
if (wanted?.trim()) {
|
|
116
|
+
const match = findEndpoint(endpoints, wanted);
|
|
117
|
+
if (match)
|
|
118
|
+
return match;
|
|
119
|
+
throw new Error(`no endpoint named "${wanted.trim()}". Available: ${endpoints.map((e) => e.slug).join(", ")}`);
|
|
120
|
+
}
|
|
121
|
+
if (selected) {
|
|
122
|
+
// Chosen in the browser moments ago during the device login.
|
|
123
|
+
const match = findEndpoint(endpoints, selected.id) ?? findEndpoint(endpoints, selected.slug);
|
|
124
|
+
if (match)
|
|
125
|
+
return match;
|
|
126
|
+
log(`endpoint "${selected.slug}" picked in the browser is not in your list; pick another`);
|
|
127
|
+
}
|
|
128
|
+
if (stored?.trim()) {
|
|
129
|
+
const match = findEndpoint(endpoints, stored);
|
|
130
|
+
if (match)
|
|
131
|
+
return match;
|
|
132
|
+
log(`default endpoint "${stored.trim()}" no longer exists; pick another`);
|
|
133
|
+
}
|
|
134
|
+
if (endpoints.length === 1)
|
|
135
|
+
return endpoints[0];
|
|
136
|
+
const picked = await pickEndpoint(endpoints, stored);
|
|
137
|
+
if (await confirmYes(`Use ${picked.slug} by default next time?`)) {
|
|
138
|
+
await updateStoredAuth({ defaultEndpoint: picked.slug });
|
|
139
|
+
log(`default endpoint set to ${picked.slug} (change it with \`heyditto endpoints use <slug>\`)`);
|
|
140
|
+
}
|
|
141
|
+
return picked;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* First run: no key saved anywhere. On a terminal, run the browser device
|
|
145
|
+
* flow with the harness as the intent so the web page can offer the endpoint
|
|
146
|
+
* picker; the browser hands back the key and (optionally) the chosen endpoint.
|
|
147
|
+
*/
|
|
148
|
+
async function ensureLoggedIn(harness) {
|
|
149
|
+
const { key } = await resolveApiKey();
|
|
150
|
+
if (key)
|
|
151
|
+
return undefined;
|
|
152
|
+
if (!interactive()) {
|
|
153
|
+
// Non-interactive callers (CI, agents) must log in explicitly.
|
|
154
|
+
await listEndpoints(); // throws the shared "no Ditto API key configured" error
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
log(`no Ditto login yet — opening your browser to sign in and pick an endpoint for ${harness === "claude" ? "Claude Code" : "Codex"}.`);
|
|
158
|
+
return browserLogin(harness);
|
|
159
|
+
}
|
|
160
|
+
/** Runs the browser device flow for a harness and saves the result. */
|
|
161
|
+
async function browserLogin(harness) {
|
|
162
|
+
const result = await deviceLogin({
|
|
163
|
+
intent: harness,
|
|
164
|
+
onCode: (userCode, url) => {
|
|
165
|
+
process.stderr.write(`\n ${url}\n\n Code: ${userCode}\n\n`);
|
|
166
|
+
openInBrowser(url);
|
|
167
|
+
process.stderr.write("Waiting for approval in the browser (Ctrl+C to cancel)…\n");
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
await saveLogin(result.apiKey, result.setDefault && result.endpoint ? { defaultEndpoint: result.endpoint.slug } : {});
|
|
171
|
+
log(`logged in${result.endpoint ? `; endpoint ${result.endpoint.slug}${result.setDefault ? " saved as default" : ""}` : ""}`);
|
|
172
|
+
return result.endpoint;
|
|
173
|
+
}
|
|
174
|
+
function forwardSignals(child) {
|
|
175
|
+
// Ctrl+C reaches the child directly through the shared terminal; the
|
|
176
|
+
// wrapper only has to survive it so it can revoke the key afterwards.
|
|
177
|
+
const onInt = () => {
|
|
178
|
+
/* keep running until the harness exits */
|
|
179
|
+
};
|
|
180
|
+
const onTerm = () => child.kill("SIGTERM");
|
|
181
|
+
const onHup = () => child.kill("SIGHUP");
|
|
182
|
+
process.on("SIGINT", onInt);
|
|
183
|
+
process.on("SIGTERM", onTerm);
|
|
184
|
+
process.on("SIGHUP", onHup);
|
|
185
|
+
return () => {
|
|
186
|
+
process.off("SIGINT", onInt);
|
|
187
|
+
process.off("SIGTERM", onTerm);
|
|
188
|
+
process.off("SIGHUP", onHup);
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
function waitForExit(child) {
|
|
192
|
+
return new Promise((resolve, reject) => {
|
|
193
|
+
child.on("error", reject);
|
|
194
|
+
child.on("exit", (code, signal) => resolve(code ?? (signal ? 128 + (os.constants.signals[signal] ?? 0) : null)));
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
/** Launches a coding harness against a Ditto inference endpoint with a temporary key. */
|
|
198
|
+
export async function launchHarness(harness, rawArgs, options) {
|
|
199
|
+
const passthrough = stripSeparator(rawArgs);
|
|
200
|
+
const budget = parseBudget(options.budget);
|
|
201
|
+
const expiresIn = parseExpiry(options.expires);
|
|
202
|
+
if (options.plan && harness !== "claude")
|
|
203
|
+
throw new Error("--plan is only supported for claude");
|
|
204
|
+
if ([options.yolo, options.yellow, options.plan].filter(Boolean).length > 1) {
|
|
205
|
+
throw new Error("choose only one of --yolo, --yellow, --plan");
|
|
206
|
+
}
|
|
207
|
+
if (options.resume !== undefined && options.continue)
|
|
208
|
+
throw new Error("use either --resume or --continue");
|
|
209
|
+
if (options.resume !== undefined && options.session)
|
|
210
|
+
throw new Error("--session cannot be combined with --resume");
|
|
211
|
+
if (!options.dryRun && !binaryAvailable(harness)) {
|
|
212
|
+
const hint = planFor(harness, {
|
|
213
|
+
baseUrl: "",
|
|
214
|
+
apiKey: "",
|
|
215
|
+
sessionId: "",
|
|
216
|
+
passthrough: [],
|
|
217
|
+
env: {},
|
|
218
|
+
}).installHint;
|
|
219
|
+
throw new Error(`"${harness}" is not on your PATH; ${hint}`);
|
|
220
|
+
}
|
|
221
|
+
// Resume: reuse the local record's Ditto session id so the traces stay in
|
|
222
|
+
// the same thread; a fresh key is minted every launch.
|
|
223
|
+
let record;
|
|
224
|
+
let resumeLast = Boolean(options.continue);
|
|
225
|
+
if (options.resume !== undefined) {
|
|
226
|
+
record =
|
|
227
|
+
typeof options.resume === "string"
|
|
228
|
+
? await readSession(options.resume)
|
|
229
|
+
: await latestSession(harness, process.cwd());
|
|
230
|
+
if (!record) {
|
|
231
|
+
throw new Error(typeof options.resume === "string"
|
|
232
|
+
? `no local session "${options.resume}"; see \`heyditto sessions\``
|
|
233
|
+
: `no previous ${harness} session to resume; see \`heyditto sessions\``);
|
|
234
|
+
}
|
|
235
|
+
if (record.harness !== harness)
|
|
236
|
+
throw new Error(`session ${record.id} was a ${record.harness} session`);
|
|
237
|
+
if (!record.harnessSessionId)
|
|
238
|
+
resumeLast = true;
|
|
239
|
+
}
|
|
240
|
+
let selected = options.dryRun ? undefined : await ensureLoggedIn(harness);
|
|
241
|
+
let catalog;
|
|
242
|
+
try {
|
|
243
|
+
catalog = await listEndpoints();
|
|
244
|
+
}
|
|
245
|
+
catch (err) {
|
|
246
|
+
// A saved key that lapsed (device-flow keys expire) sends the user back
|
|
247
|
+
// through the browser instead of a dead 401.
|
|
248
|
+
if (!(err instanceof ApiError) || err.status !== 401 || options.dryRun || !interactive())
|
|
249
|
+
throw err;
|
|
250
|
+
const { source } = await resolveApiKey();
|
|
251
|
+
if (source !== "config")
|
|
252
|
+
throw err;
|
|
253
|
+
log("your saved Ditto login is no longer valid — opening your browser to sign in again.");
|
|
254
|
+
selected = await browserLogin(harness);
|
|
255
|
+
catalog = await listEndpoints();
|
|
256
|
+
}
|
|
257
|
+
const endpoint = await resolveEndpoint(options.endpoint ?? record?.endpointSlug, catalog.endpoints, selected);
|
|
258
|
+
await assertEndpointActive(endpoint);
|
|
259
|
+
let cwd = record?.worktree ?? process.cwd();
|
|
260
|
+
let worktreePath = record?.worktree;
|
|
261
|
+
if (options.worktree !== undefined && options.worktree !== false) {
|
|
262
|
+
const name = typeof options.worktree === "string" ? options.worktree : defaultWorktreeName(harness);
|
|
263
|
+
if (options.dryRun) {
|
|
264
|
+
log(`would create worktree .worktrees/${name}`);
|
|
265
|
+
}
|
|
266
|
+
else {
|
|
267
|
+
const wt = await ensureWorktree(process.cwd(), name);
|
|
268
|
+
log(`${wt.created ? "created" : "reusing"} worktree ${wt.path} (branch ${wt.branch})`);
|
|
269
|
+
cwd = wt.path;
|
|
270
|
+
worktreePath = wt.path;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
const sessionId = record?.id ?? options.session?.trim() ?? randomUUID();
|
|
274
|
+
if (!/^[A-Za-z0-9._:@-]{1,128}$/.test(sessionId)) {
|
|
275
|
+
throw new Error("--session must match ^[A-Za-z0-9._:@-]{1,128}$");
|
|
276
|
+
}
|
|
277
|
+
const harnessSessionId = record?.harnessSessionId ?? (harness === "claude" && !resumeLast ? sessionId : undefined);
|
|
278
|
+
const model = options.model ?? record?.model ?? (harness === "codex" ? endpoint.slug : undefined);
|
|
279
|
+
const now = new Date().toISOString();
|
|
280
|
+
const keyName = options.name?.trim() || `cli:${harness}:${os.hostname()}`;
|
|
281
|
+
let key;
|
|
282
|
+
if (!options.dryRun) {
|
|
283
|
+
key = await createKey(endpoint.id, {
|
|
284
|
+
name: keyName,
|
|
285
|
+
expiresIn,
|
|
286
|
+
...(budget !== undefined ? { spendLimitTokens: budget, spendPeriod: "never" } : {}),
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
const plan = planFor(harness, {
|
|
290
|
+
baseUrl: catalog.baseUrl,
|
|
291
|
+
apiKey: key?.key ?? DRY_RUN_KEY,
|
|
292
|
+
sessionId,
|
|
293
|
+
model,
|
|
294
|
+
resumeId: record ? record.harnessSessionId : undefined,
|
|
295
|
+
resumeLast,
|
|
296
|
+
prompt: options.prompt,
|
|
297
|
+
yolo: options.yolo,
|
|
298
|
+
yellow: options.yellow,
|
|
299
|
+
plan: options.plan,
|
|
300
|
+
passthrough,
|
|
301
|
+
env: process.env,
|
|
302
|
+
});
|
|
303
|
+
const banner = [
|
|
304
|
+
`endpoint=${endpoint.slug}`,
|
|
305
|
+
`model=${model ?? "(harness default → endpoint routes)"}`,
|
|
306
|
+
`key=${key ? `…${key.keyHint || maskKey(key.key ?? "")}` : "(dry run)"}`,
|
|
307
|
+
`expires=${expiresIn}${options.keepKey ? "" : " (revoked on exit)"}`,
|
|
308
|
+
budget !== undefined ? `budget=${budget.toLocaleString()} tokens` : undefined,
|
|
309
|
+
`session=${sessionId}`,
|
|
310
|
+
]
|
|
311
|
+
.filter(Boolean)
|
|
312
|
+
.join(" ");
|
|
313
|
+
log(banner);
|
|
314
|
+
log(`traces: ${endpointURL(endpoint.id)}`);
|
|
315
|
+
if (options.dryRun) {
|
|
316
|
+
const env = Object.fromEntries(Object.entries(plan.envSet).map(([k, v]) => [k, v === DRY_RUN_KEY ? "<key>" : v]));
|
|
317
|
+
process.stdout.write(`${JSON.stringify({
|
|
318
|
+
harness,
|
|
319
|
+
command: plan.command,
|
|
320
|
+
args: plan.args,
|
|
321
|
+
env,
|
|
322
|
+
unsetEnv: plan.envUnset,
|
|
323
|
+
cwd,
|
|
324
|
+
endpoint: { id: endpoint.id, slug: endpoint.slug, model: endpoint.model },
|
|
325
|
+
sessionId,
|
|
326
|
+
key: { name: keyName, expiresIn, spendLimitTokens: budget ?? null },
|
|
327
|
+
}, null, 2)}\n`);
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
if (!key)
|
|
331
|
+
throw new Error("internal: key was not minted");
|
|
332
|
+
const nextRecord = {
|
|
333
|
+
id: sessionId,
|
|
334
|
+
harness,
|
|
335
|
+
endpointId: endpoint.id,
|
|
336
|
+
endpointSlug: endpoint.slug,
|
|
337
|
+
keyId: key.id,
|
|
338
|
+
keyHint: key.keyHint,
|
|
339
|
+
harnessSessionId,
|
|
340
|
+
cwd: record?.cwd ?? process.cwd(),
|
|
341
|
+
worktree: worktreePath,
|
|
342
|
+
model,
|
|
343
|
+
createdAt: record?.createdAt ?? now,
|
|
344
|
+
lastLaunchedAt: now,
|
|
345
|
+
launches: (record?.launches ?? 0) + 1,
|
|
346
|
+
};
|
|
347
|
+
await writeSession(nextRecord);
|
|
348
|
+
const child = spawn(plan.command, plan.args, {
|
|
349
|
+
stdio: "inherit",
|
|
350
|
+
env: childEnv(plan, process.env),
|
|
351
|
+
cwd,
|
|
352
|
+
});
|
|
353
|
+
const restore = forwardSignals(child);
|
|
354
|
+
let exitCode = null;
|
|
355
|
+
try {
|
|
356
|
+
exitCode = await waitForExit(child);
|
|
357
|
+
}
|
|
358
|
+
finally {
|
|
359
|
+
restore();
|
|
360
|
+
if (options.keepKey) {
|
|
361
|
+
log(`kept key …${key.keyHint} (expires ${expiresIn}); revoke it from the Ditto app when done`);
|
|
362
|
+
}
|
|
363
|
+
else {
|
|
364
|
+
try {
|
|
365
|
+
await revokeKey(endpoint.id, key.id);
|
|
366
|
+
log(`revoked session key …${key.keyHint}; thread kept (resume with: heyditto ${harness} --resume ${sessionId})`);
|
|
367
|
+
}
|
|
368
|
+
catch (err) {
|
|
369
|
+
log(`could not revoke key …${key.keyHint} (${err instanceof Error ? err.message : String(err)}); it expires in ${expiresIn}`);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
await writeSession({ ...nextRecord, endedAt: new Date().toISOString(), exitCode });
|
|
373
|
+
}
|
|
374
|
+
process.exitCode = exitCode ?? 1;
|
|
375
|
+
}
|
|
376
|
+
//# sourceMappingURL=launch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"launch.js","sourceRoot":"","sources":["../../src/agents/launch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EACL,QAAQ,EAIR,cAAc,EACd,SAAS,EACT,YAAY,EACZ,iBAAiB,EACjB,aAAa,EACb,SAAS,GACV,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC1E,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAsB,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7F,OAAO,EAGL,YAAY,EAGZ,QAAQ,EACR,OAAO,EACP,cAAc,GACf,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAoBpE,MAAM,WAAW,GAAG,8BAA8B,CAAC;AAEnD,SAAS,GAAG,CAAC,IAAY;IACvB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC;AAC3C,CAAC;AAED,SAAS,OAAO,CAAC,OAAgB,EAAE,KAAgB;IACjD,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AACrE,CAAC;AAED,SAAS,eAAe,CAAC,OAAe;IACtC,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;IAC/D,OAAO,SAAS,CAAC,KAAK,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC;AACvE,CAAC;AAED,SAAS,WAAW,CAAC,GAAuB;IAC1C,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACxC,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;IAC3C,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,yDAAyD,GAAG,GAAG,CAAC,CAAC;IACrH,OAAO,CAAC,CAAC;AACX,CAAC;AAED,SAAS,WAAW,CAAC,GAAuB;IAC1C,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;IACnC,IAAK,YAAkC,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAkB,CAAC;IACnF,MAAM,IAAI,KAAK,CAAC,6BAA6B,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC1E,CAAC;AAED,SAAS,WAAW,CAAC,CAAoB;IACvC,MAAM,IAAI,GAAG,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC;IAChC,IAAI,CAAC,CAAC,gBAAgB,IAAI,IAAI,IAAI,CAAC,CAAC,gBAAgB,GAAG,CAAC;QAAE,OAAO,GAAG,IAAI,CAAC,cAAc,EAAE,wBAAwB,CAAC;IAClH,OAAO,GAAG,IAAI,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,gBAAgB,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AACnL,CAAC;AAED,SAAS,WAAW;IAClB,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC9D,CAAC;AAED,KAAK,UAAU,GAAG,CAAC,QAAgB;IACjC,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC7E,IAAI,CAAC;QACH,OAAO,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9C,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;AACH,CAAC;AAED,kDAAkD;AAClD,KAAK,UAAU,UAAU,CAAC,QAAgB;IACxC,MAAM,MAAM,GAAG,CAAC,MAAM,GAAG,CAAC,GAAG,QAAQ,SAAS,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IAC/D,OAAO,MAAM,KAAK,EAAE,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,KAAK,CAAC;AAC7D,CAAC;AAED,sGAAsG;AACtG,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,SAA8B,EAAE,WAAoB;IACrF,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CACb,sGAAsG,CACvG,CAAC;IACJ,CAAC;IACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACvD,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACzB,MAAM,KAAK,GAAG;YACZ,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;YACvC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE;SACvC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAClB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,CACvI,CAAC;QACF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,gBAAgB,IAAI,CAAC,CAAC;IACxG,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC3B,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC7E,IAAI,CAAC;QACH,SAAS,CAAC;YACR,MAAM,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iCAAiC,SAAS,CAAC,MAAM,eAAe,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAC5G,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;YAC3B,IAAI,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,SAAS,CAAC,MAAM;gBAAE,OAAO,SAAS,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;YAC5F,MAAM,MAAM,GAAG,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;YAC/C,IAAI,MAAM;gBAAE,OAAO,MAAM,CAAC;YAC1B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,2BAA2B,SAAS,CAAC,MAAM,+BAA+B,CAAC,CAAC;QACnG,CAAC;IACH,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;AACH,CAAC;AAED,yGAAyG;AACzG,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,QAA2B;IACpE,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC;QAAE,OAAO;IACzC,MAAM,MAAM,GAAG,MAAM,cAAc,EAAE,CAAC;IACtC,MAAM,OAAO,GAAG,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC7D,MAAM,IAAI,KAAK,CACb,aAAa,QAAQ,CAAC,IAAI,wBAAwB,QAAQ,CAAC,MAAM,SAAS,OAAO,EAAE,CACpF,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,eAAe,CAC5B,MAA0B,EAC1B,SAA8B,EAC9B,QAAsC;IAEtC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,IAAI,WAAW,EAAE,IAAI,CAAC,MAAM,UAAU,CAAC,iEAAiE,CAAC,CAAC,EAAE,CAAC;YAC3G,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,EAAE,CAAC,CAAC;YACzC,GAAG,CAAC,oBAAoB,OAAO,CAAC,IAAI,WAAW,OAAO,CAAC,KAAK,GAAG,CAAC,CAAC;YACjE,MAAM,gBAAgB,CAAC,EAAE,eAAe,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;YAC1D,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,MAAM,IAAI,KAAK,CACb,6FAA6F,WAAW,EAAE,GAAG,CAC9G,CAAC;IACJ,CAAC;IACD,MAAM,MAAM,GAAG,CAAC,MAAM,cAAc,EAAE,CAAC,EAAE,eAAe,CAAC;IACzD,IAAI,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC;QACnB,MAAM,KAAK,GAAG,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QAC9C,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,sBAAsB,MAAM,CAAC,IAAI,EAAE,iBAAiB,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjH,CAAC;IACD,IAAI,QAAQ,EAAE,CAAC;QACb,6DAA6D;QAC7D,MAAM,KAAK,GAAG,YAAY,CAAC,SAAS,EAAE,QAAQ,CAAC,EAAE,CAAC,IAAI,YAAY,CAAC,SAAS,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC7F,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;QACxB,GAAG,CAAC,aAAa,QAAQ,CAAC,IAAI,2DAA2D,CAAC,CAAC;IAC7F,CAAC;IACD,IAAI,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC;QACnB,MAAM,KAAK,GAAG,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QAC9C,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;QACxB,GAAG,CAAC,qBAAqB,MAAM,CAAC,IAAI,EAAE,kCAAkC,CAAC,CAAC;IAC5E,CAAC;IACD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC;IAChD,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IACrD,IAAI,MAAM,UAAU,CAAC,OAAO,MAAM,CAAC,IAAI,wBAAwB,CAAC,EAAE,CAAC;QACjE,MAAM,gBAAgB,CAAC,EAAE,eAAe,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QACzD,GAAG,CAAC,2BAA2B,MAAM,CAAC,IAAI,qDAAqD,CAAC,CAAC;IACnG,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,cAAc,CAAC,OAAgB;IAC5C,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,aAAa,EAAE,CAAC;IACtC,IAAI,GAAG;QAAE,OAAO,SAAS,CAAC;IAC1B,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;QACnB,+DAA+D;QAC/D,MAAM,aAAa,EAAE,CAAC,CAAC,wDAAwD;QAC/E,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,GAAG,CAAC,iFAAiF,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC;IACxI,OAAO,YAAY,CAAC,OAAO,CAAC,CAAC;AAC/B,CAAC;AAED,uEAAuE;AACvE,KAAK,UAAU,YAAY,CAAC,OAAgB;IAC1C,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC;QAC/B,MAAM,EAAE,OAAO;QACf,MAAM,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE;YACxB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,eAAe,QAAQ,MAAM,CAAC,CAAC;YAC9D,aAAa,CAAC,GAAG,CAAC,CAAC;YACnB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,2DAA2D,CAAC,CAAC;QACpF,CAAC;KACF,CAAC,CAAC;IACH,MAAM,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACtH,GAAG,CAAC,YAAY,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,cAAc,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC9H,OAAO,MAAM,CAAC,QAAQ,CAAC;AACzB,CAAC;AAED,SAAS,cAAc,CAAC,KAAmB;IACzC,qEAAqE;IACrE,sEAAsE;IACtE,MAAM,KAAK,GAAG,GAAG,EAAE;QACjB,0CAA0C;IAC5C,CAAC,CAAC;IACF,MAAM,MAAM,GAAG,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACzC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC5B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAC9B,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC5B,OAAO,GAAG,EAAE;QACV,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QAC/B,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC/B,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,KAAmB;IACtC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC1B,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACnH,CAAC,CAAC,CAAC;AACL,CAAC;AAED,yFAAyF;AACzF,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAgB,EAAE,OAAiB,EAAE,OAAsB;IAC7F,MAAM,WAAW,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3C,MAAM,SAAS,GAAG,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/C,IAAI,OAAO,CAAC,IAAI,IAAI,OAAO,KAAK,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IACjG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5E,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACjE,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,IAAI,OAAO,CAAC,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IAC3G,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,IAAI,OAAO,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAEnH,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,EAAE;YAC5B,OAAO,EAAE,EAAE;YACX,MAAM,EAAE,EAAE;YACV,SAAS,EAAE,EAAE;YACb,WAAW,EAAE,EAAE;YACf,GAAG,EAAE,EAAE;SACR,CAAC,CAAC,WAAW,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,IAAI,OAAO,0BAA0B,IAAI,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED,0EAA0E;IAC1E,uDAAuD;IACvD,IAAI,MAAiC,CAAC;IACtC,IAAI,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC3C,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QACjC,MAAM;YACJ,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ;gBAChC,CAAC,CAAC,MAAM,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC;gBACnC,CAAC,CAAC,MAAM,aAAa,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;QAClD,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CACb,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ;gBAChC,CAAC,CAAC,qBAAqB,OAAO,CAAC,MAAM,8BAA8B;gBACnE,CAAC,CAAC,eAAe,OAAO,+CAA+C,CAC1E,CAAC;QACJ,CAAC;QACD,IAAI,MAAM,CAAC,OAAO,KAAK,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,WAAW,MAAM,CAAC,EAAE,UAAU,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;QACxG,IAAI,CAAC,MAAM,CAAC,gBAAgB;YAAE,UAAU,GAAG,IAAI,CAAC;IAClD,CAAC;IAED,IAAI,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,cAAc,CAAC,OAAO,CAAC,CAAC;IAC1E,IAAI,OAAkD,CAAC;IACvD,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,aAAa,EAAE,CAAC;IAClC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,wEAAwE;QACxE,6CAA6C;QAC7C,IAAI,CAAC,CAAC,GAAG,YAAY,QAAQ,CAAC,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,OAAO,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE;YAAE,MAAM,GAAG,CAAC;QACpG,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,EAAE,CAAC;QACzC,IAAI,MAAM,KAAK,QAAQ;YAAE,MAAM,GAAG,CAAC;QACnC,GAAG,CAAC,oFAAoF,CAAC,CAAC;QAC1F,QAAQ,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,CAAC;QACvC,OAAO,GAAG,MAAM,aAAa,EAAE,CAAC;IAClC,CAAC;IACD,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,OAAO,CAAC,QAAQ,IAAI,MAAM,EAAE,YAAY,EAAE,OAAO,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAC9G,MAAM,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IAErC,IAAI,GAAG,GAAG,MAAM,EAAE,QAAQ,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAC5C,IAAI,YAAY,GAAuB,MAAM,EAAE,QAAQ,CAAC;IACxD,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS,IAAI,OAAO,CAAC,QAAQ,KAAK,KAAK,EAAE,CAAC;QACjE,MAAM,IAAI,GAAG,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC;QACpG,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnB,GAAG,CAAC,oCAAoC,IAAI,EAAE,CAAC,CAAC;QAClD,CAAC;aAAM,CAAC;YACN,MAAM,EAAE,GAAG,MAAM,cAAc,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;YACrD,GAAG,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,aAAa,EAAE,CAAC,IAAI,YAAY,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;YACvF,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC;YACd,YAAY,GAAG,EAAE,CAAC,IAAI,CAAC;QACzB,CAAC;IACH,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,EAAE,EAAE,IAAI,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,UAAU,EAAE,CAAC;IACxE,IAAI,CAAC,2BAA2B,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IACpE,CAAC;IACD,MAAM,gBAAgB,GAAG,MAAM,EAAE,gBAAgB,IAAI,CAAC,OAAO,KAAK,QAAQ,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACnH,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,MAAM,EAAE,KAAK,IAAI,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAClG,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAErC,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,OAAO,OAAO,IAAI,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC;IAC1E,IAAI,GAA6B,CAAC;IAClC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;QACpB,GAAG,GAAG,MAAM,SAAS,CAAC,QAAQ,CAAC,EAAE,EAAE;YACjC,IAAI,EAAE,OAAO;YACb,SAAS;YACT,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACpF,CAAC,CAAC;IACL,CAAC;IAED,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,EAAE;QAC5B,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,WAAW;QAC/B,SAAS;QACT,KAAK;QACL,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,SAAS;QACtD,UAAU;QACV,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,WAAW;QACX,GAAG,EAAE,OAAO,CAAC,GAAG;KACjB,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG;QACb,YAAY,QAAQ,CAAC,IAAI,EAAE;QAC3B,SAAS,KAAK,IAAI,qCAAqC,EAAE;QACzD,OAAO,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE;QACxE,WAAW,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,oBAAoB,EAAE;QACpE,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,UAAU,MAAM,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC,CAAC,SAAS;QAC7E,WAAW,SAAS,EAAE;KACvB;SACE,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,IAAI,CAAC,CAAC;IACd,GAAG,CAAC,MAAM,CAAC,CAAC;IACZ,GAAG,CAAC,WAAW,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAE3C,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,MAAM,GAAG,GAAG,MAAM,CAAC,WAAW,CAC5B,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAClF,CAAC;QACF,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,GAAG,IAAI,CAAC,SAAS,CACf;YACE,OAAO;YACP,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,GAAG;YACH,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,GAAG;YACH,QAAQ,EAAE,EAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE;YACzE,SAAS;YACT,GAAG,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,IAAI,IAAI,EAAE;SACpE,EACD,IAAI,EACJ,CAAC,CACF,IAAI,CACN,CAAC;QACF,OAAO;IACT,CAAC;IACD,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAE1D,MAAM,UAAU,GAAkB;QAChC,EAAE,EAAE,SAAS;QACb,OAAO;QACP,UAAU,EAAE,QAAQ,CAAC,EAAE;QACvB,YAAY,EAAE,QAAQ,CAAC,IAAI;QAC3B,KAAK,EAAE,GAAG,CAAC,EAAE;QACb,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,gBAAgB;QAChB,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE;QACjC,QAAQ,EAAE,YAAY;QACtB,KAAK;QACL,SAAS,EAAE,MAAM,EAAE,SAAS,IAAI,GAAG;QACnC,cAAc,EAAE,GAAG;QACnB,QAAQ,EAAE,CAAC,MAAM,EAAE,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC;KACtC,CAAC;IACF,MAAM,YAAY,CAAC,UAAU,CAAC,CAAC;IAE/B,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE;QAC3C,KAAK,EAAE,SAAS;QAChB,GAAG,EAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC;QAChC,GAAG;KACJ,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IACtC,IAAI,QAAQ,GAAkB,IAAI,CAAC;IACnC,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,CAAC;IACtC,CAAC;YAAS,CAAC;QACT,OAAO,EAAE,CAAC;QACV,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,GAAG,CAAC,aAAa,GAAG,CAAC,OAAO,aAAa,SAAS,2CAA2C,CAAC,CAAC;QACjG,CAAC;aAAM,CAAC;YACN,IAAI,CAAC;gBACH,MAAM,SAAS,CAAC,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;gBACrC,GAAG,CAAC,wBAAwB,GAAG,CAAC,OAAO,wCAAwC,OAAO,aAAa,SAAS,GAAG,CAAC,CAAC;YACnH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,GAAG,CAAC,yBAAyB,GAAG,CAAC,OAAO,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,oBAAoB,SAAS,EAAE,CAAC,CAAC;YAChI,CAAC;QACH,CAAC;QACD,MAAM,YAAY,CAAC,EAAE,GAAG,UAAU,EAAE,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;IACrF,CAAC;IACD,OAAO,CAAC,QAAQ,GAAG,QAAQ,IAAI,CAAC,CAAC;AACnC,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Harness } from "./types.js";
|
|
2
|
+
/** One coding-agent session launched by the CLI; the Ditto session id is the file name. */
|
|
3
|
+
export interface SessionRecord {
|
|
4
|
+
id: string;
|
|
5
|
+
harness: Harness;
|
|
6
|
+
endpointId: string;
|
|
7
|
+
endpointSlug: string;
|
|
8
|
+
/** Last key minted for this session; revoked on exit unless --keep-key. */
|
|
9
|
+
keyId?: string;
|
|
10
|
+
keyHint?: string;
|
|
11
|
+
/** Harness-native id used to resume (Claude's --session-id; Codex thread id when known). */
|
|
12
|
+
harnessSessionId?: string;
|
|
13
|
+
cwd: string;
|
|
14
|
+
worktree?: string;
|
|
15
|
+
model?: string;
|
|
16
|
+
createdAt: string;
|
|
17
|
+
lastLaunchedAt: string;
|
|
18
|
+
endedAt?: string;
|
|
19
|
+
exitCode?: number | null;
|
|
20
|
+
launches: number;
|
|
21
|
+
}
|
|
22
|
+
export declare function writeSession(record: SessionRecord): Promise<void>;
|
|
23
|
+
export declare function readSession(id: string): Promise<SessionRecord | undefined>;
|
|
24
|
+
export declare function removeSession(id: string): Promise<boolean>;
|
|
25
|
+
/** All local records, most recently launched first. */
|
|
26
|
+
export declare function listSessions(): Promise<SessionRecord[]>;
|
|
27
|
+
/** Most recent record for a harness, preferring one launched from the same directory. */
|
|
28
|
+
export declare function latestSession(harness: Harness, cwd: string): Promise<SessionRecord | undefined>;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { sessionsDir } from "../config.js";
|
|
4
|
+
function fileFor(id) {
|
|
5
|
+
if (!/^[A-Za-z0-9._:@-]{1,128}$/.test(id))
|
|
6
|
+
throw new Error(`invalid session id: ${id}`);
|
|
7
|
+
return path.join(sessionsDir(), `${id}.json`);
|
|
8
|
+
}
|
|
9
|
+
export async function writeSession(record) {
|
|
10
|
+
await mkdir(sessionsDir(), { recursive: true, mode: 0o700 });
|
|
11
|
+
await writeFile(fileFor(record.id), `${JSON.stringify(record, null, 2)}\n`, { mode: 0o600 });
|
|
12
|
+
}
|
|
13
|
+
export async function readSession(id) {
|
|
14
|
+
try {
|
|
15
|
+
return JSON.parse(await readFile(fileFor(id), "utf8"));
|
|
16
|
+
}
|
|
17
|
+
catch (err) {
|
|
18
|
+
if (err.code === "ENOENT")
|
|
19
|
+
return undefined;
|
|
20
|
+
throw err;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export async function removeSession(id) {
|
|
24
|
+
try {
|
|
25
|
+
await rm(fileFor(id));
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
if (err.code === "ENOENT")
|
|
30
|
+
return false;
|
|
31
|
+
throw err;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/** All local records, most recently launched first. */
|
|
35
|
+
export async function listSessions() {
|
|
36
|
+
let names;
|
|
37
|
+
try {
|
|
38
|
+
names = await readdir(sessionsDir());
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
if (err.code === "ENOENT")
|
|
42
|
+
return [];
|
|
43
|
+
throw err;
|
|
44
|
+
}
|
|
45
|
+
const records = [];
|
|
46
|
+
for (const name of names) {
|
|
47
|
+
if (!name.endsWith(".json"))
|
|
48
|
+
continue;
|
|
49
|
+
try {
|
|
50
|
+
records.push(JSON.parse(await readFile(path.join(sessionsDir(), name), "utf8")));
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
/* skip unreadable record */
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return records.sort((a, b) => (b.lastLaunchedAt ?? "").localeCompare(a.lastLaunchedAt ?? ""));
|
|
57
|
+
}
|
|
58
|
+
/** Most recent record for a harness, preferring one launched from the same directory. */
|
|
59
|
+
export async function latestSession(harness, cwd) {
|
|
60
|
+
const all = (await listSessions()).filter((s) => s.harness === harness);
|
|
61
|
+
return all.find((s) => s.cwd === cwd || s.worktree === cwd) ?? all[0];
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=sessions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessions.js","sourceRoot":"","sources":["../../src/agents/sessions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/** Shared types for the coding-agent launchers. Pure data, no I/O. */
|
|
2
|
+
export type Harness = "claude" | "codex";
|
|
3
|
+
export declare const HARNESSES: readonly Harness[];
|
|
4
|
+
export declare const KEY_EXPIRIES: readonly ["1h", "4h", "8h", "12h", "1d", "1w", "1mo", "3mo", "6mo", "1y", "never"];
|
|
5
|
+
export type KeyExpiry = (typeof KEY_EXPIRIES)[number];
|
|
6
|
+
/** Header the Ditto gateway groups turns by; every launch sends one. */
|
|
7
|
+
export declare const SESSION_HEADER = "X-Ditto-Session-Id";
|
|
8
|
+
/** Env var the Codex provider reads the endpoint key from. */
|
|
9
|
+
export declare const CODEX_KEY_ENV = "DITTO_INFERENCE_API_KEY";
|
|
10
|
+
/** Everything a harness planner needs to build argv + env. */
|
|
11
|
+
export interface PlanInput {
|
|
12
|
+
/** Inference gateway base URL ending in /v1, e.g. https://api.heyditto.ai/v1 */
|
|
13
|
+
baseUrl: string;
|
|
14
|
+
/** Plaintext endpoint key (already minted) or a placeholder for --dry-run. */
|
|
15
|
+
apiKey: string;
|
|
16
|
+
/** Ditto session id sent as X-Ditto-Session-Id. */
|
|
17
|
+
sessionId: string;
|
|
18
|
+
/** Model id to request; undefined leaves the harness default (gateway routes it). */
|
|
19
|
+
model?: string;
|
|
20
|
+
/** Harness-native session/thread id to resume, when resuming. */
|
|
21
|
+
resumeId?: string;
|
|
22
|
+
/** Resume the most recent harness session (claude --continue / codex resume --last). */
|
|
23
|
+
resumeLast?: boolean;
|
|
24
|
+
/** Headless prompt: claude -p / codex exec. */
|
|
25
|
+
prompt?: string;
|
|
26
|
+
yolo?: boolean;
|
|
27
|
+
yellow?: boolean;
|
|
28
|
+
plan?: boolean;
|
|
29
|
+
/** Extra argv forwarded verbatim to the harness. */
|
|
30
|
+
passthrough: string[];
|
|
31
|
+
/** Parent environment to derive the child environment from. */
|
|
32
|
+
env: NodeJS.ProcessEnv;
|
|
33
|
+
}
|
|
34
|
+
export interface HarnessPlan {
|
|
35
|
+
command: string;
|
|
36
|
+
args: string[];
|
|
37
|
+
/** Env vars set on the child (in addition to the inherited environment). */
|
|
38
|
+
envSet: Record<string, string>;
|
|
39
|
+
/** Env vars removed from the child environment. */
|
|
40
|
+
envUnset: string[];
|
|
41
|
+
/** Human-readable install hint when the binary is missing. */
|
|
42
|
+
installHint: string;
|
|
43
|
+
}
|
|
44
|
+
/** Strips the first `--` separator commander leaves in a variadic passthrough list. */
|
|
45
|
+
export declare function stripSeparator(args: string[]): string[];
|
|
46
|
+
/** Applies a plan's env changes to a copy of the given environment. */
|
|
47
|
+
export declare function childEnv(plan: HarnessPlan, parent: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
48
|
+
/** Base URL with a trailing /v1 removed: what ANTHROPIC_BASE_URL expects. */
|
|
49
|
+
export declare function apiRootOf(baseUrl: string): string;
|
|
50
|
+
export declare function maskKey(key: string): string;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/** Shared types for the coding-agent launchers. Pure data, no I/O. */
|
|
2
|
+
export const HARNESSES = ["claude", "codex"];
|
|
3
|
+
export const KEY_EXPIRIES = [
|
|
4
|
+
"1h",
|
|
5
|
+
"4h",
|
|
6
|
+
"8h",
|
|
7
|
+
"12h",
|
|
8
|
+
"1d",
|
|
9
|
+
"1w",
|
|
10
|
+
"1mo",
|
|
11
|
+
"3mo",
|
|
12
|
+
"6mo",
|
|
13
|
+
"1y",
|
|
14
|
+
"never",
|
|
15
|
+
];
|
|
16
|
+
/** Header the Ditto gateway groups turns by; every launch sends one. */
|
|
17
|
+
export const SESSION_HEADER = "X-Ditto-Session-Id";
|
|
18
|
+
/** Env var the Codex provider reads the endpoint key from. */
|
|
19
|
+
export const CODEX_KEY_ENV = "DITTO_INFERENCE_API_KEY";
|
|
20
|
+
/** Strips the first `--` separator commander leaves in a variadic passthrough list. */
|
|
21
|
+
export function stripSeparator(args) {
|
|
22
|
+
const i = args.indexOf("--");
|
|
23
|
+
if (i === -1)
|
|
24
|
+
return args;
|
|
25
|
+
return [...args.slice(0, i), ...args.slice(i + 1)];
|
|
26
|
+
}
|
|
27
|
+
/** Applies a plan's env changes to a copy of the given environment. */
|
|
28
|
+
export function childEnv(plan, parent) {
|
|
29
|
+
const env = { ...parent };
|
|
30
|
+
for (const k of plan.envUnset)
|
|
31
|
+
delete env[k];
|
|
32
|
+
Object.assign(env, plan.envSet);
|
|
33
|
+
return env;
|
|
34
|
+
}
|
|
35
|
+
/** Base URL with a trailing /v1 removed: what ANTHROPIC_BASE_URL expects. */
|
|
36
|
+
export function apiRootOf(baseUrl) {
|
|
37
|
+
return baseUrl.replace(/\/+$/, "").replace(/\/v1$/, "");
|
|
38
|
+
}
|
|
39
|
+
export function maskKey(key) {
|
|
40
|
+
if (key.length <= 8)
|
|
41
|
+
return "…";
|
|
42
|
+
return `${key.slice(0, 10)}…${key.slice(-4)}`;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/agents/types.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAItE,MAAM,CAAC,MAAM,SAAS,GAAuB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AAEjE,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,KAAK;IACL,IAAI;IACJ,IAAI;IACJ,KAAK;IACL,KAAK;IACL,KAAK;IACL,IAAI;IACJ,OAAO;CACC,CAAC;AAGX,wEAAwE;AACxE,MAAM,CAAC,MAAM,cAAc,GAAG,oBAAoB,CAAC;AAEnD,8DAA8D;AAC9D,MAAM,CAAC,MAAM,aAAa,GAAG,yBAAyB,CAAC;AAsCvD,uFAAuF;AACvF,MAAM,UAAU,cAAc,CAAC,IAAc;IAC3C,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,IAAI,CAAC,KAAK,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1B,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACrD,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,QAAQ,CAAC,IAAiB,EAAE,MAAyB;IACnE,MAAM,GAAG,GAAsB,EAAE,GAAG,MAAM,EAAE,CAAC;IAC7C,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ;QAAE,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC;IAC7C,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAChC,OAAO,GAAG,CAAC;AACb,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,SAAS,CAAC,OAAe;IACvC,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,GAAW;IACjC,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO,GAAG,CAAC;IAChC,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAChD,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Harness } from "./types.js";
|
|
2
|
+
/** Folder inside the repository that holds the CLI's worktrees (kept out of git). */
|
|
3
|
+
export declare const WORKTREES_DIR = ".worktrees";
|
|
4
|
+
/** `<harness>-<yyyymmdd-hhmm>`, e.g. `claude-20260904-1530`. */
|
|
5
|
+
export declare function defaultWorktreeName(harness: Harness, now?: Date): string;
|
|
6
|
+
export declare function validWorktreeName(name: string): boolean;
|
|
7
|
+
export declare function repoRoot(cwd: string): string | undefined;
|
|
8
|
+
/** Adds `.worktrees/` to the repo root .gitignore when it is not already listed. */
|
|
9
|
+
export declare function ensureGitignore(root: string): Promise<boolean>;
|
|
10
|
+
export interface WorktreeResult {
|
|
11
|
+
path: string;
|
|
12
|
+
branch: string;
|
|
13
|
+
created: boolean;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Creates (or reuses) `<repo>/.worktrees/<name>` on a branch of the same
|
|
17
|
+
* name, mirroring how Claude Code keeps worktrees inside the repository.
|
|
18
|
+
*/
|
|
19
|
+
export declare function ensureWorktree(cwd: string, name: string): Promise<WorktreeResult>;
|