@oxagen/cli 2.1.4-957 → 2.1.4-975

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 (2) hide show
  1. package/oxagen.mjs +1636 -796
  2. package/package.json +1 -1
package/oxagen.mjs CHANGED
@@ -5307,7 +5307,22 @@ var init_envelope = __esm({
5307
5307
  // like `proof.observed`. Its strict schema is
5308
5308
  // `hostEgressRefusedMessageSchema` in `@oxagen/oxagen/sandbox-host/protocol`,
5309
5309
  // which this leaf package cannot import.
5310
- "oxagen:egress_refused": external_exports.object({}).catchall(json)
5310
+ "oxagen:egress_refused": external_exports.object({}).catchall(json),
5311
+ // The in-app assistant's frames (#5943, ADR-5969). The control plane writes
5312
+ // them on the assistant's own session (`assistant-session.ts` in
5313
+ // @oxagen/agent), never a host. A model call and a tool call each take two
5314
+ // frames: the write-ahead request, durable before the provider or the tool
5315
+ // is reached, and the completion. The history summary is the context a
5316
+ // turn carried in place of its older messages, and the goal verdict is one
5317
+ // verifier round. Each body is opaque on the wire, like `proof.observed`:
5318
+ // its members are the receipt the assistant recorded, and the readers in
5319
+ // @oxagen/run-ledger read them by name.
5320
+ "model.engine_call_started": external_exports.object({}).catchall(json),
5321
+ "model.engine_call_completed": external_exports.object({}).catchall(json),
5322
+ "tool.engine_call_started": external_exports.object({}).catchall(json),
5323
+ "tool.engine_call_completed": external_exports.object({}).catchall(json),
5324
+ "context.history_summarized": external_exports.object({}).catchall(json),
5325
+ "verification.goal_verdict": external_exports.object({}).catchall(json)
5311
5326
  };
5312
5327
  TACHO_KINDS = Object.keys(KIND_BODIES);
5313
5328
  agentIdentitySchema = external_exports.object({
@@ -13816,8 +13831,8 @@ var init_backfill = __esm({
13816
13831
  this.parentMs = ms;
13817
13832
  this.clock.ms = ms;
13818
13833
  }
13819
- const spawn7 = [];
13820
- return { events: this.mappedLine(parsed2, text5, offset, spawn7), spawn: spawn7 };
13834
+ const spawn9 = [];
13835
+ return { events: this.mappedLine(parsed2, text5, offset, spawn9), spawn: spawn9 };
13821
13836
  }
13822
13837
  /**
13823
13838
  * Begin a session still waiting for its facts once its last line is read:
@@ -13843,28 +13858,28 @@ var init_backfill = __esm({
13843
13858
  this.parentMs = timestampOf(first) ?? 0;
13844
13859
  this.clock.ms = this.parentMs;
13845
13860
  const events = this.collect(this.start(first, facts, permissionMode));
13846
- const spawn7 = [];
13861
+ const spawn9 = [];
13847
13862
  for (const item of early) {
13848
13863
  const ms = timestampOf(item.record);
13849
13864
  if (ms !== void 0) this.parentMs = Math.max(this.parentMs, ms);
13850
13865
  this.clock.ms = ms ?? this.parentMs;
13851
13866
  events.push(
13852
- ...this.mappedLine(item.record, item.text, item.offset, spawn7)
13867
+ ...this.mappedLine(item.record, item.text, item.offset, spawn9)
13853
13868
  );
13854
13869
  }
13855
13870
  this.clock.ms = this.parentMs;
13856
- return { events, spawn: spawn7 };
13871
+ return { events, spawn: spawn9 };
13857
13872
  }
13858
13873
  /** One parent line through the mapping, guarded. */
13859
- mappedLine(record, text5, offset, spawn7) {
13874
+ mappedLine(record, text5, offset, spawn9) {
13860
13875
  const spawnedBefore = this.spawned.size;
13861
- const spawnLength = spawn7.length;
13876
+ const spawnLength = spawn9.length;
13862
13877
  return this.guarded(
13863
13878
  offset,
13864
13879
  void 0,
13865
- () => this.mapped(record, text5, spawn7),
13880
+ () => this.mapped(record, text5, spawn9),
13866
13881
  () => {
13867
- spawn7.length = spawnLength;
13882
+ spawn9.length = spawnLength;
13868
13883
  for (const toolUseId of [...this.spawned.keys()].slice(spawnedBefore))
13869
13884
  this.spawned.delete(toolUseId);
13870
13885
  }
@@ -14080,7 +14095,7 @@ var init_backfill = __esm({
14080
14095
  })
14081
14096
  );
14082
14097
  }
14083
- mapped(record, text5, spawn7) {
14098
+ mapped(record, text5, spawn9) {
14084
14099
  const type = nonEmptyString(record["type"]);
14085
14100
  const ms = timestampOf(record);
14086
14101
  const events = [];
@@ -14213,7 +14228,7 @@ var init_backfill = __esm({
14213
14228
  ms
14214
14229
  )
14215
14230
  );
14216
- spawn7.push(subagent.agentId);
14231
+ spawn9.push(subagent.agentId);
14217
14232
  }
14218
14233
  return events;
14219
14234
  }
@@ -17571,14 +17586,14 @@ var init_recorder = __esm({
17571
17586
  const parent = this.options.parent;
17572
17587
  if (parent === void 0) return;
17573
17588
  const type = parent.subagentType === void 0 ? subagentType : void 0;
17574
- const spawn7 = parent.spawnToolUseId === void 0 ? spawnToolUseId : void 0;
17575
- if (type === void 0 && spawn7 === void 0) return;
17589
+ const spawn9 = parent.spawnToolUseId === void 0 ? spawnToolUseId : void 0;
17590
+ if (type === void 0 && spawn9 === void 0) return;
17576
17591
  this.options = {
17577
17592
  ...this.options,
17578
17593
  parent: {
17579
17594
  ...parent,
17580
17595
  ...type !== void 0 ? { subagentType: type } : {},
17581
- ...spawn7 !== void 0 ? { spawnToolUseId: spawn7 } : {}
17596
+ ...spawn9 !== void 0 ? { spawnToolUseId: spawn9 } : {}
17582
17597
  }
17583
17598
  };
17584
17599
  }
@@ -21029,12 +21044,12 @@ async function sealTranscript(candidate, deps, pass2) {
21029
21044
  const read2 = await readSlices(candidate.path, sliceBytes, async (lines) => {
21030
21045
  let index = 0;
21031
21046
  while (index < lines.length) {
21032
- const spawn7 = [];
21047
+ const spawn9 = [];
21033
21048
  await deps.exclusive(candidate.sessionId, () => {
21034
21049
  if (deps.heldLocally(candidate.sessionId)) throw new TakenLive();
21035
21050
  const out = [];
21036
21051
  let next = readTo;
21037
- while (spawn7.length === 0) {
21052
+ while (spawn9.length === 0) {
21038
21053
  const line = lines[index];
21039
21054
  if (line === void 0) break;
21040
21055
  index += 1;
@@ -21045,7 +21060,7 @@ async function sealTranscript(candidate, deps, pass2) {
21045
21060
  }
21046
21061
  const sealed = driver.line(line.text, line.offset);
21047
21062
  out.push(...sealed.events);
21048
- spawn7.push(...sealed.spawn);
21063
+ spawn9.push(...sealed.spawn);
21049
21064
  }
21050
21065
  emit(out);
21051
21066
  if (driver.hasChain) {
@@ -21053,7 +21068,7 @@ async function sealTranscript(candidate, deps, pass2) {
21053
21068
  partial(readTo, { status: "partial" });
21054
21069
  }
21055
21070
  });
21056
- for (const agentId of spawn7) await feedSubagent(agentId);
21071
+ for (const agentId of spawn9) await feedSubagent(agentId);
21057
21072
  }
21058
21073
  await between();
21059
21074
  });
@@ -22422,6 +22437,626 @@ var init_claude_code_mcp = __esm({
22422
22437
  }
22423
22438
  });
22424
22439
 
22440
+ // ../../packages/tacho/src/host/run-token.ts
22441
+ import { createHmac, randomBytes as randomBytes4, timingSafeEqual } from "node:crypto";
22442
+ import { readFileSync as readFileSync6 } from "node:fs";
22443
+ function keyFromBytes(bytes) {
22444
+ if (bytes.length !== KEY_BYTES)
22445
+ throw new Error(
22446
+ `run token key must be ${KEY_BYTES} bytes, got ${bytes.length}`
22447
+ );
22448
+ const id2 = createHmac("sha256", "tacho.run-token-key-id").update(bytes).digest("hex").slice(0, 16);
22449
+ return { bytes, id: id2 };
22450
+ }
22451
+ function generateRunTokenKey() {
22452
+ return keyFromBytes(randomBytes4(KEY_BYTES));
22453
+ }
22454
+ function runTokenKeyFromHex(hex) {
22455
+ const trimmed = hex.trim();
22456
+ if (!/^[0-9a-f]{64}$/i.test(trimmed))
22457
+ throw new Error("run token key file does not hold 64 hex characters");
22458
+ return keyFromBytes(Buffer.from(trimmed, "hex"));
22459
+ }
22460
+ function loadOrCreateRunTokenKey(path2) {
22461
+ try {
22462
+ return {
22463
+ key: runTokenKeyFromHex(readFileSync6(path2, "utf8")),
22464
+ created: false
22465
+ };
22466
+ } catch (error) {
22467
+ if (error.code !== "ENOENT") throw error;
22468
+ }
22469
+ const key = generateRunTokenKey();
22470
+ writeSensitiveFileAtomic(path2, `${key.bytes.toString("hex")}
22471
+ `);
22472
+ return { key, created: true };
22473
+ }
22474
+ function readRunTokenKey(path2) {
22475
+ const version2 = fileVersion(path2);
22476
+ if (version2 === void 0) {
22477
+ keysSeen.delete(path2);
22478
+ return void 0;
22479
+ }
22480
+ const seen = keysSeen.get(path2);
22481
+ if (seen?.version === version2) return seen.key;
22482
+ let key;
22483
+ try {
22484
+ key = runTokenKeyFromHex(readFileSync6(path2, "utf8"));
22485
+ } catch (error) {
22486
+ if (error.code === "ENOENT") return void 0;
22487
+ throw error;
22488
+ }
22489
+ keysSeen.set(path2, { version: version2, key });
22490
+ return key;
22491
+ }
22492
+ function b64url(bytes) {
22493
+ return bytes.toString("base64url");
22494
+ }
22495
+ function sign(key, claimsText) {
22496
+ return createHmac("sha256", key.bytes).update(claimsText, "utf8").digest();
22497
+ }
22498
+ function mintRunToken(options) {
22499
+ const ceiling = options.placement === "static" ? RUN_TOKEN_STATIC_MAX_TTL_MS : RUN_TOKEN_MAX_TTL_MS;
22500
+ const asked = options.ttlMs === void 0 ? options.placement === "static" ? RUN_TOKEN_STATIC_MAX_TTL_MS : RUN_TOKEN_DEFAULT_TTL_MS : options.ttlMs;
22501
+ if (!Number.isFinite(asked) || asked <= 0)
22502
+ throw new Error(`run token ttl must be positive, got ${String(asked)}`);
22503
+ let exp = options.now + Math.min(asked, ceiling);
22504
+ if (options.notAfter !== void 0) exp = Math.min(exp, options.notAfter);
22505
+ if (exp <= options.now)
22506
+ throw new Error("run token would already be expired when minted");
22507
+ const claims = {
22508
+ v: 1,
22509
+ tid: `rt_${randomBytes4(10).toString("hex")}`,
22510
+ host: options.host,
22511
+ harness: options.harness,
22512
+ provider: options.provider,
22513
+ placement: options.placement,
22514
+ iat: options.now,
22515
+ exp
22516
+ };
22517
+ const text5 = jcs(claims);
22518
+ const token = `${RUN_TOKEN_PREFIX}${b64url(Buffer.from(text5, "utf8"))}.${b64url(sign(options.key, text5))}`;
22519
+ return { token, claims };
22520
+ }
22521
+ function looksLikeRunToken(value) {
22522
+ return typeof value === "string" && value.startsWith(RUN_TOKEN_PREFIX) && value.length < 2048;
22523
+ }
22524
+ function peekRunTokenClaims(token) {
22525
+ if (!looksLikeRunToken(token)) return void 0;
22526
+ const body2 = token.slice(RUN_TOKEN_PREFIX.length);
22527
+ const dot = body2.indexOf(".");
22528
+ if (dot <= 0) return void 0;
22529
+ try {
22530
+ const parsed2 = JSON.parse(
22531
+ Buffer.from(body2.slice(0, dot), "base64url").toString("utf8")
22532
+ );
22533
+ const claims = runTokenClaimsSchema.safeParse(parsed2);
22534
+ return claims.success ? claims.data : void 0;
22535
+ } catch {
22536
+ return void 0;
22537
+ }
22538
+ }
22539
+ function verifyRunToken(token, options) {
22540
+ if (!looksLikeRunToken(token))
22541
+ return { ok: false, code: "run_token_malformed" };
22542
+ const body2 = token.slice(RUN_TOKEN_PREFIX.length);
22543
+ const dot = body2.indexOf(".");
22544
+ if (dot <= 0 || dot === body2.length - 1)
22545
+ return { ok: false, code: "run_token_malformed" };
22546
+ const bodyText = body2.slice(0, dot);
22547
+ let text5;
22548
+ try {
22549
+ text5 = Buffer.from(bodyText, "base64url").toString("utf8");
22550
+ } catch {
22551
+ return { ok: false, code: "run_token_malformed" };
22552
+ }
22553
+ const presented = Buffer.from(body2.slice(dot + 1), "utf8");
22554
+ const expected = Buffer.from(
22555
+ sign(options.key, text5).toString("base64url"),
22556
+ "utf8"
22557
+ );
22558
+ if (presented.length !== expected.length || !timingSafeEqual(presented, expected) || Buffer.from(text5, "utf8").toString("base64url") !== bodyText) {
22559
+ return { ok: false, code: "run_token_invalid", ...peeked(text5) };
22560
+ }
22561
+ let parsed2;
22562
+ try {
22563
+ parsed2 = JSON.parse(text5);
22564
+ } catch {
22565
+ return { ok: false, code: "run_token_malformed" };
22566
+ }
22567
+ const claims = runTokenClaimsSchema.safeParse(parsed2);
22568
+ if (!claims.success) return { ok: false, code: "run_token_malformed" };
22569
+ if (jcs(claims.data) !== text5)
22570
+ return { ok: false, code: "run_token_invalid" };
22571
+ if (claims.data.exp <= options.now)
22572
+ return { ok: false, code: "run_token_expired", claims: claims.data };
22573
+ if (claims.data.host !== options.host || claims.data.provider !== options.provider)
22574
+ return { ok: false, code: "run_token_mismatch", claims: claims.data };
22575
+ return { ok: true, claims: claims.data };
22576
+ }
22577
+ function peeked(text5) {
22578
+ try {
22579
+ const claims = runTokenClaimsSchema.safeParse(JSON.parse(text5));
22580
+ return claims.success ? { claims: claims.data } : {};
22581
+ } catch {
22582
+ return {};
22583
+ }
22584
+ }
22585
+ var RUN_TOKEN_PREFIX, RUN_TOKEN_MAX_TTL_MS, RUN_TOKEN_DEFAULT_TTL_MS, RUN_TOKEN_STATIC_MAX_TTL_MS, RUN_TOKEN_PROVIDERS, RUN_TOKEN_PLACEMENTS, runTokenClaimsSchema, KEY_BYTES, keysSeen;
22586
+ var init_run_token = __esm({
22587
+ "../../packages/tacho/src/host/run-token.ts"() {
22588
+ "use strict";
22589
+ init_zod();
22590
+ init_digest();
22591
+ init_fs();
22592
+ RUN_TOKEN_PREFIX = "oxrt_";
22593
+ RUN_TOKEN_MAX_TTL_MS = 15 * 6e4;
22594
+ RUN_TOKEN_DEFAULT_TTL_MS = RUN_TOKEN_MAX_TTL_MS;
22595
+ RUN_TOKEN_STATIC_MAX_TTL_MS = 30 * 24 * 60 * 6e4;
22596
+ RUN_TOKEN_PROVIDERS = ["anthropic", "openai"];
22597
+ RUN_TOKEN_PLACEMENTS = ["helper", "static"];
22598
+ runTokenClaimsSchema = external_exports.object({
22599
+ v: external_exports.literal(1),
22600
+ /** `rt_` + 20 hex: cited on frames in place of the token. */
22601
+ tid: external_exports.string().regex(/^rt_[0-9a-f]{20}$/),
22602
+ /** The host enrollment the token was minted for. */
22603
+ host: external_exports.string().min(1).max(64),
22604
+ /** The harness it was handed to. */
22605
+ harness: external_exports.string().min(1).max(32),
22606
+ provider: external_exports.enum(RUN_TOKEN_PROVIDERS),
22607
+ placement: external_exports.enum(RUN_TOKEN_PLACEMENTS),
22608
+ /** Epoch milliseconds. */
22609
+ iat: external_exports.number().int().nonnegative(),
22610
+ exp: external_exports.number().int().nonnegative()
22611
+ }).strict();
22612
+ KEY_BYTES = 32;
22613
+ keysSeen = /* @__PURE__ */ new Map();
22614
+ }
22615
+ });
22616
+
22617
+ // ../../packages/tacho/src/host/credential-store.ts
22618
+ import { createCipheriv, createDecipheriv, randomBytes as randomBytes5 } from "node:crypto";
22619
+ import {
22620
+ closeSync as closeSync4,
22621
+ existsSync as existsSync5,
22622
+ fsyncSync as fsyncSync3,
22623
+ openSync as openSync4,
22624
+ readFileSync as readFileSync7,
22625
+ statSync as statSync3,
22626
+ unlinkSync as unlinkSync4,
22627
+ writeSync as writeSync3
22628
+ } from "node:fs";
22629
+ function anthropicCredentialKind(secret, fallback) {
22630
+ return secret.trim().startsWith(CLAUDE_OAUTH_TOKEN_PREFIX) ? "oauth" : fallback;
22631
+ }
22632
+ function readKey(path2) {
22633
+ try {
22634
+ const hex = readFileSync7(path2, "utf8").trim();
22635
+ if (!/^[0-9a-f]{64}$/i.test(hex))
22636
+ throw new Error(`${path2} does not hold a 32-byte key`);
22637
+ return Buffer.from(hex, "hex");
22638
+ } catch (error) {
22639
+ if (error.code === "ENOENT") return void 0;
22640
+ throw error;
22641
+ }
22642
+ }
22643
+ function loadOrCreateKey(path2) {
22644
+ const existing = readKey(path2);
22645
+ if (existing !== void 0) return existing;
22646
+ const key = randomBytes5(KEY_BYTES2);
22647
+ writeSensitiveFileAtomic(path2, `${key.toString("hex")}
22648
+ `);
22649
+ return key;
22650
+ }
22651
+ function requireKey(path2) {
22652
+ const key = readKey(path2);
22653
+ if (key === void 0)
22654
+ throw new Error(
22655
+ `${path2} is missing, so the credentials in custody cannot be opened`
22656
+ );
22657
+ return key;
22658
+ }
22659
+ function overwriteInPlace(path2) {
22660
+ let fd2;
22661
+ try {
22662
+ const size = statSync3(path2).size;
22663
+ fd2 = openSync4(path2, "r+");
22664
+ writeSync3(fd2, randomBytes5(Math.max(size, KEY_BYTES2 * 2)), 0, void 0, 0);
22665
+ fsyncSync3(fd2);
22666
+ } catch (error) {
22667
+ if (error.code !== "ENOENT") throw error;
22668
+ } finally {
22669
+ if (fd2 !== void 0) closeSync4(fd2);
22670
+ }
22671
+ }
22672
+ function seal(key, secret, aad) {
22673
+ const nonce = randomBytes5(12);
22674
+ const cipher = createCipheriv("aes-256-gcm", key, nonce);
22675
+ cipher.setAAD(Buffer.from(aad, "utf8"));
22676
+ const ciphertext = Buffer.concat([
22677
+ cipher.update(secret, "utf8"),
22678
+ cipher.final()
22679
+ ]);
22680
+ return {
22681
+ nonce: nonce.toString("base64"),
22682
+ ciphertext: ciphertext.toString("base64"),
22683
+ tag: cipher.getAuthTag().toString("base64")
22684
+ };
22685
+ }
22686
+ function open(key, sealed, aad) {
22687
+ const decipher = createDecipheriv(
22688
+ "aes-256-gcm",
22689
+ key,
22690
+ Buffer.from(sealed.nonce, "base64")
22691
+ );
22692
+ decipher.setAAD(Buffer.from(aad, "utf8"));
22693
+ decipher.setAuthTag(Buffer.from(sealed.tag, "base64"));
22694
+ return Buffer.concat([
22695
+ decipher.update(Buffer.from(sealed.ciphertext, "base64")),
22696
+ decipher.final()
22697
+ ]).toString("utf8");
22698
+ }
22699
+ function credentialPrefix(secret) {
22700
+ const head2 = secret.slice(0, Math.min(8, Math.max(0, secret.length - 4)));
22701
+ return head2.length > 0 ? `${head2}\u2026` : "";
22702
+ }
22703
+ function custodyOf(entry2) {
22704
+ return {
22705
+ provider: entry2.provider,
22706
+ kind: entry2.kind,
22707
+ source: entry2.source,
22708
+ taken_at: entry2.taken_at,
22709
+ prefix: entry2.prefix
22710
+ };
22711
+ }
22712
+ function openCredentialStore(paths) {
22713
+ let entriesSeen;
22714
+ let keySeen;
22715
+ const keyForWrite = () => loadOrCreateKey(paths.key);
22716
+ function forgetKey() {
22717
+ keySeen?.key.fill(0);
22718
+ keySeen = void 0;
22719
+ }
22720
+ function keyForRead() {
22721
+ const version2 = fileVersion(paths.key);
22722
+ if (version2 !== void 0 && keySeen?.version === version2)
22723
+ return keySeen.key;
22724
+ forgetKey();
22725
+ const key = requireKey(paths.key);
22726
+ if (version2 !== void 0) keySeen = { version: version2, key };
22727
+ return key;
22728
+ }
22729
+ function readAll() {
22730
+ const version2 = fileVersion(paths.file);
22731
+ if (version2 === void 0) {
22732
+ entriesSeen = void 0;
22733
+ forgetKey();
22734
+ return [];
22735
+ }
22736
+ if (entriesSeen?.version === version2) return entriesSeen.entries;
22737
+ let text5;
22738
+ try {
22739
+ text5 = readFileSync7(paths.file, "utf8");
22740
+ } catch (error) {
22741
+ if (error.code === "ENOENT") return [];
22742
+ throw error;
22743
+ }
22744
+ let raw;
22745
+ try {
22746
+ raw = JSON.parse(text5);
22747
+ } catch (error) {
22748
+ throw new Error(
22749
+ `${paths.file} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`
22750
+ );
22751
+ }
22752
+ const parsed2 = fileSchema.safeParse(raw);
22753
+ if (!parsed2.success)
22754
+ throw new Error(
22755
+ `${paths.file} is not a credential store this build can read: ${parsed2.error.issues[0]?.message ?? "invalid"}`
22756
+ );
22757
+ entriesSeen = { version: version2, entries: parsed2.data.entries };
22758
+ return parsed2.data.entries;
22759
+ }
22760
+ function writeAll2(entries2) {
22761
+ if (entries2.length === 0) {
22762
+ if (existsSync5(paths.file)) unlinkSync4(paths.file);
22763
+ return;
22764
+ }
22765
+ writeSensitiveFileAtomic(
22766
+ paths.file,
22767
+ `${JSON.stringify({ schema: CREDENTIAL_STORE_SCHEMA, entries: entries2 }, null, 2)}
22768
+ `
22769
+ );
22770
+ }
22771
+ return {
22772
+ has: (provider) => readAll().some((e) => e.provider === provider),
22773
+ read: (provider) => {
22774
+ const entry2 = readAll().find((e) => e.provider === provider);
22775
+ if (entry2 === void 0) return void 0;
22776
+ return {
22777
+ kind: entry2.kind,
22778
+ secret: open(
22779
+ keyForRead(),
22780
+ entry2.sealed,
22781
+ `${CREDENTIAL_STORE_SCHEMA}:${provider}`
22782
+ )
22783
+ };
22784
+ },
22785
+ take: (provider, { kind, secret }, source, now) => {
22786
+ if (secret.trim().length === 0)
22787
+ throw new Error("refusing to take an empty credential into custody");
22788
+ const entry2 = {
22789
+ provider,
22790
+ kind,
22791
+ source,
22792
+ taken_at: new Date(now).toISOString(),
22793
+ // A ChatGPT login is JSON, whose head says nothing; it is named.
22794
+ prefix: kind === "chatgpt" ? "login" : credentialPrefix(secret),
22795
+ sealed: seal(
22796
+ keyForWrite(),
22797
+ secret,
22798
+ `${CREDENTIAL_STORE_SCHEMA}:${provider}`
22799
+ )
22800
+ };
22801
+ writeAll2([...readAll().filter((e) => e.provider !== provider), entry2]);
22802
+ return custodyOf(entry2);
22803
+ },
22804
+ release: (provider) => {
22805
+ const entries2 = readAll();
22806
+ const entry2 = entries2.find((e) => e.provider === provider);
22807
+ if (entry2 === void 0) return void 0;
22808
+ const secret = open(
22809
+ keyForRead(),
22810
+ entry2.sealed,
22811
+ `${CREDENTIAL_STORE_SCHEMA}:${provider}`
22812
+ );
22813
+ writeAll2(entries2.filter((e) => e.provider !== provider));
22814
+ return { kind: entry2.kind, secret };
22815
+ },
22816
+ status: () => readAll().map(custodyOf),
22817
+ shred: () => {
22818
+ let overwrite;
22819
+ try {
22820
+ overwriteInPlace(paths.key);
22821
+ } catch (error) {
22822
+ overwrite = error;
22823
+ }
22824
+ for (const path2 of [paths.file, paths.key])
22825
+ if (existsSync5(path2)) unlinkSync4(path2);
22826
+ entriesSeen = void 0;
22827
+ forgetKey();
22828
+ if (overwrite !== void 0)
22829
+ throw new Error(
22830
+ `${paths.key} was deleted but could not be overwritten first: ${overwrite instanceof Error ? overwrite.message : String(overwrite)}`
22831
+ );
22832
+ }
22833
+ };
22834
+ }
22835
+ var CREDENTIAL_STORE_SCHEMA, CREDENTIAL_SOURCES, CREDENTIAL_KINDS, CLAUDE_OAUTH_TOKEN_PREFIX, sealedSchema, entrySchema, fileSchema, KEY_BYTES2;
22836
+ var init_credential_store = __esm({
22837
+ "../../packages/tacho/src/host/credential-store.ts"() {
22838
+ "use strict";
22839
+ init_zod();
22840
+ init_fs();
22841
+ init_run_token();
22842
+ CREDENTIAL_STORE_SCHEMA = "tacho.credentials.v1";
22843
+ CREDENTIAL_SOURCES = [
22844
+ /** `env.ANTHROPIC_API_KEY` in Claude Code's user settings. */
22845
+ "claude-code:settings.env",
22846
+ /** `OPENAI_API_KEY`, or the ChatGPT login's `tokens`, in Codex's `auth.json`. */
22847
+ "codex:auth.json",
22848
+ /** A ChatGPT login the gateway refreshed, replacing the one it took. */
22849
+ "chatgpt:refresh",
22850
+ /**
22851
+ * `TACHO_BROKER_<PROVIDER>_API_KEY`, or `CLAUDE_CODE_OAUTH_TOKEN`, in the
22852
+ * enrolling shell.
22853
+ */
22854
+ "enroll:env",
22855
+ /**
22856
+ * The subscription token `claude setup-token` printed, which
22857
+ * `oxagen credential login` took straight into custody.
22858
+ */
22859
+ "claude:setup-token",
22860
+ /**
22861
+ * The run token in an Oxagen Agent Runners sandbox's `launch` message. It
22862
+ * is spent at the cloud gateway, which attaches the operator's model
22863
+ * credential. It is not a model credential itself.
22864
+ */
22865
+ "sandbox:launch"
22866
+ ];
22867
+ CREDENTIAL_KINDS = [
22868
+ "api_key",
22869
+ "bearer",
22870
+ "oauth",
22871
+ "chatgpt"
22872
+ ];
22873
+ CLAUDE_OAUTH_TOKEN_PREFIX = "sk-ant-oat";
22874
+ sealedSchema = external_exports.object({
22875
+ /** AES-256-GCM: 12-byte nonce, ciphertext, 16-byte tag, all base64. */
22876
+ nonce: external_exports.string().min(1),
22877
+ ciphertext: external_exports.string().min(1),
22878
+ tag: external_exports.string().min(1)
22879
+ }).strict();
22880
+ entrySchema = external_exports.object({
22881
+ provider: external_exports.enum(RUN_TOKEN_PROVIDERS),
22882
+ kind: external_exports.enum(CREDENTIAL_KINDS),
22883
+ source: external_exports.enum(CREDENTIAL_SOURCES),
22884
+ taken_at: external_exports.string(),
22885
+ /** The first few characters, the way a vendor console shows a key. */
22886
+ prefix: external_exports.string().max(12),
22887
+ sealed: sealedSchema
22888
+ }).strict();
22889
+ fileSchema = external_exports.object({
22890
+ schema: external_exports.literal(CREDENTIAL_STORE_SCHEMA),
22891
+ entries: external_exports.array(entrySchema)
22892
+ }).strict();
22893
+ KEY_BYTES2 = 32;
22894
+ }
22895
+ });
22896
+
22897
+ // ../../packages/tacho/src/host/claude-setup-token.ts
22898
+ import { spawn } from "node:child_process";
22899
+ import { accessSync as accessSync2, constants as constants2 } from "node:fs";
22900
+ import { delimiter, join as join13 } from "node:path";
22901
+ function isSubscriptionToken(value) {
22902
+ return TOKEN.test(value.trim());
22903
+ }
22904
+ function extractSetupToken(output) {
22905
+ const lines = output.replace(ANSI, "").split(/\r?\n|\r/).map((line) => line.trim());
22906
+ let found;
22907
+ for (let i2 = 0; i2 < lines.length; i2++) {
22908
+ const line = lines[i2];
22909
+ const start = line.lastIndexOf(CLAUDE_OAUTH_TOKEN_PREFIX);
22910
+ if (start < 0) continue;
22911
+ let token = "";
22912
+ for (const char of line.slice(start)) {
22913
+ if (!TOKEN_CHAR.test(char)) break;
22914
+ token += char;
22915
+ }
22916
+ if (token.length === line.length - start)
22917
+ for (let j = i2 + 1; j < lines.length; j++) {
22918
+ const next = lines[j];
22919
+ if (next.length === 0 || ![...next].every((c) => TOKEN_CHAR.test(c)))
22920
+ break;
22921
+ token += next;
22922
+ }
22923
+ if (isSubscriptionToken(token)) found = token;
22924
+ }
22925
+ return found;
22926
+ }
22927
+ function findClaudeBinary(env, home) {
22928
+ return findHarnessBinary("claude", env, home);
22929
+ }
22930
+ function findHarnessBinary(name, env, home) {
22931
+ const file = process.platform === "win32" ? `${name}.exe` : name;
22932
+ const candidates = [
22933
+ ...(env["PATH"] ?? "").split(delimiter).filter((d) => d.length > 0),
22934
+ join13(home, ".local", "bin"),
22935
+ join13(home, ".claude", "local"),
22936
+ join13(home, ".npm-global", "bin"),
22937
+ "/opt/homebrew/bin",
22938
+ "/usr/local/bin"
22939
+ ].map((dir) => join13(dir, file));
22940
+ for (const path2 of candidates) {
22941
+ try {
22942
+ accessSync2(path2, constants2.X_OK);
22943
+ return path2;
22944
+ } catch {
22945
+ }
22946
+ }
22947
+ return void 0;
22948
+ }
22949
+ function setupTokenCommand(claude, platform) {
22950
+ const quoted3 = `'${claude.replace(/'/g, `'\\''`)}'`;
22951
+ const inner = `stty cols 1000 2>/dev/null; exec ${quoted3} setup-token`;
22952
+ if (platform === "darwin")
22953
+ return { file: "script", args: ["-q", "/dev/null", "sh", "-c", inner] };
22954
+ if (platform === "linux")
22955
+ return { file: "script", args: ["-q", "-e", "-c", inner, "/dev/null"] };
22956
+ return void 0;
22957
+ }
22958
+ function shellQuote(value) {
22959
+ return `'${value.replace(/'/g, `'\\''`)}'`;
22960
+ }
22961
+ function setupTokenShellLine(claude, platform) {
22962
+ const command2 = setupTokenCommand(claude, platform);
22963
+ if (command2 === void 0) return void 0;
22964
+ const script = [command2.file, ...command2.args].map(shellQuote).join(" ");
22965
+ return `sleep 2147483647 | { ${script}; echo "${SETUP_TOKEN_EXIT_MARK}$?"; }`;
22966
+ }
22967
+ function runClaudeSetupToken(options) {
22968
+ const command2 = setupTokenCommand(
22969
+ options.claude,
22970
+ options.platform ?? process.platform
22971
+ );
22972
+ return new Promise((resolve25, reject) => {
22973
+ if (command2 === void 0) {
22974
+ const child2 = spawn(options.claude, ["setup-token"], {
22975
+ stdio: "inherit",
22976
+ env: options.env ?? process.env
22977
+ });
22978
+ child2.on("error", reject);
22979
+ child2.on(
22980
+ "close",
22981
+ (code) => resolve25({ token: void 0, code: code ?? 1, captured: false })
22982
+ );
22983
+ return;
22984
+ }
22985
+ const env = options.env ?? process.env;
22986
+ if (options.interactive) {
22987
+ const child2 = spawn(command2.file, command2.args, {
22988
+ stdio: ["inherit", "pipe", "inherit"],
22989
+ env
22990
+ });
22991
+ let output2 = "";
22992
+ child2.stdout?.setEncoding("utf8");
22993
+ child2.stdout?.on("data", (chunk2) => {
22994
+ output2 += chunk2;
22995
+ options.write(chunk2);
22996
+ });
22997
+ child2.on("error", reject);
22998
+ child2.on(
22999
+ "close",
23000
+ (code) => resolve25({
23001
+ token: extractSetupToken(output2),
23002
+ code: code ?? 1,
23003
+ captured: true
23004
+ })
23005
+ );
23006
+ return;
23007
+ }
23008
+ const line = setupTokenShellLine(
23009
+ options.claude,
23010
+ options.platform ?? process.platform
23011
+ );
23012
+ const child = spawn("sh", ["-c", line], {
23013
+ detached: true,
23014
+ stdio: ["ignore", "pipe", "inherit"],
23015
+ env
23016
+ });
23017
+ let output = "";
23018
+ let exited;
23019
+ const mark = new RegExp(`${SETUP_TOKEN_EXIT_MARK}(\\d+)`);
23020
+ const stopGroup = () => {
23021
+ try {
23022
+ if (child.pid !== void 0) process.kill(-child.pid, "SIGTERM");
23023
+ } catch {
23024
+ }
23025
+ };
23026
+ child.stdout?.setEncoding("utf8");
23027
+ child.stdout?.on("data", (chunk2) => {
23028
+ output += chunk2;
23029
+ const found = mark.exec(output);
23030
+ options.write(chunk2.replace(mark, "").replace(SETUP_TOKEN_EXIT_MARK, ""));
23031
+ if (found !== null && exited === void 0) {
23032
+ exited = Number(found[1]);
23033
+ stopGroup();
23034
+ }
23035
+ });
23036
+ child.on("error", reject);
23037
+ child.on(
23038
+ "close",
23039
+ (code) => resolve25({
23040
+ token: extractSetupToken(output.replace(mark, "")),
23041
+ code: exited ?? code ?? 1,
23042
+ captured: true
23043
+ })
23044
+ );
23045
+ });
23046
+ }
23047
+ var TOKEN, TOKEN_CHAR, ANSI, SETUP_TOKEN_EXIT_MARK;
23048
+ var init_claude_setup_token = __esm({
23049
+ "../../packages/tacho/src/host/claude-setup-token.ts"() {
23050
+ "use strict";
23051
+ init_credential_store();
23052
+ TOKEN = /^sk-ant-oat\d{2}-[A-Za-z0-9_-]{20,}$/;
23053
+ TOKEN_CHAR = /[A-Za-z0-9_-]/;
23054
+ ANSI = // biome-ignore lint/suspicious/noControlCharactersInRegex: terminal escapes
23055
+ /\u001b\][^\u0007\u001b]*(?:\u0007|\u001b\\)|\u001b\[[0-?]*[ -/]*[@-~]|\u001b[@-Z\\-_]/g;
23056
+ SETUP_TOKEN_EXIT_MARK = "__oxagen_setup_token_exit__=";
23057
+ }
23058
+ });
23059
+
22425
23060
  // ../../packages/tacho/src/host/model-base-url-toml.ts
22426
23061
  function splitLines(text5) {
22427
23062
  const lines = [];
@@ -22539,8 +23174,8 @@ var init_model_base_url_toml = __esm({
22539
23174
  });
22540
23175
 
22541
23176
  // ../../packages/tacho/src/host/model-base-url.ts
22542
- import { chmodSync as chmodSync3, existsSync as existsSync5, readFileSync as readFileSync6, unlinkSync as unlinkSync4 } from "node:fs";
22543
- import { basename as basename4, dirname as dirname7, join as join13 } from "node:path";
23177
+ import { chmodSync as chmodSync3, existsSync as existsSync6, readFileSync as readFileSync8, unlinkSync as unlinkSync5 } from "node:fs";
23178
+ import { basename as basename4, dirname as dirname7, join as join14 } from "node:path";
22544
23179
  function claudeToolSearchEnabled(value) {
22545
23180
  return typeof value === "string" && /^(true|auto(:\d+)?)$/i.test(value);
22546
23181
  }
@@ -22554,19 +23189,19 @@ function isModelProxyBaseUrl(harness, value) {
22554
23189
  }
22555
23190
  function modelBaseUrlFile(harness, homes) {
22556
23191
  if (harness === "claude-code")
22557
- return join13(
23192
+ return join14(
22558
23193
  homes.claudeConfigDir ?? harnessConfigDirs(homes.home).claudeConfigDir,
22559
23194
  "settings.json"
22560
23195
  );
22561
23196
  if (harness === "codex")
22562
- return join13(
23197
+ return join14(
22563
23198
  homes.codexHome ?? harnessConfigDirs(homes.home).codexHome,
22564
23199
  "config.toml"
22565
23200
  );
22566
- const stellaHome = homes.stellaHome ?? join13(homes.home, ".stella");
22567
- const toml = join13(stellaHome, "stella.toml");
22568
- const json2 = join13(stellaHome, "settings.json");
22569
- return !existsSync5(toml) && existsSync5(json2) ? json2 : toml;
23201
+ const stellaHome = homes.stellaHome ?? join14(homes.home, ".stella");
23202
+ const toml = join14(stellaHome, "stella.toml");
23203
+ const json2 = join14(stellaHome, "settings.json");
23204
+ return !existsSync6(toml) && existsSync6(json2) ? json2 : toml;
22570
23205
  }
22571
23206
  function keyLabel(harness) {
22572
23207
  if (harness === "claude-code") return `env.${CLAUDE_KEY}`;
@@ -22576,7 +23211,7 @@ function isJsonFile(file) {
22576
23211
  return file.endsWith(".json");
22577
23212
  }
22578
23213
  function sidecarBeside(file, contract) {
22579
- return join13(dirname7(file), `.${basename4(file)}.${contract}.json`);
23214
+ return join14(dirname7(file), `.${basename4(file)}.${contract}.json`);
22580
23215
  }
22581
23216
  function sidecarFor(file) {
22582
23217
  return sidecarBeside(file, "oxagen-model-base-url");
@@ -22707,9 +23342,9 @@ function stellaManagedSettingsPath(platform = process.platform, env = process.en
22707
23342
  const named = env["STELLA_MANAGED_SETTINGS"];
22708
23343
  if (named !== void 0 && named.length > 0) return named;
22709
23344
  const dir = platform === "darwin" ? "/Library/Application Support/stella" : "/etc/stella";
22710
- const toml = join13(dir, "stella.toml");
22711
- const json2 = join13(dir, "settings.json");
22712
- return !existsSync5(toml) && existsSync5(json2) ? json2 : toml;
23345
+ const toml = join14(dir, "stella.toml");
23346
+ const json2 = join14(dir, "settings.json");
23347
+ return !existsSync6(toml) && existsSync6(json2) ? json2 : toml;
22713
23348
  }
22714
23349
  function managedShadow(harness, managedFile, expected) {
22715
23350
  try {
@@ -22917,7 +23552,7 @@ function describe3(harness, options, { changed, text: text5, sidecar, unreadable
22917
23552
  }
22918
23553
  function readBytesIfExists(path2) {
22919
23554
  try {
22920
- return readFileSync6(path2);
23555
+ return readFileSync8(path2);
22921
23556
  } catch (error) {
22922
23557
  if (error.code === "ENOENT") return void 0;
22923
23558
  throw error;
@@ -23031,7 +23666,7 @@ function restoreOne(harness, options) {
23031
23666
  const { sidecar, unreadable } = sidecarOrWhy(backup, harness);
23032
23667
  const text5 = readTextIfExists(file);
23033
23668
  const dropSidecar = () => {
23034
- if (existsSync5(backup)) unlinkSync4(backup);
23669
+ if (existsSync6(backup)) unlinkSync5(backup);
23035
23670
  };
23036
23671
  const after = (changed, left) => ({
23037
23672
  changed,
@@ -23050,7 +23685,7 @@ function restoreOne(harness, options) {
23050
23685
  writeFileAtomicPreserving(file, original);
23051
23686
  left = original.toString("utf8");
23052
23687
  } else {
23053
- unlinkSync4(file);
23688
+ unlinkSync5(file);
23054
23689
  }
23055
23690
  dropSidecar();
23056
23691
  return after(true, left);
@@ -23163,186 +23798,66 @@ var init_model_base_url = __esm({
23163
23798
  }
23164
23799
  });
23165
23800
 
23166
- // ../../packages/tacho/src/host/run-token.ts
23167
- import { createHmac, randomBytes as randomBytes4, timingSafeEqual } from "node:crypto";
23168
- import { readFileSync as readFileSync7 } from "node:fs";
23169
- function keyFromBytes(bytes) {
23170
- if (bytes.length !== KEY_BYTES)
23171
- throw new Error(
23172
- `run token key must be ${KEY_BYTES} bytes, got ${bytes.length}`
23173
- );
23174
- const id2 = createHmac("sha256", "tacho.run-token-key-id").update(bytes).digest("hex").slice(0, 16);
23175
- return { bytes, id: id2 };
23176
- }
23177
- function generateRunTokenKey() {
23178
- return keyFromBytes(randomBytes4(KEY_BYTES));
23179
- }
23180
- function runTokenKeyFromHex(hex) {
23181
- const trimmed = hex.trim();
23182
- if (!/^[0-9a-f]{64}$/i.test(trimmed))
23183
- throw new Error("run token key file does not hold 64 hex characters");
23184
- return keyFromBytes(Buffer.from(trimmed, "hex"));
23801
+ // ../../packages/tacho/src/host/model-credential.ts
23802
+ import { chmodSync as chmodSync4, existsSync as existsSync7, lstatSync as lstatSync2, unlinkSync as unlinkSync6 } from "node:fs";
23803
+ import { join as join15 } from "node:path";
23804
+ function claudeMemberFor(kind) {
23805
+ return kind === "oauth" ? CLAUDE_OAUTH_TOKEN : kind === "bearer" ? CLAUDE_AUTH_TOKEN : CLAUDE_API_KEY;
23185
23806
  }
23186
- function loadOrCreateRunTokenKey(path2) {
23187
- try {
23188
- return {
23189
- key: runTokenKeyFromHex(readFileSync7(path2, "utf8")),
23190
- created: false
23191
- };
23192
- } catch (error) {
23193
- if (error.code !== "ENOENT") throw error;
23807
+ function claudeEnvCredentials(env) {
23808
+ const found = [];
23809
+ for (const [member3, kind] of CLAUDE_MEMBERS) {
23810
+ const value = env[member3];
23811
+ if (isSecret(value))
23812
+ found.push({
23813
+ member: member3,
23814
+ credential: {
23815
+ kind: anthropicCredentialKind(value, kind),
23816
+ secret: value
23817
+ }
23818
+ });
23194
23819
  }
23195
- const key = generateRunTokenKey();
23196
- writeSensitiveFileAtomic(path2, `${key.bytes.toString("hex")}
23197
- `);
23198
- return { key, created: true };
23820
+ return found;
23199
23821
  }
23200
- function readRunTokenKey(path2) {
23201
- const version2 = fileVersion(path2);
23202
- if (version2 === void 0) {
23203
- keysSeen.delete(path2);
23822
+ function chatGptTokensOf(auth) {
23823
+ const tokens = auth[CODEX_TOKENS];
23824
+ if (typeof tokens !== "object" || tokens === null || Array.isArray(tokens))
23204
23825
  return void 0;
23205
- }
23206
- const seen = keysSeen.get(path2);
23207
- if (seen?.version === version2) return seen.key;
23208
- let key;
23209
- try {
23210
- key = runTokenKeyFromHex(readFileSync7(path2, "utf8"));
23211
- } catch (error) {
23212
- if (error.code === "ENOENT") return void 0;
23213
- throw error;
23214
- }
23215
- keysSeen.set(path2, { version: version2, key });
23216
- return key;
23217
- }
23218
- function b64url(bytes) {
23219
- return bytes.toString("base64url");
23220
- }
23221
- function sign(key, claimsText) {
23222
- return createHmac("sha256", key.bytes).update(claimsText, "utf8").digest();
23826
+ const record = tokens;
23827
+ return isSecret(record["access_token"]) ? record : void 0;
23223
23828
  }
23224
- function mintRunToken(options) {
23225
- const ceiling = options.placement === "static" ? RUN_TOKEN_STATIC_MAX_TTL_MS : RUN_TOKEN_MAX_TTL_MS;
23226
- const asked = options.ttlMs === void 0 ? options.placement === "static" ? RUN_TOKEN_STATIC_MAX_TTL_MS : RUN_TOKEN_DEFAULT_TTL_MS : options.ttlMs;
23227
- if (!Number.isFinite(asked) || asked <= 0)
23228
- throw new Error(`run token ttl must be positive, got ${String(asked)}`);
23229
- let exp = options.now + Math.min(asked, ceiling);
23230
- if (options.notAfter !== void 0) exp = Math.min(exp, options.notAfter);
23231
- if (exp <= options.now)
23232
- throw new Error("run token would already be expired when minted");
23233
- const claims = {
23234
- v: 1,
23235
- tid: `rt_${randomBytes4(10).toString("hex")}`,
23236
- host: options.host,
23237
- harness: options.harness,
23238
- provider: options.provider,
23239
- placement: options.placement,
23240
- iat: options.now,
23241
- exp
23829
+ function encodeChatGptLogin(tokens) {
23830
+ const login = {
23831
+ access_token: tokens["access_token"],
23832
+ refresh_token: typeof tokens["refresh_token"] === "string" ? tokens["refresh_token"] : ""
23242
23833
  };
23243
- const text5 = jcs(claims);
23244
- const token = `${RUN_TOKEN_PREFIX}${b64url(Buffer.from(text5, "utf8"))}.${b64url(sign(options.key, text5))}`;
23245
- return { token, claims };
23246
- }
23247
- function looksLikeRunToken(value) {
23248
- return typeof value === "string" && value.startsWith(RUN_TOKEN_PREFIX) && value.length < 2048;
23834
+ if (typeof tokens["id_token"] === "string")
23835
+ login.id_token = tokens["id_token"];
23836
+ if (typeof tokens["account_id"] === "string")
23837
+ login.account_id = tokens["account_id"];
23838
+ return JSON.stringify(login);
23249
23839
  }
23250
- function peekRunTokenClaims(token) {
23251
- if (!looksLikeRunToken(token)) return void 0;
23252
- const body2 = token.slice(RUN_TOKEN_PREFIX.length);
23253
- const dot = body2.indexOf(".");
23254
- if (dot <= 0) return void 0;
23840
+ function decodeChatGptLogin(secret) {
23255
23841
  try {
23256
- const parsed2 = JSON.parse(
23257
- Buffer.from(body2.slice(0, dot), "base64url").toString("utf8")
23258
- );
23259
- const claims = runTokenClaimsSchema.safeParse(parsed2);
23260
- return claims.success ? claims.data : void 0;
23842
+ const raw = JSON.parse(secret);
23843
+ if (typeof raw.access_token !== "string" || raw.access_token.length === 0)
23844
+ return void 0;
23845
+ return {
23846
+ access_token: raw.access_token,
23847
+ refresh_token: typeof raw.refresh_token === "string" ? raw.refresh_token : "",
23848
+ ...typeof raw.id_token === "string" ? { id_token: raw.id_token } : {},
23849
+ ...typeof raw.account_id === "string" ? { account_id: raw.account_id } : {}
23850
+ };
23261
23851
  } catch {
23262
23852
  return void 0;
23263
23853
  }
23264
23854
  }
23265
- function verifyRunToken(token, options) {
23266
- if (!looksLikeRunToken(token))
23267
- return { ok: false, code: "run_token_malformed" };
23268
- const body2 = token.slice(RUN_TOKEN_PREFIX.length);
23269
- const dot = body2.indexOf(".");
23270
- if (dot <= 0 || dot === body2.length - 1)
23271
- return { ok: false, code: "run_token_malformed" };
23272
- const bodyText = body2.slice(0, dot);
23273
- let text5;
23274
- try {
23275
- text5 = Buffer.from(bodyText, "base64url").toString("utf8");
23276
- } catch {
23277
- return { ok: false, code: "run_token_malformed" };
23278
- }
23279
- const presented = Buffer.from(body2.slice(dot + 1), "utf8");
23280
- const expected = Buffer.from(
23281
- sign(options.key, text5).toString("base64url"),
23282
- "utf8"
23283
- );
23284
- if (presented.length !== expected.length || !timingSafeEqual(presented, expected) || Buffer.from(text5, "utf8").toString("base64url") !== bodyText) {
23285
- return { ok: false, code: "run_token_invalid", ...peeked(text5) };
23286
- }
23287
- let parsed2;
23288
- try {
23289
- parsed2 = JSON.parse(text5);
23290
- } catch {
23291
- return { ok: false, code: "run_token_malformed" };
23292
- }
23293
- const claims = runTokenClaimsSchema.safeParse(parsed2);
23294
- if (!claims.success) return { ok: false, code: "run_token_malformed" };
23295
- if (jcs(claims.data) !== text5)
23296
- return { ok: false, code: "run_token_invalid" };
23297
- if (claims.data.exp <= options.now)
23298
- return { ok: false, code: "run_token_expired", claims: claims.data };
23299
- if (claims.data.host !== options.host || claims.data.provider !== options.provider)
23300
- return { ok: false, code: "run_token_mismatch", claims: claims.data };
23301
- return { ok: true, claims: claims.data };
23302
- }
23303
- function peeked(text5) {
23304
- try {
23305
- const claims = runTokenClaimsSchema.safeParse(JSON.parse(text5));
23306
- return claims.success ? { claims: claims.data } : {};
23307
- } catch {
23308
- return {};
23309
- }
23855
+ function codexTokenMember(auth) {
23856
+ const tokens = chatGptTokensOf(auth);
23857
+ if (tokens !== void 0) return tokens["access_token"];
23858
+ const key = auth[CODEX_KEY2];
23859
+ return typeof key === "string" ? key : void 0;
23310
23860
  }
23311
- var RUN_TOKEN_PREFIX, RUN_TOKEN_MAX_TTL_MS, RUN_TOKEN_DEFAULT_TTL_MS, RUN_TOKEN_STATIC_MAX_TTL_MS, RUN_TOKEN_PROVIDERS, RUN_TOKEN_PLACEMENTS, runTokenClaimsSchema, KEY_BYTES, keysSeen;
23312
- var init_run_token = __esm({
23313
- "../../packages/tacho/src/host/run-token.ts"() {
23314
- "use strict";
23315
- init_zod();
23316
- init_digest();
23317
- init_fs();
23318
- RUN_TOKEN_PREFIX = "oxrt_";
23319
- RUN_TOKEN_MAX_TTL_MS = 15 * 6e4;
23320
- RUN_TOKEN_DEFAULT_TTL_MS = RUN_TOKEN_MAX_TTL_MS;
23321
- RUN_TOKEN_STATIC_MAX_TTL_MS = 30 * 24 * 60 * 6e4;
23322
- RUN_TOKEN_PROVIDERS = ["anthropic", "openai"];
23323
- RUN_TOKEN_PLACEMENTS = ["helper", "static"];
23324
- runTokenClaimsSchema = external_exports.object({
23325
- v: external_exports.literal(1),
23326
- /** `rt_` + 20 hex: cited on frames in place of the token. */
23327
- tid: external_exports.string().regex(/^rt_[0-9a-f]{20}$/),
23328
- /** The host enrollment the token was minted for. */
23329
- host: external_exports.string().min(1).max(64),
23330
- /** The harness it was handed to. */
23331
- harness: external_exports.string().min(1).max(32),
23332
- provider: external_exports.enum(RUN_TOKEN_PROVIDERS),
23333
- placement: external_exports.enum(RUN_TOKEN_PLACEMENTS),
23334
- /** Epoch milliseconds. */
23335
- iat: external_exports.number().int().nonnegative(),
23336
- exp: external_exports.number().int().nonnegative()
23337
- }).strict();
23338
- KEY_BYTES = 32;
23339
- keysSeen = /* @__PURE__ */ new Map();
23340
- }
23341
- });
23342
-
23343
- // ../../packages/tacho/src/host/model-credential.ts
23344
- import { chmodSync as chmodSync4, existsSync as existsSync6, lstatSync as lstatSync2, unlinkSync as unlinkSync5 } from "node:fs";
23345
- import { join as join14 } from "node:path";
23346
23861
  function isTachoHelper(value) {
23347
23862
  return typeof value === "string" && HELPER_MARK.test(value);
23348
23863
  }
@@ -23350,10 +23865,10 @@ function helperCommandFor(tachoCommand) {
23350
23865
  return `${tachoCommand} credential issue --harness claude-code`;
23351
23866
  }
23352
23867
  function fileFor2(harness, homes) {
23353
- return harness === "claude-code" ? join14(
23868
+ return harness === "claude-code" ? join15(
23354
23869
  homes.claudeConfigDir ?? harnessConfigDirs(homes.home).claudeConfigDir,
23355
23870
  "settings.json"
23356
- ) : join14(
23871
+ ) : join15(
23357
23872
  homes.codexHome ?? harnessConfigDirs(homes.home).codexHome,
23358
23873
  "auth.json"
23359
23874
  );
@@ -23396,7 +23911,9 @@ function readSidecar2(path2, harness) {
23396
23911
  existed: parsed2["existed"] === true,
23397
23912
  written_sha256: written2,
23398
23913
  taken: Array.isArray(taken) ? taken.filter(
23399
- (t) => typeof t === "object" && t !== null && typeof t.member === "string" && (t.kind === "api_key" || t.kind === "bearer")
23914
+ (t) => typeof t === "object" && t !== null && typeof t.member === "string" && CREDENTIAL_KINDS.includes(
23915
+ t.kind
23916
+ )
23400
23917
  ) : []
23401
23918
  };
23402
23919
  if (harness === "codex") return { ...common, harness };
@@ -23419,7 +23936,7 @@ function isSecret(value) {
23419
23936
  return typeof value === "string" && value.length > 0;
23420
23937
  }
23421
23938
  function holdsBothClaudeMembers(env) {
23422
- return isSecret(env[CLAUDE_API_KEY]) && isSecret(env[CLAUDE_AUTH_TOKEN]);
23939
+ return CLAUDE_MEMBERS.filter(([member3]) => isSecret(env[member3])).length > 1;
23423
23940
  }
23424
23941
  function managedHelperShadow(managedFile, expected) {
23425
23942
  try {
@@ -23469,7 +23986,7 @@ function describe4(harness, options, { changed, text: text5, reason: reason3, un
23469
23986
  const current = settings[HELPER_KEY];
23470
23987
  helper = typeof current === "string" ? current : null;
23471
23988
  const env = envOf(settings) ?? {};
23472
- brokered = isTachoHelper(current) && typeof env[CLAUDE_API_KEY] !== "string" && typeof env[CLAUDE_AUTH_TOKEN] !== "string";
23989
+ brokered = isTachoHelper(current) && CLAUDE_MEMBERS.every(([member3]) => typeof env[member3] !== "string");
23473
23990
  if (!brokered && holdsBothClaudeMembers(env)) why ??= "two_credentials";
23474
23991
  const managed = managedHelperShadow(
23475
23992
  internals.managedSettingsFile ?? claudeManagedSettingsPath(),
@@ -23479,14 +23996,14 @@ function describe4(harness, options, { changed, text: text5, reason: reason3, un
23479
23996
  if (managed.unreadable !== void 0) unreadable.push(managed.unreadable);
23480
23997
  } else {
23481
23998
  const auth = parseForReport(text5, file, unreadable);
23482
- const key = auth[CODEX_KEY2];
23483
- brokered = looksLikeRunToken(typeof key === "string" ? key : void 0);
23999
+ const key = codexTokenMember(auth);
24000
+ brokered = looksLikeRunToken(key);
23484
24001
  if (brokered) {
23485
24002
  const claims = peekRunTokenClaims(key);
23486
24003
  if (claims !== void 0)
23487
24004
  tokenExpiresAt = new Date(claims.exp).toISOString();
23488
24005
  }
23489
- if (!brokered && why === void 0 && auth["tokens"] !== void 0)
24006
+ if (!brokered && why === void 0 && auth[CODEX_TOKENS] !== void 0)
23490
24007
  why = "subscription_login";
23491
24008
  }
23492
24009
  return {
@@ -23519,21 +24036,15 @@ function applyClaude(options, taken) {
23519
24036
  return { changed: false, text: text5, reason: "two_credentials" };
23520
24037
  const rest = { ...env ?? {} };
23521
24038
  const took = [];
23522
- for (const [member3, kind] of [
23523
- [CLAUDE_API_KEY, "api_key"],
23524
- [CLAUDE_AUTH_TOKEN, "bearer"]
23525
- ]) {
23526
- const value = rest[member3];
23527
- if (isSecret(value)) {
23528
- taken.push({
23529
- harness: "claude-code",
23530
- provider: "anthropic",
23531
- credential: { kind, secret: value },
23532
- member: `env.${member3}`
23533
- });
23534
- took.push({ member: member3, kind });
23535
- delete rest[member3];
23536
- }
24039
+ for (const { member: member3, credential } of claudeEnvCredentials(rest)) {
24040
+ taken.push({
24041
+ harness: "claude-code",
24042
+ provider: "anthropic",
24043
+ credential,
24044
+ member: `env.${member3}`
24045
+ });
24046
+ took.push({ member: member3, kind: credential.kind });
24047
+ delete rest[member3];
23537
24048
  }
23538
24049
  const helperCommand = options.helperCommand;
23539
24050
  if (helperCommand === void 0)
@@ -23581,7 +24092,49 @@ function applyCodex(options, taken) {
23581
24092
  const existing = readSidecar2(backup, "codex");
23582
24093
  const current = auth[CODEX_KEY2];
23583
24094
  const hasKey = typeof current === "string" && current.length > 0;
23584
- if (auth["tokens"] !== void 0 && !looksLikeRunToken(typeof current === "string" ? current : void 0)) {
24095
+ const tokens = chatGptTokensOf(auth);
24096
+ if (tokens !== void 0) {
24097
+ const access2 = tokens["access_token"];
24098
+ const ours = looksLikeRunToken(access2);
24099
+ if (!ours)
24100
+ taken.push({
24101
+ harness: "codex",
24102
+ provider: "openai",
24103
+ credential: { kind: "chatgpt", secret: encodeChatGptLogin(tokens) },
24104
+ member: CODEX_TOKENS
24105
+ });
24106
+ if (token === void 0) {
24107
+ if (!ours) taken.pop();
24108
+ return { changed: false, text: text5, reason: "no_token" };
24109
+ }
24110
+ if (access2 === token && existing !== void 0)
24111
+ return { changed: false, text: text5 };
24112
+ auth[CODEX_TOKENS] = {
24113
+ ...tokens,
24114
+ access_token: token,
24115
+ refresh_token: CHATGPT_REFRESH_HELD
24116
+ };
24117
+ auth[CODEX_LAST_REFRESH] = (/* @__PURE__ */ new Date()).toISOString();
24118
+ const next2 = serializeJsonLike(text5, auth);
24119
+ const sidecar2 = existing ? {
24120
+ ...existing,
24121
+ written_sha256: sha256Hex(next2),
24122
+ taken: [
24123
+ ...existing.taken.filter((t) => t.member !== CODEX_TOKENS),
24124
+ { member: CODEX_TOKENS, kind: "chatgpt" }
24125
+ ]
24126
+ } : {
24127
+ schema: SIDECAR_SCHEMA2,
24128
+ harness: "codex",
24129
+ existed: true,
24130
+ written_sha256: sha256Hex(next2),
24131
+ taken: [{ member: CODEX_TOKENS, kind: "chatgpt" }]
24132
+ };
24133
+ writeSidecar(backup, sidecar2);
24134
+ writeFileAtomicPreserving(file, next2);
24135
+ return { changed: true, text: next2 };
24136
+ }
24137
+ if (auth[CODEX_TOKENS] !== void 0 && !looksLikeRunToken(typeof current === "string" ? current : void 0)) {
23585
24138
  return { changed: false, text: text5, reason: "subscription_login" };
23586
24139
  }
23587
24140
  if (hasKey && !looksLikeRunToken(current)) {
@@ -23616,11 +24169,11 @@ function restoreClaude(options, released, sidecar) {
23616
24169
  const backup = sidecarFor2(file);
23617
24170
  const text5 = readTextIfExists(file);
23618
24171
  const dropSidecar = () => {
23619
- if (existsSync6(backup)) unlinkSync5(backup);
24172
+ if (existsSync7(backup)) unlinkSync6(backup);
23620
24173
  };
23621
24174
  if (text5 === void 0) {
23622
24175
  if (released !== void 0) {
23623
- const member3 = released.kind === "bearer" ? CLAUDE_AUTH_TOKEN : CLAUDE_API_KEY;
24176
+ const member3 = claudeMemberFor(released.kind);
23624
24177
  const written2 = serializeJsonLike(void 0, {
23625
24178
  env: { [member3]: released.secret }
23626
24179
  });
@@ -23640,11 +24193,11 @@ function restoreClaude(options, released, sidecar) {
23640
24193
  touched = true;
23641
24194
  }
23642
24195
  const current = envOf(settings);
23643
- const foreignKey = current !== void 0 && (isSecret(current[CLAUDE_API_KEY]) || isSecret(current[CLAUDE_AUTH_TOKEN]));
24196
+ const foreignKey = current !== void 0 && CLAUDE_MEMBERS.some(([member3]) => isSecret(current[member3]));
23644
24197
  const why = foreignKey ? { reason: "foreign_key_present" } : {};
23645
24198
  let secretRestored = false;
23646
24199
  if (released !== void 0 && !foreignKey) {
23647
- const member3 = sidecar?.taken.find((t) => t.kind === released.kind)?.member ?? (released.kind === "bearer" ? CLAUDE_AUTH_TOKEN : CLAUDE_API_KEY);
24200
+ const member3 = sidecar?.taken.find((t) => t.kind === released.kind)?.member ?? claudeMemberFor(released.kind);
23648
24201
  const env = { ...current ?? {} };
23649
24202
  env[member3] = released.secret;
23650
24203
  settings["env"] = env;
@@ -23674,7 +24227,7 @@ function restoreCodex(options, released, sidecar) {
23674
24227
  const backup = sidecarFor2(file);
23675
24228
  const text5 = readTextIfExists(file);
23676
24229
  const dropSidecar = () => {
23677
- if (existsSync6(backup)) unlinkSync5(backup);
24230
+ if (existsSync7(backup)) unlinkSync6(backup);
23678
24231
  };
23679
24232
  if (text5 === void 0) {
23680
24233
  if (released !== void 0) {
@@ -23689,6 +24242,18 @@ function restoreCodex(options, released, sidecar) {
23689
24242
  return { changed: false, text: text5, secretRestored: false };
23690
24243
  }
23691
24244
  const auth = parseJsonObject(text5, file);
24245
+ const tokens = chatGptTokensOf(auth);
24246
+ if (tokens !== void 0 && looksLikeRunToken(tokens["access_token"])) {
24247
+ const login = released?.kind === "chatgpt" ? decodeChatGptLogin(released.secret) : void 0;
24248
+ if (login !== void 0) {
24249
+ auth[CODEX_TOKENS] = { ...tokens, ...login };
24250
+ auth[CODEX_LAST_REFRESH] = (/* @__PURE__ */ new Date()).toISOString();
24251
+ } else delete auth[CODEX_TOKENS];
24252
+ const next2 = serializeJsonLike(text5, auth);
24253
+ writeFileAtomicPreserving(file, next2);
24254
+ dropSidecar();
24255
+ return { changed: true, text: next2, secretRestored: login !== void 0 };
24256
+ }
23692
24257
  const current = auth[CODEX_KEY2];
23693
24258
  if (!looksLikeRunToken(typeof current === "string" ? current : void 0)) {
23694
24259
  dropSidecar();
@@ -23702,7 +24267,7 @@ function restoreCodex(options, released, sidecar) {
23702
24267
  if (released !== void 0) auth[CODEX_KEY2] = released.secret;
23703
24268
  else delete auth[CODEX_KEY2];
23704
24269
  if (sidecar !== void 0 && !sidecar.existed && Object.keys(auth).length === 0) {
23705
- unlinkSync5(file);
24270
+ unlinkSync6(file);
23706
24271
  dropSidecar();
23707
24272
  return {
23708
24273
  changed: true,
@@ -23765,22 +24330,30 @@ async function peekModelCredentials(options) {
23765
24330
  if (harness === "claude-code") {
23766
24331
  const env = envOf(document) ?? {};
23767
24332
  if (holdsBothClaudeMembers(env)) continue;
23768
- for (const [member3, kind] of [
23769
- [CLAUDE_API_KEY, "api_key"],
23770
- [CLAUDE_AUTH_TOKEN, "bearer"]
23771
- ]) {
23772
- const value = env[member3];
23773
- if (isSecret(value))
24333
+ for (const { member: member3, credential } of claudeEnvCredentials(env))
24334
+ taken.push({
24335
+ harness,
24336
+ provider: "anthropic",
24337
+ credential,
24338
+ member: `env.${member3}`
24339
+ });
24340
+ } else {
24341
+ const tokens = chatGptTokensOf(document);
24342
+ if (tokens !== void 0) {
24343
+ if (!looksLikeRunToken(tokens["access_token"]))
23774
24344
  taken.push({
23775
24345
  harness,
23776
- provider: "anthropic",
23777
- credential: { kind, secret: value },
23778
- member: `env.${member3}`
24346
+ provider: "openai",
24347
+ credential: {
24348
+ kind: "chatgpt",
24349
+ secret: encodeChatGptLogin(tokens)
24350
+ },
24351
+ member: CODEX_TOKENS
23779
24352
  });
24353
+ continue;
23780
24354
  }
23781
- } else {
23782
24355
  const current = document[CODEX_KEY2];
23783
- if (document["tokens"] === void 0 && typeof current === "string" && current.length > 0 && !looksLikeRunToken(current))
24356
+ if (document[CODEX_TOKENS] === void 0 && typeof current === "string" && current.length > 0 && !looksLikeRunToken(current))
23784
24357
  taken.push({
23785
24358
  harness,
23786
24359
  provider: "openai",
@@ -23806,8 +24379,8 @@ function hasOrphanedModelCredential(harness, home, dirs = {}) {
23806
24379
  try {
23807
24380
  const document = parseJsonObject(text5, file);
23808
24381
  if (harness === "claude-code") return isTachoHelper(document[HELPER_KEY]);
23809
- const key = document[CODEX_KEY2];
23810
- return looksLikeRunToken(typeof key === "string" ? key : void 0);
24382
+ const key = codexTokenMember(document);
24383
+ return looksLikeRunToken(key);
23811
24384
  } catch {
23812
24385
  return text5.includes("credential issue --harness") || text5.includes("oxrt_");
23813
24386
  }
@@ -23829,24 +24402,46 @@ function staticTokenStillGood(token, host, keyPath2, now) {
23829
24402
  });
23830
24403
  return verdict.ok && verdict.claims.exp - now > staticTokenRenewWindowMs(host, now);
23831
24404
  }
24405
+ function restateCodexLastRefresh(home, now, dirs = {}) {
24406
+ const file = fileFor2("codex", { ...dirs, home });
24407
+ const text5 = readTextIfExists(file);
24408
+ if (text5 === void 0 || isSymlink(file)) return false;
24409
+ const auth = parseJsonObject(text5, file);
24410
+ const tokens = chatGptTokensOf(auth);
24411
+ if (tokens === void 0 || !looksLikeRunToken(tokens["access_token"]))
24412
+ return false;
24413
+ const last = Date.parse(
24414
+ typeof auth[CODEX_LAST_REFRESH] === "string" ? auth[CODEX_LAST_REFRESH] : ""
24415
+ );
24416
+ if (Number.isFinite(last) && now - last < CODEX_LAST_REFRESH_RESTATE_MS)
24417
+ return false;
24418
+ auth[CODEX_LAST_REFRESH] = new Date(now).toISOString();
24419
+ const next = serializeJsonLike(text5, auth);
24420
+ const backup = sidecarFor2(file);
24421
+ const sidecar = readSidecar2(backup, "codex");
24422
+ if (sidecar !== void 0)
24423
+ writeSidecar(backup, { ...sidecar, written_sha256: sha256Hex(next) });
24424
+ writeFileAtomicPreserving(file, next);
24425
+ return true;
24426
+ }
23832
24427
  function readCodexApiKeyMember(home, dirs = {}) {
23833
24428
  const file = fileFor2("codex", { ...dirs, home });
23834
24429
  try {
23835
24430
  const text5 = readTextIfExists(file);
23836
24431
  if (text5 === void 0) return void 0;
23837
- const value = parseJsonObject(text5, file)[CODEX_KEY2];
23838
- return typeof value === "string" ? value : void 0;
24432
+ return codexTokenMember(parseJsonObject(text5, file));
23839
24433
  } catch {
23840
24434
  return void 0;
23841
24435
  }
23842
24436
  }
23843
- var HARNESS_PROVIDER, SIDECAR_SCHEMA2, HELPER_KEY, CLAUDE_API_KEY, CLAUDE_AUTH_TOKEN, CODEX_KEY2, HELPER_MARK, STATIC_TOKEN_RENEW_WINDOW_MS;
24437
+ var HARNESS_PROVIDER, SIDECAR_SCHEMA2, HELPER_KEY, CLAUDE_API_KEY, CLAUDE_AUTH_TOKEN, CLAUDE_OAUTH_TOKEN, CLAUDE_MEMBERS, CODEX_KEY2, CODEX_TOKENS, CODEX_LAST_REFRESH, CHATGPT_REFRESH_HELD, HELPER_MARK, STATIC_TOKEN_RENEW_WINDOW_MS, CODEX_LAST_REFRESH_RESTATE_MS;
23844
24438
  var init_model_credential = __esm({
23845
24439
  "../../packages/tacho/src/host/model-credential.ts"() {
23846
24440
  "use strict";
23847
24441
  init_digest();
23848
24442
  init_fs();
23849
24443
  init_wire();
24444
+ init_credential_store();
23850
24445
  init_model_base_url();
23851
24446
  init_paths();
23852
24447
  init_run_token();
@@ -23855,14 +24450,24 @@ var init_model_credential = __esm({
23855
24450
  HELPER_KEY = "apiKeyHelper";
23856
24451
  CLAUDE_API_KEY = "ANTHROPIC_API_KEY";
23857
24452
  CLAUDE_AUTH_TOKEN = "ANTHROPIC_AUTH_TOKEN";
24453
+ CLAUDE_OAUTH_TOKEN = "CLAUDE_CODE_OAUTH_TOKEN";
24454
+ CLAUDE_MEMBERS = [
24455
+ [CLAUDE_API_KEY, "api_key"],
24456
+ [CLAUDE_AUTH_TOKEN, "bearer"],
24457
+ [CLAUDE_OAUTH_TOKEN, "oauth"]
24458
+ ];
23858
24459
  CODEX_KEY2 = "OPENAI_API_KEY";
24460
+ CODEX_TOKENS = "tokens";
24461
+ CODEX_LAST_REFRESH = "last_refresh";
24462
+ CHATGPT_REFRESH_HELD = "held-by-oxagen-gateway";
23859
24463
  HELPER_MARK = /\bcredential issue --harness claude-code\s*$/;
23860
24464
  STATIC_TOKEN_RENEW_WINDOW_MS = 7 * 24 * 60 * 6e4;
24465
+ CODEX_LAST_REFRESH_RESTATE_MS = 5 * 24 * 60 * 6e4;
23861
24466
  }
23862
24467
  });
23863
24468
 
23864
24469
  // ../../packages/tacho/src/cli/credential.ts
23865
- import { existsSync as existsSync7 } from "node:fs";
24470
+ import { existsSync as existsSync8 } from "node:fs";
23866
24471
  import { dirname as dirname8 } from "node:path";
23867
24472
  function harnessDirsOf(deps) {
23868
24473
  return {
@@ -23982,15 +24587,15 @@ function describeHarness(entry2) {
23982
24587
  }
23983
24588
  switch (entry2.reason) {
23984
24589
  case "subscription_login":
23985
- return `${label2}: signed in with a ChatGPT login, which the gateway cannot take into custody; its own login crosses the proxy`;
24590
+ return `${label2}: signed in with a ChatGPT login that crosses the proxy as its own (run \`oxagen credential login --harness codex\` to put it in the gateway's custody)`;
23986
24591
  case "symlink":
23987
24592
  return `${label2}: ${entry2.file} is a symbolic link, so it was left alone; its own credential crosses the proxy`;
23988
24593
  case "no_file":
23989
24594
  return `${label2}: no ${entry2.file} yet; its own credential crosses the proxy`;
23990
24595
  case "two_credentials":
23991
- return `${label2}: ${entry2.file} sets both ANTHROPIC_API_KEY and ANTHROPIC_AUTH_TOKEN in env, and the gateway holds one ${HARNESS_PROVIDER[entry2.harness]} credential; remove one and run \`oxagen agent enroll\` again. Its own credential crosses the proxy`;
24596
+ return `${label2}: ${entry2.file} sets more than one of ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN and CLAUDE_CODE_OAUTH_TOKEN in env, and the gateway holds one ${HARNESS_PROVIDER[entry2.harness]} credential; keep one and run \`oxagen agent enroll\` again. Its own credential crosses the proxy`;
23992
24597
  default:
23993
- return `${label2}: holds its own credential, which crosses the proxy (run \`oxagen agent enroll\` to broker it)`;
24598
+ return entry2.harness === "claude-code" ? `${label2}: holds its own credential, which crosses the proxy (run \`oxagen credential login\` to put your Claude subscription in the gateway's custody)` : `${label2}: holds its own credential, which crosses the proxy (run \`oxagen agent enroll\` to broker it)`;
23994
24599
  }
23995
24600
  }
23996
24601
  async function brokerCredentials(host, harnesses, deps) {
@@ -24018,11 +24623,17 @@ async function brokerCredentials(host, harnesses, deps) {
24018
24623
  if (!offered.has(provider) && typeof fromEnv === "string" && fromEnv.trim().length > 0)
24019
24624
  offered.set(provider, {
24020
24625
  credential: {
24021
- kind: provider === "anthropic" ? "api_key" : "bearer",
24626
+ kind: provider === "anthropic" ? anthropicCredentialKind(fromEnv, "api_key") : "bearer",
24022
24627
  secret: fromEnv.trim()
24023
24628
  },
24024
24629
  source: "enroll:env"
24025
24630
  });
24631
+ const oauth = deps.env[CLAUDE_OAUTH_TOKEN_ENV]?.trim();
24632
+ if (provider === "anthropic" && !offered.has(provider) && oauth !== void 0 && isSubscriptionToken(oauth))
24633
+ offered.set(provider, {
24634
+ credential: { kind: "oauth", secret: oauth },
24635
+ source: "enroll:env"
24636
+ });
24026
24637
  }
24027
24638
  const takenNow = [];
24028
24639
  const staticTokens = {};
@@ -24033,8 +24644,7 @@ async function brokerCredentials(host, harnesses, deps) {
24033
24644
  takenNow.push(provider);
24034
24645
  }
24035
24646
  if (targets.includes("codex") && store.has("openai")) {
24036
- const before = (await contract.read({ home: deps.home, harnesses: ["codex"] })).harnesses[0];
24037
- if (before?.reason !== "subscription_login") {
24647
+ {
24038
24648
  const current = readCodexApiKeyMember(deps.home, harnessDirsOf(deps));
24039
24649
  if (!staticTokenStillGood(
24040
24650
  current,
@@ -24085,7 +24695,7 @@ async function brokerCredentials(host, harnesses, deps) {
24085
24695
  reason: "no_token"
24086
24696
  };
24087
24697
  warnings.push(
24088
- `${TACHO_HARNESS_LABELS[entry2.harness]} keeps its own login: no ${provider} key was found in ${entry2.file} or ${brokerEnvVar(provider)}, so there is nothing for the gateway to take into custody. A subscription login crosses the proxy as it is`
24698
+ provider === "anthropic" ? `${TACHO_HARNESS_LABELS[entry2.harness]} keeps its own login: the gateway holds no Anthropic credential yet. Run \`oxagen credential login\` to sign in with your Claude subscription, or put a key in ${entry2.file} and enroll again` : `${TACHO_HARNESS_LABELS[entry2.harness]} keeps its own login: no ${provider} key was found in ${entry2.file} or ${brokerEnvVar(provider)}, so there is nothing for the gateway to take into custody`
24089
24699
  );
24090
24700
  }
24091
24701
  continue;
@@ -24131,7 +24741,7 @@ async function restoreCredentials(host, deps, mode = "unenroll", only) {
24131
24741
  try {
24132
24742
  if (host !== void 0 && !host.harnesses.includes(harness)) {
24133
24743
  const dirs = harnessDirsOf(deps);
24134
- const hasReceipt = existsSync7(
24744
+ const hasReceipt = existsSync8(
24135
24745
  modelCredentialBackupPath(harness, deps.home, dirs)
24136
24746
  );
24137
24747
  if (!hasReceipt && !hasOrphanedModelCredential(harness, deps.home, dirs))
@@ -24141,8 +24751,13 @@ async function restoreCredentials(host, deps, mode = "unenroll", only) {
24141
24751
  const label2 = TACHO_HARNESS_LABELS[harness];
24142
24752
  let released;
24143
24753
  let unreadable;
24754
+ let fromLogin = false;
24144
24755
  try {
24145
- released = store?.read(provider);
24756
+ fromLogin = store?.status().some(
24757
+ (c) => c.provider === provider && c.source === "claude:setup-token"
24758
+ ) === true;
24759
+ if (fromLogin) store?.release(provider);
24760
+ else released = store?.read(provider);
24146
24761
  } catch (error) {
24147
24762
  unreadable = error instanceof Error ? error.message : String(error);
24148
24763
  }
@@ -24186,10 +24801,200 @@ async function restoreCredentials(host, deps, mode = "unenroll", only) {
24186
24801
  }
24187
24802
  return { restored, failed: failed3, warnings, custodyUnreadable };
24188
24803
  }
24189
- var MODEL_CREDENTIAL_HARNESSES, CREDENTIAL_MODES;
24804
+ async function acquireSubscriptionToken(options, deps) {
24805
+ const io = deps.subscriptionLogin;
24806
+ if (options.tokenStdin === true) {
24807
+ const text5 = (await io?.readStdin())?.trim() ?? "";
24808
+ return isSubscriptionToken(text5) ? { token: text5, source: "claude:setup-token" } : {
24809
+ detail: "stdin did not hold a Claude subscription token (sk-ant-oat\u2026). Pipe in what `claude setup-token` printed"
24810
+ };
24811
+ }
24812
+ const fromEnv = deps.env[CLAUDE_OAUTH_TOKEN_ENV]?.trim();
24813
+ if (fromEnv !== void 0 && isSubscriptionToken(fromEnv))
24814
+ return { token: fromEnv, source: "enroll:env" };
24815
+ if (io === void 0)
24816
+ return {
24817
+ detail: `no Claude subscription token: set ${CLAUDE_OAUTH_TOKEN_ENV} or pipe one in with --token-stdin`
24818
+ };
24819
+ const claude = io.findClaude();
24820
+ if (claude === void 0)
24821
+ return {
24822
+ detail: "Claude Code is not installed, so `claude setup-token` cannot run. Install it, or pipe a token in with --token-stdin"
24823
+ };
24824
+ deps.out(
24825
+ "Signing in to your Claude subscription with `claude setup-token`. Finish the sign-in in your browser."
24826
+ );
24827
+ const run3 = await io.runSetupToken(
24828
+ claude,
24829
+ (chunk2) => process.stdout.write(
24830
+ chunk2.replace(/sk-ant-oat[A-Za-z0-9_-]*/g, "sk-ant-oat\u2026 (sent to Oxagen)")
24831
+ )
24832
+ );
24833
+ if (run3.token !== void 0)
24834
+ return { token: run3.token, source: "claude:setup-token" };
24835
+ if (io.interactive) {
24836
+ const pasted = await io.promptSecret(
24837
+ "Paste the token `claude setup-token` printed (sk-ant-oat\u2026): "
24838
+ );
24839
+ if (pasted !== void 0 && isSubscriptionToken(pasted))
24840
+ return { token: pasted, source: "claude:setup-token" };
24841
+ return {
24842
+ detail: pasted === void 0 || pasted.length === 0 ? "no token was pasted" : "that is not a Claude subscription token (sk-ant-oat\u2026)"
24843
+ };
24844
+ }
24845
+ return {
24846
+ detail: run3.code === 0 ? "`claude setup-token` finished, but no token could be read from its output. Run `oxagen credential login` in a terminal" : `\`claude setup-token\` exited with ${run3.code}. Run \`oxagen credential login\` in a terminal`
24847
+ };
24848
+ }
24849
+ async function signInIfNoCredential(harnesses, deps) {
24850
+ const store = deps.credentialStore;
24851
+ if (harnesses.includes("codex") && store !== void 0 && deps.subscriptionLogin?.interactive === true && !store.has("openai") && (deps.env[brokerEnvVar("openai")]?.trim() ?? "").length === 0 && (await deps.modelCredentials?.peek({
24852
+ home: deps.home,
24853
+ harnesses: ["codex"]
24854
+ }) ?? []).length === 0) {
24855
+ const why = await ensureCodexLogin(deps);
24856
+ if (why !== void 0)
24857
+ deps.err(
24858
+ `warning: ChatGPT sign-in for Codex did not finish (${why}). Run \`oxagen credential login --harness codex\` to try again`
24859
+ );
24860
+ }
24861
+ if (!harnesses.includes("claude-code") || store === void 0 || deps.subscriptionLogin?.interactive !== true || store.has("anthropic"))
24862
+ return;
24863
+ if ([brokerEnvVar("anthropic"), CLAUDE_OAUTH_TOKEN_ENV].some(
24864
+ (name) => (deps.env[name]?.trim() ?? "").length > 0
24865
+ ))
24866
+ return;
24867
+ const inFile = await deps.modelCredentials?.peek({
24868
+ home: deps.home,
24869
+ harnesses: ["claude-code"],
24870
+ helperCommand: deps.runtime.credentialHelperCommand
24871
+ });
24872
+ if ((inFile ?? []).some((t) => t.provider === "anthropic")) return;
24873
+ const acquired = await acquireSubscriptionToken({}, deps);
24874
+ if (acquired.token === void 0) {
24875
+ deps.err(
24876
+ `warning: Claude subscription sign-in did not finish (${acquired.detail}). Run \`oxagen credential login\` to try again`
24877
+ );
24878
+ return;
24879
+ }
24880
+ const custody = store.take(
24881
+ "anthropic",
24882
+ { kind: "oauth", secret: acquired.token },
24883
+ acquired.source,
24884
+ deps.now()
24885
+ );
24886
+ deps.out(
24887
+ ` Claude subscription ${custody.prefix} taken into the gateway's custody`
24888
+ );
24889
+ }
24890
+ async function routedToGateway(host, harness, deps) {
24891
+ if (deps.modelBaseUrls === void 0) return false;
24892
+ try {
24893
+ const state = await deps.modelBaseUrls.read({
24894
+ home: deps.home,
24895
+ stellaHome: dirname8(deps.paths.stellaToml),
24896
+ port: modelProxyPortFor(host),
24897
+ harnesses: [harness]
24898
+ });
24899
+ const entry2 = state.harnesses.find((h) => h.harness === harness);
24900
+ return entry2?.ours === true && entry2.shadowedBy === void 0;
24901
+ } catch {
24902
+ return false;
24903
+ }
24904
+ }
24905
+ async function codexHasChatGptLogin(deps) {
24906
+ const offered = await deps.modelCredentials?.peek({
24907
+ home: deps.home,
24908
+ harnesses: ["codex"]
24909
+ });
24910
+ return (offered ?? []).some((t) => t.credential.kind === "chatgpt");
24911
+ }
24912
+ async function ensureCodexLogin(deps) {
24913
+ if (await codexHasChatGptLogin(deps)) return void 0;
24914
+ const io = deps.subscriptionLogin;
24915
+ const codex = io?.findCodex();
24916
+ if (io === void 0 || codex === void 0)
24917
+ return "Codex is not installed, so `codex login` cannot run. Install it and try again";
24918
+ deps.out(
24919
+ "Signing in to ChatGPT with `codex login`. Finish the sign-in in your browser."
24920
+ );
24921
+ const code = await io.runCodexLogin(codex);
24922
+ if (code !== 0) return `\`codex login\` exited with ${code}`;
24923
+ return await codexHasChatGptLogin(deps) ? void 0 : "`codex login` finished, but ~/.codex/auth.json holds no ChatGPT login";
24924
+ }
24925
+ async function codexLogin(deps) {
24926
+ const store = deps.credentialStore;
24927
+ const held = store?.status().some(
24928
+ (c) => c.provider === "openai" && c.kind === "chatgpt"
24929
+ );
24930
+ if (held !== true) {
24931
+ const why = await ensureCodexLogin(deps);
24932
+ if (why !== void 0)
24933
+ return { ok: false, harnesses: [], warnings: [], detail: why };
24934
+ }
24935
+ const host = readHostFileLenient(deps.paths.hostFile).host;
24936
+ if (host === void 0 || !host.harnesses.includes("codex") || !await routedToGateway(host, "codex", deps))
24937
+ return {
24938
+ ok: true,
24939
+ harnesses: [],
24940
+ warnings: [],
24941
+ detail: "Codex is signed in to ChatGPT. Run `oxagen agent enroll --harness codex` to route it through the gateway, which then holds the login"
24942
+ };
24943
+ const outcome = await brokerCredentials(host, ["codex"], deps);
24944
+ return {
24945
+ ok: true,
24946
+ source: "codex:auth.json",
24947
+ harnesses: outcome.harnesses,
24948
+ warnings: outcome.warnings,
24949
+ detail: outcome.harnesses.some((h) => h.brokered) ? "Codex now holds a run token, and the gateway sends your ChatGPT login with every call" : "Codex is signed in, but its login stays in its own file. See the warnings above"
24950
+ };
24951
+ }
24952
+ async function credentialLogin(options, deps) {
24953
+ const store = deps.credentialStore;
24954
+ if (store === void 0)
24955
+ return {
24956
+ ok: false,
24957
+ harnesses: [],
24958
+ warnings: [],
24959
+ detail: "this build holds no credential store"
24960
+ };
24961
+ if (options.harness === "codex") return codexLogin(deps);
24962
+ const acquired = await acquireSubscriptionToken(options, deps);
24963
+ if (acquired.token === void 0)
24964
+ return { ok: false, harnesses: [], warnings: [], detail: acquired.detail };
24965
+ const custody = store.take(
24966
+ "anthropic",
24967
+ { kind: "oauth", secret: acquired.token },
24968
+ acquired.source,
24969
+ deps.now()
24970
+ );
24971
+ deps.out(
24972
+ `Claude subscription ${custody.prefix} taken into the gateway's custody (${deps.paths.credentials})`
24973
+ );
24974
+ const host = readHostFileLenient(deps.paths.hostFile).host;
24975
+ if (host === void 0 || !host.harnesses.includes("claude-code") || !await routedToGateway(host, "claude-code", deps))
24976
+ return {
24977
+ ok: true,
24978
+ source: acquired.source,
24979
+ harnesses: [],
24980
+ warnings: [],
24981
+ detail: "Run `oxagen agent enroll` to route Claude Code through the gateway. It will use this subscription"
24982
+ };
24983
+ const outcome = await brokerCredentials(host, ["claude-code"], deps);
24984
+ return {
24985
+ ok: true,
24986
+ source: acquired.source,
24987
+ harnesses: outcome.harnesses,
24988
+ warnings: outcome.warnings,
24989
+ detail: outcome.harnesses.some((h) => h.brokered) ? "Claude Code now holds a run token, and the gateway sends your subscription with every call" : "The subscription is in custody. Run `oxagen agent enroll` to route Claude Code through the gateway"
24990
+ };
24991
+ }
24992
+ var MODEL_CREDENTIAL_HARNESSES, CREDENTIAL_MODES, CLAUDE_OAUTH_TOKEN_ENV;
24190
24993
  var init_credential = __esm({
24191
24994
  "../../packages/tacho/src/cli/credential.ts"() {
24192
24995
  "use strict";
24996
+ init_claude_setup_token();
24997
+ init_credential_store();
24193
24998
  init_host_file();
24194
24999
  init_model_credential();
24195
25000
  init_agents();
@@ -24202,11 +25007,12 @@ var init_credential = __esm({
24202
25007
  "brokered",
24203
25008
  "passthrough"
24204
25009
  ];
25010
+ CLAUDE_OAUTH_TOKEN_ENV = "CLAUDE_CODE_OAUTH_TOKEN";
24205
25011
  }
24206
25012
  });
24207
25013
 
24208
25014
  // ../../packages/tacho/src/host/codex-app-server.ts
24209
- import { spawn } from "node:child_process";
25015
+ import { spawn as spawn2 } from "node:child_process";
24210
25016
  function cmdArgument(value) {
24211
25017
  let quoted3 = "";
24212
25018
  let slashes = 0;
@@ -24244,7 +25050,7 @@ function codexAppServerClient(options) {
24244
25050
  let child;
24245
25051
  try {
24246
25052
  const invocation = spawnInvocation(options.binary, ["app-server"]);
24247
- child = spawn(invocation.command, invocation.args, {
25053
+ child = spawn2(invocation.command, invocation.args, {
24248
25054
  cwd: options.cwd,
24249
25055
  env: options.env,
24250
25056
  stdio: ["pipe", "pipe", "pipe"],
@@ -24377,266 +25183,6 @@ var init_codex_app_server = __esm({
24377
25183
  }
24378
25184
  });
24379
25185
 
24380
- // ../../packages/tacho/src/host/credential-store.ts
24381
- import { createCipheriv, createDecipheriv, randomBytes as randomBytes5 } from "node:crypto";
24382
- import {
24383
- closeSync as closeSync4,
24384
- existsSync as existsSync8,
24385
- fsyncSync as fsyncSync3,
24386
- openSync as openSync4,
24387
- readFileSync as readFileSync8,
24388
- statSync as statSync3,
24389
- unlinkSync as unlinkSync6,
24390
- writeSync as writeSync3
24391
- } from "node:fs";
24392
- function readKey(path2) {
24393
- try {
24394
- const hex = readFileSync8(path2, "utf8").trim();
24395
- if (!/^[0-9a-f]{64}$/i.test(hex))
24396
- throw new Error(`${path2} does not hold a 32-byte key`);
24397
- return Buffer.from(hex, "hex");
24398
- } catch (error) {
24399
- if (error.code === "ENOENT") return void 0;
24400
- throw error;
24401
- }
24402
- }
24403
- function loadOrCreateKey(path2) {
24404
- const existing = readKey(path2);
24405
- if (existing !== void 0) return existing;
24406
- const key = randomBytes5(KEY_BYTES2);
24407
- writeSensitiveFileAtomic(path2, `${key.toString("hex")}
24408
- `);
24409
- return key;
24410
- }
24411
- function requireKey(path2) {
24412
- const key = readKey(path2);
24413
- if (key === void 0)
24414
- throw new Error(
24415
- `${path2} is missing, so the credentials in custody cannot be opened`
24416
- );
24417
- return key;
24418
- }
24419
- function overwriteInPlace(path2) {
24420
- let fd2;
24421
- try {
24422
- const size = statSync3(path2).size;
24423
- fd2 = openSync4(path2, "r+");
24424
- writeSync3(fd2, randomBytes5(Math.max(size, KEY_BYTES2 * 2)), 0, void 0, 0);
24425
- fsyncSync3(fd2);
24426
- } catch (error) {
24427
- if (error.code !== "ENOENT") throw error;
24428
- } finally {
24429
- if (fd2 !== void 0) closeSync4(fd2);
24430
- }
24431
- }
24432
- function seal(key, secret, aad) {
24433
- const nonce = randomBytes5(12);
24434
- const cipher = createCipheriv("aes-256-gcm", key, nonce);
24435
- cipher.setAAD(Buffer.from(aad, "utf8"));
24436
- const ciphertext = Buffer.concat([
24437
- cipher.update(secret, "utf8"),
24438
- cipher.final()
24439
- ]);
24440
- return {
24441
- nonce: nonce.toString("base64"),
24442
- ciphertext: ciphertext.toString("base64"),
24443
- tag: cipher.getAuthTag().toString("base64")
24444
- };
24445
- }
24446
- function open(key, sealed, aad) {
24447
- const decipher = createDecipheriv(
24448
- "aes-256-gcm",
24449
- key,
24450
- Buffer.from(sealed.nonce, "base64")
24451
- );
24452
- decipher.setAAD(Buffer.from(aad, "utf8"));
24453
- decipher.setAuthTag(Buffer.from(sealed.tag, "base64"));
24454
- return Buffer.concat([
24455
- decipher.update(Buffer.from(sealed.ciphertext, "base64")),
24456
- decipher.final()
24457
- ]).toString("utf8");
24458
- }
24459
- function credentialPrefix(secret) {
24460
- const head2 = secret.slice(0, Math.min(8, Math.max(0, secret.length - 4)));
24461
- return head2.length > 0 ? `${head2}\u2026` : "";
24462
- }
24463
- function custodyOf(entry2) {
24464
- return {
24465
- provider: entry2.provider,
24466
- kind: entry2.kind,
24467
- source: entry2.source,
24468
- taken_at: entry2.taken_at,
24469
- prefix: entry2.prefix
24470
- };
24471
- }
24472
- function openCredentialStore(paths) {
24473
- let entriesSeen;
24474
- let keySeen;
24475
- const keyForWrite = () => loadOrCreateKey(paths.key);
24476
- function forgetKey() {
24477
- keySeen?.key.fill(0);
24478
- keySeen = void 0;
24479
- }
24480
- function keyForRead() {
24481
- const version2 = fileVersion(paths.key);
24482
- if (version2 !== void 0 && keySeen?.version === version2)
24483
- return keySeen.key;
24484
- forgetKey();
24485
- const key = requireKey(paths.key);
24486
- if (version2 !== void 0) keySeen = { version: version2, key };
24487
- return key;
24488
- }
24489
- function readAll() {
24490
- const version2 = fileVersion(paths.file);
24491
- if (version2 === void 0) {
24492
- entriesSeen = void 0;
24493
- forgetKey();
24494
- return [];
24495
- }
24496
- if (entriesSeen?.version === version2) return entriesSeen.entries;
24497
- let text5;
24498
- try {
24499
- text5 = readFileSync8(paths.file, "utf8");
24500
- } catch (error) {
24501
- if (error.code === "ENOENT") return [];
24502
- throw error;
24503
- }
24504
- let raw;
24505
- try {
24506
- raw = JSON.parse(text5);
24507
- } catch (error) {
24508
- throw new Error(
24509
- `${paths.file} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`
24510
- );
24511
- }
24512
- const parsed2 = fileSchema.safeParse(raw);
24513
- if (!parsed2.success)
24514
- throw new Error(
24515
- `${paths.file} is not a credential store this build can read: ${parsed2.error.issues[0]?.message ?? "invalid"}`
24516
- );
24517
- entriesSeen = { version: version2, entries: parsed2.data.entries };
24518
- return parsed2.data.entries;
24519
- }
24520
- function writeAll2(entries2) {
24521
- if (entries2.length === 0) {
24522
- if (existsSync8(paths.file)) unlinkSync6(paths.file);
24523
- return;
24524
- }
24525
- writeSensitiveFileAtomic(
24526
- paths.file,
24527
- `${JSON.stringify({ schema: CREDENTIAL_STORE_SCHEMA, entries: entries2 }, null, 2)}
24528
- `
24529
- );
24530
- }
24531
- return {
24532
- has: (provider) => readAll().some((e) => e.provider === provider),
24533
- read: (provider) => {
24534
- const entry2 = readAll().find((e) => e.provider === provider);
24535
- if (entry2 === void 0) return void 0;
24536
- return {
24537
- kind: entry2.kind,
24538
- secret: open(
24539
- keyForRead(),
24540
- entry2.sealed,
24541
- `${CREDENTIAL_STORE_SCHEMA}:${provider}`
24542
- )
24543
- };
24544
- },
24545
- take: (provider, { kind, secret }, source, now) => {
24546
- if (secret.trim().length === 0)
24547
- throw new Error("refusing to take an empty credential into custody");
24548
- const entry2 = {
24549
- provider,
24550
- kind,
24551
- source,
24552
- taken_at: new Date(now).toISOString(),
24553
- prefix: credentialPrefix(secret),
24554
- sealed: seal(
24555
- keyForWrite(),
24556
- secret,
24557
- `${CREDENTIAL_STORE_SCHEMA}:${provider}`
24558
- )
24559
- };
24560
- writeAll2([...readAll().filter((e) => e.provider !== provider), entry2]);
24561
- return custodyOf(entry2);
24562
- },
24563
- release: (provider) => {
24564
- const entries2 = readAll();
24565
- const entry2 = entries2.find((e) => e.provider === provider);
24566
- if (entry2 === void 0) return void 0;
24567
- const secret = open(
24568
- keyForRead(),
24569
- entry2.sealed,
24570
- `${CREDENTIAL_STORE_SCHEMA}:${provider}`
24571
- );
24572
- writeAll2(entries2.filter((e) => e.provider !== provider));
24573
- return { kind: entry2.kind, secret };
24574
- },
24575
- status: () => readAll().map(custodyOf),
24576
- shred: () => {
24577
- let overwrite;
24578
- try {
24579
- overwriteInPlace(paths.key);
24580
- } catch (error) {
24581
- overwrite = error;
24582
- }
24583
- for (const path2 of [paths.file, paths.key])
24584
- if (existsSync8(path2)) unlinkSync6(path2);
24585
- entriesSeen = void 0;
24586
- forgetKey();
24587
- if (overwrite !== void 0)
24588
- throw new Error(
24589
- `${paths.key} was deleted but could not be overwritten first: ${overwrite instanceof Error ? overwrite.message : String(overwrite)}`
24590
- );
24591
- }
24592
- };
24593
- }
24594
- var CREDENTIAL_STORE_SCHEMA, CREDENTIAL_SOURCES, CREDENTIAL_KINDS, sealedSchema, entrySchema, fileSchema, KEY_BYTES2;
24595
- var init_credential_store = __esm({
24596
- "../../packages/tacho/src/host/credential-store.ts"() {
24597
- "use strict";
24598
- init_zod();
24599
- init_fs();
24600
- init_run_token();
24601
- CREDENTIAL_STORE_SCHEMA = "tacho.credentials.v1";
24602
- CREDENTIAL_SOURCES = [
24603
- /** `env.ANTHROPIC_API_KEY` in Claude Code's user settings. */
24604
- "claude-code:settings.env",
24605
- /** `OPENAI_API_KEY` in Codex's `auth.json`. */
24606
- "codex:auth.json",
24607
- /** `TACHO_BROKER_<PROVIDER>_API_KEY` in the enrolling shell. */
24608
- "enroll:env",
24609
- /**
24610
- * The run token in an Oxagen Agent Runners sandbox's `launch` message. It
24611
- * is spent at the cloud gateway, which attaches the operator's model
24612
- * credential. It is not a model credential itself.
24613
- */
24614
- "sandbox:launch"
24615
- ];
24616
- CREDENTIAL_KINDS = ["api_key", "bearer"];
24617
- sealedSchema = external_exports.object({
24618
- /** AES-256-GCM: 12-byte nonce, ciphertext, 16-byte tag, all base64. */
24619
- nonce: external_exports.string().min(1),
24620
- ciphertext: external_exports.string().min(1),
24621
- tag: external_exports.string().min(1)
24622
- }).strict();
24623
- entrySchema = external_exports.object({
24624
- provider: external_exports.enum(RUN_TOKEN_PROVIDERS),
24625
- kind: external_exports.enum(CREDENTIAL_KINDS),
24626
- source: external_exports.enum(CREDENTIAL_SOURCES),
24627
- taken_at: external_exports.string(),
24628
- /** The first few characters, the way a vendor console shows a key. */
24629
- prefix: external_exports.string().max(12),
24630
- sealed: sealedSchema
24631
- }).strict();
24632
- fileSchema = external_exports.object({
24633
- schema: external_exports.literal(CREDENTIAL_STORE_SCHEMA),
24634
- entries: external_exports.array(entrySchema)
24635
- }).strict();
24636
- KEY_BYTES2 = 32;
24637
- }
24638
- });
24639
-
24640
25186
  // ../../packages/tacho/src/host/claude-config-lock.ts
24641
25187
  import { mkdirSync as mkdirSync4, rmdirSync as rmdirSync3, statSync as statSync4 } from "node:fs";
24642
25188
  function sleepSync(ms) {
@@ -24709,7 +25255,7 @@ var init_claude_config_lock = __esm({
24709
25255
  });
24710
25256
 
24711
25257
  // ../../packages/tacho/src/host/service.ts
24712
- import { join as join15 } from "node:path";
25258
+ import { join as join16 } from "node:path";
24713
25259
  import {
24714
25260
  existsSync as existsSync9,
24715
25261
  readdirSync as readdirSync6,
@@ -24794,8 +25340,8 @@ function blockingSleep(ms) {
24794
25340
  }
24795
25341
  function launchdManager(options) {
24796
25342
  const sleep2 = options.sleep ?? blockingSleep;
24797
- const dir = join15(options.home, "Library", "LaunchAgents");
24798
- const unitPath = join15(dir, `${SERVICE_LABEL}.plist`);
25343
+ const dir = join16(options.home, "Library", "LaunchAgents");
25344
+ const unitPath = join16(dir, `${SERVICE_LABEL}.plist`);
24799
25345
  const domain = `gui/${options.uid ?? process.getuid?.() ?? 501}`;
24800
25346
  const target2 = `${domain}/${SERVICE_LABEL}`;
24801
25347
  const loaded = () => options.exec("launchctl", ["print", target2]).status === 0;
@@ -24900,9 +25446,9 @@ function stopByPidFile(options) {
24900
25446
  );
24901
25447
  }
24902
25448
  function systemdManager(options) {
24903
- const dir = join15(options.home, ".config", "systemd", "user");
24904
- const unitPath = join15(dir, "tachod.service");
24905
- const wants = join15(dir, "default.target.wants");
25449
+ const dir = join16(options.home, ".config", "systemd", "user");
25450
+ const unitPath = join16(dir, "tachod.service");
25451
+ const wants = join16(dir, "default.target.wants");
24906
25452
  return {
24907
25453
  kind: "systemd",
24908
25454
  unitPath,
@@ -25053,8 +25599,8 @@ function windowsCreatedMs(exec4, pid) {
25053
25599
  return result2.status === 0 && /^\d+$/.test(text5) ? Number(text5) : void 0;
25054
25600
  }
25055
25601
  function schtasksManager(options) {
25056
- const launcher = options.launcherPath ?? join15(options.home, "tachod.cmd");
25057
- const pidPath = options.pidPath ?? join15(launcher, "..", "tachod.pid");
25602
+ const launcher = options.launcherPath ?? join16(options.home, "tachod.cmd");
25603
+ const pidPath = options.pidPath ?? join16(launcher, "..", "tachod.pid");
25058
25604
  const liveRecord = () => {
25059
25605
  if (!existsSync9(pidPath)) return void 0;
25060
25606
  const record = parseDaemonPid(readFileSync9(pidPath, "utf8"));
@@ -25099,7 +25645,7 @@ function schtasksManager(options) {
25099
25645
  unitPath: launcher,
25100
25646
  install: (spec) => {
25101
25647
  stopDaemon();
25102
- ensureDir(join15(launcher, ".."), 493);
25648
+ ensureDir(join16(launcher, ".."), 493);
25103
25649
  writeSensitiveFileAtomic(
25104
25650
  launcher,
25105
25651
  renderWindowsLauncher(
@@ -25231,7 +25777,7 @@ import { readFileSync as readFileSync10 } from "node:fs";
25231
25777
  import { dirname as dirname9, resolve as resolve3 } from "node:path";
25232
25778
  import { fileURLToPath } from "node:url";
25233
25779
  function readVersion() {
25234
- if (true) return "2.1.4-957";
25780
+ if (true) return "2.1.4-975";
25235
25781
  try {
25236
25782
  const here = dirname9(fileURLToPath(import.meta.url));
25237
25783
  const pkg = JSON.parse(
@@ -25251,7 +25797,7 @@ var init_version = __esm({
25251
25797
  });
25252
25798
 
25253
25799
  // ../../packages/tacho/src/cli/deps.ts
25254
- import { spawnSync as spawnSync4 } from "node:child_process";
25800
+ import { spawn as spawn3, spawnSync as spawnSync4 } from "node:child_process";
25255
25801
  import { randomBytes as randomBytes7 } from "node:crypto";
25256
25802
  import { existsSync as existsSync10 } from "node:fs";
25257
25803
  import { get as httpGet, request as httpRequest } from "node:http";
@@ -25316,7 +25862,7 @@ function transientBinDir(binDir, env = process.env) {
25316
25862
  return "an AppImage mount";
25317
25863
  return void 0;
25318
25864
  }
25319
- function shellQuote(value, platform = process.platform) {
25865
+ function shellQuote2(value, platform = process.platform) {
25320
25866
  if (/^[A-Za-z0-9_@%+=:,./-]+$/.test(value)) return value;
25321
25867
  if (platform === "win32") return `"${value}"`;
25322
25868
  return `'${value.replace(/'/g, "'\\''")}'`;
@@ -25367,8 +25913,8 @@ function runtimeCommands(entry2 = process.argv[1], env = process.env, nodePath =
25367
25913
  const dir = P.dirname(tacho);
25368
25914
  const transient2 = transientBinDir(dir, env);
25369
25915
  return {
25370
- hookCommand: `${shellQuote(tacho, platform)} hook`,
25371
- credentialHelperCommand: helperCommandFor(shellQuote(tacho, platform)),
25916
+ hookCommand: `${shellQuote2(tacho, platform)} hook`,
25917
+ credentialHelperCommand: helperCommandFor(shellQuote2(tacho, platform)),
25372
25918
  daemonCommand: [tacho, "daemon"],
25373
25919
  mcpStdioCommand: [tacho, "mcp-stdio"],
25374
25920
  binDir: dir,
@@ -25382,9 +25928,9 @@ function runtimeCommands(entry2 = process.argv[1], env = process.env, nodePath =
25382
25928
  const flagged = transient !== void 0 ? { transient } : {};
25383
25929
  const node2 = stableExecutablePath(nodePath, platform, exists);
25384
25930
  return {
25385
- hookCommand: `${shellQuote(node2, platform)} ${shellQuote(P.join(binDir, "tacho-hook.mjs"), platform)}`,
25931
+ hookCommand: `${shellQuote2(node2, platform)} ${shellQuote2(P.join(binDir, "tacho-hook.mjs"), platform)}`,
25386
25932
  credentialHelperCommand: helperCommandFor(
25387
- `${shellQuote(node2, platform)} ${shellQuote(P.join(binDir, "tacho.mjs"), platform)}`
25933
+ `${shellQuote2(node2, platform)} ${shellQuote2(P.join(binDir, "tacho.mjs"), platform)}`
25388
25934
  ),
25389
25935
  daemonCommand: [node2, P.join(binDir, "tachod.mjs")],
25390
25936
  mcpStdioCommand: [node2, P.join(binDir, "tacho.mjs"), "mcp-stdio"],
@@ -25412,7 +25958,7 @@ function oxagenRuntimeCommands(entry2 = process.argv[1], env = process.env, node
25412
25958
  } else {
25413
25959
  return runtimeCommands(void 0, env, nodePath, platform, false, exists);
25414
25960
  }
25415
- const line = prefix.map((word) => shellQuote(word, platform)).join(" ");
25961
+ const line = prefix.map((word) => shellQuote2(word, platform)).join(" ");
25416
25962
  const binDir = P.dirname(prefix[prefix.length - 1]);
25417
25963
  const transient = transientBinDir(binDir, env);
25418
25964
  return {
@@ -25550,6 +26096,63 @@ function settleOrThrow(harnessFiles) {
25550
26096
  );
25551
26097
  return outcomes;
25552
26098
  }
26099
+ function promptHidden(question) {
26100
+ const stdin = process.stdin;
26101
+ if (!stdin.isTTY) return Promise.resolve(void 0);
26102
+ return new Promise((resolve25) => {
26103
+ process.stderr.write(question);
26104
+ let value = "";
26105
+ stdin.setRawMode(true);
26106
+ stdin.resume();
26107
+ stdin.setEncoding("utf8");
26108
+ const done = (answer) => {
26109
+ stdin.setRawMode(false);
26110
+ stdin.pause();
26111
+ stdin.off("data", onData);
26112
+ process.stderr.write("\n");
26113
+ resolve25(answer);
26114
+ };
26115
+ const onData = (chunk2) => {
26116
+ for (const char of chunk2) {
26117
+ if (char === "\r" || char === "\n") return done(value.trim());
26118
+ if (char === "" || char === "") return done(void 0);
26119
+ if (char === "\x7F" || char === "\b") value = value.slice(0, -1);
26120
+ else value += char;
26121
+ }
26122
+ };
26123
+ stdin.on("data", onData);
26124
+ });
26125
+ }
26126
+ function realSubscriptionLogin(env, home) {
26127
+ return {
26128
+ interactive: process.stdin.isTTY === true && process.stderr.isTTY === true,
26129
+ findClaude: () => findClaudeBinary(env, home),
26130
+ runSetupToken: (claude, write) => runClaudeSetupToken({
26131
+ claude,
26132
+ interactive: process.stdin.isTTY === true,
26133
+ write
26134
+ }),
26135
+ promptSecret: promptHidden,
26136
+ findCodex: () => findHarnessBinary("codex", env, home),
26137
+ runCodexLogin: (codex) => new Promise((resolve25, reject) => {
26138
+ const child = spawn3(codex, ["login"], {
26139
+ stdio: [process.stdin.isTTY ? "inherit" : "pipe", "inherit", "inherit"],
26140
+ env: process.env
26141
+ });
26142
+ child.on("error", reject);
26143
+ child.on("close", (code) => {
26144
+ child.stdin?.destroy();
26145
+ resolve25(code ?? 1);
26146
+ });
26147
+ }),
26148
+ readStdin: async () => {
26149
+ let text5 = "";
26150
+ process.stdin.setEncoding("utf8");
26151
+ for await (const chunk2 of process.stdin) text5 += chunk2;
26152
+ return text5;
26153
+ }
26154
+ };
26155
+ }
25553
26156
  function defaultCliDeps(overrides = {}, managed = {}) {
25554
26157
  const env = overrides.env ?? process.env;
25555
26158
  const home = overrides.home ?? homedir3();
@@ -25739,6 +26342,7 @@ function defaultCliDeps(overrides = {}, managed = {}) {
25739
26342
  file: paths.credentials,
25740
26343
  key: paths.credentialsKey
25741
26344
  }),
26345
+ subscriptionLogin: realSubscriptionLogin(env, home),
25742
26346
  daemonPost: async (path2, body2) => {
25743
26347
  const host = readHostFile(paths.hostFile);
25744
26348
  if (host === void 0) return void 0;
@@ -25832,6 +26436,7 @@ var init_deps = __esm({
25832
26436
  "../../packages/tacho/src/cli/deps.ts"() {
25833
26437
  "use strict";
25834
26438
  init_hook_client();
26439
+ init_claude_setup_token();
25835
26440
  init_codex_app_server();
25836
26441
  init_credential_store();
25837
26442
  init_claude_config_lock();
@@ -26657,7 +27262,7 @@ import {
26657
27262
  unlinkSync as unlinkSync8
26658
27263
  } from "node:fs";
26659
27264
  import { open as open2 } from "node:fs/promises";
26660
- import { join as join16 } from "node:path";
27265
+ import { join as join17 } from "node:path";
26661
27266
  function parseStoredBody(text5) {
26662
27267
  let value;
26663
27268
  try {
@@ -26858,7 +27463,7 @@ var init_wal_index = __esm({
26858
27463
  /** The scan `ensureAsync` has running for a session, shared by callers. */
26859
27464
  building = /* @__PURE__ */ new Map();
26860
27465
  sidecarFor(sessionUuid2) {
26861
- return join16(this.dir, `${sessionUuid2}${SIDECAR_SUFFIX}`);
27466
+ return join17(this.dir, `${sessionUuid2}${SIDECAR_SUFFIX}`);
26862
27467
  }
26863
27468
  /** Whether a name in the WAL directory is one of these sidecars. */
26864
27469
  static isSidecar(name) {
@@ -27090,7 +27695,7 @@ import {
27090
27695
  writeSync as writeSync4
27091
27696
  } from "node:fs";
27092
27697
  import { randomUUID } from "node:crypto";
27093
- import { join as join17 } from "node:path";
27698
+ import { join as join18 } from "node:path";
27094
27699
  function activityAt(event) {
27095
27700
  const at2 = Date.parse(event.ts);
27096
27701
  return Number.isFinite(at2) ? at2 : Number.NEGATIVE_INFINITY;
@@ -27154,7 +27759,7 @@ var init_wal = __esm({
27154
27759
  this.dir = dir;
27155
27760
  ensureDir(dir);
27156
27761
  this.bodyIndexes = new BodyIndexStore(dir);
27157
- this.cursorPath = join17(dir, "cursor.json");
27762
+ this.cursorPath = join18(dir, "cursor.json");
27158
27763
  let raw;
27159
27764
  if (onCursorSetAside !== void 0)
27160
27765
  raw = readJsonStateFile(this.cursorPath, onCursorSetAside);
@@ -27234,10 +27839,10 @@ var init_wal = __esm({
27234
27839
  */
27235
27840
  dirtyPaths = /* @__PURE__ */ new Set();
27236
27841
  fileFor(sessionUuid2) {
27237
- return join17(this.dir, `${sessionUuid2}.ndjson`);
27842
+ return join18(this.dir, `${sessionUuid2}.ndjson`);
27238
27843
  }
27239
27844
  bodyFileFor(sessionUuid2) {
27240
- return join17(this.dir, `${sessionUuid2}.bodies.jsonl`);
27845
+ return join18(this.dir, `${sessionUuid2}.bodies.jsonl`);
27241
27846
  }
27242
27847
  persistCursor() {
27243
27848
  this.flush();
@@ -28666,7 +29271,7 @@ ${lines.join("\n")}
28666
29271
  for (const name of readdirSync7(this.dir)) {
28667
29272
  if (abandonedRewrite.test(name)) {
28668
29273
  try {
28669
- unlinkSync9(join17(this.dir, name));
29274
+ unlinkSync9(join18(this.dir, name));
28670
29275
  } catch (error) {
28671
29276
  this.bodyFailure(name.slice(0, 36), "cleanup", error);
28672
29277
  }
@@ -28813,7 +29418,7 @@ function githubConfigure(options, rootDeps) {
28813
29418
  const helperBase = deps.runtime.credentialHelperCommand;
28814
29419
  if (!helperBase)
28815
29420
  throw new Error("This installation has no credential helper command");
28816
- const helper = `!${helperBase.replace(/credential issue --harness claude-code$/, "github credential")} --harness ${shellQuote(options.harness, deps.platform)} --cwd ${shellQuote(cwd, deps.platform)}`;
29421
+ const helper = `!${helperBase.replace(/credential issue --harness claude-code$/, "github credential")} --harness ${shellQuote2(options.harness, deps.platform)} --cwd ${shellQuote2(cwd, deps.platform)}`;
28817
29422
  const previous = (host.github_repositories ?? []).find(
28818
29423
  (entry2) => sameReceipt(entry2, cwd, repository)
28819
29424
  );
@@ -29031,15 +29636,15 @@ var init_github = __esm({
29031
29636
 
29032
29637
  // ../../packages/tacho/src/host/harness-path.ts
29033
29638
  import { spawnSync as spawnSync5 } from "node:child_process";
29034
- import { delimiter, join as join18 } from "node:path";
29639
+ import { delimiter as delimiter2, join as join19 } from "node:path";
29035
29640
  function knownDirs(home) {
29036
29641
  return [
29037
- join18(home, ".local", "bin"),
29038
- join18(home, ".bun", "bin"),
29039
- join18(home, ".npm-global", "bin"),
29040
- join18(home, ".volta", "bin"),
29041
- join18(home, ".cargo", "bin"),
29042
- join18(home, "bin"),
29642
+ join19(home, ".local", "bin"),
29643
+ join19(home, ".bun", "bin"),
29644
+ join19(home, ".npm-global", "bin"),
29645
+ join19(home, ".volta", "bin"),
29646
+ join19(home, ".cargo", "bin"),
29647
+ join19(home, "bin"),
29043
29648
  "/opt/homebrew/bin",
29044
29649
  "/usr/local/bin",
29045
29650
  "/usr/bin",
@@ -29079,10 +29684,10 @@ function harnessPath(env, home, loginPath) {
29079
29684
  seen.add(dir);
29080
29685
  dirs.push(dir);
29081
29686
  };
29082
- for (const dir of (loginPath ?? "").split(delimiter)) add2(dir);
29083
- for (const dir of (env["PATH"] ?? "").split(delimiter)) add2(dir);
29687
+ for (const dir of (loginPath ?? "").split(delimiter2)) add2(dir);
29688
+ for (const dir of (env["PATH"] ?? "").split(delimiter2)) add2(dir);
29084
29689
  for (const dir of knownDirs(home)) add2(dir);
29085
- return dirs.join(delimiter);
29690
+ return dirs.join(delimiter2);
29086
29691
  }
29087
29692
  var MARK, LOGIN_SHELL_TIMEOUT_MS;
29088
29693
  var init_harness_path = __esm({
@@ -29159,7 +29764,7 @@ var init_policy_mode = __esm({
29159
29764
 
29160
29765
  // ../../packages/tacho/src/host/wal-ceiling.ts
29161
29766
  import { statfsSync } from "node:fs";
29162
- import { join as join19 } from "node:path";
29767
+ import { join as join20 } from "node:path";
29163
29768
  function freeBytesOn(dir) {
29164
29769
  try {
29165
29770
  const stats2 = statfsSync(dir);
@@ -29206,7 +29811,7 @@ function isDrop(value) {
29206
29811
  function readWalCeilingState(walDir) {
29207
29812
  let raw;
29208
29813
  try {
29209
- raw = readJsonFileIfExists(join19(walDir, STATE_FILE));
29814
+ raw = readJsonFileIfExists(join20(walDir, STATE_FILE));
29210
29815
  } catch (error) {
29211
29816
  if (error instanceof SyntaxError) return void 0;
29212
29817
  throw error;
@@ -29406,7 +30011,7 @@ var init_wal_ceiling = __esm({
29406
30011
  const changed = this.unsaved || prior === void 0 || prior.stalled_sessions !== next.stalled_sessions || prior.drops.length !== next.drops.length || prior.drops.at(-1)?.dropped_at !== next.drops.at(-1)?.dropped_at || !sameClocks(prior.stall_clocks, next.stall_clocks) || next.stalled_sessions > 0 && (prior.stalled_bytes !== next.stalled_bytes || prior.ceiling_bytes !== next.ceiling_bytes);
29407
30012
  this.state = next;
29408
30013
  if (!changed) return;
29409
- const path2 = join19(this.walDir, STATE_FILE);
30014
+ const path2 = join20(this.walDir, STATE_FILE);
29410
30015
  try {
29411
30016
  writeSensitiveFileAtomic(path2, JSON.stringify(next));
29412
30017
  this.unsaved = false;
@@ -29910,7 +30515,7 @@ import {
29910
30515
  rmdirSync as rmdirSync5,
29911
30516
  rmSync as rmSync2
29912
30517
  } from "node:fs";
29913
- import { dirname as dirname12, join as join20 } from "node:path";
30518
+ import { dirname as dirname12, join as join21 } from "node:path";
29914
30519
  async function revokeOnControlPlane(host, options, deps, warnings) {
29915
30520
  const resolved = resolveCredentials(
29916
30521
  {
@@ -30521,7 +31126,7 @@ async function unenrollLocked(options, deps) {
30521
31126
  ];
30522
31127
  const purged = parts.filter(([, path2, recursive]) => remove2(path2, recursive)).map(([name]) => name);
30523
31128
  let failed3 = purged.length < parts.length;
30524
- if (!existsSync15(join20(deps.paths.dir, HARNESS_RECEIPTS)) && !remove2(join20(deps.paths.dir, HARNESS_BACKUPS), true))
31129
+ if (!existsSync15(join21(deps.paths.dir, HARNESS_RECEIPTS)) && !remove2(join21(deps.paths.dir, HARNESS_BACKUPS), true))
30525
31130
  failed3 = true;
30526
31131
  const logShared = otherLiveAgents(deps.paths, deps.paths.dir).length > 0;
30527
31132
  if (!logShared) {
@@ -30579,7 +31184,7 @@ var init_unenroll = __esm({
30579
31184
 
30580
31185
  // ../../packages/tacho/src/cli/enroll.ts
30581
31186
  import { existsSync as existsSync16, lstatSync as lstatSync4, rmSync as rmSync3 } from "node:fs";
30582
- import { dirname as dirname13, isAbsolute, join as join21 } from "node:path";
31187
+ import { dirname as dirname13, isAbsolute, join as join22 } from "node:path";
30583
31188
  function rootRefusal(command2, deps, allowRoot) {
30584
31189
  if (allowRoot === true || deps.getuid?.() !== 0) return void 0;
30585
31190
  const user = deps.env["SUDO_USER"] ?? "<user>";
@@ -30605,7 +31210,7 @@ function runtimeOf(host) {
30605
31210
  if (first === void 0 || !files2.every((file) => existsSync16(file)))
30606
31211
  return void 0;
30607
31212
  const binDir = dirname13(first);
30608
- const tacho = host.daemon_command[0] === first ? shellQuote(first) : `${host.daemon_command[0]} ${shellQuote(join21(binDir, "tacho.mjs"))}`;
31213
+ const tacho = host.daemon_command[0] === first ? shellQuote2(first) : `${host.daemon_command[0]} ${shellQuote2(join22(binDir, "tacho.mjs"))}`;
30609
31214
  return {
30610
31215
  hookCommand: host.hook_command,
30611
31216
  credentialHelperCommand: helperCommandFor(tacho),
@@ -31699,6 +32304,7 @@ ${problems.map((problem) => ` ${problem}`).join("\n")}`
31699
32304
  const mode = options.credentials ?? "brokered";
31700
32305
  try {
31701
32306
  if (mode === "brokered") {
32307
+ await signInIfNoCredential(reaching, deps);
31702
32308
  const outcome = await brokerCredentials(host, reaching, deps);
31703
32309
  for (const entry2 of outcome.harnesses)
31704
32310
  deps.out(` ${describeHarness(entry2)}`);
@@ -32861,21 +33467,21 @@ import {
32861
33467
  statSync as statSync7,
32862
33468
  unlinkSync as unlinkSync10
32863
33469
  } from "node:fs";
32864
- import { dirname as dirname14, isAbsolute as isAbsolute2, join as join22, relative, resolve as resolve7, sep } from "node:path";
33470
+ import { dirname as dirname14, isAbsolute as isAbsolute2, join as join23, relative, resolve as resolve7, sep } from "node:path";
32865
33471
  function dataLocalDir(home, env, platform) {
32866
33472
  if (platform === "darwin")
32867
- return join22(home, "Library", "Application Support");
33473
+ return join23(home, "Library", "Application Support");
32868
33474
  if (platform === "win32")
32869
- return env["LOCALAPPDATA"] ?? join22(home, "AppData", "Local");
33475
+ return env["LOCALAPPDATA"] ?? join23(home, "AppData", "Local");
32870
33476
  const xdg = env["XDG_DATA_HOME"];
32871
- return xdg !== void 0 && isAbsolute2(xdg) ? xdg : join22(home, ".local", "share");
33477
+ return xdg !== void 0 && isAbsolute2(xdg) ? xdg : join23(home, ".local", "share");
32872
33478
  }
32873
33479
  function desktopPlaces(deps) {
32874
- const oxagenDir = join22(deps.home, ".config", "oxagen");
33480
+ const oxagenDir = join23(deps.home, ".config", "oxagen");
32875
33481
  return {
32876
33482
  oxagenDir,
32877
- desktopConfig: join22(oxagenDir, "desktop.json"),
32878
- copies: join22(
33483
+ desktopConfig: join23(oxagenDir, "desktop.json"),
33484
+ copies: join23(
32879
33485
  dataLocalDir(deps.home, deps.env, deps.platform),
32880
33486
  "oxagen",
32881
33487
  "bin"
@@ -33120,7 +33726,7 @@ function undoEntry(entry2, deps, tally2) {
33120
33726
  }
33121
33727
  function versionDirs(copies) {
33122
33728
  try {
33123
- return readdirSync9(copies, { withFileTypes: true }).filter((entry2) => entry2.isDirectory() && !entry2.name.startsWith(".")).map((entry2) => join22(copies, entry2.name)).sort();
33729
+ return readdirSync9(copies, { withFileTypes: true }).filter((entry2) => entry2.isDirectory() && !entry2.name.startsWith(".")).map((entry2) => join23(copies, entry2.name)).sort();
33124
33730
  } catch {
33125
33731
  return [];
33126
33732
  }
@@ -33156,7 +33762,7 @@ function journaledCopies(journal, copies, tally2) {
33156
33762
  function removeSidecars(dir, platform, tally2) {
33157
33763
  const note = platform === "win32" ? `. Windows keeps a running program's file, so delete ${dir} after this command exits` : "";
33158
33764
  for (const name of ["oxagen", "tacho"]) {
33159
- const file = join22(dir, platform === "win32" ? `${name}.exe` : name);
33765
+ const file = join23(dir, platform === "win32" ? `${name}.exe` : name);
33160
33766
  removeFile(file, tally2, note);
33161
33767
  }
33162
33768
  }
@@ -33244,7 +33850,7 @@ async function uninstall(options, deps) {
33244
33850
  tally2.left.push(`cannot remove ${dir}: ${reasonOf3(error)}`);
33245
33851
  }
33246
33852
  }
33247
- const configDir = join22(deps.home, ".config");
33853
+ const configDir = join23(deps.home, ".config");
33248
33854
  if (record.configDirCreated && removeDirIfEmpty(configDir))
33249
33855
  tally2.removed.push(configDir);
33250
33856
  for (const path2 of tally2.removed) deps.out(` removed ${path2}`);
@@ -33658,9 +34264,9 @@ var init_run = __esm({
33658
34264
  });
33659
34265
 
33660
34266
  // ../../packages/tacho/src/cli/agent-run.ts
33661
- import { spawn as spawn2 } from "node:child_process";
34267
+ import { spawn as spawn4 } from "node:child_process";
33662
34268
  import { randomUUID as randomUUID2 } from "node:crypto";
33663
- import { constants as constants2 } from "node:os";
34269
+ import { constants as constants3 } from "node:os";
33664
34270
  import { posix as posix3, win32 as win324 } from "node:path";
33665
34271
  function programName(program2) {
33666
34272
  const base2 = (program2.includes("\\") ? win324 : posix3).basename(program2);
@@ -33686,7 +34292,7 @@ function sessionRefusal(stdout) {
33686
34292
  function exitCodeOf(exit) {
33687
34293
  if (exit.error !== void 0) return 1;
33688
34294
  if (exit.code !== null) return exit.code;
33689
- const number2 = exit.signal !== null ? constants2.signals[exit.signal] : void 0;
34295
+ const number2 = exit.signal !== null ? constants3.signals[exit.signal] : void 0;
33690
34296
  return number2 !== void 0 ? 128 + number2 : 1;
33691
34297
  }
33692
34298
  function spawnAgent(command2, args, options) {
@@ -33697,7 +34303,7 @@ function spawnAgent(command2, args, options) {
33697
34303
  options.env
33698
34304
  );
33699
34305
  return new Promise((resolve25) => {
33700
- const child = spawn2(invocation.command, invocation.args, {
34306
+ const child = spawn4(invocation.command, invocation.args, {
33701
34307
  cwd: options.cwd,
33702
34308
  env: options.env,
33703
34309
  stdio: "inherit",
@@ -33922,11 +34528,11 @@ var init_work_order_start = __esm({
33922
34528
 
33923
34529
  // ../../packages/tacho/src/host/work-orders.ts
33924
34530
  import { readdirSync as readdirSync10, rmSync as rmSync5 } from "node:fs";
33925
- import { join as join23 } from "node:path";
34531
+ import { join as join24 } from "node:path";
33926
34532
  function orderFile(paths, id2) {
33927
34533
  if (!WORK_ORDER_ID_PATTERN.test(id2))
33928
34534
  throw new Error(`${JSON.stringify(id2)} is not a work order id`);
33929
- return join23(paths.workOrders, `${id2}.json`);
34535
+ return join24(paths.workOrders, `${id2}.json`);
33930
34536
  }
33931
34537
  function readKept(path2) {
33932
34538
  try {
@@ -33976,7 +34582,7 @@ function removeWorkOrder(paths, id2) {
33976
34582
  function runningFile(paths, id2) {
33977
34583
  if (!WORK_ORDER_ID_PATTERN.test(id2))
33978
34584
  throw new Error(`${JSON.stringify(id2)} is not a work order id`);
33979
- return join23(paths.workOrders, `${id2}.running`);
34585
+ return join24(paths.workOrders, `${id2}.running`);
33980
34586
  }
33981
34587
  function processIsAlive(pid) {
33982
34588
  try {
@@ -34378,10 +34984,12 @@ var init_work = __esm({
34378
34984
  var cli_exports = {};
34379
34985
  __export(cli_exports, {
34380
34986
  BACKFILL_EXIT: () => BACKFILL_EXIT,
34987
+ CLAUDE_OAUTH_TOKEN_ENV: () => CLAUDE_OAUTH_TOKEN_ENV,
34381
34988
  CONTAINED_AGENTS: () => CONTAINED_AGENTS,
34382
34989
  CURSOR_COVERAGE_NOTE: () => CURSOR_COVERAGE_NOTE,
34383
34990
  MODEL_CREDENTIAL_HARNESSES: () => MODEL_CREDENTIAL_HARNESSES,
34384
34991
  SHIPPING_STALL_MS: () => SHIPPING_STALL_MS,
34992
+ acquireSubscriptionToken: () => acquireSubscriptionToken,
34385
34993
  addMissingClaudeCodeMcp: () => addMissingClaudeCodeMcp,
34386
34994
  agentNameFromCommand: () => agentNameFromCommand,
34387
34995
  backfillCommand: () => backfillCommand,
@@ -34389,6 +34997,7 @@ __export(cli_exports, {
34389
34997
  canServeOxagenTools: () => canServeOxagenTools,
34390
34998
  claudeFacts: () => claudeFacts,
34391
34999
  credentialIssue: () => credentialIssue,
35000
+ credentialLogin: () => credentialLogin,
34392
35001
  credentialStatus: () => credentialStatus,
34393
35002
  cursorAppFacts: () => cursorAppFacts,
34394
35003
  cursorFacts: () => cursorFacts,
@@ -34436,9 +35045,10 @@ __export(cli_exports, {
34436
35045
  runtimeCommands: () => runtimeCommands,
34437
35046
  serviceInstalled: () => serviceInstalled,
34438
35047
  sessionRefusal: () => sessionRefusal,
34439
- shellQuote: () => shellQuote,
35048
+ shellQuote: () => shellQuote2,
34440
35049
  shimError: () => shimError,
34441
35050
  shippingHealth: () => shippingHealth,
35051
+ signInIfNoCredential: () => signInIfNoCredential,
34442
35052
  spawnAgent: () => spawnAgent,
34443
35053
  stableExecutablePath: () => stableExecutablePath,
34444
35054
  status: () => status,
@@ -38173,6 +38783,7 @@ function containedBridgeHandler(options) {
38173
38783
  const modelPaths = options.harness === "claude-code" ? ["/model/v1/messages", "/model/v1/messages/count_tokens"] : ["/model/v1/responses", "/model/v1/chat/completions"];
38174
38784
  if (request3.method === "POST" && modelPaths.includes(path2)) {
38175
38785
  const credential = options.issueCredential();
38786
+ const chatgpt = options.harness === "codex" && options.chatgptLogin?.() === true;
38176
38787
  request3.headers = {
38177
38788
  "content-type": "application/json",
38178
38789
  ...request3.headers["content-length"] ? { "content-length": request3.headers["content-length"] } : {},
@@ -38180,9 +38791,12 @@ function containedBridgeHandler(options) {
38180
38791
  ...request3.headers["anthropic-beta"] ? { "anthropic-beta": request3.headers["anthropic-beta"] } : {},
38181
38792
  host: `127.0.0.1:${options.modelPort}`,
38182
38793
  "x-oxagen-session": options.sessionId,
38183
- ...options.harness === "claude-code" ? { "x-api-key": credential } : { authorization: `Bearer ${credential}` }
38794
+ ...options.harness === "claude-code" ? { "x-api-key": credential } : { authorization: `Bearer ${credential}` },
38795
+ // Marks the call as a ChatGPT login's; the gateway puts the
38796
+ // login's own account in its place.
38797
+ ...chatgpt ? { "chatgpt-account-id": "custody" } : {}
38184
38798
  };
38185
- request3.url = options.harness === "claude-code" ? path2.replace("/model", "/anthropic") : path2.replace("/model", "/openai");
38799
+ request3.url = options.harness === "claude-code" ? path2.replace("/model", "/anthropic") : chatgpt ? path2.replace("/model/v1", "/backend-api/codex") : path2.replace("/model", "/openai");
38186
38800
  options.model(request3, response);
38187
38801
  return;
38188
38802
  }
@@ -38334,7 +38948,7 @@ var init_bridge = __esm({
38334
38948
 
38335
38949
  // ../../packages/tacho/src/contained/workspace.ts
38336
38950
  import { lstatSync as lstatSync6, readFileSync as readFileSync14, readdirSync as readdirSync11, realpathSync as realpathSync3 } from "node:fs";
38337
- import { isAbsolute as isAbsolute3, join as join24, relative as relative2, resolve as resolve9, sep as sep2 } from "node:path";
38951
+ import { isAbsolute as isAbsolute3, join as join25, relative as relative2, resolve as resolve9, sep as sep2 } from "node:path";
38338
38952
  function within(root, path2) {
38339
38953
  const rel = relative2(root, path2);
38340
38954
  return rel === "" || !isAbsolute3(rel) && rel !== ".." && !rel.startsWith(`..${sep2}`);
@@ -38364,7 +38978,7 @@ function validateContainedWorkspace(workspace, sessionDirectory, mountInfo = rea
38364
38978
  }
38365
38979
  const visit2 = (directory) => {
38366
38980
  for (const entry2 of readdirSync11(directory)) {
38367
- const path2 = join24(directory, entry2);
38981
+ const path2 = join25(directory, entry2);
38368
38982
  if (CREDENTIAL_PATHS.has(entry2) || isEnvFile(entry2))
38369
38983
  throw new Error(
38370
38984
  `Remove local credential files from the contained checkout before launch: ${named(path2)}`
@@ -38398,7 +39012,7 @@ function validateContainedWorkspace(workspace, sessionDirectory, mountInfo = rea
38398
39012
  }
38399
39013
  function gitDirectoryMounts(workspace) {
38400
39014
  const root = realpathSync3(workspace);
38401
- const dotGit = join24(root, ".git");
39015
+ const dotGit = join25(root, ".git");
38402
39016
  let stat7;
38403
39017
  try {
38404
39018
  stat7 = lstatSync6(dotGit);
@@ -38436,7 +39050,7 @@ function gitDirectoryMounts(workspace) {
38436
39050
  if (gitDir !== void 0) {
38437
39051
  let common;
38438
39052
  try {
38439
- common = readFileSync14(join24(gitDir, "commondir"), "utf8").trim();
39053
+ common = readFileSync14(join25(gitDir, "commondir"), "utf8").trim();
38440
39054
  } catch {
38441
39055
  common = void 0;
38442
39056
  }
@@ -38463,7 +39077,7 @@ var init_workspace = __esm({
38463
39077
  // ../../packages/tacho/src/collector/hardened-git.ts
38464
39078
  import { execFile as execFile2 } from "node:child_process";
38465
39079
  import { lstatSync as lstatSync7, readFileSync as readFileSync15, statSync as statSync8 } from "node:fs";
38466
- import { dirname as dirname15, join as join25, resolve as resolve10 } from "node:path";
39080
+ import { dirname as dirname15, join as join26, resolve as resolve10 } from "node:path";
38467
39081
  function hardenedGitArgs(cwd, args, globals = []) {
38468
39082
  const subcommand = args[0];
38469
39083
  const end = args.indexOf("--");
@@ -38480,9 +39094,9 @@ function hardenedGitArgs(cwd, args, globals = []) {
38480
39094
  ];
38481
39095
  }
38482
39096
  function hardenedGitShellPrefix() {
38483
- return ["git", ...HARDENED_GIT_CONFIG.map(shellQuote2)].join(" ");
39097
+ return ["git", ...HARDENED_GIT_CONFIG.map(shellQuote3)].join(" ");
38484
39098
  }
38485
- function shellQuote2(value) {
39099
+ function shellQuote3(value) {
38486
39100
  return /^[A-Za-z0-9_./=:-]+$/.test(value) ? value : `'${value.replace(/'/g, "'\\''")}'`;
38487
39101
  }
38488
39102
  function hardenedGitExecOptions(repository) {
@@ -38502,7 +39116,7 @@ function gitIdentity(repository, deps = DEFAULT_IDENTITY_DEPS) {
38502
39116
  };
38503
39117
  }
38504
39118
  for (let at2 = directory; ; at2 = dirname15(at2)) {
38505
- const marker = join25(at2, ".git");
39119
+ const marker = join26(at2, ".git");
38506
39120
  const link = tryStat(deps.lstat, marker);
38507
39121
  if (link !== void 0) {
38508
39122
  owners.push(link);
@@ -38510,7 +39124,7 @@ function gitIdentity(repository, deps = DEFAULT_IDENTITY_DEPS) {
38510
39124
  if (target2 !== void 0) {
38511
39125
  owners.push(target2);
38512
39126
  if (target2.isDirectory()) {
38513
- const config = tryStat(deps.stat, join25(marker, "config"));
39127
+ const config = tryStat(deps.stat, join26(marker, "config"));
38514
39128
  if (config !== void 0) owners.push(config);
38515
39129
  }
38516
39130
  }
@@ -38662,7 +39276,7 @@ var init_hardened_git = __esm({
38662
39276
 
38663
39277
  // ../../packages/tacho/src/contained/profile.ts
38664
39278
  import { createHash as createHash6 } from "node:crypto";
38665
- import { isAbsolute as isAbsolute4, join as join26, relative as relative3, sep as sep3 } from "node:path";
39279
+ import { isAbsolute as isAbsolute4, join as join27, relative as relative3, sep as sep3 } from "node:path";
38666
39280
  function containerPath(workspace, path2) {
38667
39281
  const inside2 = relative3(workspace, path2);
38668
39282
  if (inside2 === "" || isAbsolute4(inside2) || inside2 === ".." || inside2.startsWith(`..${sep3}`))
@@ -38672,7 +39286,7 @@ function containerPath(workspace, path2) {
38672
39286
  return `/workspace/${inside2.split(sep3).join("/")}`;
38673
39287
  }
38674
39288
  function gitMountPairs(spec) {
38675
- if (!spec.gitMounts.includes(join26(spec.workspace, ".git")))
39289
+ if (!spec.gitMounts.includes(join27(spec.workspace, ".git")))
38676
39290
  throw new Error(
38677
39291
  "Contained execution must mount the repository's .git read-only"
38678
39292
  );
@@ -38829,7 +39443,7 @@ var init_profile = __esm({
38829
39443
  });
38830
39444
 
38831
39445
  // ../../packages/tacho/src/contained/launcher.ts
38832
- import { execFile as execFile3, spawn as spawn3 } from "node:child_process";
39446
+ import { execFile as execFile3, spawn as spawn5 } from "node:child_process";
38833
39447
  import { randomBytes as randomBytes8 } from "node:crypto";
38834
39448
  import {
38835
39449
  chmodSync as chmodSync7,
@@ -38839,7 +39453,7 @@ import {
38839
39453
  writeFileSync as writeFileSync2
38840
39454
  } from "node:fs";
38841
39455
  import { tmpdir } from "node:os";
38842
- import { isAbsolute as isAbsolute5, join as join27 } from "node:path";
39456
+ import { isAbsolute as isAbsolute5, join as join28 } from "node:path";
38843
39457
  import { promisify } from "node:util";
38844
39458
  function reason(error) {
38845
39459
  return error instanceof Error ? error.message : String(error);
@@ -38878,7 +39492,7 @@ async function launchContainedAgent(options) {
38878
39492
  if (digest6 === void 0)
38879
39493
  throw new Error("The operator's contained image is not installed");
38880
39494
  const sessionId = `contained-${randomBytes8(16).toString("hex")}`;
38881
- const directory = mkdtempSync(join27(tmpdir(), "oxagen-contained-"));
39495
+ const directory = mkdtempSync(join28(tmpdir(), "oxagen-contained-"));
38882
39496
  chmodSync7(directory, 448);
38883
39497
  let prepared;
38884
39498
  let containerCreated = false;
@@ -38899,7 +39513,7 @@ async function launchContainedAgent(options) {
38899
39513
  for (const [name2, contents] of entries2) {
38900
39514
  if (!/^[a-z0-9.-]+$/.test(name2))
38901
39515
  throw new Error("Invalid contained configuration filename");
38902
- writeFileSync2(join27(directory, name2), contents, {
39516
+ writeFileSync2(join28(directory, name2), contents, {
38903
39517
  mode: 256,
38904
39518
  flag: "wx"
38905
39519
  });
@@ -38930,7 +39544,7 @@ async function launchContainedAgent(options) {
38930
39544
  if (options.signal?.aborted)
38931
39545
  throw new Error("Contained run cancelled before start");
38932
39546
  exitCode = await new Promise((resolve25, reject) => {
38933
- const child = spawn3("docker", ["start", "--attach", name], {
39547
+ const child = spawn5("docker", ["start", "--attach", name], {
38934
39548
  stdio: ["ignore", "pipe", "pipe"]
38935
39549
  });
38936
39550
  const stop = () => {
@@ -39298,8 +39912,8 @@ var init_privilege = __esm({
39298
39912
 
39299
39913
  // ../../packages/tacho/src/contained/sandbox/launcher.ts
39300
39914
  import { randomBytes as randomBytes9 } from "node:crypto";
39301
- import { join as join28 } from "node:path";
39302
- function shellQuote3(value) {
39915
+ import { join as join29 } from "node:path";
39916
+ function shellQuote4(value) {
39303
39917
  return `'${value.replace(/'/g, `'\\''`)}'`;
39304
39918
  }
39305
39919
  function sandboxHarnessEnvironment(request3, gatewayPort) {
@@ -39325,7 +39939,7 @@ function ptyCommand(argv) {
39325
39939
  "-f",
39326
39940
  "-e",
39327
39941
  "-c",
39328
- `exec ${argv.map(shellQuote3).join(" ")}`,
39942
+ `exec ${argv.map(shellQuote4).join(" ")}`,
39329
39943
  "/dev/null"
39330
39944
  ]
39331
39945
  };
@@ -39388,7 +40002,7 @@ async function launchSandboxAgent(options) {
39388
40002
  { ...asAgent, cwd: SANDBOX_AGENT_HOME, timeoutMs: 15 * 6e4 }
39389
40003
  );
39390
40004
  for (const [name, contents] of Object.entries(claudeCodeUserState())) {
39391
- const path2 = join28(SANDBOX_AGENT_HOME, name);
40005
+ const path2 = join29(SANDBOX_AGENT_HOME, name);
39392
40006
  system.writeFile(path2, contents, 384);
39393
40007
  system.chown(path2, SANDBOX_AGENT_UID, SANDBOX_AGENT_GID);
39394
40008
  }
@@ -39512,7 +40126,7 @@ var init_request = __esm({
39512
40126
  });
39513
40127
 
39514
40128
  // ../../packages/tacho/src/contained/sandbox/system.ts
39515
- import { execFile as execFile4, spawn as spawn4 } from "node:child_process";
40129
+ import { execFile as execFile4, spawn as spawn6 } from "node:child_process";
39516
40130
  import {
39517
40131
  chmodSync as chmodSync8,
39518
40132
  chownSync as chownSync2,
@@ -39543,7 +40157,7 @@ var init_system = __esm({
39543
40157
  return { stdout: String(answer.stdout), stderr: String(answer.stderr) };
39544
40158
  },
39545
40159
  spawn: (file, args, options) => {
39546
- const child = spawn4(file, [...args], {
40160
+ const child = spawn6(file, [...args], {
39547
40161
  ...options.uid !== void 0 ? { uid: options.uid } : {},
39548
40162
  ...options.gid !== void 0 ? { gid: options.gid } : {},
39549
40163
  ...options.cwd !== void 0 ? { cwd: options.cwd } : {},
@@ -39594,10 +40208,10 @@ var init_system = __esm({
39594
40208
  });
39595
40209
 
39596
40210
  // ../../packages/tacho/src/contained/runner.ts
39597
- import { join as join29 } from "node:path";
40211
+ import { join as join30 } from "node:path";
39598
40212
  function containedHookEnv(harness, workspace) {
39599
- const home = join29(workspace, ".oxagen-contained", "home");
39600
- return harness === "codex" ? { CODEX_HOME: join29(home, ".codex") } : { CLAUDE_CONFIG_DIR: join29(home, ".claude") };
40213
+ const home = join30(workspace, ".oxagen-contained", "home");
40214
+ return harness === "codex" ? { CODEX_HOME: join30(home, ".codex") } : { CLAUDE_CONFIG_DIR: join30(home, ".claude") };
39601
40215
  }
39602
40216
  function containedLaunchEndpoint(host) {
39603
40217
  const ingest = new URL(host.endpoints.ingest);
@@ -39693,6 +40307,7 @@ function createContainedRunner(options) {
39693
40307
  throw new Error("Credential custody unavailable");
39694
40308
  return answer.body.token;
39695
40309
  },
40310
+ ...options.chatgptLogin !== void 0 ? { chatgptLogin: options.chatgptLogin } : {},
39696
40311
  model: (request3, response) => options.model.handle(request3, response),
39697
40312
  hook: options.hook,
39698
40313
  opening: route.opening,
@@ -39795,7 +40410,7 @@ function createContainedRunner(options) {
39795
40410
  sessionUuid2 = started.recorder.sessionUuid;
39796
40411
  active2.set(sessionUuid2, controller);
39797
40412
  const bridge = await startContainedBridge({
39798
- socketPath: join29(directory, "bridge.sock"),
40413
+ socketPath: join30(directory, "bridge.sock"),
39799
40414
  ...bridgeRoutes({
39800
40415
  sessionId,
39801
40416
  workspace,
@@ -39879,7 +40494,7 @@ function createContainedRunner(options) {
39879
40494
  const abort = () => controller.abort();
39880
40495
  signal?.addEventListener("abort", abort, { once: true });
39881
40496
  if (signal?.aborted) abort();
39882
- const env = { CLAUDE_CONFIG_DIR: join29(SANDBOX_AGENT_HOME, ".claude") };
40497
+ const env = { CLAUDE_CONFIG_DIR: join30(SANDBOX_AGENT_HOME, ".claude") };
39883
40498
  let sessionUuid2;
39884
40499
  let launchedSessionId;
39885
40500
  let opened = false;
@@ -40012,14 +40627,96 @@ var init_runner = __esm({
40012
40627
  }
40013
40628
  });
40014
40629
 
40630
+ // ../../packages/tacho/src/host/chatgpt-refresh.ts
40631
+ function jwtExpiryMs(token) {
40632
+ const payload = token.split(".")[1];
40633
+ if (payload === void 0) return void 0;
40634
+ try {
40635
+ const claims = JSON.parse(
40636
+ Buffer.from(payload, "base64url").toString("utf8")
40637
+ );
40638
+ return typeof claims.exp === "number" ? claims.exp * 1e3 : void 0;
40639
+ } catch {
40640
+ return void 0;
40641
+ }
40642
+ }
40643
+ function chatGptLoginDue(login, takenAt, now) {
40644
+ const exp = jwtExpiryMs(login.access_token);
40645
+ if (exp !== void 0) return exp - now < CHATGPT_REFRESH_MARGIN_MS;
40646
+ return now - takenAt > CHATGPT_REFRESH_MAX_AGE_MS;
40647
+ }
40648
+ async function refreshChatGptLogin(login, fetchImpl) {
40649
+ if (login.refresh_token.length === 0)
40650
+ throw new Error("the ChatGPT login in custody has no refresh token");
40651
+ const response = await fetchImpl(CHATGPT_TOKEN_URL, {
40652
+ method: "POST",
40653
+ headers: { "Content-Type": "application/json" },
40654
+ body: JSON.stringify({
40655
+ client_id: CODEX_OAUTH_CLIENT_ID,
40656
+ grant_type: "refresh_token",
40657
+ refresh_token: login.refresh_token,
40658
+ scope: "openid profile email"
40659
+ })
40660
+ });
40661
+ if (!response.ok)
40662
+ throw new Error(
40663
+ `auth.openai.com refused to refresh the ChatGPT login (${response.status}); run \`codex login\`, then \`oxagen agent enroll\``
40664
+ );
40665
+ let body2;
40666
+ try {
40667
+ body2 = JSON.parse(await response.text());
40668
+ } catch {
40669
+ throw new Error("auth.openai.com answered with something other than JSON");
40670
+ }
40671
+ if (typeof body2.access_token !== "string" || body2.access_token.length === 0)
40672
+ throw new Error("auth.openai.com answered without an access token");
40673
+ return {
40674
+ ...login,
40675
+ access_token: body2.access_token,
40676
+ refresh_token: typeof body2.refresh_token === "string" ? body2.refresh_token : login.refresh_token,
40677
+ ...typeof body2.id_token === "string" ? { id_token: body2.id_token } : {}
40678
+ };
40679
+ }
40680
+ async function refreshChatGptCustody(store, fetchImpl, now) {
40681
+ const entry2 = store.status().find((c) => c.provider === "openai" && c.kind === "chatgpt");
40682
+ if (entry2 === void 0) return "none";
40683
+ const held = store.read("openai");
40684
+ const login = held?.kind === "chatgpt" ? decodeChatGptLogin(held.secret) : void 0;
40685
+ if (login === void 0) return { failed: "custody holds no ChatGPT login" };
40686
+ if (!chatGptLoginDue(login, Date.parse(entry2.taken_at), now)) return "fresh";
40687
+ try {
40688
+ const next = await refreshChatGptLogin(login, fetchImpl);
40689
+ store.take(
40690
+ "openai",
40691
+ { kind: "chatgpt", secret: JSON.stringify(next) },
40692
+ "chatgpt:refresh",
40693
+ now
40694
+ );
40695
+ return "refreshed";
40696
+ } catch (error) {
40697
+ return { failed: error instanceof Error ? error.message : String(error) };
40698
+ }
40699
+ }
40700
+ var CODEX_OAUTH_CLIENT_ID, CHATGPT_TOKEN_URL, CHATGPT_REFRESH_MARGIN_MS, CHATGPT_REFRESH_MAX_AGE_MS;
40701
+ var init_chatgpt_refresh = __esm({
40702
+ "../../packages/tacho/src/host/chatgpt-refresh.ts"() {
40703
+ "use strict";
40704
+ init_model_credential();
40705
+ CODEX_OAUTH_CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
40706
+ CHATGPT_TOKEN_URL = "https://auth.openai.com/oauth/token";
40707
+ CHATGPT_REFRESH_MARGIN_MS = 60 * 6e4;
40708
+ CHATGPT_REFRESH_MAX_AGE_MS = 7 * 24 * 60 * 6e4;
40709
+ }
40710
+ });
40711
+
40015
40712
  // ../../packages/tacho/src/host/repositories.ts
40016
40713
  import { existsSync as existsSync18, readFileSync as readFileSync17, statSync as statSync10 } from "node:fs";
40017
- import { dirname as dirname17, join as join30, resolve as resolve11, sep as sep4 } from "node:path";
40714
+ import { dirname as dirname17, join as join31, resolve as resolve11, sep as sep4 } from "node:path";
40018
40715
  function repositoriesFile(home) {
40019
- return join30(home.tachoDir, "repositories.json");
40716
+ return join31(home.tachoDir, "repositories.json");
40020
40717
  }
40021
40718
  function workTreesDir(home) {
40022
- return join30(home.tachoDir, "work");
40719
+ return join31(home.tachoDir, "work");
40023
40720
  }
40024
40721
  function readIndex(home) {
40025
40722
  let raw;
@@ -40071,7 +40768,7 @@ function recordCheckout(home, canonical3, root, seenAt) {
40071
40768
  return true;
40072
40769
  }
40073
40770
  function mainCheckoutOf(root) {
40074
- const dotGit = join30(root, ".git");
40771
+ const dotGit = join31(root, ".git");
40075
40772
  try {
40076
40773
  if (!statSync10(dotGit).isFile()) return root;
40077
40774
  const line = readFileSync17(dotGit, "utf8").trim();
@@ -40081,13 +40778,13 @@ function mainCheckoutOf(root) {
40081
40778
  const worktrees = dirname17(gitdir);
40082
40779
  if (!worktrees.endsWith(`${sep4}.git${sep4}worktrees`)) return root;
40083
40780
  const clone4 = dirname17(dirname17(worktrees));
40084
- return existsSync18(join30(clone4, ".git")) ? clone4 : root;
40781
+ return existsSync18(join31(clone4, ".git")) ? clone4 : root;
40085
40782
  } catch {
40086
40783
  return root;
40087
40784
  }
40088
40785
  }
40089
40786
  function defaultIsCheckout(root) {
40090
- return existsSync18(join30(root, ".git"));
40787
+ return existsSync18(join31(root, ".git"));
40091
40788
  }
40092
40789
  function findCheckout(home, repository, host, deps = {}) {
40093
40790
  const isCheckout = deps.isCheckout ?? defaultIsCheckout;
@@ -40135,7 +40832,7 @@ var init_repositories = __esm({
40135
40832
 
40136
40833
  // ../../packages/tacho/src/collector/detector.ts
40137
40834
  import { promises as fs3 } from "node:fs";
40138
- import { basename as basename5, join as join31 } from "node:path";
40835
+ import { basename as basename5, join as join32 } from "node:path";
40139
40836
  async function eachLimited(items, limit, task) {
40140
40837
  let next = 0;
40141
40838
  const workers = Array.from(
@@ -40161,7 +40858,7 @@ async function scanProject(dir) {
40161
40858
  await eachLimited(names2, SCAN_CONCURRENCY, async (name) => {
40162
40859
  const match = SESSION_FILE.exec(name);
40163
40860
  if (match === null) return;
40164
- const path2 = join31(dir, name);
40861
+ const path2 = join32(dir, name);
40165
40862
  try {
40166
40863
  const st = await fs3.stat(path2);
40167
40864
  out.push({ sessionId: match[1], path: path2, mtimeMs: st.mtimeMs });
@@ -40202,7 +40899,7 @@ var init_detector = __esm({
40202
40899
  continue;
40203
40900
  }
40204
40901
  await eachLimited(names2, SCAN_CONCURRENCY, async (name) => {
40205
- const dir = join31(root, name);
40902
+ const dir = join32(root, name);
40206
40903
  try {
40207
40904
  const st = await fs3.stat(dir);
40208
40905
  if (st.isDirectory()) dirs.push({ dir, mtimeMs: st.mtimeMs });
@@ -40442,7 +41139,7 @@ var init_detector = __esm({
40442
41139
  transcript_path: transcript.path,
40443
41140
  transcript_mtime: new Date(transcript.mtimeMs).toISOString(),
40444
41141
  claude_pids: processes.map((p) => p.pid),
40445
- project: basename5(join31(transcript.path, ".."))
41142
+ project: basename5(join32(transcript.path, ".."))
40446
41143
  }
40447
41144
  })
40448
41145
  );
@@ -40812,9 +41509,9 @@ var init_git_facts = __esm({
40812
41509
  });
40813
41510
 
40814
41511
  // ../../packages/tacho/src/collector/work-order-autostart.ts
40815
- import { spawn as spawn5 } from "node:child_process";
41512
+ import { spawn as spawn7 } from "node:child_process";
40816
41513
  import { closeSync as closeSync7, existsSync as existsSync19, openSync as openSync7 } from "node:fs";
40817
- import { dirname as dirname18, join as join32 } from "node:path";
41514
+ import { dirname as dirname18, join as join33 } from "node:path";
40818
41515
  function asError(error) {
40819
41516
  return error instanceof Error ? error : new Error(String(error));
40820
41517
  }
@@ -40867,7 +41564,7 @@ function createWorkOrderAutostart(deps) {
40867
41564
  }
40868
41565
  async function abandon(id2) {
40869
41566
  forget(id2);
40870
- const worktree = join32(workTreesDir(paths), id2);
41567
+ const worktree = join33(workTreesDir(paths), id2);
40871
41568
  if (!existsSync19(worktree)) return;
40872
41569
  const [common, branch, head2] = await Promise.all([
40873
41570
  git6(worktree, ["rev-parse", "--path-format=absolute", "--git-common-dir"]),
@@ -40905,7 +41602,7 @@ function createWorkOrderAutostart(deps) {
40905
41602
  return waitMs;
40906
41603
  }
40907
41604
  async function prepareWorktree(root, id2, itemNumber) {
40908
- const worktree = join32(workTreesDir(paths), id2);
41605
+ const worktree = join33(workTreesDir(paths), id2);
40909
41606
  const logPath = `${worktree}.log`;
40910
41607
  if (existsSync19(worktree)) {
40911
41608
  const [branch2, head2] = await Promise.all([
@@ -40966,9 +41663,17 @@ function createWorkOrderAutostart(deps) {
40966
41663
  log(`work order ${id2}: the harness ${ended}`);
40967
41664
  return;
40968
41665
  }
40969
- const [status2, ahead] = await Promise.all([
41666
+ const [status2, ahead, current] = await Promise.all([
40970
41667
  git6(worktree, ["status", "--porcelain"]),
40971
- base2 === void 0 ? Promise.resolve({ ok: false, out: "", error: "no base commit" }) : git6(worktree, ["rev-list", "--count", `${base2}..HEAD`])
41668
+ base2 === void 0 ? Promise.resolve({ ok: false, out: "", error: "no base commit" }) : git6(worktree, [
41669
+ "rev-list",
41670
+ "--count",
41671
+ "HEAD",
41672
+ "--not",
41673
+ base2,
41674
+ "--remotes"
41675
+ ]),
41676
+ git6(worktree, ["branch", "--show-current"])
40972
41677
  ]);
40973
41678
  const clean = status2.ok && status2.out.length === 0 && ahead.ok && ahead.out === "0";
40974
41679
  if (!clean || root === void 0) {
@@ -40984,13 +41689,26 @@ function createWorkOrderAutostart(deps) {
40984
41689
  );
40985
41690
  if (!removed.ok) {
40986
41691
  log(
40987
- `work order ${id2}: the harness ${ended} and left no work, but Git could not remove ${worktree}: ${removed.error}`
41692
+ `work order ${id2}: the harness ${ended} and left nothing that is not on a remote, but Git could not remove ${worktree}: ${removed.error}`
40988
41693
  );
40989
41694
  return;
40990
41695
  }
40991
- if (branch !== void 0) await git6(root, ["branch", "-D", branch]);
41696
+ const used = /* @__PURE__ */ new Set();
41697
+ if (branch !== void 0) used.add(branch);
41698
+ if (current.ok && current.out.length > 0) used.add(current.out);
41699
+ for (const name of used) {
41700
+ const unpushed = await git6(root, [
41701
+ "rev-list",
41702
+ "--count",
41703
+ name,
41704
+ "--not",
41705
+ "--remotes"
41706
+ ]);
41707
+ if (unpushed.ok && unpushed.out === "0")
41708
+ await git6(root, ["branch", "-D", name]);
41709
+ }
40992
41710
  log(
40993
- `work order ${id2}: the harness ${ended} and left no work, so its worktree is removed${mark.log !== void 0 ? `. Its output is in ${mark.log}` : ""}.`
41711
+ `work order ${id2}: the harness ${ended} and left nothing that is not on a remote, so its worktree is removed${mark.log !== void 0 ? `. Its output is in ${mark.log}` : ""}.`
40994
41712
  );
40995
41713
  }
40996
41714
  function watch2(id2, workspace, exited) {
@@ -41188,7 +41906,7 @@ var init_work_order_autostart = __esm({
41188
41906
  };
41189
41907
  let settled2 = false;
41190
41908
  try {
41191
- const child = spawn5(command2, args, {
41909
+ const child = spawn7(command2, args, {
41192
41910
  cwd: options.cwd,
41193
41911
  env: options.env,
41194
41912
  // Its own process group, so a daemon restart does not stop the run.
@@ -41275,7 +41993,7 @@ import {
41275
41993
  rm,
41276
41994
  unlink
41277
41995
  } from "node:fs/promises";
41278
- import { dirname as dirname19, join as join33 } from "node:path";
41996
+ import { dirname as dirname19, join as join34 } from "node:path";
41279
41997
  function byPath(a, b3) {
41280
41998
  return a.path < b3.path ? -1 : a.path > b3.path ? 1 : 0;
41281
41999
  }
@@ -41318,7 +42036,7 @@ async function contentHash(absolutePath, kind, keep) {
41318
42036
  if (keep !== void 0) {
41319
42037
  try {
41320
42038
  await mkdir(keep.dir, { recursive: true, mode: 448 });
41321
- const temp2 = join33(keep.dir, `.partial-${randomUUID3()}`);
42039
+ const temp2 = join34(keep.dir, `.partial-${randomUUID3()}`);
41322
42040
  copy = {
41323
42041
  temp: temp2,
41324
42042
  handle: await open3(temp2, "wx", keep.executable ? 448 : 384)
@@ -41362,7 +42080,7 @@ async function settleCopy(temp, name) {
41362
42080
  if (temp === void 0) return;
41363
42081
  if (name !== void 0)
41364
42082
  try {
41365
- await rename(temp, join33(dirname19(temp), name));
42083
+ await rename(temp, join34(dirname19(temp), name));
41366
42084
  return;
41367
42085
  } catch {
41368
42086
  }
@@ -41378,7 +42096,7 @@ async function copiedBytes(dir) {
41378
42096
  let total2 = 0;
41379
42097
  for (const name of names2) {
41380
42098
  try {
41381
- total2 += (await lstat(join33(dir, name))).size;
42099
+ total2 += (await lstat(join34(dir, name))).size;
41382
42100
  } catch {
41383
42101
  }
41384
42102
  }
@@ -41394,7 +42112,7 @@ async function removeCopiesOutside(root, live) {
41394
42112
  const keep = new Set(live());
41395
42113
  await Promise.all(
41396
42114
  names2.filter((name) => !keep.has(name)).map(
41397
- (name) => rm(join33(root, name), { recursive: true, force: true }).catch(
42115
+ (name) => rm(join34(root, name), { recursive: true, force: true }).catch(
41398
42116
  () => void 0
41399
42117
  )
41400
42118
  )
@@ -41501,7 +42219,7 @@ async function contributionOf(exec4, cwd, root, repoRelative, entry2, copies) {
41501
42219
  let copy = null;
41502
42220
  if (entry2 !== null) {
41503
42221
  if (copies === void 0 || !COPY_NAME.test(entry2[0])) return void 0;
41504
- copy = join33(copies, entry2[0]);
42222
+ copy = join34(copies, entry2[0]);
41505
42223
  const kept = await statOf(copy);
41506
42224
  if (kept === void 0 || kept === "absent" || kept.kind !== "file")
41507
42225
  return void 0;
@@ -41903,7 +42621,7 @@ var init_session_changes = __esm({
41903
42621
  });
41904
42622
 
41905
42623
  // ../../packages/tacho/src/collector/session-commits.ts
41906
- import { join as join34 } from "node:path";
42624
+ import { join as join35 } from "node:path";
41907
42625
  function parseMeta(stdout) {
41908
42626
  const out = [];
41909
42627
  for (const record of stdout.split("\0")) {
@@ -42028,7 +42746,7 @@ async function readSessionCommits(exec4, cwd, input) {
42028
42746
  const test = input.tests[commit.sha];
42029
42747
  const toolUseId = callAt(times.get(commit.sha), calls);
42030
42748
  const written2 = input.written;
42031
- const outside = merge || written2 === void 0 || root === void 0 ? void 0 : files2.some((file) => !written2.has(join34(root, file.path)));
42749
+ const outside = merge || written2 === void 0 || root === void 0 ? void 0 : files2.some((file) => !written2.has(join35(root, file.path)));
42032
42750
  return {
42033
42751
  sha: commit.sha,
42034
42752
  parent_shas: commit.parents.slice(0, MAX_COMMIT_PARENTS),
@@ -42076,7 +42794,7 @@ var init_session_commits = __esm({
42076
42794
 
42077
42795
  // ../../packages/tacho/src/collector/worktree-snapshot.ts
42078
42796
  import { lstat as lstat2 } from "node:fs/promises";
42079
- import { join as join35 } from "node:path";
42797
+ import { join as join36 } from "node:path";
42080
42798
  function headerPath(prefix, path2) {
42081
42799
  const name = `${prefix}${path2}`;
42082
42800
  let quoted3 = false;
@@ -42160,7 +42878,7 @@ async function worktreeFingerprint(status2, root) {
42160
42878
  const path2 = statusPath(record);
42161
42879
  if (path2 === null) return "";
42162
42880
  try {
42163
- const info = await lstat2(join35(root, path2));
42881
+ const info = await lstat2(join36(root, path2));
42164
42882
  return `${info.size}:${info.mtimeMs}:${info.ctimeMs}`;
42165
42883
  } catch {
42166
42884
  return "absent";
@@ -42268,7 +42986,7 @@ async function readWorktreeSnapshot(exec4, cwd, baseline, measured) {
42268
42986
  }
42269
42987
  let present;
42270
42988
  try {
42271
- present = (await lstat2(join35(root, path2))).isFile();
42989
+ present = (await lstat2(join36(root, path2))).isFile();
42272
42990
  } catch {
42273
42991
  present = false;
42274
42992
  }
@@ -42371,10 +43089,10 @@ var init_worktree_snapshot = __esm({
42371
43089
  });
42372
43090
 
42373
43091
  // ../../packages/tacho/src/collector/git-lane.ts
42374
- import { join as join36 } from "node:path";
43092
+ import { join as join37 } from "node:path";
42375
43093
  function copiesDirOf(root, session) {
42376
43094
  const uuid = session.recorder.sessionUuid;
42377
- return /^[0-9a-f-]{36}$/i.test(uuid) ? join36(root, uuid) : void 0;
43095
+ return /^[0-9a-f-]{36}$/i.test(uuid) ? join37(root, uuid) : void 0;
42378
43096
  }
42379
43097
  function holdsBaseline(session) {
42380
43098
  return session.baselineCommit !== void 0 || Object.keys(session.baselines ?? {}).length > 0;
@@ -45742,7 +46460,7 @@ var init_hook_queues = __esm({
45742
46460
 
45743
46461
  // ../../packages/tacho/src/collector/memory-capture/memory-reader.ts
45744
46462
  import { createRequire as createRequire2 } from "node:module";
45745
- import { isAbsolute as isAbsolute8, join as join37, sep as sep6 } from "node:path";
46463
+ import { isAbsolute as isAbsolute8, join as join38, sep as sep6 } from "node:path";
45746
46464
  function claudeCodeLocation(projectsDir, memoryDir) {
45747
46465
  return {
45748
46466
  harness: "claude-code",
@@ -45754,13 +46472,13 @@ function claudeCodeLocation(projectsDir, memoryDir) {
45754
46472
  }
45755
46473
  function claudeCodeMemoryLocations(configDir, projectDirs = []) {
45756
46474
  const locations = [
45757
- claudeCodeLocation(() => join37(configDir, "projects"), "memory"),
45758
- claudeCodeLocation(() => join37(configDir, "agent-memory"), "")
46475
+ claudeCodeLocation(() => join38(configDir, "projects"), "memory"),
46476
+ claudeCodeLocation(() => join38(configDir, "agent-memory"), "")
45759
46477
  ];
45760
46478
  for (const dir of projectDirs.slice(0, MEMORY_PROJECT_DIRS_MAX))
45761
46479
  locations.push(
45762
- claudeCodeLocation(() => join37(dir, ".claude", "agent-memory"), ""),
45763
- claudeCodeLocation(() => join37(dir, ".claude", "agent-memory-local"), "")
46480
+ claudeCodeLocation(() => join38(dir, ".claude", "agent-memory"), ""),
46481
+ claudeCodeLocation(() => join38(dir, ".claude", "agent-memory-local"), "")
45764
46482
  );
45765
46483
  return locations;
45766
46484
  }
@@ -45945,13 +46663,13 @@ function createMemoryReader(deps) {
45945
46663
  const projects = await list2(top);
45946
46664
  let complete = projects.complete;
45947
46665
  for (const project2 of projects.names) {
45948
- const dir = location.memoryDir === "" ? join37(top, project2) : join37(top, project2, location.memoryDir);
46666
+ const dir = location.memoryDir === "" ? join38(top, project2) : join38(top, project2, location.memoryDir);
45949
46667
  const files2 = await list2(dir);
45950
46668
  if (!files2.complete) complete = false;
45951
46669
  for (const name of files2.names) {
45952
46670
  if (!name.endsWith(location.extension)) continue;
45953
46671
  if (location.skip.includes(name)) continue;
45954
- const path2 = join37(dir, name);
46672
+ const path2 = join38(dir, name);
45955
46673
  const file = await readAt2(location.harness, path2);
45956
46674
  if (file.kind === "absent" || file.kind === "empty") continue;
45957
46675
  paths.push(path2);
@@ -46037,8 +46755,8 @@ var init_memory_reader = __esm({
46037
46755
  MEMORY_TYPE_PATTERN = /^[a-z][a-z0-9_-]{0,31}$/;
46038
46756
  MEMORY_PROJECT_DIRS_MAX = 200;
46039
46757
  HARNESS_MEMORY_LOCATIONS = [
46040
- claudeCodeLocation((home) => join37(home, ".claude", "projects"), "memory"),
46041
- claudeCodeLocation((home) => join37(home, ".claude", "agent-memory"), "")
46758
+ claudeCodeLocation((home) => join38(home, ".claude", "projects"), "memory"),
46759
+ claudeCodeLocation((home) => join38(home, ".claude", "agent-memory"), "")
46042
46760
  ];
46043
46761
  FRONTMATTER = /^---[ \t]*\r?\n(?:([\s\S]*?)\r?\n)?---[ \t]*(?:\r?\n|$)/;
46044
46762
  FRONTMATTER_LINE = /^([ \t]*)([A-Za-z_][\w-]*)[ \t]*:[ \t]*(.*)$/;
@@ -46530,7 +47248,7 @@ var init_memory_recall = __esm({
46530
47248
  });
46531
47249
 
46532
47250
  // ../../packages/tacho/src/collector/memory-capture/memory-uses.ts
46533
- import { basename as basename6, dirname as dirname21, isAbsolute as isAbsolute9, join as join38, resolve as resolve14 } from "node:path";
47251
+ import { basename as basename6, dirname as dirname21, isAbsolute as isAbsolute9, join as join39, resolve as resolve14 } from "node:path";
46534
47252
  function memoryFileOf(path2, locations, home) {
46535
47253
  if (!isAbsolute9(path2)) return void 0;
46536
47254
  const file = resolve14(path2);
@@ -46548,7 +47266,7 @@ function memoryFileOf(path2, locations, home) {
46548
47266
  return void 0;
46549
47267
  }
46550
47268
  function pathOf(word, cwd, home) {
46551
- const expanded = /^(?:~|\$HOME|\$\{HOME\})\//.test(word) ? join38(home, word.slice(word.indexOf("/") + 1)) : word;
47269
+ const expanded = /^(?:~|\$HOME|\$\{HOME\})\//.test(word) ? join39(home, word.slice(word.indexOf("/") + 1)) : word;
46552
47270
  if (isAbsolute9(expanded)) return expanded;
46553
47271
  if (cwd !== void 0 && isAbsolute9(cwd)) return resolve14(cwd, expanded);
46554
47272
  return void 0;
@@ -46804,7 +47522,7 @@ ${use.path}`;
46804
47522
  });
46805
47523
 
46806
47524
  // ../../packages/tacho/src/collector/memory-capture/stella-store.ts
46807
- import { dirname as dirname22, isAbsolute as isAbsolute10, join as join39, resolve as resolve15 } from "node:path";
47525
+ import { dirname as dirname22, isAbsolute as isAbsolute10, join as join40, resolve as resolve15 } from "node:path";
46808
47526
  function queryStellaStore(path2, afterSeq, limit) {
46809
47527
  const db = new (nodeSqlite()).DatabaseSync(path2, { readOnly: true });
46810
47528
  try {
@@ -46894,7 +47612,7 @@ async function stellaStoreOf(dir, exists) {
46894
47612
  if (!isAbsolute10(dir)) return void 0;
46895
47613
  let at2 = resolve15(dir);
46896
47614
  for (let depth = 0; depth < WORKSPACE_SEARCH_DEPTH; depth += 1) {
46897
- const candidate = join39(at2, STELLA_CONTEXT_DB);
47615
+ const candidate = join40(at2, STELLA_CONTEXT_DB);
46898
47616
  if (await exists(candidate)) return candidate;
46899
47617
  const up = dirname22(at2);
46900
47618
  if (up === at2) return void 0;
@@ -46907,7 +47625,7 @@ var init_stella_store = __esm({
46907
47625
  "../../packages/tacho/src/collector/memory-capture/stella-store.ts"() {
46908
47626
  "use strict";
46909
47627
  init_memory_reader();
46910
- STELLA_CONTEXT_DB = join39(".stella", "private", "context.db");
47628
+ STELLA_CONTEXT_DB = join40(".stella", "private", "context.db");
46911
47629
  STELLA_MEMORIES_VIEW = "export_memories_v1";
46912
47630
  STELLA_USES_VIEW = "export_memory_uses_v1";
46913
47631
  STELLA_USES_PER_READ = 5e3;
@@ -47569,7 +48287,7 @@ var init_cloud_link = __esm({
47569
48287
 
47570
48288
  // ../../packages/tacho/src/collector/local-servers/digest.ts
47571
48289
  import { createHash as createHash10 } from "node:crypto";
47572
- import { join as join40 } from "node:path";
48290
+ import { join as join41 } from "node:path";
47573
48291
  function rememberBounded(map, key, value) {
47574
48292
  if (!map.has(key) && map.size >= MAX_REMEMBERED_DIGESTS) {
47575
48293
  const oldest = map.keys().next();
@@ -47606,7 +48324,7 @@ function npmNameSegment(name) {
47606
48324
  return name.startsWith("@") ? `@${encodeURIComponent(name.slice(1))}` : encodeURIComponent(name);
47607
48325
  }
47608
48326
  async function whichOnPath(command2, pathValue, search) {
47609
- const candidates = command2.includes("/") || command2.includes("\\") ? [command2] : (pathValue ?? "").split(search.delimiter).filter((dir) => dir.length > 0).map((dir) => join40(dir, command2));
48327
+ const candidates = command2.includes("/") || command2.includes("\\") ? [command2] : (pathValue ?? "").split(search.delimiter).filter((dir) => dir.length > 0).map((dir) => join41(dir, command2));
47610
48328
  for (const candidate of candidates) {
47611
48329
  for (const extension of search.extensions) {
47612
48330
  if (await search.isExecutable(candidate + extension))
@@ -48609,7 +49327,7 @@ var init_local_servers = __esm({
48609
49327
 
48610
49328
  // ../../packages/tacho/src/collector/local-servers/machine.ts
48611
49329
  import { spawn as nodeSpawn } from "node:child_process";
48612
- import { access, constants as constants3, readFile, realpath, stat } from "node:fs/promises";
49330
+ import { access, constants as constants4, readFile, realpath, stat } from "node:fs/promises";
48613
49331
  function machineParked(host) {
48614
49332
  if (host.revoked_at !== null || host.host_status === "revoked")
48615
49333
  return "the enrollment is revoked";
@@ -48634,7 +49352,7 @@ function createMachineLink(host, fetch2, env) {
48634
49352
  async function isExecutable(path2) {
48635
49353
  try {
48636
49354
  if (!(await stat(path2)).isFile()) return false;
48637
- await access(path2, constants3.X_OK);
49355
+ await access(path2, constants4.X_OK);
48638
49356
  return true;
48639
49357
  } catch {
48640
49358
  return false;
@@ -48902,9 +49620,9 @@ import {
48902
49620
  writeFile
48903
49621
  } from "node:fs/promises";
48904
49622
  import { homedir as homedir5 } from "node:os";
48905
- import { dirname as dirname23, join as join41 } from "node:path";
49623
+ import { dirname as dirname23, join as join42 } from "node:path";
48906
49624
  function stagingFolder(root, name) {
48907
- return join41(root, `.${name}${STAGING_SUFFIX}`);
49625
+ return join42(root, `.${name}${STAGING_SUFFIX}`);
48908
49626
  }
48909
49627
  function isStagingName(name) {
48910
49628
  return name.startsWith(".") && name.endsWith(STAGING_SUFFIX);
@@ -48947,17 +49665,17 @@ function envDir(env, key) {
48947
49665
  function skillsRoot(harness, env = process.env, home = homedir5()) {
48948
49666
  switch (harness) {
48949
49667
  case "claude-code":
48950
- return join41(
48951
- envDir(env, "CLAUDE_CONFIG_DIR") ?? join41(home, ".claude"),
49668
+ return join42(
49669
+ envDir(env, "CLAUDE_CONFIG_DIR") ?? join42(home, ".claude"),
48952
49670
  "skills"
48953
49671
  );
48954
49672
  case "codex": {
48955
49673
  const codexHome = envDir(env, "CODEX_HOME");
48956
- return codexHome === null ? join41(home, ".agents", "skills") : join41(codexHome, "skills");
49674
+ return codexHome === null ? join42(home, ".agents", "skills") : join42(codexHome, "skills");
48957
49675
  }
48958
49676
  case "stella":
48959
- return join41(
48960
- envDir(env, "STELLA_HOME") ?? join41(home, ".stella"),
49677
+ return join42(
49678
+ envDir(env, "STELLA_HOME") ?? join42(home, ".stella"),
48961
49679
  "skills"
48962
49680
  );
48963
49681
  case "cursor":
@@ -49018,7 +49736,7 @@ async function readMarker(folder) {
49018
49736
  if (!entries2.includes(SESSION_MARKER)) return { state: "foreign" };
49019
49737
  try {
49020
49738
  const parsed2 = JSON.parse(
49021
- await readFile2(join41(folder, SESSION_MARKER), "utf8")
49739
+ await readFile2(join42(folder, SESSION_MARKER), "utf8")
49022
49740
  );
49023
49741
  return isMarker(parsed2) ? { state: "ours", marker: parsed2 } : { state: "foreign" };
49024
49742
  } catch {
@@ -49035,22 +49753,22 @@ function liveSessions(marker, now) {
49035
49753
  return live;
49036
49754
  }
49037
49755
  async function writeMarker(folder, marker) {
49038
- const temp = join41(folder, MARKER_TEMP);
49756
+ const temp = join42(folder, MARKER_TEMP);
49039
49757
  await writeFile(temp, `${JSON.stringify(marker, null, 2)}
49040
49758
  `);
49041
- await rename2(temp, join41(folder, SESSION_MARKER));
49759
+ await rename2(temp, join42(folder, SESSION_MARKER));
49042
49760
  }
49043
49761
  async function writeSkill(root, skill, marker) {
49044
- const folder = join41(root, skill.name);
49762
+ const folder = join42(root, skill.name);
49045
49763
  const staging = stagingFolder(root, skill.name);
49046
49764
  await rm2(folder, { recursive: true, force: true });
49047
49765
  await rm2(staging, { recursive: true, force: true });
49048
49766
  await mkdir2(staging);
49049
49767
  await writeMarker(staging, { digest: UNFINISHED_DIGEST, sessions: {} });
49050
49768
  await rename2(staging, folder);
49051
- await writeFile(join41(folder, "SKILL.md"), skillMarkdown(skill));
49769
+ await writeFile(join42(folder, "SKILL.md"), skillMarkdown(skill));
49052
49770
  for (const file of skill.files) {
49053
- const target2 = join41(folder, file.path);
49771
+ const target2 = join42(folder, file.path);
49054
49772
  await mkdir2(dirname23(target2), { recursive: true });
49055
49773
  await writeFile(target2, file.content);
49056
49774
  }
@@ -49079,7 +49797,7 @@ async function placeSkills(root, sessionId, skills, now = /* @__PURE__ */ new Da
49079
49797
  result2.warnings.push(refusal);
49080
49798
  continue;
49081
49799
  }
49082
- const folder = join41(root, skill.name);
49800
+ const folder = join42(root, skill.name);
49083
49801
  if (taken.has(skill.name)) {
49084
49802
  result2.skipped.push(skill.name);
49085
49803
  result2.warnings.push(
@@ -49144,7 +49862,7 @@ async function removeSkills(root, sessionId, now = /* @__PURE__ */ new Date()) {
49144
49862
  throw error;
49145
49863
  }
49146
49864
  for (const name of names2.sort(compareText)) {
49147
- const folder = join41(root, name);
49865
+ const folder = join42(root, name);
49148
49866
  if (isStagingName(name)) {
49149
49867
  await rm2(folder, { recursive: true, force: true });
49150
49868
  continue;
@@ -50066,13 +50784,27 @@ function connectionTokens(raw) {
50066
50784
  }
50067
50785
  return named;
50068
50786
  }
50787
+ function withOAuthBeta(value) {
50788
+ const flags = (value ?? "").split(",").map((flag2) => flag2.trim()).filter((flag2) => flag2.length > 0);
50789
+ if (!flags.includes(ANTHROPIC_OAUTH_BETA)) flags.push(ANTHROPIC_OAUTH_BETA);
50790
+ return flags.join(",");
50791
+ }
50069
50792
  function upstreamRequestHeaders(raw, host, bodyLength, dropContentEncoding, attach) {
50070
50793
  const named = connectionTokens(raw);
50071
50794
  const out = ["Host", host];
50795
+ const oauth = attach?.kind === "oauth";
50796
+ let beta;
50072
50797
  for (let i2 = 0; i2 + 1 < raw.length; i2 += 2) {
50073
50798
  const name = raw[i2];
50074
50799
  const lower = name.toLowerCase();
50075
50800
  if (HOP_BY_HOP.has(lower) || named.has(lower)) continue;
50801
+ if (attach?.kind === "chatgpt" && attach.accountId !== void 0 && lower === CHATGPT_ACCOUNT_HEADER)
50802
+ continue;
50803
+ if (oauth && lower === "anthropic-beta") {
50804
+ const value = raw[i2 + 1];
50805
+ beta = beta === void 0 ? value : `${beta},${value}`;
50806
+ continue;
50807
+ }
50076
50808
  if (lower === "host" || lower === "content-length") continue;
50077
50809
  if (lower === "accept-encoding" || lower === "expect") continue;
50078
50810
  if (lower === TACHO_MODEL_SESSION_HEADER) continue;
@@ -50084,6 +50816,9 @@ function upstreamRequestHeaders(raw, host, bodyLength, dropContentEncoding, atta
50084
50816
  if (attach !== void 0) {
50085
50817
  if (attach.kind === "api_key") out.push("X-Api-Key", attach.secret);
50086
50818
  else out.push("Authorization", `Bearer ${attach.secret}`);
50819
+ if (oauth) out.push("anthropic-beta", withOAuthBeta(beta));
50820
+ if (attach.kind === "chatgpt" && attach.accountId !== void 0)
50821
+ out.push("ChatGPT-Account-ID", attach.accountId);
50087
50822
  }
50088
50823
  out.push("Accept-Encoding", "identity");
50089
50824
  if (bodyLength > 0 || raw.some((h, i2) => i2 % 2 === 0 && /^content-length$/i.test(h)))
@@ -50117,7 +50852,7 @@ function providerError(provider, status2, code, message) {
50117
50852
  };
50118
50853
  return { status: status2, body: JSON.stringify(body2) };
50119
50854
  }
50120
- var DEFAULT_MODEL_UPSTREAMS, MODEL_PROXY_ROUTES, HOP_BY_HOP, CREDENTIAL_HEADERS;
50855
+ var DEFAULT_MODEL_UPSTREAMS, MODEL_PROXY_ROUTES, HOP_BY_HOP, CREDENTIAL_HEADERS, CHATGPT_ACCOUNT_HEADER, ANTHROPIC_OAUTH_BETA;
50121
50856
  var init_model_routes = __esm({
50122
50857
  "../../packages/tacho/src/collector/model-routes.ts"() {
50123
50858
  "use strict";
@@ -50146,6 +50881,8 @@ var init_model_routes = __esm({
50146
50881
  "upgrade"
50147
50882
  ]);
50148
50883
  CREDENTIAL_HEADERS = ["authorization", "x-api-key"];
50884
+ CHATGPT_ACCOUNT_HEADER = "chatgpt-account-id";
50885
+ ANTHROPIC_OAUTH_BETA = "oauth-2025-04-20";
50149
50886
  }
50150
50887
  });
50151
50888
 
@@ -50877,7 +51614,7 @@ function createModelProxy(deps) {
50877
51614
  function resolveCredential(req, route) {
50878
51615
  const broker = deps.credentials;
50879
51616
  const presented = presentedCredential(req);
50880
- const brokered = broker !== void 0 && route.upstream !== "chatgpt" && route.harness !== "stella" && broker.brokered(route.provider);
51617
+ const brokered = broker !== void 0 && route.harness !== "stella" && broker.brokered(route.provider) && route.upstream === "chatgpt" === (broker.kind?.(route.provider) === "chatgpt");
50881
51618
  if (broker === void 0 || !brokered) {
50882
51619
  if (presented !== void 0 && looksLikeRunToken(presented.value)) {
50883
51620
  const claims = peekRunTokenClaims(presented.value);
@@ -50932,6 +51669,27 @@ function createModelProxy(deps) {
50932
51669
  }
50933
51670
  };
50934
51671
  }
51672
+ if (held2.kind === "chatgpt") {
51673
+ const login = decodeChatGptLogin(held2.secret);
51674
+ if (login === void 0)
51675
+ return {
51676
+ basis: TACHO_CREDENTIAL_GATEWAY_BROKERED,
51677
+ claims: verdict.claims,
51678
+ refusal: {
51679
+ code: "credential_unavailable",
51680
+ message: CREDENTIAL_MESSAGES.credential_unavailable
51681
+ }
51682
+ };
51683
+ return {
51684
+ basis: TACHO_CREDENTIAL_GATEWAY_BROKERED,
51685
+ claims: verdict.claims,
51686
+ attach: {
51687
+ kind: "chatgpt",
51688
+ secret: login.access_token,
51689
+ ...login.account_id !== void 0 ? { accountId: login.account_id } : {}
51690
+ }
51691
+ };
51692
+ }
50935
51693
  return {
50936
51694
  basis: TACHO_CREDENTIAL_GATEWAY_BROKERED,
50937
51695
  claims: verdict.claims,
@@ -51622,6 +52380,15 @@ function createModelProxy(deps) {
51622
52380
  if (result2.path !== path2 && result2.path.startsWith("/"))
51623
52381
  path2 = result2.path;
51624
52382
  }
52383
+ if (credential.attach?.kind === "chatgpt") {
52384
+ const sent2 = injected ? injectedJson : json2();
52385
+ if (sent2 !== void 0 && sent2["store"] !== false) {
52386
+ const unstored = { ...sent2, store: false };
52387
+ if (injected) injectedJson = unstored;
52388
+ body2 = Buffer.from(JSON.stringify(unstored), "utf8");
52389
+ dropContentEncoding = true;
52390
+ }
52391
+ }
51625
52392
  const requestModel = askedModel;
51626
52393
  const requestEffort = requestEffortOf(injected ? injectedJson : json2());
51627
52394
  const sent = injected ? body2 : readable();
@@ -52186,6 +52953,7 @@ var init_model_proxy = __esm({
52186
52953
  init_frame_body();
52187
52954
  init_replay_grade();
52188
52955
  init_bundle();
52956
+ init_model_credential();
52189
52957
  init_run_token();
52190
52958
  init_wire();
52191
52959
  init_cache_keep_alive();
@@ -52921,12 +53689,12 @@ var init_server = __esm({
52921
53689
 
52922
53690
  // ../../packages/tacho/src/collector/refused.ts
52923
53691
  import { readdirSync as readdirSync12, readFileSync as readFileSync19, statSync as statSync12 } from "node:fs";
52924
- import { join as join42 } from "node:path";
53692
+ import { join as join43 } from "node:path";
52925
53693
  function refusalRetryable(refusal) {
52926
53694
  return refusal === "malformed" || refusal === "parked";
52927
53695
  }
52928
53696
  function refusedRecordPath(dir, event) {
52929
- return join42(dir, `${event.session_uuid}-${String(event.seq).padStart(8, "0")}.json`);
53697
+ return join43(dir, `${event.session_uuid}-${String(event.seq).padStart(8, "0")}.json`);
52930
53698
  }
52931
53699
  function newRefusedRecord(event, reason3, refusal, at2, body2) {
52932
53700
  const retryable = refusalRetryable(refusal);
@@ -53002,7 +53770,7 @@ function scanRefused(dir, now, limit = MAX_REFUSED_RETRIES_PER_PASS) {
53002
53770
  };
53003
53771
  const due = [];
53004
53772
  for (const name of names2) {
53005
- const entry2 = readRefusedEntry(join42(dir, name));
53773
+ const entry2 = readRefusedEntry(join43(dir, name));
53006
53774
  if (entry2 === void 0) continue;
53007
53775
  summary.total += 1;
53008
53776
  if (summary.lastRefusedAt === void 0 || entry2.refusedAt > summary.lastRefusedAt)
@@ -53039,7 +53807,7 @@ var init_refused = __esm({
53039
53807
 
53040
53808
  // ../../packages/tacho/src/collector/spool.ts
53041
53809
  import { existsSync as existsSync22, readFileSync as readFileSync20, unlinkSync as unlinkSync12 } from "node:fs";
53042
- import { join as join43 } from "node:path";
53810
+ import { join as join44 } from "node:path";
53043
53811
  function sessionOwnedElsewhere(error) {
53044
53812
  return error.status === 403 && error.body.includes(SESSION_OWNED_ELSEWHERE);
53045
53813
  }
@@ -53272,7 +54040,7 @@ var init_spool = __esm({
53272
54040
  }
53273
54041
  /** Add a body to a quarantine record that was written without one. */
53274
54042
  stashBodyBeside(event, body2) {
53275
- const path2 = join43(
54043
+ const path2 = join44(
53276
54044
  this.options.quarantineDir,
53277
54045
  `${event.session_uuid}-${String(event.seq).padStart(8, "0")}.json`
53278
54046
  );
@@ -53928,7 +54696,7 @@ import {
53928
54696
  } from "node:fs";
53929
54697
  import { readdir as readdir3, readFile as readFile3, stat as stat2 } from "node:fs/promises";
53930
54698
  import { homedir as homedir7, hostname as osHostname2 } from "node:os";
53931
- import { dirname as dirname24, join as join44 } from "node:path";
54699
+ import { dirname as dirname24, join as join45 } from "node:path";
53932
54700
  import { spawnSync as spawnSync7 } from "node:child_process";
53933
54701
  function cloudGatewayUpstreams(origin = CLOUD_GATEWAY_ORIGIN) {
53934
54702
  const base2 = new URL(origin).origin;
@@ -54672,7 +55440,7 @@ async function initializeDaemon(options, server, port, ready) {
54672
55440
  controlReachable: lastControlAt !== void 0 && now() - lastControlAt < 2 * timers.bundleRefreshMs
54673
55441
  };
54674
55442
  }
54675
- const bodyPurgeOwedPath = join44(paths.wal, "body-purge-owed");
55443
+ const bodyPurgeOwedPath = join45(paths.wal, "body-purge-owed");
54676
55444
  function markBodyPurgeOwed(retention, dropped) {
54677
55445
  try {
54678
55446
  ensureDir(paths.wal);
@@ -54949,7 +55717,7 @@ async function initializeDaemon(options, server, port, ready) {
54949
55717
  }
54950
55718
  void workOrderAutostart.reconcile();
54951
55719
  }
54952
- const lastIngestFile = join44(paths.dir, "last-ingest.json");
55720
+ const lastIngestFile = join45(paths.dir, "last-ingest.json");
54953
55721
  const shipper = new Shipper({
54954
55722
  wal,
54955
55723
  client,
@@ -55471,7 +56239,7 @@ async function initializeDaemon(options, server, port, ready) {
55471
56239
  async function readSpoolFile(name) {
55472
56240
  try {
55473
56241
  const file = parseSpoolFile(
55474
- await readFile3(join44(paths.spool, name), "utf8")
56242
+ await readFile3(join45(paths.spool, name), "utf8")
55475
56243
  );
55476
56244
  spoolFacts.set(name, spoolFactsOf(file));
55477
56245
  return file;
@@ -55660,7 +56428,7 @@ async function initializeDaemon(options, server, port, ready) {
55660
56428
  function setAsideConflictingTerminal(uuid, pending, conflict) {
55661
56429
  const name = `${uuid}-terminal-conflict-${String(conflict.seq).padStart(8, "0")}.json`;
55662
56430
  writeSensitiveFileAtomic(
55663
- join44(paths.quarantine, name),
56431
+ join45(paths.quarantine, name),
55664
56432
  JSON.stringify(
55665
56433
  {
55666
56434
  reason: conflict.message,
@@ -55740,8 +56508,8 @@ async function initializeDaemon(options, server, port, ready) {
55740
56508
  function moveToFailedSpool(path2, name, reason3) {
55741
56509
  log(`spool file ${name} moved to spool/failed/: ${reason3}`);
55742
56510
  try {
55743
- ensureDir(join44(paths.spool, "failed"));
55744
- renameSync4(path2, join44(paths.spool, "failed", name));
56511
+ ensureDir(join45(paths.spool, "failed"));
56512
+ renameSync4(path2, join45(paths.spool, "failed", name));
55745
56513
  } catch (error) {
55746
56514
  log(
55747
56515
  `spool file ${name} could not be moved to spool/failed/: ${error instanceof Error ? error.message : String(error)}`
@@ -55794,7 +56562,7 @@ async function initializeDaemon(options, server, port, ready) {
55794
56562
  continue;
55795
56563
  }
55796
56564
  reads += 1;
55797
- const path2 = join44(paths.spool, name);
56565
+ const path2 = join45(paths.spool, name);
55798
56566
  let file;
55799
56567
  try {
55800
56568
  file = await readSpoolFile(name);
@@ -56183,6 +56951,13 @@ async function initializeDaemon(options, server, port, ready) {
56183
56951
  ...options.pauseHold,
56184
56952
  credentials: {
56185
56953
  brokered: (provider) => inCustody(provider),
56954
+ kind: (provider) => {
56955
+ try {
56956
+ return credentialStore.status().find((entry2) => entry2.provider === provider)?.kind;
56957
+ } catch {
56958
+ return void 0;
56959
+ }
56960
+ },
56186
56961
  custody: (provider) => {
56187
56962
  try {
56188
56963
  return credentialStore.read(provider);
@@ -56247,6 +57022,13 @@ async function initializeDaemon(options, server, port, ready) {
56247
57022
  record,
56248
57023
  model: modelProxy,
56249
57024
  modelPort: () => modelProxyListener.port(),
57025
+ chatgptLogin: () => {
57026
+ try {
57027
+ return credentialStore.status().some((c) => c.provider === "openai" && c.kind === "chatgpt");
57028
+ } catch {
57029
+ return false;
57030
+ }
57031
+ },
56250
57032
  issueCredential: (harness) => issueRunToken(
56251
57033
  { harness },
56252
57034
  {
@@ -56621,7 +57403,7 @@ async function initializeDaemon(options, server, port, ready) {
56621
57403
  let removed = 0;
56622
57404
  for (const name of readdirSync13(paths.quarantine)) {
56623
57405
  if (!name.endsWith(".json")) continue;
56624
- const file = join44(paths.quarantine, name);
57406
+ const file = join45(paths.quarantine, name);
56625
57407
  try {
56626
57408
  const refusedAt = readRefusedEntry(file)?.refusedAt ?? statSync13(file).mtimeMs;
56627
57409
  if (at2 - refusedAt < retainMs) continue;
@@ -56877,8 +57659,29 @@ async function initializeDaemon(options, server, port, ready) {
56877
57659
  });
56878
57660
  }
56879
57661
  let lastStaticRenewalAt = 0;
57662
+ let lastLoginRefreshAt = 0;
56880
57663
  async function renewStaticTokens() {
56881
57664
  if (!host.harnesses.includes("codex")) return;
57665
+ if (now() - lastLoginRefreshAt >= CHATGPT_LOGIN_CHECK_MS) {
57666
+ lastLoginRefreshAt = now();
57667
+ try {
57668
+ const refreshed = await refreshChatGptCustody(
57669
+ credentialStore,
57670
+ options.fetch ?? fetch,
57671
+ now()
57672
+ );
57673
+ if (refreshed === "refreshed")
57674
+ log("refreshed the ChatGPT login in custody");
57675
+ else if (typeof refreshed === "object")
57676
+ log(`ChatGPT login refresh: ${refreshed.failed}`);
57677
+ if (refreshed !== "none")
57678
+ restateCodexLastRefresh(options.home ?? homedir7(), now());
57679
+ } catch (error) {
57680
+ log(
57681
+ `ChatGPT login refresh: ${error instanceof Error ? error.message : String(error)}`
57682
+ );
57683
+ }
57684
+ }
56882
57685
  if (now() - lastStaticRenewalAt < STATIC_TOKEN_RENEWAL_CHECK_MS) return;
56883
57686
  lastStaticRenewalAt = now();
56884
57687
  if (host.host_status !== "active" || !inCustody("openai")) return;
@@ -56951,7 +57754,7 @@ async function initializeDaemon(options, server, port, ready) {
56951
57754
  let memoryScan;
56952
57755
  if (options.listen ?? true) {
56953
57756
  const codexMemories = createCodexMemoryStore({
56954
- path: join44(dirname24(paths.codexHooks), CODEX_MEMORY_STORE_FILE),
57757
+ path: join45(dirname24(paths.codexHooks), CODEX_MEMORY_STORE_FILE),
56955
57758
  stat: (path2) => stat2(path2),
56956
57759
  log
56957
57760
  });
@@ -57096,7 +57899,7 @@ async function initializeDaemon(options, server, port, ready) {
57096
57899
  }
57097
57900
  };
57098
57901
  }
57099
- var DEFAULT_TIMERS, STATIC_TOKEN_RENEWAL_CHECK_MS, MEMORY_SCAN_MS, CLOUD_GATEWAY_ORIGIN, CLOUD_GATEWAY_BASE_PATH, QUEUED_PROMPT_CLASS, RECORDER_EVENTS_KEPT, owedBodyPurgeSchema, objectSchema, spoolFileSchema, otlpResourceListSchema, otlpPayloadSchema, defaultExecAsync, STOPPING, STOPPED_EXEC, STATE_WRITE_DEFER_MS;
57902
+ var DEFAULT_TIMERS, STATIC_TOKEN_RENEWAL_CHECK_MS, CHATGPT_LOGIN_CHECK_MS, MEMORY_SCAN_MS, CLOUD_GATEWAY_ORIGIN, CLOUD_GATEWAY_BASE_PATH, QUEUED_PROMPT_CLASS, RECORDER_EVENTS_KEPT, owedBodyPurgeSchema, objectSchema, spoolFileSchema, otlpResourceListSchema, otlpPayloadSchema, defaultExecAsync, STOPPING, STOPPED_EXEC, STATE_WRITE_DEFER_MS;
57100
57903
  var init_daemon = __esm({
57101
57904
  "../../packages/tacho/src/collector/daemon.ts"() {
57102
57905
  "use strict";
@@ -57118,6 +57921,7 @@ var init_daemon = __esm({
57118
57921
  init_claude_code_mcp_writer();
57119
57922
  init_model_base_url();
57120
57923
  init_model_credential();
57924
+ init_chatgpt_refresh();
57121
57925
  init_run_token();
57122
57926
  init_process_scan();
57123
57927
  init_retention();
@@ -57190,6 +57994,7 @@ var init_daemon = __esm({
57190
57994
  hookBundleWaitMs: 2e3
57191
57995
  };
57192
57996
  STATIC_TOKEN_RENEWAL_CHECK_MS = 60 * 6e4;
57997
+ CHATGPT_LOGIN_CHECK_MS = 10 * 6e4;
57193
57998
  MEMORY_SCAN_MS = 5 * 6e4;
57194
57999
  CLOUD_GATEWAY_ORIGIN = "https://api.oxagen.sh";
57195
58000
  CLOUD_GATEWAY_BASE_PATH = "/v1/gateway";
@@ -57454,7 +58259,7 @@ var init_run2 = __esm({
57454
58259
  // ../../packages/tacho/src/arp/bundle.ts
57455
58260
  import {
57456
58261
  closeSync as closeSync8,
57457
- constants as constants4,
58262
+ constants as constants5,
57458
58263
  fstatSync as fstatSync2,
57459
58264
  lstatSync as lstatSync8,
57460
58265
  mkdirSync as mkdirSync6,
@@ -57463,7 +58268,7 @@ import {
57463
58268
  realpathSync as realpathSync5,
57464
58269
  writeFileSync as writeFileSync4
57465
58270
  } from "node:fs";
57466
- import { dirname as dirname25, join as join45, resolve as resolve17 } from "node:path";
58271
+ import { dirname as dirname25, join as join46, resolve as resolve17 } from "node:path";
57467
58272
  function bundlePath(root, relative11, create2 = false) {
57468
58273
  const absolute = resolve17(root);
57469
58274
  if (create2) mkdirSync6(absolute, { recursive: true, mode: 448 });
@@ -57474,7 +58279,7 @@ function bundlePath(root, relative11, create2 = false) {
57474
58279
  let current = base2;
57475
58280
  const parts = relative11.split("/");
57476
58281
  for (let i2 = 0; i2 < parts.length; i2++) {
57477
- current = join45(current, parts[i2]);
58282
+ current = join46(current, parts[i2]);
57478
58283
  try {
57479
58284
  const stat7 = lstatSync8(current);
57480
58285
  if (stat7.isSymbolicLink() || i2 < parts.length - 1 && !stat7.isDirectory()) {
@@ -57495,7 +58300,7 @@ function bundlePath(root, relative11, create2 = false) {
57495
58300
  }
57496
58301
  function readBounded(root, relative11, limit = ARP_MAX_BLOB_BYTES) {
57497
58302
  const path2 = bundlePath(root, relative11);
57498
- const fd2 = openSync8(path2, constants4.O_RDONLY | constants4.O_NOFOLLOW);
58303
+ const fd2 = openSync8(path2, constants5.O_RDONLY | constants5.O_NOFOLLOW);
57499
58304
  try {
57500
58305
  const stat7 = fstatSync2(fd2);
57501
58306
  if (!stat7.isFile() || stat7.size > limit)
@@ -57520,7 +58325,7 @@ function writeNew(root, relative11, bytes) {
57520
58325
  const path2 = bundlePath(root, relative11, true);
57521
58326
  const fd2 = openSync8(
57522
58327
  path2,
57523
- constants4.O_WRONLY | constants4.O_CREAT | constants4.O_EXCL | constants4.O_NOFOLLOW,
58328
+ constants5.O_WRONLY | constants5.O_CREAT | constants5.O_EXCL | constants5.O_NOFOLLOW,
57524
58329
  384
57525
58330
  );
57526
58331
  try {
@@ -58425,7 +59230,7 @@ var init_oracles = __esm({
58425
59230
  import { randomUUID as randomUUID4 } from "node:crypto";
58426
59231
  import {
58427
59232
  closeSync as closeSync9,
58428
- constants as constants5,
59233
+ constants as constants6,
58429
59234
  fstatSync as fstatSync3,
58430
59235
  lstatSync as lstatSync9,
58431
59236
  mkdirSync as mkdirSync7,
@@ -58435,7 +59240,7 @@ import {
58435
59240
  rmSync as rmSync8,
58436
59241
  writeFileSync as writeFileSync5
58437
59242
  } from "node:fs";
58438
- import { dirname as dirname26, isAbsolute as isAbsolute11, join as join46, relative as relative5, resolve as resolve18, sep as sep7 } from "node:path";
59243
+ import { dirname as dirname26, isAbsolute as isAbsolute11, join as join47, relative as relative5, resolve as resolve18, sep as sep7 } from "node:path";
58439
59244
  function outsideProfile(path2) {
58440
59245
  return HARNESS_CONFIG_PATH.test(path2) || CREDENTIAL_PATH.test(path2);
58441
59246
  }
@@ -58446,7 +59251,7 @@ function sameJson(bytes, expected) {
58446
59251
  return jcs(JSON.parse(bytes.toString("utf8"))) === jcs(expected);
58447
59252
  }
58448
59253
  function readRegular(label2, path2, limit) {
58449
- const fd2 = openSync9(path2, constants5.O_RDONLY | constants5.O_NOFOLLOW);
59254
+ const fd2 = openSync9(path2, constants6.O_RDONLY | constants6.O_NOFOLLOW);
58450
59255
  try {
58451
59256
  const before = fstatSync3(fd2);
58452
59257
  if (!before.isFile() || before.size > limit)
@@ -58491,7 +59296,7 @@ function within2(root, path2) {
58491
59296
  }
58492
59297
  function newPath(path2) {
58493
59298
  const full = resolve18(path2);
58494
- return join46(
59299
+ return join47(
58495
59300
  realpathSync6(dirname26(full)),
58496
59301
  full.slice(dirname26(full).length + 1)
58497
59302
  );
@@ -58505,7 +59310,7 @@ function sourcePath(root, path2) {
58505
59310
  }
58506
59311
  let current = root;
58507
59312
  for (const part2 of path2.split("/")) {
58508
- current = join46(current, part2);
59313
+ current = join47(current, part2);
58509
59314
  if (lstatSync9(current).isSymbolicLink())
58510
59315
  arpFail(
58511
59316
  `${path2} is a symlink or passes through one. Symlinks require a resource adapter.`
@@ -58772,10 +59577,10 @@ function prepareCheckpoint(options) {
58772
59577
  });
58773
59578
  mkdirSync7(destination, { mode: 448 });
58774
59579
  try {
58775
- const restored = join46(destination, "workspace");
59580
+ const restored = join47(destination, "workspace");
58776
59581
  mkdirSync7(restored, { mode: 448 });
58777
59582
  for (const item of restore) {
58778
- const path2 = join46(restored, item.path);
59583
+ const path2 = join47(restored, item.path);
58779
59584
  if (item.kind === "directory")
58780
59585
  mkdirSync7(path2, { recursive: true, mode: 448 });
58781
59586
  else {
@@ -58786,9 +59591,9 @@ function prepareCheckpoint(options) {
58786
59591
  });
58787
59592
  }
58788
59593
  }
58789
- const promptDir = join46(restored, ".arp");
59594
+ const promptDir = join47(restored, ".arp");
58790
59595
  mkdirSync7(promptDir, { mode: 448 });
58791
- const promptFile = join46(promptDir, "handoff.json");
59596
+ const promptFile = join47(promptDir, "handoff.json");
58792
59597
  const prompt = {
58793
59598
  checkpoint_digest: checkpointDigest,
58794
59599
  task: task.data.request,
@@ -58805,7 +59610,7 @@ function prepareCheckpoint(options) {
58805
59610
  flag: "wx",
58806
59611
  mode: 384
58807
59612
  });
58808
- const reportPath = join46(destination, "report.json");
59613
+ const reportPath = join47(destination, "report.json");
58809
59614
  writeFileSync5(
58810
59615
  reportPath,
58811
59616
  jcs(
@@ -59182,6 +59987,41 @@ function buildTachoProgram(options = {}) {
59182
59987
  deps.err(`${name} credential: ${result2.detail}`);
59183
59988
  process.exitCode = 1;
59184
59989
  });
59990
+ credential.command("login").description(
59991
+ "Sign in with your subscription and put it in the gateway's custody, so gateway and contained runs use it: Claude (`claude setup-token`) or ChatGPT for Codex (`codex login`)"
59992
+ ).option("--harness <name>", "claude-code (default) | codex").option(
59993
+ "--token-stdin",
59994
+ "Claude Code only: read a token `claude setup-token` printed from stdin instead of signing in"
59995
+ ).option("--json", "Print the outcome as JSON").action(
59996
+ async (opts) => {
59997
+ const harness = opts.harness ?? "claude-code";
59998
+ if (harness !== "claude-code" && harness !== "codex") {
59999
+ deps.err(
60000
+ `${name} credential login: --harness takes claude-code or codex; got "${harness}"`
60001
+ );
60002
+ process.exitCode = 1;
60003
+ return;
60004
+ }
60005
+ const outcome = await credentialLogin(
60006
+ {
60007
+ harness,
60008
+ ...opts.tokenStdin === true ? { tokenStdin: true } : {}
60009
+ },
60010
+ deps
60011
+ );
60012
+ if (opts.json === true) deps.out(JSON.stringify(outcome, null, 2));
60013
+ else {
60014
+ for (const entry2 of outcome.harnesses)
60015
+ deps.out(` ${describeHarness(entry2)}`);
60016
+ for (const warning of outcome.warnings)
60017
+ deps.err(`warning: ${warning}`);
60018
+ (outcome.ok ? deps.out : deps.err)(
60019
+ `${outcome.ok ? "" : `${name} credential login: `}${outcome.detail}`
60020
+ );
60021
+ }
60022
+ if (!outcome.ok) process.exitCode = 1;
60023
+ }
60024
+ );
59185
60025
  credential.command("status").description(
59186
60026
  "Which providers the gateway holds, and how each harness gets its credential"
59187
60027
  ).option("--json", "Machine-readable output").action(async (opts) => {
@@ -59446,7 +60286,7 @@ var init_package = __esm({
59446
60286
  "package.json"() {
59447
60287
  package_default = {
59448
60288
  name: "@oxagen/cli",
59449
- version: "2.1.4-957",
60289
+ version: "2.1.4-975",
59450
60290
  description: "Oxagen governance CLI \u2014 spend, lineage, grounding, credentials, and audit (agentic coding lives in the stella CLI)",
59451
60291
  type: "module",
59452
60292
  main: "./dist/index.js",
@@ -59513,10 +60353,10 @@ var init_package = __esm({
59513
60353
 
59514
60354
  // src/lib/atomic-write.ts
59515
60355
  import { writeFileSync as writeFileSync6, renameSync as renameSync5, unlinkSync as unlinkSync15, existsSync as existsSync24 } from "node:fs";
59516
- import { dirname as dirname27, join as join47 } from "node:path";
60356
+ import { dirname as dirname27, join as join48 } from "node:path";
59517
60357
  function atomicWriteFileSync(path2, data, mode) {
59518
60358
  const dir = dirname27(path2);
59519
- const tmp = join47(
60359
+ const tmp = join48(
59520
60360
  dir,
59521
60361
  `.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`
59522
60362
  );
@@ -59541,7 +60381,7 @@ var init_atomic_write = __esm({
59541
60381
 
59542
60382
  // src/lib/config.ts
59543
60383
  import { homedir as homedir8 } from "os";
59544
- import { join as join48 } from "path";
60384
+ import { join as join49 } from "path";
59545
60385
  import { readFileSync as readFileSync24, mkdirSync as mkdirSync8, existsSync as existsSync25, statSync as statSync14 } from "fs";
59546
60386
  function getConfigDir() {
59547
60387
  return CONFIG_DIR;
@@ -59628,8 +60468,8 @@ var CONFIG_DIR, CONFIG_FILE, STRING_FIELDS, TELEMETRY_FIELDS, cached2;
59628
60468
  var init_config = __esm({
59629
60469
  "src/lib/config.ts"() {
59630
60470
  init_atomic_write();
59631
- CONFIG_DIR = join48(homedir8(), ".config", "oxagen");
59632
- CONFIG_FILE = join48(CONFIG_DIR, "config.json");
60471
+ CONFIG_DIR = join49(homedir8(), ".config", "oxagen");
60472
+ CONFIG_FILE = join49(CONFIG_DIR, "config.json");
59633
60473
  STRING_FIELDS = [
59634
60474
  "token",
59635
60475
  "orgSlug",
@@ -59674,16 +60514,16 @@ import {
59674
60514
  writeFile as writeFile2
59675
60515
  } from "node:fs/promises";
59676
60516
  import { homedir as homedir9 } from "node:os";
59677
- import { join as join49 } from "node:path";
60517
+ import { join as join50 } from "node:path";
59678
60518
  function isDebugEnabled() {
59679
60519
  const v = process.env[DEBUG_ENV];
59680
60520
  return v === "1" || v === "true";
59681
60521
  }
59682
60522
  function logsDir() {
59683
- return join49(homedir9(), ".oxagen", "logs");
60523
+ return join50(homedir9(), ".oxagen", "logs");
59684
60524
  }
59685
60525
  function debugLogFile() {
59686
- return join49(logsDir(), "cli.output");
60526
+ return join50(logsDir(), "cli.output");
59687
60527
  }
59688
60528
  function sanitize(value, depth = 0) {
59689
60529
  if (value === null || value === void 0) return value;
@@ -62978,9 +63818,9 @@ var init_git = __esm({
62978
63818
 
62979
63819
  // ../../packages/steering-freshness/src/cache.ts
62980
63820
  import { mkdir as mkdir4, readFile as readFile6, writeFile as writeFile4 } from "node:fs/promises";
62981
- import { dirname as dirname28, join as join50 } from "node:path";
63821
+ import { dirname as dirname28, join as join51 } from "node:path";
62982
63822
  function stampPath(gitCommonDir) {
62983
- return join50(gitCommonDir, "oxagen", "steering-freshness.json");
63823
+ return join51(gitCommonDir, "oxagen", "steering-freshness.json");
62984
63824
  }
62985
63825
  async function readFetchStamp(gitCommonDir, io = defaultIo) {
62986
63826
  try {
@@ -63032,24 +63872,24 @@ var init_cache = __esm({
63032
63872
  // ../../packages/steering-freshness/src/hooks.ts
63033
63873
  import { mkdir as mkdir5, readFile as readFile7, writeFile as writeFile5 } from "node:fs/promises";
63034
63874
  import { homedir as homedir10 } from "node:os";
63035
- import { dirname as dirname29, join as join51 } from "node:path";
63875
+ import { dirname as dirname29, join as join52 } from "node:path";
63036
63876
  function hookCommand(harness) {
63037
63877
  return `oxagen steering gate --harness ${harness}`;
63038
63878
  }
63039
63879
  function hookConfigPath(projectRoot, harness, env = process.env, home = homedir10()) {
63040
63880
  switch (harness) {
63041
63881
  case "claude-code":
63042
- return join51(projectRoot, ".claude", "settings.json");
63882
+ return join52(projectRoot, ".claude", "settings.json");
63043
63883
  case "codex":
63044
- return join51(env["CODEX_HOME"] ?? join51(home, ".codex"), "hooks.json");
63884
+ return join52(env["CODEX_HOME"] ?? join52(home, ".codex"), "hooks.json");
63045
63885
  case "cursor":
63046
- return join51(home, ".cursor", "hooks.json");
63886
+ return join52(home, ".cursor", "hooks.json");
63047
63887
  case "stella":
63048
- return join51(env["STELLA_HOME"] ?? join51(home, ".stella"), "stella.toml");
63888
+ return join52(env["STELLA_HOME"] ?? join52(home, ".stella"), "stella.toml");
63049
63889
  }
63050
63890
  }
63051
63891
  function stellaJsonPath(env, home) {
63052
- return join51(env["STELLA_HOME"] ?? join51(home, ".stella"), "settings.json");
63892
+ return join52(env["STELLA_HOME"] ?? join52(home, ".stella"), "settings.json");
63053
63893
  }
63054
63894
  function isRecord7(v) {
63055
63895
  return v !== null && typeof v === "object" && !Array.isArray(v);
@@ -63709,7 +64549,7 @@ var init_policy = __esm({
63709
64549
  // ../../packages/steering-freshness/src/settings.ts
63710
64550
  import { readFile as readFile8 } from "node:fs/promises";
63711
64551
  import { homedir as homedir11 } from "node:os";
63712
- import { join as join52 } from "node:path";
64552
+ import { join as join53 } from "node:path";
63713
64553
  async function readLayer(scope, path2, read2) {
63714
64554
  let text5;
63715
64555
  try {
@@ -63761,14 +64601,14 @@ function parseLayer(scope, path2, text5) {
63761
64601
  }
63762
64602
  async function loadSteeringSettings({
63763
64603
  projectRoot,
63764
- userSettingsPath = join52(homedir11(), USER_SETTINGS_RELATIVE),
64604
+ userSettingsPath = join53(homedir11(), USER_SETTINGS_RELATIVE),
63765
64605
  read: read2 = readFile8,
63766
64606
  workspacePolicy = null
63767
64607
  }) {
63768
64608
  const targets = [
63769
64609
  ["user", userSettingsPath],
63770
- ["project", join52(projectRoot, PROJECT_DIR_NAME, PROJECT_SETTINGS_FILE)],
63771
- ["local", join52(projectRoot, PROJECT_DIR_NAME, LOCAL_SETTINGS_FILE)]
64610
+ ["project", join53(projectRoot, PROJECT_DIR_NAME, PROJECT_SETTINGS_FILE)],
64611
+ ["local", join53(projectRoot, PROJECT_DIR_NAME, LOCAL_SETTINGS_FILE)]
63772
64612
  ];
63773
64613
  const layers = [];
63774
64614
  const warnings = [];
@@ -63831,7 +64671,7 @@ var init_settings = __esm({
63831
64671
  "use strict";
63832
64672
  init_git();
63833
64673
  init_policy();
63834
- USER_SETTINGS_RELATIVE = join52(
64674
+ USER_SETTINGS_RELATIVE = join53(
63835
64675
  ".config",
63836
64676
  "oxagen",
63837
64677
  "settings.json"
@@ -63844,7 +64684,7 @@ var init_settings = __esm({
63844
64684
 
63845
64685
  // ../../packages/steering-freshness/src/check.ts
63846
64686
  import { lstat as lstat3 } from "node:fs/promises";
63847
- import { isAbsolute as isAbsolute12, join as join53, resolve as resolve19 } from "node:path";
64687
+ import { isAbsolute as isAbsolute12, join as join54, resolve as resolve19 } from "node:path";
63848
64688
  function publishedCommits(platform) {
63849
64689
  if (platform.headCommits && platform.headCommits.length > 0)
63850
64690
  return platform.headCommits;
@@ -64181,7 +65021,7 @@ async function absentFromDisk(root, paths) {
64181
65021
  const flags = await Promise.all(
64182
65022
  paths.map(async (path2) => {
64183
65023
  try {
64184
- await lstat3(join53(root, path2));
65024
+ await lstat3(join54(root, path2));
64185
65025
  return false;
64186
65026
  } catch {
64187
65027
  return true;
@@ -64240,7 +65080,7 @@ var init_check = __esm({
64240
65080
  // ../../packages/steering-freshness/src/sync.ts
64241
65081
  import { mkdtemp, rm as rm3, writeFile as writeFile6 } from "node:fs/promises";
64242
65082
  import { tmpdir as tmpdir2 } from "node:os";
64243
- import { join as join54 } from "node:path";
65083
+ import { join as join55 } from "node:path";
64244
65084
  function refuse3(refusal, message) {
64245
65085
  return {
64246
65086
  applied: false,
@@ -64421,9 +65261,9 @@ async function syncSteering(opts) {
64421
65261
  };
64422
65262
  }
64423
65263
  async function commitPaths(ctx, message, paths) {
64424
- const dir = await mkdtemp(join54(tmpdir2(), "oxagen-steering-sync-"));
65264
+ const dir = await mkdtemp(join55(tmpdir2(), "oxagen-steering-sync-"));
64425
65265
  try {
64426
- const list2 = join54(dir, "pathspec");
65266
+ const list2 = join55(dir, "pathspec");
64427
65267
  await writeFile6(list2, `${paths.join("\0")}\0`, "utf8");
64428
65268
  await git3(
64429
65269
  ctx,
@@ -64951,9 +65791,9 @@ var init_paths2 = __esm({
64951
65791
 
64952
65792
  // src/commands/workspace-link.ts
64953
65793
  import { existsSync as existsSync26, mkdirSync as mkdirSync9, readFileSync as readFileSync25 } from "node:fs";
64954
- import { dirname as dirname30, join as join55 } from "node:path";
65794
+ import { dirname as dirname30, join as join56 } from "node:path";
64955
65795
  function workspaceLinkPath(cwd) {
64956
- return join55(cwd, WORKSPACE_LINK_PATH);
65796
+ return join56(cwd, WORKSPACE_LINK_PATH);
64957
65797
  }
64958
65798
  function isRecord8(value) {
64959
65799
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -65043,7 +65883,7 @@ __export(steering_exports, {
65043
65883
  });
65044
65884
  import { execFileSync } from "node:child_process";
65045
65885
  import { existsSync as existsSync27, realpathSync as realpathSync7 } from "node:fs";
65046
- import { dirname as dirname31, join as join56, normalize, parse as parsePath } from "node:path";
65886
+ import { dirname as dirname31, join as join57, normalize, parse as parsePath } from "node:path";
65047
65887
  function findProjectRoot(start) {
65048
65888
  const { root } = parsePath(start);
65049
65889
  const rawGitRoot = gitRootOr(start);
@@ -65052,7 +65892,7 @@ function findProjectRoot(start) {
65052
65892
  if (gitRoot !== null) return gitRoot;
65053
65893
  let dir = from;
65054
65894
  for (; ; ) {
65055
- if (existsSync27(join56(dir, PROJECT_DIR_NAME))) return dir;
65895
+ if (existsSync27(join57(dir, PROJECT_DIR_NAME))) return dir;
65056
65896
  if (dir === root) return from;
65057
65897
  const parent = dirname31(dir);
65058
65898
  if (parent === dir) return from;
@@ -78530,10 +79370,10 @@ var init_run_list = __esm({
78530
79370
  /** `owner/name` as the frame recorded it; null when it recorded none. */
78531
79371
  repository: external_exports.string().max(512).nullable(),
78532
79372
  /**
78533
- * The state read from `tacho.run_pull_requests`, which forge webhooks and
78534
- * one read when the link landed keep current (ADR-192). Null when no row
78535
- * exists or no forge has reported the pull request, and a caller then
78536
- * renders "status unknown", never a guessed "open".
79373
+ * The state `forge.pull_requests` holds for the pull request, which the
79374
+ * forge sync keeps current from each delivery and each recorded link
79375
+ * (ADR-288, #5949). Null when the store holds no row for it, and a caller
79376
+ * then renders "status unknown", never a guessed "open".
78537
79377
  */
78538
79378
  state: external_exports.enum(["open", "draft", "merged", "closed"]).nullable(),
78539
79379
  /**
@@ -81417,7 +82257,7 @@ function findSecretsAndPii(text5) {
81417
82257
  const findings = [];
81418
82258
  if (/-----BEGIN [A-Z ]*PRIVATE KEY-----/.test(text5))
81419
82259
  findings.push("private key block");
81420
- for (const token of text5.match(TOKEN) ?? []) {
82260
+ for (const token of text5.match(TOKEN2) ?? []) {
81421
82261
  if (isSecretToken(token)) {
81422
82262
  findings.push("credential token");
81423
82263
  break;
@@ -81444,7 +82284,7 @@ function findSecretsAndPii(text5) {
81444
82284
  }
81445
82285
  return findings;
81446
82286
  }
81447
- var SECRET_PREFIXES, SENSITIVE_KEY_MARKERS, TOKEN;
82287
+ var SECRET_PREFIXES, SENSITIVE_KEY_MARKERS, TOKEN2;
81448
82288
  var init_secrets = __esm({
81449
82289
  "../../packages/steering-check/src/secrets.ts"() {
81450
82290
  "use strict";
@@ -81495,7 +82335,7 @@ var init_secrets = __esm({
81495
82335
  "session_id",
81496
82336
  "client_secret"
81497
82337
  ];
81498
- TOKEN = /[A-Za-z0-9_\-./+~]+/g;
82338
+ TOKEN2 = /[A-Za-z0-9_\-./+~]+/g;
81499
82339
  }
81500
82340
  });
81501
82341
 
@@ -82443,7 +83283,7 @@ __export(steering_import_exports, {
82443
83283
  });
82444
83284
  import { readdir as readdir4, realpath as realpath2, stat as stat4 } from "node:fs/promises";
82445
83285
  import { homedir as homedir12 } from "node:os";
82446
- import { basename as basename8, extname, join as join57, relative as relative7, sep as sep9 } from "node:path";
83286
+ import { basename as basename8, extname, join as join58, relative as relative7, sep as sep9 } from "node:path";
82447
83287
  function envDir2(env, key) {
82448
83288
  const value = env[key];
82449
83289
  return value === void 0 || value.trim() === "" ? null : value;
@@ -82451,34 +83291,34 @@ function envDir2(env, key) {
82451
83291
  function harnessHome(harness, env = process.env, home = homedir12()) {
82452
83292
  switch (harness) {
82453
83293
  case "claude-code": {
82454
- const config = envDir2(env, "CLAUDE_CONFIG_DIR") ?? join57(home, ".claude");
83294
+ const config = envDir2(env, "CLAUDE_CONFIG_DIR") ?? join58(home, ".claude");
82455
83295
  return {
82456
83296
  harness,
82457
83297
  folders: [
82458
83298
  {
82459
- dir: skillsRoot("claude-code", env, home) ?? join57(config, "skills"),
83299
+ dir: skillsRoot("claude-code", env, home) ?? join58(config, "skills"),
82460
83300
  mount: ".claude/skills"
82461
83301
  },
82462
- { dir: join57(config, "commands"), mount: ".claude/commands" },
82463
- { dir: join57(config, "agents"), mount: ".claude/agents" }
83302
+ { dir: join58(config, "commands"), mount: ".claude/commands" },
83303
+ { dir: join58(config, "agents"), mount: ".claude/agents" }
82464
83304
  ],
82465
83305
  instructions: [
82466
- { file: join57(config, "CLAUDE.md"), filename: ".claude/CLAUDE.md" }
83306
+ { file: join58(config, "CLAUDE.md"), filename: ".claude/CLAUDE.md" }
82467
83307
  ]
82468
83308
  };
82469
83309
  }
82470
83310
  case "codex": {
82471
- const codexHome = envDir2(env, "CODEX_HOME") ?? join57(home, ".codex");
83311
+ const codexHome = envDir2(env, "CODEX_HOME") ?? join58(home, ".codex");
82472
83312
  return {
82473
83313
  harness,
82474
83314
  folders: [
82475
83315
  {
82476
- dir: skillsRoot("codex", env, home) ?? join57(home, ".agents", "skills"),
83316
+ dir: skillsRoot("codex", env, home) ?? join58(home, ".agents", "skills"),
82477
83317
  mount: ".agents/skills"
82478
83318
  }
82479
83319
  ],
82480
83320
  instructions: ["AGENTS.override.md", "AGENTS.md"].map((name) => ({
82481
- file: join57(codexHome, name),
83321
+ file: join58(codexHome, name),
82482
83322
  filename: `.codex/${name}`
82483
83323
  }))
82484
83324
  };
@@ -82487,8 +83327,8 @@ function harnessHome(harness, env = process.env, home = homedir12()) {
82487
83327
  return {
82488
83328
  harness,
82489
83329
  folders: [
82490
- { dir: join57(home, ".cursor", "skills"), mount: ".cursor/skills" },
82491
- { dir: join57(home, ".cursor", "commands"), mount: ".cursor/commands" }
83330
+ { dir: join58(home, ".cursor", "skills"), mount: ".cursor/skills" },
83331
+ { dir: join58(home, ".cursor", "commands"), mount: ".cursor/commands" }
82492
83332
  ],
82493
83333
  instructions: []
82494
83334
  };
@@ -82534,7 +83374,7 @@ async function findMarkdownFiles(paths, harness) {
82534
83374
  }
82535
83375
  const found = [];
82536
83376
  for (const entry2 of entries2.sort(byName)) {
82537
- const path2 = join57(dir, entry2.name);
83377
+ const path2 = join58(dir, entry2.name);
82538
83378
  if (entry2.isDirectory()) {
82539
83379
  if (!entry2.name.startsWith(".") && entry2.name !== "node_modules")
82540
83380
  found.push(...await filesUnder(path2, from));
@@ -82556,7 +83396,7 @@ async function findMarkdownFiles(paths, harness) {
82556
83396
  const { folder } = frame;
82557
83397
  const named = (rel) => frame.fixedNames ? { filename: rel } : {};
82558
83398
  for (const entry2 of entries2) {
82559
- const path2 = join57(dir, entry2.name);
83399
+ const path2 = join58(dir, entry2.name);
82560
83400
  const rel = frame.relOf(path2);
82561
83401
  if (entry2.isDirectory()) {
82562
83402
  if (entry2.name === "node_modules") continue;
@@ -82615,7 +83455,7 @@ async function findMarkdownFiles(paths, harness) {
82615
83455
  }
82616
83456
  if (folderGiven) {
82617
83457
  const catalogue = CATALOGUE_FOLDERS.has(basename8(path2));
82618
- const root = catalogue ? join57(path2, "..") : path2;
83458
+ const root = catalogue ? join58(path2, "..") : path2;
82619
83459
  await walk2(path2, {
82620
83460
  relOf: (p) => under(root, p),
82621
83461
  folder: path2,
@@ -84275,10 +85115,10 @@ __export(verify_exports, {
84275
85115
  verifyBundle: () => verifyBundle3
84276
85116
  });
84277
85117
  import { existsSync as existsSync28, readFileSync as readFileSync26, statSync as statSync15 } from "node:fs";
84278
- import { join as join58 } from "node:path";
85118
+ import { join as join59 } from "node:path";
84279
85119
  function readDirectory(dir) {
84280
85120
  const read2 = (name) => {
84281
- const path2 = join58(dir, name);
85121
+ const path2 = join59(dir, name);
84282
85122
  return existsSync28(path2) ? readFileSync26(path2, "utf8") : void 0;
84283
85123
  };
84284
85124
  return assemble(read2, dir);
@@ -85233,7 +86073,7 @@ var init_conversation = __esm({
85233
86073
  });
85234
86074
 
85235
86075
  // src/auth/open-browser.ts
85236
- import { spawn as spawn6 } from "node:child_process";
86076
+ import { spawn as spawn8 } from "node:child_process";
85237
86077
  function openBrowser(url) {
85238
86078
  try {
85239
86079
  let cmd;
@@ -85251,7 +86091,7 @@ function openBrowser(url) {
85251
86091
  cmd = "xdg-open";
85252
86092
  args = [url];
85253
86093
  }
85254
- const child = spawn6(cmd, args, { detached: true, stdio: "ignore" });
86094
+ const child = spawn8(cmd, args, { detached: true, stdio: "ignore" });
85255
86095
  child.on("error", () => {
85256
86096
  });
85257
86097
  child.unref();
@@ -85407,7 +86247,7 @@ import {
85407
86247
  writeFileSync as writeFileSync7
85408
86248
  } from "node:fs";
85409
86249
  import { homedir as homedir13, hostname as osHostname3 } from "node:os";
85410
- import { join as join59, relative as relative8, resolve as resolve22, sep as sep10 } from "node:path";
86250
+ import { join as join60, relative as relative8, resolve as resolve22, sep as sep10 } from "node:path";
85411
86251
  function git4(cwd, args) {
85412
86252
  return new Promise((done) => {
85413
86253
  try {
@@ -85454,7 +86294,7 @@ function parseRemoteRepository(url) {
85454
86294
  }
85455
86295
  function oxagenPresent(root) {
85456
86296
  try {
85457
- return readdirSync14(join59(root, ".oxagen")).some(
86297
+ return readdirSync14(join60(root, ".oxagen")).some(
85458
86298
  (name) => name !== "workspace.json"
85459
86299
  );
85460
86300
  } catch {
@@ -85463,18 +86303,18 @@ function oxagenPresent(root) {
85463
86303
  }
85464
86304
  function symlinkState(root) {
85465
86305
  try {
85466
- if (!lstatSync10(join59(root, ".stella")).isDirectory()) return "none";
86306
+ if (!lstatSync10(join60(root, ".stella")).isDirectory()) return "none";
85467
86307
  } catch {
85468
86308
  return "none";
85469
86309
  }
85470
86310
  let oxagenReal;
85471
86311
  try {
85472
- oxagenReal = realpathSync8(join59(root, ".oxagen"));
86312
+ oxagenReal = realpathSync8(join60(root, ".oxagen"));
85473
86313
  } catch {
85474
86314
  return "missing";
85475
86315
  }
85476
86316
  for (const link of STELLA_LINKS) {
85477
- const at2 = join59(root, link);
86317
+ const at2 = join60(root, link);
85478
86318
  try {
85479
86319
  if (!lstatSync10(at2).isSymbolicLink()) return "missing";
85480
86320
  const target2 = realpathSync8(at2);
@@ -85488,7 +86328,7 @@ function symlinkState(root) {
85488
86328
  return "linked";
85489
86329
  }
85490
86330
  function machineId(configDir = getConfigDir()) {
85491
- const file = join59(configDir, MACHINE_ID_FILE);
86331
+ const file = join60(configDir, MACHINE_ID_FILE);
85492
86332
  let secret = null;
85493
86333
  try {
85494
86334
  if (existsSync29(file)) {
@@ -85570,12 +86410,12 @@ async function ensureWorkspaceLinkIgnored(root) {
85570
86410
  const topDir = resolve22(top);
85571
86411
  const entry2 = relative8(
85572
86412
  topDir,
85573
- join59(realpathOr2(root), ".oxagen", "workspace.json")
86413
+ join60(realpathOr2(root), ".oxagen", "workspace.json")
85574
86414
  ).split(sep10).join("/");
85575
86415
  if (entry2.startsWith("../")) return null;
85576
86416
  const rule = await git4(topDir, ["check-ignore", "--no-index", "-v", entry2]);
85577
86417
  if (rule !== null) return null;
85578
- const gitignore = join59(resolve22(top), ".gitignore");
86418
+ const gitignore = join60(resolve22(top), ".gitignore");
85579
86419
  let existing = "";
85580
86420
  try {
85581
86421
  existing = readFileSync27(gitignore, "utf8");
@@ -86100,7 +86940,7 @@ import {
86100
86940
  import {
86101
86941
  dirname as dirname33,
86102
86942
  isAbsolute as isAbsolute14,
86103
- join as join60,
86943
+ join as join61,
86104
86944
  parse as parsePath2,
86105
86945
  posix as posix4,
86106
86946
  sep as sep11
@@ -86220,7 +87060,7 @@ function findLinkedRoot(start) {
86220
87060
  }
86221
87061
  function fsReader(root) {
86222
87062
  return (path2) => {
86223
- const abs = join60(root, ...path2.split("/"));
87063
+ const abs = join61(root, ...path2.split("/"));
86224
87064
  try {
86225
87065
  const st = lstatSync11(abs);
86226
87066
  if (!st.isFile()) return Buffer.from(`\0not-a-file:${abs}`);
@@ -86231,14 +87071,14 @@ function fsReader(root) {
86231
87071
  };
86232
87072
  }
86233
87073
  function assertInsideOxagen(root, path2) {
86234
- const oxagenAbs = join60(root, OXAGEN_DIR);
87074
+ const oxagenAbs = join61(root, OXAGEN_DIR);
86235
87075
  let oxagenReal;
86236
87076
  try {
86237
87077
  oxagenReal = realpathSync9(oxagenAbs);
86238
87078
  } catch {
86239
87079
  return;
86240
87080
  }
86241
- const abs = join60(root, ...path2.split("/"));
87081
+ const abs = join61(root, ...path2.split("/"));
86242
87082
  try {
86243
87083
  if (lstatSync11(abs).isSymbolicLink()) {
86244
87084
  throw new Error(
@@ -86268,8 +87108,8 @@ function assertInsideOxagen(root, path2) {
86268
87108
  }
86269
87109
  }
86270
87110
  function pruneEmptyDirs(root, path2) {
86271
- const stop = join60(root, OXAGEN_DIR);
86272
- let dir = dirname33(join60(root, ...path2.split("/")));
87111
+ const stop = join61(root, OXAGEN_DIR);
87112
+ let dir = dirname33(join61(root, ...path2.split("/")));
86273
87113
  while (dir.startsWith(stop + sep11)) {
86274
87114
  try {
86275
87115
  if (readdirSync15(dir).length > 0) return;
@@ -86284,12 +87124,12 @@ function applyPlan(root, plan) {
86284
87124
  for (const w of plan.writes) assertInsideOxagen(root, w.path);
86285
87125
  for (const d of plan.deletes) assertInsideOxagen(root, d);
86286
87126
  for (const w of plan.writes) {
86287
- const abs = join60(root, ...w.path.split("/"));
87127
+ const abs = join61(root, ...w.path.split("/"));
86288
87128
  mkdirSync11(dirname33(abs), { recursive: true });
86289
87129
  atomicWriteFileSync(abs, w.content);
86290
87130
  }
86291
87131
  for (const d of plan.deletes) {
86292
- rmSync10(join60(root, ...d.split("/")), { force: true });
87132
+ rmSync10(join61(root, ...d.split("/")), { force: true });
86293
87133
  pruneEmptyDirs(root, d);
86294
87134
  }
86295
87135
  }
@@ -108252,7 +109092,7 @@ function invalidArguments(message) {
108252
109092
  return new BuildError("Invalid arguments", message);
108253
109093
  }
108254
109094
  function checkedName(parameter) {
108255
- if (!TOKEN2.test(parameter.name)) {
109095
+ if (!TOKEN3.test(parameter.name)) {
108256
109096
  throw new BuildError(
108257
109097
  "Invalid request",
108258
109098
  `The ${parameter.in} parameter name ${parameter.name} is not an HTTP token.`
@@ -108334,7 +109174,7 @@ function cookiePairs(parameter, value) {
108334
109174
  ]
108335
109175
  ] : shape.kind === "list" ? shape.items.map((item) => [name, item]) : shape.entries;
108336
109176
  for (const [cookie, text5] of pairs) {
108337
- if (!TOKEN2.test(cookie)) {
109177
+ if (!TOKEN3.test(cookie)) {
108338
109178
  throw invalidArguments(
108339
109179
  `The cookie ${parameter.name} holds a key that is not an HTTP token, so no cookie can take it as a name.`
108340
109180
  );
@@ -108377,12 +109217,12 @@ function queryEntries(parameter, value) {
108377
109217
  }
108378
109218
  if (shape.items.length === 0) return [];
108379
109219
  if (explode) return shape.items.map((item) => pair(name, item));
108380
- const [raw, delimiter2] = style === "form" ? [",", ","] : style === "spaceDelimited" ? [" ", "%20"] : ["|", "|"];
109220
+ const [raw, delimiter3] = style === "form" ? [",", ","] : style === "spaceDelimited" ? [" ", "%20"] : ["|", "|"];
108381
109221
  return [
108382
109222
  entry(
108383
109223
  name,
108384
109224
  shape.items.join(raw),
108385
- `${enc(name)}=${shape.items.map(val).join(delimiter2)}`
109225
+ `${enc(name)}=${shape.items.map(val).join(delimiter3)}`
108386
109226
  )
108387
109227
  ];
108388
109228
  }
@@ -108599,7 +109439,7 @@ function createHttpSender(options = {}) {
108599
109439
  }
108600
109440
  };
108601
109441
  }
108602
- var IDEMPOTENT_METHODS, RESERVED_HEADERS, TOKEN2, UNSAFE_HEADER_VALUE, UNSAFE_COOKIE_VALUE;
109442
+ var IDEMPOTENT_METHODS, RESERVED_HEADERS, TOKEN3, UNSAFE_HEADER_VALUE, UNSAFE_COOKIE_VALUE;
108603
109443
  var init_http = __esm({
108604
109444
  "../../packages/mcp-studio/src/execute/http.ts"() {
108605
109445
  "use strict";
@@ -108627,7 +109467,7 @@ var init_http = __esm({
108627
109467
  "proxy-authorization",
108628
109468
  "cookie"
108629
109469
  ]);
108630
- TOKEN2 = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
109470
+ TOKEN3 = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
108631
109471
  UNSAFE_HEADER_VALUE = /[\r\n\0]/;
108632
109472
  UNSAFE_COOKIE_VALUE = /[;\r\n\0]/;
108633
109473
  }
@@ -130164,7 +131004,7 @@ import {
130164
131004
  readlinkSync as readlinkSync4,
130165
131005
  statSync as statSync16
130166
131006
  } from "node:fs";
130167
- import { dirname as dirname34, isAbsolute as isAbsolute15, join as join61, relative as relative9, resolve as resolve24, sep as sep12 } from "node:path";
131007
+ import { dirname as dirname34, isAbsolute as isAbsolute15, join as join62, relative as relative9, resolve as resolve24, sep as sep12 } from "node:path";
130168
131008
  function git5(cwd, args, input) {
130169
131009
  try {
130170
131010
  return execFileSync2("git", args, {
@@ -130196,7 +131036,7 @@ function commitOf2(root, ref2) {
130196
131036
  return sha2.length > 0 ? sha2 : null;
130197
131037
  }
130198
131038
  function readWorkingFile(root, path2) {
130199
- const abs = join61(root, ...path2.split("/"));
131039
+ const abs = join62(root, ...path2.split("/"));
130200
131040
  try {
130201
131041
  const stat7 = lstatSync12(abs);
130202
131042
  if (stat7.isSymbolicLink()) return readlinkSync4(abs, "utf8");
@@ -130290,7 +131130,7 @@ function isDir(path2) {
130290
131130
  function findSteeringRoot(start) {
130291
131131
  let dir = resolve24(start);
130292
131132
  for (; ; ) {
130293
- if (isFile(join61(dir, WORKSPACE_TOML_PATH)) || isFile(join61(dir, AGENTS_MD_PATH)) && isDir(join61(dir, STEERING_DIR))) {
131133
+ if (isFile(join62(dir, WORKSPACE_TOML_PATH)) || isFile(join62(dir, AGENTS_MD_PATH)) && isDir(join62(dir, STEERING_DIR))) {
130294
131134
  return dir;
130295
131135
  }
130296
131136
  const parent = dirname34(dir);
@@ -130370,7 +131210,7 @@ function cacheFile(cacheDir, root) {
130370
131210
  key: token === void 0 ? null : createHash20("sha256").update(token).digest("hex").slice(0, 16)
130371
131211
  };
130372
131212
  const key = createHash20("sha256").update(JSON.stringify([root, identity])).digest("hex").slice(0, 32);
130373
- return join61(cacheDir, `${key}.json`);
131213
+ return join62(cacheDir, `${key}.json`);
130374
131214
  }
130375
131215
  function readCache(file, now) {
130376
131216
  let entry2;
@@ -130484,7 +131324,7 @@ function defaultDeps2() {
130484
131324
  return {
130485
131325
  fetchPublished: fetchSteeringIndex,
130486
131326
  cedar: cedarHooks,
130487
- cacheDir: join61(getConfigDir(), "cache", "steering-check"),
131327
+ cacheDir: join62(getConfigDir(), "cache", "steering-check"),
130488
131328
  now: () => Date.now()
130489
131329
  };
130490
131330
  }
@@ -134367,7 +135207,7 @@ var init_src9 = __esm({
134367
135207
 
134368
135208
  // src/commands/codegraph-upload/files.ts
134369
135209
  import { readdir as readdir5, stat as stat5 } from "node:fs/promises";
134370
- import { join as join62, relative as relative10, sep as sep13 } from "node:path";
135210
+ import { join as join63, relative as relative10, sep as sep13 } from "node:path";
134371
135211
  function hasGlobChars(pattern) {
134372
135212
  return /[*?[\]{}]/.test(pattern);
134373
135213
  }
@@ -134379,7 +135219,7 @@ async function walk(root, dir, out) {
134379
135219
  const entries2 = await readdir5(dir, { withFileTypes: true });
134380
135220
  for (const entry2 of entries2) {
134381
135221
  if (entry2.isSymbolicLink()) continue;
134382
- const full = join62(dir, entry2.name);
135222
+ const full = join63(dir, entry2.name);
134383
135223
  if (entry2.isDirectory()) {
134384
135224
  if (!SKIP_DIRS.has(entry2.name)) await walk(root, full, out);
134385
135225
  } else if (entry2.isFile()) {
@@ -134391,7 +135231,7 @@ async function expandPattern(root, pattern) {
134391
135231
  const wanted = normalize2(pattern.trim());
134392
135232
  if (!hasGlobChars(wanted)) {
134393
135233
  try {
134394
- const info = await stat5(join62(root, wanted));
135234
+ const info = await stat5(join63(root, wanted));
134395
135235
  return info.isFile() ? [wanted] : [];
134396
135236
  } catch {
134397
135237
  return [];
@@ -134542,7 +135382,7 @@ var init_token = __esm({
134542
135382
  });
134543
135383
 
134544
135384
  // src/commands/codegraph-upload/run.ts
134545
- import { join as join63 } from "node:path";
135385
+ import { join as join64 } from "node:path";
134546
135386
  function addDropped(into, more) {
134547
135387
  into.sensitiveValues += more.sensitiveValues;
134548
135388
  into.secretData += more.secretData;
@@ -134560,7 +135400,7 @@ async function uploadOne(deps, config, token, group, path2, totals2) {
134560
135400
  const label2 = `${group.kind}/${group.source} ${path2}`;
134561
135401
  let bytes;
134562
135402
  try {
134563
- bytes = await deps.readFile(join63(deps.cwd, path2));
135403
+ bytes = await deps.readFile(join64(deps.cwd, path2));
134564
135404
  } catch (error) {
134565
135405
  totals2.failed += 1;
134566
135406
  deps.log(`error: ${label2}: cannot read the file: ${error.message}`);