@cabane/companion 0.6.19 → 0.6.20
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/dist/cli.js +100 -626
- package/dist/runtime.js +82 -608
- package/package.json +2 -1
package/dist/runtime.js
CHANGED
|
@@ -309,14 +309,14 @@ function localAgentConfig(cfg, agent) {
|
|
|
309
309
|
return map[agent.agentId] ?? map[agent.agentUsername] ?? map[`${agent.workspaceSlug}/${agent.agentUsername}`] ?? {};
|
|
310
310
|
}
|
|
311
311
|
function loadConfig() {
|
|
312
|
-
const
|
|
313
|
-
if (!existsSync(
|
|
312
|
+
const path = configPath();
|
|
313
|
+
if (!existsSync(path)) return null;
|
|
314
314
|
let raw;
|
|
315
315
|
try {
|
|
316
|
-
raw = readFileSync(
|
|
316
|
+
raw = readFileSync(path, "utf8");
|
|
317
317
|
} catch (err) {
|
|
318
318
|
throw new ConfigError(
|
|
319
|
-
`couldn't read ${
|
|
319
|
+
`couldn't read ${path}: ${err instanceof Error ? err.message : String(err)}`
|
|
320
320
|
);
|
|
321
321
|
}
|
|
322
322
|
if (raw.trim().length === 0) return null;
|
|
@@ -325,7 +325,7 @@ function loadConfig() {
|
|
|
325
325
|
parsed = JSON.parse(raw);
|
|
326
326
|
} catch (err) {
|
|
327
327
|
throw new ConfigError(
|
|
328
|
-
`${
|
|
328
|
+
`${path} is not valid JSON: ${err instanceof Error ? err.message : String(err)}`
|
|
329
329
|
);
|
|
330
330
|
}
|
|
331
331
|
const result = companionConfigSchema.safeParse(parsed);
|
|
@@ -333,30 +333,30 @@ function loadConfig() {
|
|
|
333
333
|
const agentIssue = result.error.issues.find((i) => i.path[0] === "agents");
|
|
334
334
|
if (agentIssue) {
|
|
335
335
|
throw new ConfigError(
|
|
336
|
-
`${
|
|
336
|
+
`${path}: invalid "agents" config at \`${agentIssue.path.join(".")}\` \u2014 ${agentIssue.message}. Fix the agents block in the config and retry.`
|
|
337
337
|
);
|
|
338
338
|
}
|
|
339
339
|
throw new ConfigError(
|
|
340
|
-
`${
|
|
340
|
+
`${path} is from an incompatible or older version of the companion, or was hand-edited. Run \`cabane-companion pair\` to re-pair, or \`cabane-companion logout --purge\` to reset.`
|
|
341
341
|
);
|
|
342
342
|
}
|
|
343
343
|
return result.data;
|
|
344
344
|
}
|
|
345
345
|
function saveConfig(cfg) {
|
|
346
|
-
const
|
|
347
|
-
mkdirSync(dirname(
|
|
346
|
+
const path = configPath();
|
|
347
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
348
348
|
try {
|
|
349
349
|
chmodSync(cabaneDir(), 448);
|
|
350
350
|
} catch {
|
|
351
351
|
}
|
|
352
|
-
const tmp = `${
|
|
352
|
+
const tmp = `${path}.${process.pid}.tmp`;
|
|
353
353
|
try {
|
|
354
354
|
writeFileSync(tmp, JSON.stringify(cfg, null, 2) + "\n", { mode: 384 });
|
|
355
355
|
try {
|
|
356
356
|
chmodSync(tmp, 384);
|
|
357
357
|
} catch {
|
|
358
358
|
}
|
|
359
|
-
renameSync(tmp,
|
|
359
|
+
renameSync(tmp, path);
|
|
360
360
|
} catch (err) {
|
|
361
361
|
try {
|
|
362
362
|
rmSync(tmp, { force: true });
|
|
@@ -417,8 +417,8 @@ function consoleMessageFormat(log, messageKey) {
|
|
|
417
417
|
var cached = null;
|
|
418
418
|
function getLogger() {
|
|
419
419
|
if (cached) return cached;
|
|
420
|
-
const
|
|
421
|
-
mkdirSync2(dirname2(
|
|
420
|
+
const path = companionLogPath();
|
|
421
|
+
mkdirSync2(dirname2(path), { recursive: true });
|
|
422
422
|
const streams = [];
|
|
423
423
|
if (process.env.CABANE_COMPANION_DAEMON !== "1") {
|
|
424
424
|
const consoleStream = pretty({
|
|
@@ -428,7 +428,7 @@ function getLogger() {
|
|
|
428
428
|
});
|
|
429
429
|
streams.push({ level: "info", stream: consoleStream });
|
|
430
430
|
}
|
|
431
|
-
streams.push({ level: "debug", stream: createWriteStream(
|
|
431
|
+
streams.push({ level: "debug", stream: createWriteStream(path, { flags: "a" }) });
|
|
432
432
|
cached = pino({ level: "debug" }, pino.multistream(streams));
|
|
433
433
|
return cached;
|
|
434
434
|
}
|
|
@@ -807,12 +807,12 @@ function clampLimit(raw, fallback, max = 200) {
|
|
|
807
807
|
if (!Number.isFinite(n) || n <= 0) return fallback;
|
|
808
808
|
return Math.min(Math.floor(n), max);
|
|
809
809
|
}
|
|
810
|
-
function tailFile(
|
|
811
|
-
if (!existsSync2(
|
|
810
|
+
function tailFile(path, lines) {
|
|
811
|
+
if (!existsSync2(path)) return [];
|
|
812
812
|
const MAX_BYTES = 256 * 1024;
|
|
813
813
|
let fd;
|
|
814
814
|
try {
|
|
815
|
-
fd = openSync(
|
|
815
|
+
fd = openSync(path, "r");
|
|
816
816
|
const size = fstatSync(fd).size;
|
|
817
817
|
const start = Math.max(0, size - MAX_BYTES);
|
|
818
818
|
const len = size - start;
|
|
@@ -1054,9 +1054,9 @@ function serialize(state) {
|
|
|
1054
1054
|
return JSON.stringify(state, null, 2) + "\n";
|
|
1055
1055
|
}
|
|
1056
1056
|
function writeRuntimeState(state) {
|
|
1057
|
-
const
|
|
1057
|
+
const path = runtimePath();
|
|
1058
1058
|
mkdirSync3(cabaneDir(), { recursive: true });
|
|
1059
|
-
writeFileSync2(
|
|
1059
|
+
writeFileSync2(path, serialize(state), "utf8");
|
|
1060
1060
|
}
|
|
1061
1061
|
function acquireRuntimeState(state) {
|
|
1062
1062
|
const live = readLiveRuntimeState();
|
|
@@ -1076,15 +1076,15 @@ function acquireRuntimeState(state) {
|
|
|
1076
1076
|
return { acquired: true };
|
|
1077
1077
|
}
|
|
1078
1078
|
function clearRuntimeState() {
|
|
1079
|
-
const
|
|
1080
|
-
if (existsSync3(
|
|
1079
|
+
const path = runtimePath();
|
|
1080
|
+
if (existsSync3(path)) rmSync2(path, { force: true });
|
|
1081
1081
|
}
|
|
1082
1082
|
function readLiveRuntimeState() {
|
|
1083
|
-
const
|
|
1084
|
-
if (!existsSync3(
|
|
1083
|
+
const path = runtimePath();
|
|
1084
|
+
if (!existsSync3(path)) return null;
|
|
1085
1085
|
let parsed;
|
|
1086
1086
|
try {
|
|
1087
|
-
parsed = JSON.parse(readFileSync2(
|
|
1087
|
+
parsed = JSON.parse(readFileSync2(path, "utf8"));
|
|
1088
1088
|
} catch {
|
|
1089
1089
|
return null;
|
|
1090
1090
|
}
|
|
@@ -1148,8 +1148,8 @@ var CabaneApi = class {
|
|
|
1148
1148
|
// One HTTP attempt — no retry. Throws `ApiError` on a 4xx/5xx response and
|
|
1149
1149
|
// rethrows transport errors (fetch reject) unchanged so the caller's retry
|
|
1150
1150
|
// logic can classify them.
|
|
1151
|
-
async attempt(method,
|
|
1152
|
-
const res = await fetch(`${this.base}${
|
|
1151
|
+
async attempt(method, path, body, signal) {
|
|
1152
|
+
const res = await fetch(`${this.base}${path}`, {
|
|
1153
1153
|
method,
|
|
1154
1154
|
headers: {
|
|
1155
1155
|
Authorization: `Bearer ${this.opts.token}`,
|
|
@@ -1175,12 +1175,12 @@ var CabaneApi = class {
|
|
|
1175
1175
|
}
|
|
1176
1176
|
return parsed;
|
|
1177
1177
|
}
|
|
1178
|
-
async request(method,
|
|
1178
|
+
async request(method, path, body, opts = {}) {
|
|
1179
1179
|
const { signal, retry = false } = opts;
|
|
1180
1180
|
const maxAttempts = retry ? RETRY_BACKOFF_MS.length + 1 : 1;
|
|
1181
1181
|
for (let attempt = 1; ; attempt++) {
|
|
1182
1182
|
try {
|
|
1183
|
-
return await this.attempt(method,
|
|
1183
|
+
return await this.attempt(method, path, body, signal);
|
|
1184
1184
|
} catch (err) {
|
|
1185
1185
|
if (attempt >= maxAttempts || signal?.aborted || !isRetryable(err)) throw err;
|
|
1186
1186
|
await sleep(RETRY_BACKOFF_MS[attempt - 1], signal);
|
|
@@ -1206,9 +1206,9 @@ var CabaneApi = class {
|
|
|
1206
1206
|
// delivers it once the API returns. `(turnId, seq)` is the server's
|
|
1207
1207
|
// idempotency key, so a replay whose original POST's fate is unknown
|
|
1208
1208
|
// converges instead of duplicating.
|
|
1209
|
-
async durableCommit(kind,
|
|
1209
|
+
async durableCommit(kind, path, body, turnId, seq, signal) {
|
|
1210
1210
|
try {
|
|
1211
|
-
await this.request("POST",
|
|
1211
|
+
await this.request("POST", path, body, {
|
|
1212
1212
|
retry: true,
|
|
1213
1213
|
...signal ? { signal } : {}
|
|
1214
1214
|
});
|
|
@@ -1217,7 +1217,7 @@ var CabaneApi = class {
|
|
|
1217
1217
|
if (!outbox) throw err;
|
|
1218
1218
|
if (signal?.aborted || isAbortError(err)) throw err;
|
|
1219
1219
|
if (!isRetryable(err)) throw err;
|
|
1220
|
-
outbox.persist({ enqueuedAt: Date.now(), turnId, seq, method: "POST", path
|
|
1220
|
+
outbox.persist({ enqueuedAt: Date.now(), turnId, seq, method: "POST", path, body, kind });
|
|
1221
1221
|
this.opts.log?.warn(
|
|
1222
1222
|
{ kind, turnId, seq, err: err instanceof Error ? err.message : String(err) },
|
|
1223
1223
|
"companion: commit queued to outbox after transient failure (will drain when the API returns)"
|
|
@@ -1369,12 +1369,12 @@ var CabaneApi = class {
|
|
|
1369
1369
|
// left best-effort: it's lower-stakes and self-heals on the next turn, so it
|
|
1370
1370
|
// stays a single-shot PATCH and is deliberately out of CT93's scope.
|
|
1371
1371
|
setActiveRun(workspaceId, conversationId, agentId, body) {
|
|
1372
|
-
const
|
|
1372
|
+
const path = `/api/workspaces/${workspaceId}/conversations/${conversationId}/participants/agents/${agentId}/active-run`;
|
|
1373
1373
|
const touchesFlag = Object.prototype.hasOwnProperty.call(body, "activeRunStartedAt");
|
|
1374
1374
|
if (touchesFlag && this.opts.outbox) {
|
|
1375
|
-
return this.durableActiveRunWrite(
|
|
1375
|
+
return this.durableActiveRunWrite(path, conversationId, agentId, body);
|
|
1376
1376
|
}
|
|
1377
|
-
return this.request("PATCH",
|
|
1377
|
+
return this.request("PATCH", path, body);
|
|
1378
1378
|
}
|
|
1379
1379
|
// CT93: send-or-enqueue for an active-run flag write, with last-writer-wins
|
|
1380
1380
|
// across the (conversation, agent) pair. Mirrors `durableCommit`, with two
|
|
@@ -1388,11 +1388,11 @@ var CabaneApi = class {
|
|
|
1388
1388
|
// later and clobber the state we just wrote (the cross-turn race: turn N's
|
|
1389
1389
|
// queued clear vs. turn N+1's live set). Combined with persist-overwrites-
|
|
1390
1390
|
// by-key, this is the full last-writer-wins guarantee.
|
|
1391
|
-
async durableActiveRunWrite(
|
|
1391
|
+
async durableActiveRunWrite(path, conversationId, agentId, body) {
|
|
1392
1392
|
const outbox = this.opts.outbox;
|
|
1393
1393
|
const key = activeRunOutboxKey(conversationId, agentId);
|
|
1394
1394
|
try {
|
|
1395
|
-
await this.request("PATCH",
|
|
1395
|
+
await this.request("PATCH", path, body, { retry: true });
|
|
1396
1396
|
outbox?.remove(key, ACTIVE_RUN_OUTBOX_SEQ);
|
|
1397
1397
|
} catch (err) {
|
|
1398
1398
|
if (!outbox) throw err;
|
|
@@ -1405,7 +1405,7 @@ var CabaneApi = class {
|
|
|
1405
1405
|
turnId: key,
|
|
1406
1406
|
seq: ACTIVE_RUN_OUTBOX_SEQ,
|
|
1407
1407
|
method: "PATCH",
|
|
1408
|
-
path
|
|
1408
|
+
path,
|
|
1409
1409
|
body,
|
|
1410
1410
|
kind: "active-run"
|
|
1411
1411
|
});
|
|
@@ -1493,8 +1493,8 @@ var CabaneApi = class {
|
|
|
1493
1493
|
// shared resolver the in-app path uses. Omitting it (older call sites) returns
|
|
1494
1494
|
// the agent default — graceful degradation, no version coupling.
|
|
1495
1495
|
getAgentSelf(conversationId) {
|
|
1496
|
-
const
|
|
1497
|
-
return this.request("GET",
|
|
1496
|
+
const path = conversationId ? `/api/agent/me?conversationId=${encodeURIComponent(conversationId)}` : `/api/agent/me`;
|
|
1497
|
+
return this.request("GET", path);
|
|
1498
1498
|
}
|
|
1499
1499
|
// The companion fetches the triggering message body by listing the
|
|
1500
1500
|
// conversation's messages and finding the one with `id === messageId`.
|
|
@@ -1549,8 +1549,8 @@ var DeviceApi = class {
|
|
|
1549
1549
|
get base() {
|
|
1550
1550
|
return this.opts.baseUrl.endsWith("/") ? this.opts.baseUrl.slice(0, -1) : this.opts.baseUrl;
|
|
1551
1551
|
}
|
|
1552
|
-
async request(method,
|
|
1553
|
-
const res = await fetch(`${this.base}${
|
|
1552
|
+
async request(method, path, body) {
|
|
1553
|
+
const res = await fetch(`${this.base}${path}`, {
|
|
1554
1554
|
method,
|
|
1555
1555
|
headers: {
|
|
1556
1556
|
Authorization: `Bearer ${this.opts.deviceToken}`,
|
|
@@ -1614,11 +1614,11 @@ function credentialsPath() {
|
|
|
1614
1614
|
}
|
|
1615
1615
|
var credentialStoreSchema = z3.record(z3.string(), z3.string());
|
|
1616
1616
|
function load() {
|
|
1617
|
-
const
|
|
1618
|
-
if (!existsSync4(
|
|
1617
|
+
const path = credentialsPath();
|
|
1618
|
+
if (!existsSync4(path)) return {};
|
|
1619
1619
|
let raw;
|
|
1620
1620
|
try {
|
|
1621
|
-
raw = readFileSync3(
|
|
1621
|
+
raw = readFileSync3(path, "utf8");
|
|
1622
1622
|
} catch {
|
|
1623
1623
|
return {};
|
|
1624
1624
|
}
|
|
@@ -1631,20 +1631,20 @@ function load() {
|
|
|
1631
1631
|
}
|
|
1632
1632
|
}
|
|
1633
1633
|
function save(map) {
|
|
1634
|
-
const
|
|
1635
|
-
mkdirSync4(dirname4(
|
|
1634
|
+
const path = credentialsPath();
|
|
1635
|
+
mkdirSync4(dirname4(path), { recursive: true });
|
|
1636
1636
|
try {
|
|
1637
1637
|
chmodSync2(cabaneDir(), 448);
|
|
1638
1638
|
} catch {
|
|
1639
1639
|
}
|
|
1640
|
-
const tmp = `${
|
|
1640
|
+
const tmp = `${path}.${process.pid}.tmp`;
|
|
1641
1641
|
try {
|
|
1642
1642
|
writeFileSync3(tmp, JSON.stringify(map, null, 2) + "\n", { mode: 384 });
|
|
1643
1643
|
try {
|
|
1644
1644
|
chmodSync2(tmp, 384);
|
|
1645
1645
|
} catch {
|
|
1646
1646
|
}
|
|
1647
|
-
renameSync2(tmp,
|
|
1647
|
+
renameSync2(tmp, path);
|
|
1648
1648
|
} catch (err) {
|
|
1649
1649
|
try {
|
|
1650
1650
|
rmSync3(tmp, { force: true });
|
|
@@ -1683,15 +1683,15 @@ function pathFor(workspaceId) {
|
|
|
1683
1683
|
return join7(cabaneDir(), "cursors", encodeURIComponent(workspaceId));
|
|
1684
1684
|
}
|
|
1685
1685
|
function readCursor(workspaceId) {
|
|
1686
|
-
const
|
|
1687
|
-
if (!existsSync5(
|
|
1688
|
-
const raw = readFileSync4(
|
|
1686
|
+
const path = pathFor(workspaceId);
|
|
1687
|
+
if (!existsSync5(path)) return null;
|
|
1688
|
+
const raw = readFileSync4(path, "utf8").trim();
|
|
1689
1689
|
return raw.length > 0 ? raw : null;
|
|
1690
1690
|
}
|
|
1691
1691
|
function writeCursor(workspaceId, eventId) {
|
|
1692
|
-
const
|
|
1692
|
+
const path = pathFor(workspaceId);
|
|
1693
1693
|
mkdirSync5(join7(cabaneDir(), "cursors"), { recursive: true });
|
|
1694
|
-
writeFileSync4(
|
|
1694
|
+
writeFileSync4(path, eventId + "\n", "utf8");
|
|
1695
1695
|
}
|
|
1696
1696
|
|
|
1697
1697
|
// src/cursor-tracker.ts
|
|
@@ -1744,10 +1744,10 @@ function pathFor2(log, workspaceId) {
|
|
|
1744
1744
|
return join8(dir(log), encodeURIComponent(workspaceId));
|
|
1745
1745
|
}
|
|
1746
1746
|
function readIds(log, workspaceId) {
|
|
1747
|
-
const
|
|
1748
|
-
if (!existsSync6(
|
|
1747
|
+
const path = pathFor2(log, workspaceId);
|
|
1748
|
+
if (!existsSync6(path)) return [];
|
|
1749
1749
|
try {
|
|
1750
|
-
return readFileSync5(
|
|
1750
|
+
return readFileSync5(path, "utf8").split("\n").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
1751
1751
|
} catch {
|
|
1752
1752
|
return [];
|
|
1753
1753
|
}
|
|
@@ -1784,10 +1784,10 @@ function resumePathFor(workspaceId) {
|
|
|
1784
1784
|
}
|
|
1785
1785
|
function readResumeCounts(workspaceId) {
|
|
1786
1786
|
const out = /* @__PURE__ */ new Map();
|
|
1787
|
-
const
|
|
1788
|
-
if (!existsSync6(
|
|
1787
|
+
const path = resumePathFor(workspaceId);
|
|
1788
|
+
if (!existsSync6(path)) return out;
|
|
1789
1789
|
try {
|
|
1790
|
-
for (const line of readFileSync5(
|
|
1790
|
+
for (const line of readFileSync5(path, "utf8").split("\n")) {
|
|
1791
1791
|
const trimmed = line.trim();
|
|
1792
1792
|
if (!trimmed) continue;
|
|
1793
1793
|
const tab = trimmed.lastIndexOf(" ");
|
|
@@ -4725,536 +4725,10 @@ function isStringRecord2(v) {
|
|
|
4725
4725
|
return !!v && typeof v === "object" && Object.values(v).every((x) => typeof x === "string");
|
|
4726
4726
|
}
|
|
4727
4727
|
|
|
4728
|
-
// node_modules/.pnpm/@openai+codex-sdk@0.147.0/node_modules/@openai/codex-sdk/dist/index.js
|
|
4729
|
-
import { promises as fs } from "fs";
|
|
4730
|
-
import os from "os";
|
|
4731
|
-
import path from "path";
|
|
4732
|
-
import { spawn as spawn4 } from "child_process";
|
|
4733
|
-
import { statSync } from "fs";
|
|
4734
|
-
import path2 from "path";
|
|
4735
|
-
import readline from "readline";
|
|
4736
|
-
import { createRequire } from "module";
|
|
4737
|
-
async function createOutputSchemaFile(schema) {
|
|
4738
|
-
if (schema === void 0) {
|
|
4739
|
-
return { cleanup: async () => {
|
|
4740
|
-
} };
|
|
4741
|
-
}
|
|
4742
|
-
if (!isJsonObject(schema)) {
|
|
4743
|
-
throw new Error("outputSchema must be a plain JSON object");
|
|
4744
|
-
}
|
|
4745
|
-
const schemaDir = await fs.mkdtemp(path.join(os.tmpdir(), "codex-output-schema-"));
|
|
4746
|
-
const schemaPath = path.join(schemaDir, "schema.json");
|
|
4747
|
-
const cleanup = async () => {
|
|
4748
|
-
try {
|
|
4749
|
-
await fs.rm(schemaDir, { recursive: true, force: true });
|
|
4750
|
-
} catch {
|
|
4751
|
-
}
|
|
4752
|
-
};
|
|
4753
|
-
try {
|
|
4754
|
-
await fs.writeFile(schemaPath, JSON.stringify(schema), "utf8");
|
|
4755
|
-
return { schemaPath, cleanup };
|
|
4756
|
-
} catch (error) {
|
|
4757
|
-
await cleanup();
|
|
4758
|
-
throw error;
|
|
4759
|
-
}
|
|
4760
|
-
}
|
|
4761
|
-
function isJsonObject(value) {
|
|
4762
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4763
|
-
}
|
|
4764
|
-
var Thread = class {
|
|
4765
|
-
_exec;
|
|
4766
|
-
_options;
|
|
4767
|
-
_id;
|
|
4768
|
-
_threadOptions;
|
|
4769
|
-
/** Returns the ID of the thread. Populated after the first turn starts. */
|
|
4770
|
-
get id() {
|
|
4771
|
-
return this._id;
|
|
4772
|
-
}
|
|
4773
|
-
/* @internal */
|
|
4774
|
-
constructor(exec, options, threadOptions, id = null) {
|
|
4775
|
-
this._exec = exec;
|
|
4776
|
-
this._options = options;
|
|
4777
|
-
this._id = id;
|
|
4778
|
-
this._threadOptions = threadOptions;
|
|
4779
|
-
}
|
|
4780
|
-
/** Provides the input to the agent and streams events as they are produced during the turn. */
|
|
4781
|
-
async runStreamed(input, turnOptions = {}) {
|
|
4782
|
-
return { events: this.runStreamedInternal(input, turnOptions) };
|
|
4783
|
-
}
|
|
4784
|
-
async *runStreamedInternal(input, turnOptions = {}) {
|
|
4785
|
-
const { schemaPath, cleanup } = await createOutputSchemaFile(turnOptions.outputSchema);
|
|
4786
|
-
const options = this._threadOptions;
|
|
4787
|
-
const { prompt, images } = normalizeInput(input);
|
|
4788
|
-
const generator = this._exec.run({
|
|
4789
|
-
input: prompt,
|
|
4790
|
-
baseUrl: this._options.baseUrl,
|
|
4791
|
-
apiKey: this._options.apiKey,
|
|
4792
|
-
threadId: this._id,
|
|
4793
|
-
images,
|
|
4794
|
-
model: options?.model,
|
|
4795
|
-
sandboxMode: options?.sandboxMode,
|
|
4796
|
-
workingDirectory: options?.workingDirectory,
|
|
4797
|
-
skipGitRepoCheck: options?.skipGitRepoCheck,
|
|
4798
|
-
outputSchemaFile: schemaPath,
|
|
4799
|
-
modelReasoningEffort: options?.modelReasoningEffort,
|
|
4800
|
-
signal: turnOptions.signal,
|
|
4801
|
-
networkAccessEnabled: options?.networkAccessEnabled,
|
|
4802
|
-
webSearchMode: options?.webSearchMode,
|
|
4803
|
-
webSearchEnabled: options?.webSearchEnabled,
|
|
4804
|
-
approvalPolicy: options?.approvalPolicy,
|
|
4805
|
-
additionalDirectories: options?.additionalDirectories
|
|
4806
|
-
});
|
|
4807
|
-
try {
|
|
4808
|
-
for await (const item of generator) {
|
|
4809
|
-
let parsed;
|
|
4810
|
-
try {
|
|
4811
|
-
parsed = JSON.parse(item);
|
|
4812
|
-
} catch (error) {
|
|
4813
|
-
throw new Error(`Failed to parse item: ${item}`, { cause: error });
|
|
4814
|
-
}
|
|
4815
|
-
if (parsed.type === "thread.started") {
|
|
4816
|
-
this._id = parsed.thread_id;
|
|
4817
|
-
} else if (parsed.type === "turn.completed") {
|
|
4818
|
-
parsed.usage.cache_write_input_tokens ??= 0;
|
|
4819
|
-
}
|
|
4820
|
-
yield parsed;
|
|
4821
|
-
}
|
|
4822
|
-
} finally {
|
|
4823
|
-
await cleanup();
|
|
4824
|
-
}
|
|
4825
|
-
}
|
|
4826
|
-
/** Provides the input to the agent and returns the completed turn. */
|
|
4827
|
-
async run(input, turnOptions = {}) {
|
|
4828
|
-
const generator = this.runStreamedInternal(input, turnOptions);
|
|
4829
|
-
const items = [];
|
|
4830
|
-
let finalResponse = "";
|
|
4831
|
-
let usage = null;
|
|
4832
|
-
let turnFailure = null;
|
|
4833
|
-
for await (const event of generator) {
|
|
4834
|
-
if (event.type === "item.completed") {
|
|
4835
|
-
if (event.item.type === "agent_message") {
|
|
4836
|
-
finalResponse = event.item.text;
|
|
4837
|
-
}
|
|
4838
|
-
items.push(event.item);
|
|
4839
|
-
} else if (event.type === "turn.completed") {
|
|
4840
|
-
usage = event.usage;
|
|
4841
|
-
} else if (event.type === "turn.failed") {
|
|
4842
|
-
turnFailure = event.error;
|
|
4843
|
-
break;
|
|
4844
|
-
}
|
|
4845
|
-
}
|
|
4846
|
-
if (turnFailure) {
|
|
4847
|
-
throw new Error(turnFailure.message);
|
|
4848
|
-
}
|
|
4849
|
-
return { items, finalResponse, usage };
|
|
4850
|
-
}
|
|
4851
|
-
};
|
|
4852
|
-
function normalizeInput(input) {
|
|
4853
|
-
if (typeof input === "string") {
|
|
4854
|
-
return { prompt: input, images: [] };
|
|
4855
|
-
}
|
|
4856
|
-
const promptParts = [];
|
|
4857
|
-
const images = [];
|
|
4858
|
-
for (const item of input) {
|
|
4859
|
-
if (item.type === "text") {
|
|
4860
|
-
promptParts.push(item.text);
|
|
4861
|
-
} else if (item.type === "local_image") {
|
|
4862
|
-
images.push(item.path);
|
|
4863
|
-
}
|
|
4864
|
-
}
|
|
4865
|
-
return { prompt: promptParts.join("\n\n"), images };
|
|
4866
|
-
}
|
|
4867
|
-
var INTERNAL_ORIGINATOR_ENV = "CODEX_INTERNAL_ORIGINATOR_OVERRIDE";
|
|
4868
|
-
var TYPESCRIPT_SDK_ORIGINATOR = "codex_sdk_ts";
|
|
4869
|
-
var CODEX_NPM_NAME = "@openai/codex";
|
|
4870
|
-
var PLATFORM_PACKAGE_BY_TARGET = {
|
|
4871
|
-
"x86_64-unknown-linux-musl": "@openai/codex-linux-x64",
|
|
4872
|
-
"aarch64-unknown-linux-musl": "@openai/codex-linux-arm64",
|
|
4873
|
-
"x86_64-apple-darwin": "@openai/codex-darwin-x64",
|
|
4874
|
-
"aarch64-apple-darwin": "@openai/codex-darwin-arm64",
|
|
4875
|
-
"x86_64-pc-windows-msvc": "@openai/codex-win32-x64",
|
|
4876
|
-
"aarch64-pc-windows-msvc": "@openai/codex-win32-arm64"
|
|
4877
|
-
};
|
|
4878
|
-
var moduleRequire = createRequire(import.meta.url);
|
|
4879
|
-
var CodexExec = class {
|
|
4880
|
-
executablePath;
|
|
4881
|
-
pathDirs;
|
|
4882
|
-
envOverride;
|
|
4883
|
-
configOverrides;
|
|
4884
|
-
constructor(executablePath = null, env, configOverrides) {
|
|
4885
|
-
if (executablePath) {
|
|
4886
|
-
this.executablePath = executablePath;
|
|
4887
|
-
this.pathDirs = [];
|
|
4888
|
-
} else {
|
|
4889
|
-
const resolved = findCodexPath();
|
|
4890
|
-
this.executablePath = resolved.executablePath;
|
|
4891
|
-
this.pathDirs = resolved.pathDirs;
|
|
4892
|
-
}
|
|
4893
|
-
this.envOverride = env;
|
|
4894
|
-
this.configOverrides = configOverrides;
|
|
4895
|
-
}
|
|
4896
|
-
async *run(args) {
|
|
4897
|
-
const commandArgs = ["exec", "--experimental-json"];
|
|
4898
|
-
if (this.configOverrides) {
|
|
4899
|
-
for (const override of serializeConfigOverrides(this.configOverrides)) {
|
|
4900
|
-
commandArgs.push("--config", override);
|
|
4901
|
-
}
|
|
4902
|
-
}
|
|
4903
|
-
if (args.baseUrl) {
|
|
4904
|
-
commandArgs.push(
|
|
4905
|
-
"--config",
|
|
4906
|
-
`openai_base_url=${toTomlValue(args.baseUrl, "openai_base_url")}`
|
|
4907
|
-
);
|
|
4908
|
-
}
|
|
4909
|
-
if (args.model) {
|
|
4910
|
-
commandArgs.push("--model", args.model);
|
|
4911
|
-
}
|
|
4912
|
-
if (args.sandboxMode) {
|
|
4913
|
-
commandArgs.push("--sandbox", args.sandboxMode);
|
|
4914
|
-
}
|
|
4915
|
-
if (args.workingDirectory) {
|
|
4916
|
-
commandArgs.push("--cd", args.workingDirectory);
|
|
4917
|
-
}
|
|
4918
|
-
if (args.additionalDirectories?.length) {
|
|
4919
|
-
for (const dir2 of args.additionalDirectories) {
|
|
4920
|
-
commandArgs.push("--add-dir", dir2);
|
|
4921
|
-
}
|
|
4922
|
-
}
|
|
4923
|
-
if (args.skipGitRepoCheck) {
|
|
4924
|
-
commandArgs.push("--skip-git-repo-check");
|
|
4925
|
-
}
|
|
4926
|
-
if (args.outputSchemaFile) {
|
|
4927
|
-
commandArgs.push("--output-schema", args.outputSchemaFile);
|
|
4928
|
-
}
|
|
4929
|
-
if (args.modelReasoningEffort) {
|
|
4930
|
-
commandArgs.push("--config", `model_reasoning_effort="${args.modelReasoningEffort}"`);
|
|
4931
|
-
}
|
|
4932
|
-
if (args.networkAccessEnabled !== void 0) {
|
|
4933
|
-
commandArgs.push(
|
|
4934
|
-
"--config",
|
|
4935
|
-
`sandbox_workspace_write.network_access=${args.networkAccessEnabled}`
|
|
4936
|
-
);
|
|
4937
|
-
}
|
|
4938
|
-
if (args.webSearchMode) {
|
|
4939
|
-
commandArgs.push("--config", `web_search="${args.webSearchMode}"`);
|
|
4940
|
-
} else if (args.webSearchEnabled === true) {
|
|
4941
|
-
commandArgs.push("--config", `web_search="live"`);
|
|
4942
|
-
} else if (args.webSearchEnabled === false) {
|
|
4943
|
-
commandArgs.push("--config", `web_search="disabled"`);
|
|
4944
|
-
}
|
|
4945
|
-
if (args.approvalPolicy) {
|
|
4946
|
-
commandArgs.push("--config", `approval_policy="${args.approvalPolicy}"`);
|
|
4947
|
-
}
|
|
4948
|
-
if (args.threadId) {
|
|
4949
|
-
commandArgs.push("resume", args.threadId);
|
|
4950
|
-
}
|
|
4951
|
-
if (args.images?.length) {
|
|
4952
|
-
for (const image of args.images) {
|
|
4953
|
-
commandArgs.push("--image", image);
|
|
4954
|
-
}
|
|
4955
|
-
}
|
|
4956
|
-
const env = {};
|
|
4957
|
-
if (this.envOverride) {
|
|
4958
|
-
Object.assign(env, this.envOverride);
|
|
4959
|
-
} else {
|
|
4960
|
-
for (const [key, value] of Object.entries(process.env)) {
|
|
4961
|
-
if (value !== void 0) {
|
|
4962
|
-
env[key] = value;
|
|
4963
|
-
}
|
|
4964
|
-
}
|
|
4965
|
-
}
|
|
4966
|
-
if (!env[INTERNAL_ORIGINATOR_ENV]) {
|
|
4967
|
-
env[INTERNAL_ORIGINATOR_ENV] = TYPESCRIPT_SDK_ORIGINATOR;
|
|
4968
|
-
}
|
|
4969
|
-
if (args.apiKey) {
|
|
4970
|
-
env.CODEX_API_KEY = args.apiKey;
|
|
4971
|
-
}
|
|
4972
|
-
if (this.pathDirs.length > 0) {
|
|
4973
|
-
prependPathDirs(env, this.pathDirs);
|
|
4974
|
-
}
|
|
4975
|
-
const child = spawn4(this.executablePath, commandArgs, {
|
|
4976
|
-
env,
|
|
4977
|
-
signal: args.signal
|
|
4978
|
-
});
|
|
4979
|
-
let spawnError = null;
|
|
4980
|
-
child.once("error", (err) => spawnError = err);
|
|
4981
|
-
if (!child.stdin) {
|
|
4982
|
-
child.kill();
|
|
4983
|
-
throw new Error("Child process has no stdin");
|
|
4984
|
-
}
|
|
4985
|
-
child.stdin.write(args.input);
|
|
4986
|
-
child.stdin.end();
|
|
4987
|
-
if (!child.stdout) {
|
|
4988
|
-
child.kill();
|
|
4989
|
-
throw new Error("Child process has no stdout");
|
|
4990
|
-
}
|
|
4991
|
-
const stderrChunks = [];
|
|
4992
|
-
if (child.stderr) {
|
|
4993
|
-
child.stderr.on("data", (data) => {
|
|
4994
|
-
stderrChunks.push(data);
|
|
4995
|
-
});
|
|
4996
|
-
}
|
|
4997
|
-
const exitPromise = new Promise(
|
|
4998
|
-
(resolve) => {
|
|
4999
|
-
child.once("exit", (code, signal) => {
|
|
5000
|
-
resolve({ code, signal });
|
|
5001
|
-
});
|
|
5002
|
-
}
|
|
5003
|
-
);
|
|
5004
|
-
const rl = readline.createInterface({
|
|
5005
|
-
input: child.stdout,
|
|
5006
|
-
crlfDelay: Infinity
|
|
5007
|
-
});
|
|
5008
|
-
try {
|
|
5009
|
-
for await (const line of rl) {
|
|
5010
|
-
yield line;
|
|
5011
|
-
}
|
|
5012
|
-
if (spawnError) throw spawnError;
|
|
5013
|
-
const { code, signal } = await exitPromise;
|
|
5014
|
-
if (code !== 0 || signal) {
|
|
5015
|
-
const stderrBuffer = Buffer.concat(stderrChunks);
|
|
5016
|
-
const detail = signal ? `signal ${signal}` : `code ${code ?? 1}`;
|
|
5017
|
-
throw new Error(`Codex Exec exited with ${detail}: ${stderrBuffer.toString("utf8")}`);
|
|
5018
|
-
}
|
|
5019
|
-
} finally {
|
|
5020
|
-
rl.close();
|
|
5021
|
-
child.removeAllListeners();
|
|
5022
|
-
try {
|
|
5023
|
-
if (!child.killed) child.kill();
|
|
5024
|
-
} catch {
|
|
5025
|
-
}
|
|
5026
|
-
}
|
|
5027
|
-
}
|
|
5028
|
-
};
|
|
5029
|
-
function serializeConfigOverrides(configOverrides) {
|
|
5030
|
-
const overrides = [];
|
|
5031
|
-
flattenConfigOverrides(configOverrides, "", overrides);
|
|
5032
|
-
return overrides;
|
|
5033
|
-
}
|
|
5034
|
-
function flattenConfigOverrides(value, prefix, overrides) {
|
|
5035
|
-
if (!isPlainObject(value)) {
|
|
5036
|
-
if (prefix) {
|
|
5037
|
-
overrides.push(`${prefix}=${toTomlValue(value, prefix)}`);
|
|
5038
|
-
return;
|
|
5039
|
-
} else {
|
|
5040
|
-
throw new Error("Codex config overrides must be a plain object");
|
|
5041
|
-
}
|
|
5042
|
-
}
|
|
5043
|
-
const entries = Object.entries(value);
|
|
5044
|
-
if (!prefix && entries.length === 0) {
|
|
5045
|
-
return;
|
|
5046
|
-
}
|
|
5047
|
-
if (prefix && entries.length === 0) {
|
|
5048
|
-
overrides.push(`${prefix}={}`);
|
|
5049
|
-
return;
|
|
5050
|
-
}
|
|
5051
|
-
for (const [key, child] of entries) {
|
|
5052
|
-
if (!key) {
|
|
5053
|
-
throw new Error("Codex config override keys must be non-empty strings");
|
|
5054
|
-
}
|
|
5055
|
-
if (child === void 0) {
|
|
5056
|
-
continue;
|
|
5057
|
-
}
|
|
5058
|
-
const path3 = prefix ? `${prefix}.${key}` : key;
|
|
5059
|
-
if (isPlainObject(child)) {
|
|
5060
|
-
flattenConfigOverrides(child, path3, overrides);
|
|
5061
|
-
} else {
|
|
5062
|
-
overrides.push(`${path3}=${toTomlValue(child, path3)}`);
|
|
5063
|
-
}
|
|
5064
|
-
}
|
|
5065
|
-
}
|
|
5066
|
-
function toTomlValue(value, path3) {
|
|
5067
|
-
if (typeof value === "string") {
|
|
5068
|
-
return JSON.stringify(value);
|
|
5069
|
-
} else if (typeof value === "number") {
|
|
5070
|
-
if (!Number.isFinite(value)) {
|
|
5071
|
-
throw new Error(`Codex config override at ${path3} must be a finite number`);
|
|
5072
|
-
}
|
|
5073
|
-
return `${value}`;
|
|
5074
|
-
} else if (typeof value === "boolean") {
|
|
5075
|
-
return value ? "true" : "false";
|
|
5076
|
-
} else if (Array.isArray(value)) {
|
|
5077
|
-
const rendered = value.map((item, index) => toTomlValue(item, `${path3}[${index}]`));
|
|
5078
|
-
return `[${rendered.join(", ")}]`;
|
|
5079
|
-
} else if (isPlainObject(value)) {
|
|
5080
|
-
const parts = [];
|
|
5081
|
-
for (const [key, child] of Object.entries(value)) {
|
|
5082
|
-
if (!key) {
|
|
5083
|
-
throw new Error("Codex config override keys must be non-empty strings");
|
|
5084
|
-
}
|
|
5085
|
-
if (child === void 0) {
|
|
5086
|
-
continue;
|
|
5087
|
-
}
|
|
5088
|
-
parts.push(`${formatTomlKey(key)} = ${toTomlValue(child, `${path3}.${key}`)}`);
|
|
5089
|
-
}
|
|
5090
|
-
return `{${parts.join(", ")}}`;
|
|
5091
|
-
} else if (value === null) {
|
|
5092
|
-
throw new Error(`Codex config override at ${path3} cannot be null`);
|
|
5093
|
-
} else {
|
|
5094
|
-
const typeName = typeof value;
|
|
5095
|
-
throw new Error(`Unsupported Codex config override value at ${path3}: ${typeName}`);
|
|
5096
|
-
}
|
|
5097
|
-
}
|
|
5098
|
-
var TOML_BARE_KEY = /^[A-Za-z0-9_-]+$/;
|
|
5099
|
-
function formatTomlKey(key) {
|
|
5100
|
-
return TOML_BARE_KEY.test(key) ? key : JSON.stringify(key);
|
|
5101
|
-
}
|
|
5102
|
-
function isPlainObject(value) {
|
|
5103
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5104
|
-
}
|
|
5105
|
-
function findCodexPath() {
|
|
5106
|
-
const { platform, arch } = process;
|
|
5107
|
-
let targetTriple = null;
|
|
5108
|
-
switch (platform) {
|
|
5109
|
-
case "linux":
|
|
5110
|
-
case "android":
|
|
5111
|
-
switch (arch) {
|
|
5112
|
-
case "x64":
|
|
5113
|
-
targetTriple = "x86_64-unknown-linux-musl";
|
|
5114
|
-
break;
|
|
5115
|
-
case "arm64":
|
|
5116
|
-
targetTriple = "aarch64-unknown-linux-musl";
|
|
5117
|
-
break;
|
|
5118
|
-
default:
|
|
5119
|
-
break;
|
|
5120
|
-
}
|
|
5121
|
-
break;
|
|
5122
|
-
case "darwin":
|
|
5123
|
-
switch (arch) {
|
|
5124
|
-
case "x64":
|
|
5125
|
-
targetTriple = "x86_64-apple-darwin";
|
|
5126
|
-
break;
|
|
5127
|
-
case "arm64":
|
|
5128
|
-
targetTriple = "aarch64-apple-darwin";
|
|
5129
|
-
break;
|
|
5130
|
-
default:
|
|
5131
|
-
break;
|
|
5132
|
-
}
|
|
5133
|
-
break;
|
|
5134
|
-
case "win32":
|
|
5135
|
-
switch (arch) {
|
|
5136
|
-
case "x64":
|
|
5137
|
-
targetTriple = "x86_64-pc-windows-msvc";
|
|
5138
|
-
break;
|
|
5139
|
-
case "arm64":
|
|
5140
|
-
targetTriple = "aarch64-pc-windows-msvc";
|
|
5141
|
-
break;
|
|
5142
|
-
default:
|
|
5143
|
-
break;
|
|
5144
|
-
}
|
|
5145
|
-
break;
|
|
5146
|
-
default:
|
|
5147
|
-
break;
|
|
5148
|
-
}
|
|
5149
|
-
if (!targetTriple) {
|
|
5150
|
-
throw new Error(`Unsupported platform: ${platform} (${arch})`);
|
|
5151
|
-
}
|
|
5152
|
-
const platformPackage = PLATFORM_PACKAGE_BY_TARGET[targetTriple];
|
|
5153
|
-
if (!platformPackage) {
|
|
5154
|
-
throw new Error(`Unsupported target triple: ${targetTriple}`);
|
|
5155
|
-
}
|
|
5156
|
-
let vendorRoot;
|
|
5157
|
-
try {
|
|
5158
|
-
const codexPackageJsonPath = moduleRequire.resolve(`${CODEX_NPM_NAME}/package.json`);
|
|
5159
|
-
const codexRequire = createRequire(codexPackageJsonPath);
|
|
5160
|
-
const platformPackageJsonPath = codexRequire.resolve(`${platformPackage}/package.json`);
|
|
5161
|
-
vendorRoot = path2.join(path2.dirname(platformPackageJsonPath), "vendor");
|
|
5162
|
-
} catch {
|
|
5163
|
-
throw new Error(
|
|
5164
|
-
`Unable to locate Codex CLI binaries. Ensure ${CODEX_NPM_NAME} is installed with optional dependencies.`
|
|
5165
|
-
);
|
|
5166
|
-
}
|
|
5167
|
-
const codexBinaryName = process.platform === "win32" ? "codex.exe" : "codex";
|
|
5168
|
-
const nativePackage = resolveNativePackage(vendorRoot, targetTriple, codexBinaryName);
|
|
5169
|
-
if (!nativePackage) {
|
|
5170
|
-
throw new Error(
|
|
5171
|
-
`Unable to locate Codex CLI binaries for ${targetTriple}. Ensure ${CODEX_NPM_NAME} is installed with optional dependencies.`
|
|
5172
|
-
);
|
|
5173
|
-
}
|
|
5174
|
-
return nativePackage;
|
|
5175
|
-
}
|
|
5176
|
-
function resolveNativePackage(vendorRoot, targetTriple, codexBinaryName) {
|
|
5177
|
-
const packageRoot = path2.join(vendorRoot, targetTriple);
|
|
5178
|
-
const packageBinaryPath = path2.join(packageRoot, "bin", codexBinaryName);
|
|
5179
|
-
if (isFile(packageBinaryPath) && isFile(path2.join(packageRoot, "codex-package.json"))) {
|
|
5180
|
-
return {
|
|
5181
|
-
executablePath: packageBinaryPath,
|
|
5182
|
-
pathDirs: existingDirs(path2.join(packageRoot, "codex-path"))
|
|
5183
|
-
};
|
|
5184
|
-
}
|
|
5185
|
-
const legacyBinaryPath = path2.join(packageRoot, "codex", codexBinaryName);
|
|
5186
|
-
if (isFile(legacyBinaryPath)) {
|
|
5187
|
-
return {
|
|
5188
|
-
executablePath: legacyBinaryPath,
|
|
5189
|
-
pathDirs: existingDirs(path2.join(packageRoot, "path"))
|
|
5190
|
-
};
|
|
5191
|
-
}
|
|
5192
|
-
return null;
|
|
5193
|
-
}
|
|
5194
|
-
function existingDirs(...dirs) {
|
|
5195
|
-
return dirs.filter(isDirectory);
|
|
5196
|
-
}
|
|
5197
|
-
function prependPathDirs(env, pathDirs, platform = process.platform) {
|
|
5198
|
-
const pathKey = pathEnvKey(env, platform);
|
|
5199
|
-
if (platform === "win32") {
|
|
5200
|
-
for (const key of Object.keys(env)) {
|
|
5201
|
-
if (key.toLowerCase() === "path" && key !== pathKey) {
|
|
5202
|
-
delete env[key];
|
|
5203
|
-
}
|
|
5204
|
-
}
|
|
5205
|
-
}
|
|
5206
|
-
const existingEntries = (env[pathKey] ?? "").split(path2.delimiter).filter((entry) => entry.length > 0 && !pathDirs.includes(entry));
|
|
5207
|
-
env[pathKey] = [...pathDirs, ...existingEntries].join(path2.delimiter);
|
|
5208
|
-
}
|
|
5209
|
-
function pathEnvKey(env, platform) {
|
|
5210
|
-
if (platform !== "win32") {
|
|
5211
|
-
return "PATH";
|
|
5212
|
-
}
|
|
5213
|
-
const matchingKeys = Object.keys(env).filter((key) => key.toLowerCase() === "path");
|
|
5214
|
-
return matchingKeys.includes("Path") ? "Path" : matchingKeys.at(-1) ?? "PATH";
|
|
5215
|
-
}
|
|
5216
|
-
function isFile(filePath) {
|
|
5217
|
-
try {
|
|
5218
|
-
return statSync(filePath).isFile();
|
|
5219
|
-
} catch {
|
|
5220
|
-
return false;
|
|
5221
|
-
}
|
|
5222
|
-
}
|
|
5223
|
-
function isDirectory(filePath) {
|
|
5224
|
-
try {
|
|
5225
|
-
return statSync(filePath).isDirectory();
|
|
5226
|
-
} catch {
|
|
5227
|
-
return false;
|
|
5228
|
-
}
|
|
5229
|
-
}
|
|
5230
|
-
var Codex = class {
|
|
5231
|
-
exec;
|
|
5232
|
-
options;
|
|
5233
|
-
constructor(options = {}) {
|
|
5234
|
-
const { codexPathOverride, env, config } = options;
|
|
5235
|
-
this.exec = new CodexExec(codexPathOverride, env, config);
|
|
5236
|
-
this.options = options;
|
|
5237
|
-
}
|
|
5238
|
-
/**
|
|
5239
|
-
* Starts a new conversation with an agent.
|
|
5240
|
-
* @returns A new thread instance.
|
|
5241
|
-
*/
|
|
5242
|
-
startThread(options = {}) {
|
|
5243
|
-
return new Thread(this.exec, this.options, options);
|
|
5244
|
-
}
|
|
5245
|
-
/**
|
|
5246
|
-
* Resumes a conversation with an agent based on the thread id.
|
|
5247
|
-
* Threads are persisted in ~/.codex/sessions.
|
|
5248
|
-
*
|
|
5249
|
-
* @param id The id of the thread to resume.
|
|
5250
|
-
* @returns A new thread instance.
|
|
5251
|
-
*/
|
|
5252
|
-
resumeThread(id, options = {}) {
|
|
5253
|
-
return new Thread(this.exec, this.options, options, id);
|
|
5254
|
-
}
|
|
5255
|
-
};
|
|
5256
|
-
|
|
5257
4728
|
// packages/agent-runtime/src/codex/transport.ts
|
|
4729
|
+
import {
|
|
4730
|
+
Codex
|
|
4731
|
+
} from "@openai/codex-sdk";
|
|
5258
4732
|
function buildSdkThreadOptions(spec) {
|
|
5259
4733
|
return {
|
|
5260
4734
|
...spec.model ? { model: spec.model } : {},
|
|
@@ -6046,7 +5520,7 @@ var ConnectorHealthStore = class {
|
|
|
6046
5520
|
|
|
6047
5521
|
// src/dispatcher.ts
|
|
6048
5522
|
import { randomUUID } from "crypto";
|
|
6049
|
-
import { appendFileSync as appendFileSync2, existsSync as existsSync9, mkdirSync as mkdirSync9, statSync
|
|
5523
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync9, mkdirSync as mkdirSync9, statSync } from "fs";
|
|
6050
5524
|
import { join as join13 } from "path";
|
|
6051
5525
|
|
|
6052
5526
|
// src/summon.ts
|
|
@@ -6384,10 +5858,10 @@ import { join as join9 } from "path";
|
|
|
6384
5858
|
var PREFIX = "cabane-codex-instructions-";
|
|
6385
5859
|
async function writeCodexInstructionsFile(contents) {
|
|
6386
5860
|
const dir2 = await mkdtemp(join9(tmpdir(), PREFIX));
|
|
6387
|
-
const
|
|
6388
|
-
await writeFile(
|
|
5861
|
+
const path = join9(dir2, "instructions.md");
|
|
5862
|
+
await writeFile(path, contents, { encoding: "utf8", mode: 384 });
|
|
6389
5863
|
return {
|
|
6390
|
-
path
|
|
5864
|
+
path,
|
|
6391
5865
|
cleanup: async () => {
|
|
6392
5866
|
await rm(dir2, { recursive: true, force: true });
|
|
6393
5867
|
}
|
|
@@ -6407,10 +5881,10 @@ function pathFor3(workspaceId, conversationId, agentId) {
|
|
|
6407
5881
|
return join10(conversationDir(workspaceId, conversationId), `${encodeURIComponent(agentId)}.json`);
|
|
6408
5882
|
}
|
|
6409
5883
|
function readPrepared(workspaceId, conversationId, agentId) {
|
|
6410
|
-
const
|
|
6411
|
-
if (!existsSync7(
|
|
5884
|
+
const path = pathFor3(workspaceId, conversationId, agentId);
|
|
5885
|
+
if (!existsSync7(path)) return null;
|
|
6412
5886
|
try {
|
|
6413
|
-
const parsed = JSON.parse(readFileSync6(
|
|
5887
|
+
const parsed = JSON.parse(readFileSync6(path, "utf8"));
|
|
6414
5888
|
if (parsed && typeof parsed.cwd === "string" && parsed.cwd.length > 0) {
|
|
6415
5889
|
return {
|
|
6416
5890
|
cwd: parsed.cwd,
|
|
@@ -6444,14 +5918,14 @@ function secretsPath() {
|
|
|
6444
5918
|
}
|
|
6445
5919
|
var secretStoreSchema = z13.record(z13.string(), z13.string());
|
|
6446
5920
|
function loadSecretStore() {
|
|
6447
|
-
const
|
|
6448
|
-
if (!existsSync8(
|
|
5921
|
+
const path = secretsPath();
|
|
5922
|
+
if (!existsSync8(path)) return makeStore({});
|
|
6449
5923
|
let raw;
|
|
6450
5924
|
try {
|
|
6451
|
-
raw = readFileSync7(
|
|
5925
|
+
raw = readFileSync7(path, "utf8");
|
|
6452
5926
|
} catch (err) {
|
|
6453
5927
|
throw new ConfigError(
|
|
6454
|
-
`couldn't read ${
|
|
5928
|
+
`couldn't read ${path}: ${err instanceof Error ? err.message : String(err)}`
|
|
6455
5929
|
);
|
|
6456
5930
|
}
|
|
6457
5931
|
if (raw.trim().length === 0) return makeStore({});
|
|
@@ -6460,13 +5934,13 @@ function loadSecretStore() {
|
|
|
6460
5934
|
parsed = JSON.parse(raw);
|
|
6461
5935
|
} catch (err) {
|
|
6462
5936
|
throw new ConfigError(
|
|
6463
|
-
`${
|
|
5937
|
+
`${path} is not valid JSON: ${err instanceof Error ? err.message : String(err)}. It must be a flat object of "NAME": "value" secret pairs.`
|
|
6464
5938
|
);
|
|
6465
5939
|
}
|
|
6466
5940
|
const result = secretStoreSchema.safeParse(parsed);
|
|
6467
5941
|
if (!result.success) {
|
|
6468
5942
|
throw new ConfigError(
|
|
6469
|
-
`${
|
|
5943
|
+
`${path} must be a flat object mapping secret names to string values (e.g. { "GITHUB_TOKEN": "ghp_\u2026" }).`
|
|
6470
5944
|
);
|
|
6471
5945
|
}
|
|
6472
5946
|
return makeStore(result.data);
|
|
@@ -6902,7 +6376,7 @@ function checkoutState(cwd) {
|
|
|
6902
6376
|
if (!existsSync9(gitPath)) return { ok: false, reason: `${cwd} holds no git metadata` };
|
|
6903
6377
|
let stat;
|
|
6904
6378
|
try {
|
|
6905
|
-
stat =
|
|
6379
|
+
stat = statSync(gitPath);
|
|
6906
6380
|
} catch (error) {
|
|
6907
6381
|
return { ok: false, reason: `${gitPath} is unreadable (${error.message})` };
|
|
6908
6382
|
}
|
|
@@ -8333,8 +7807,8 @@ function sleep2(ms) {
|
|
|
8333
7807
|
}
|
|
8334
7808
|
|
|
8335
7809
|
// src/version.ts
|
|
8336
|
-
import { createRequire
|
|
8337
|
-
var pkg =
|
|
7810
|
+
import { createRequire } from "module";
|
|
7811
|
+
var pkg = createRequire(import.meta.url)("../package.json");
|
|
8338
7812
|
var COMPANION_VERSION = pkg.version;
|
|
8339
7813
|
|
|
8340
7814
|
// src/supervisor.ts
|
|
@@ -9138,9 +8612,9 @@ var CompanionSupervisor = class {
|
|
|
9138
8612
|
};
|
|
9139
8613
|
function defaultReexec() {
|
|
9140
8614
|
clearRuntimeState();
|
|
9141
|
-
void import("child_process").then(({ spawn:
|
|
8615
|
+
void import("child_process").then(({ spawn: spawn4 }) => {
|
|
9142
8616
|
try {
|
|
9143
|
-
const child =
|
|
8617
|
+
const child = spawn4(process.execPath, process.argv.slice(1), {
|
|
9144
8618
|
stdio: "inherit",
|
|
9145
8619
|
detached: false
|
|
9146
8620
|
});
|
|
@@ -9224,8 +8698,8 @@ function recordCrash(rec) {
|
|
|
9224
8698
|
}
|
|
9225
8699
|
function clearCrash() {
|
|
9226
8700
|
try {
|
|
9227
|
-
const
|
|
9228
|
-
if (existsSync11(
|
|
8701
|
+
const path = crashMarkerPath();
|
|
8702
|
+
if (existsSync11(path)) rmSync7(path, { force: true });
|
|
9229
8703
|
} catch {
|
|
9230
8704
|
}
|
|
9231
8705
|
}
|