@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.
Files changed (3) hide show
  1. package/dist/cli.js +100 -626
  2. package/dist/runtime.js +82 -608
  3. 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 path3 = configPath();
313
- if (!existsSync(path3)) return null;
312
+ const path = configPath();
313
+ if (!existsSync(path)) return null;
314
314
  let raw;
315
315
  try {
316
- raw = readFileSync(path3, "utf8");
316
+ raw = readFileSync(path, "utf8");
317
317
  } catch (err) {
318
318
  throw new ConfigError(
319
- `couldn't read ${path3}: ${err instanceof Error ? err.message : String(err)}`
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
- `${path3} is not valid JSON: ${err instanceof Error ? err.message : String(err)}`
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
- `${path3}: invalid "agents" config at \`${agentIssue.path.join(".")}\` \u2014 ${agentIssue.message}. Fix the agents block in the config and retry.`
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
- `${path3} 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.`
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 path3 = configPath();
347
- mkdirSync(dirname(path3), { recursive: true });
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 = `${path3}.${process.pid}.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, path3);
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 path3 = companionLogPath();
421
- mkdirSync2(dirname2(path3), { recursive: true });
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(path3, { flags: "a" }) });
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(path3, lines) {
811
- if (!existsSync2(path3)) return [];
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(path3, "r");
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 path3 = runtimePath();
1057
+ const path = runtimePath();
1058
1058
  mkdirSync3(cabaneDir(), { recursive: true });
1059
- writeFileSync2(path3, serialize(state), "utf8");
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 path3 = runtimePath();
1080
- if (existsSync3(path3)) rmSync2(path3, { force: true });
1079
+ const path = runtimePath();
1080
+ if (existsSync3(path)) rmSync2(path, { force: true });
1081
1081
  }
1082
1082
  function readLiveRuntimeState() {
1083
- const path3 = runtimePath();
1084
- if (!existsSync3(path3)) return null;
1083
+ const path = runtimePath();
1084
+ if (!existsSync3(path)) return null;
1085
1085
  let parsed;
1086
1086
  try {
1087
- parsed = JSON.parse(readFileSync2(path3, "utf8"));
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, path3, body, signal) {
1152
- const res = await fetch(`${this.base}${path3}`, {
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, path3, body, opts = {}) {
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, path3, body, signal);
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, path3, body, turnId, seq, signal) {
1209
+ async durableCommit(kind, path, body, turnId, seq, signal) {
1210
1210
  try {
1211
- await this.request("POST", path3, body, {
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: path3, body, kind });
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 path3 = `/api/workspaces/${workspaceId}/conversations/${conversationId}/participants/agents/${agentId}/active-run`;
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(path3, conversationId, agentId, body);
1375
+ return this.durableActiveRunWrite(path, conversationId, agentId, body);
1376
1376
  }
1377
- return this.request("PATCH", path3, body);
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(path3, conversationId, agentId, body) {
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", path3, body, { retry: true });
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: path3,
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 path3 = conversationId ? `/api/agent/me?conversationId=${encodeURIComponent(conversationId)}` : `/api/agent/me`;
1497
- return this.request("GET", path3);
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, path3, body) {
1553
- const res = await fetch(`${this.base}${path3}`, {
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 path3 = credentialsPath();
1618
- if (!existsSync4(path3)) return {};
1617
+ const path = credentialsPath();
1618
+ if (!existsSync4(path)) return {};
1619
1619
  let raw;
1620
1620
  try {
1621
- raw = readFileSync3(path3, "utf8");
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 path3 = credentialsPath();
1635
- mkdirSync4(dirname4(path3), { recursive: true });
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 = `${path3}.${process.pid}.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, path3);
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 path3 = pathFor(workspaceId);
1687
- if (!existsSync5(path3)) return null;
1688
- const raw = readFileSync4(path3, "utf8").trim();
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 path3 = pathFor(workspaceId);
1692
+ const path = pathFor(workspaceId);
1693
1693
  mkdirSync5(join7(cabaneDir(), "cursors"), { recursive: true });
1694
- writeFileSync4(path3, eventId + "\n", "utf8");
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 path3 = pathFor2(log, workspaceId);
1748
- if (!existsSync6(path3)) return [];
1747
+ const path = pathFor2(log, workspaceId);
1748
+ if (!existsSync6(path)) return [];
1749
1749
  try {
1750
- return readFileSync5(path3, "utf8").split("\n").map((s) => s.trim()).filter((s) => s.length > 0);
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 path3 = resumePathFor(workspaceId);
1788
- if (!existsSync6(path3)) return out;
1787
+ const path = resumePathFor(workspaceId);
1788
+ if (!existsSync6(path)) return out;
1789
1789
  try {
1790
- for (const line of readFileSync5(path3, "utf8").split("\n")) {
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 as statSync2 } from "fs";
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 path3 = join9(dir2, "instructions.md");
6388
- await writeFile(path3, contents, { encoding: "utf8", mode: 384 });
5861
+ const path = join9(dir2, "instructions.md");
5862
+ await writeFile(path, contents, { encoding: "utf8", mode: 384 });
6389
5863
  return {
6390
- path: path3,
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 path3 = pathFor3(workspaceId, conversationId, agentId);
6411
- if (!existsSync7(path3)) return null;
5884
+ const path = pathFor3(workspaceId, conversationId, agentId);
5885
+ if (!existsSync7(path)) return null;
6412
5886
  try {
6413
- const parsed = JSON.parse(readFileSync6(path3, "utf8"));
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 path3 = secretsPath();
6448
- if (!existsSync8(path3)) return makeStore({});
5921
+ const path = secretsPath();
5922
+ if (!existsSync8(path)) return makeStore({});
6449
5923
  let raw;
6450
5924
  try {
6451
- raw = readFileSync7(path3, "utf8");
5925
+ raw = readFileSync7(path, "utf8");
6452
5926
  } catch (err) {
6453
5927
  throw new ConfigError(
6454
- `couldn't read ${path3}: ${err instanceof Error ? err.message : String(err)}`
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
- `${path3} is not valid JSON: ${err instanceof Error ? err.message : String(err)}. It must be a flat object of "NAME": "value" secret pairs.`
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
- `${path3} must be a flat object mapping secret names to string values (e.g. { "GITHUB_TOKEN": "ghp_\u2026" }).`
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 = statSync2(gitPath);
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 as createRequire2 } from "module";
8337
- var pkg = createRequire2(import.meta.url)("../package.json");
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: spawn5 }) => {
8615
+ void import("child_process").then(({ spawn: spawn4 }) => {
9142
8616
  try {
9143
- const child = spawn5(process.execPath, process.argv.slice(1), {
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 path3 = crashMarkerPath();
9228
- if (existsSync11(path3)) rmSync7(path3, { force: true });
8701
+ const path = crashMarkerPath();
8702
+ if (existsSync11(path)) rmSync7(path, { force: true });
9229
8703
  } catch {
9230
8704
  }
9231
8705
  }