@oxagen/cli 2.1.4-955 → 2.1.4-965
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/oxagen.mjs +1698 -845
- package/package.json +1 -1
package/oxagen.mjs
CHANGED
|
@@ -13816,8 +13816,8 @@ var init_backfill = __esm({
|
|
|
13816
13816
|
this.parentMs = ms;
|
|
13817
13817
|
this.clock.ms = ms;
|
|
13818
13818
|
}
|
|
13819
|
-
const
|
|
13820
|
-
return { events: this.mappedLine(parsed2, text5, offset,
|
|
13819
|
+
const spawn9 = [];
|
|
13820
|
+
return { events: this.mappedLine(parsed2, text5, offset, spawn9), spawn: spawn9 };
|
|
13821
13821
|
}
|
|
13822
13822
|
/**
|
|
13823
13823
|
* Begin a session still waiting for its facts once its last line is read:
|
|
@@ -13843,28 +13843,28 @@ var init_backfill = __esm({
|
|
|
13843
13843
|
this.parentMs = timestampOf(first) ?? 0;
|
|
13844
13844
|
this.clock.ms = this.parentMs;
|
|
13845
13845
|
const events = this.collect(this.start(first, facts, permissionMode));
|
|
13846
|
-
const
|
|
13846
|
+
const spawn9 = [];
|
|
13847
13847
|
for (const item of early) {
|
|
13848
13848
|
const ms = timestampOf(item.record);
|
|
13849
13849
|
if (ms !== void 0) this.parentMs = Math.max(this.parentMs, ms);
|
|
13850
13850
|
this.clock.ms = ms ?? this.parentMs;
|
|
13851
13851
|
events.push(
|
|
13852
|
-
...this.mappedLine(item.record, item.text, item.offset,
|
|
13852
|
+
...this.mappedLine(item.record, item.text, item.offset, spawn9)
|
|
13853
13853
|
);
|
|
13854
13854
|
}
|
|
13855
13855
|
this.clock.ms = this.parentMs;
|
|
13856
|
-
return { events, spawn:
|
|
13856
|
+
return { events, spawn: spawn9 };
|
|
13857
13857
|
}
|
|
13858
13858
|
/** One parent line through the mapping, guarded. */
|
|
13859
|
-
mappedLine(record, text5, offset,
|
|
13859
|
+
mappedLine(record, text5, offset, spawn9) {
|
|
13860
13860
|
const spawnedBefore = this.spawned.size;
|
|
13861
|
-
const spawnLength =
|
|
13861
|
+
const spawnLength = spawn9.length;
|
|
13862
13862
|
return this.guarded(
|
|
13863
13863
|
offset,
|
|
13864
13864
|
void 0,
|
|
13865
|
-
() => this.mapped(record, text5,
|
|
13865
|
+
() => this.mapped(record, text5, spawn9),
|
|
13866
13866
|
() => {
|
|
13867
|
-
|
|
13867
|
+
spawn9.length = spawnLength;
|
|
13868
13868
|
for (const toolUseId of [...this.spawned.keys()].slice(spawnedBefore))
|
|
13869
13869
|
this.spawned.delete(toolUseId);
|
|
13870
13870
|
}
|
|
@@ -14080,7 +14080,7 @@ var init_backfill = __esm({
|
|
|
14080
14080
|
})
|
|
14081
14081
|
);
|
|
14082
14082
|
}
|
|
14083
|
-
mapped(record, text5,
|
|
14083
|
+
mapped(record, text5, spawn9) {
|
|
14084
14084
|
const type = nonEmptyString(record["type"]);
|
|
14085
14085
|
const ms = timestampOf(record);
|
|
14086
14086
|
const events = [];
|
|
@@ -14213,7 +14213,7 @@ var init_backfill = __esm({
|
|
|
14213
14213
|
ms
|
|
14214
14214
|
)
|
|
14215
14215
|
);
|
|
14216
|
-
|
|
14216
|
+
spawn9.push(subagent.agentId);
|
|
14217
14217
|
}
|
|
14218
14218
|
return events;
|
|
14219
14219
|
}
|
|
@@ -17571,14 +17571,14 @@ var init_recorder = __esm({
|
|
|
17571
17571
|
const parent = this.options.parent;
|
|
17572
17572
|
if (parent === void 0) return;
|
|
17573
17573
|
const type = parent.subagentType === void 0 ? subagentType : void 0;
|
|
17574
|
-
const
|
|
17575
|
-
if (type === void 0 &&
|
|
17574
|
+
const spawn9 = parent.spawnToolUseId === void 0 ? spawnToolUseId : void 0;
|
|
17575
|
+
if (type === void 0 && spawn9 === void 0) return;
|
|
17576
17576
|
this.options = {
|
|
17577
17577
|
...this.options,
|
|
17578
17578
|
parent: {
|
|
17579
17579
|
...parent,
|
|
17580
17580
|
...type !== void 0 ? { subagentType: type } : {},
|
|
17581
|
-
...
|
|
17581
|
+
...spawn9 !== void 0 ? { spawnToolUseId: spawn9 } : {}
|
|
17582
17582
|
}
|
|
17583
17583
|
};
|
|
17584
17584
|
}
|
|
@@ -21029,12 +21029,12 @@ async function sealTranscript(candidate, deps, pass2) {
|
|
|
21029
21029
|
const read2 = await readSlices(candidate.path, sliceBytes, async (lines) => {
|
|
21030
21030
|
let index = 0;
|
|
21031
21031
|
while (index < lines.length) {
|
|
21032
|
-
const
|
|
21032
|
+
const spawn9 = [];
|
|
21033
21033
|
await deps.exclusive(candidate.sessionId, () => {
|
|
21034
21034
|
if (deps.heldLocally(candidate.sessionId)) throw new TakenLive();
|
|
21035
21035
|
const out = [];
|
|
21036
21036
|
let next = readTo;
|
|
21037
|
-
while (
|
|
21037
|
+
while (spawn9.length === 0) {
|
|
21038
21038
|
const line = lines[index];
|
|
21039
21039
|
if (line === void 0) break;
|
|
21040
21040
|
index += 1;
|
|
@@ -21045,7 +21045,7 @@ async function sealTranscript(candidate, deps, pass2) {
|
|
|
21045
21045
|
}
|
|
21046
21046
|
const sealed = driver.line(line.text, line.offset);
|
|
21047
21047
|
out.push(...sealed.events);
|
|
21048
|
-
|
|
21048
|
+
spawn9.push(...sealed.spawn);
|
|
21049
21049
|
}
|
|
21050
21050
|
emit(out);
|
|
21051
21051
|
if (driver.hasChain) {
|
|
@@ -21053,7 +21053,7 @@ async function sealTranscript(candidate, deps, pass2) {
|
|
|
21053
21053
|
partial(readTo, { status: "partial" });
|
|
21054
21054
|
}
|
|
21055
21055
|
});
|
|
21056
|
-
for (const agentId of
|
|
21056
|
+
for (const agentId of spawn9) await feedSubagent(agentId);
|
|
21057
21057
|
}
|
|
21058
21058
|
await between();
|
|
21059
21059
|
});
|
|
@@ -22422,6 +22422,575 @@ var init_claude_code_mcp = __esm({
|
|
|
22422
22422
|
}
|
|
22423
22423
|
});
|
|
22424
22424
|
|
|
22425
|
+
// ../../packages/tacho/src/host/run-token.ts
|
|
22426
|
+
import { createHmac, randomBytes as randomBytes4, timingSafeEqual } from "node:crypto";
|
|
22427
|
+
import { readFileSync as readFileSync6 } from "node:fs";
|
|
22428
|
+
function keyFromBytes(bytes) {
|
|
22429
|
+
if (bytes.length !== KEY_BYTES)
|
|
22430
|
+
throw new Error(
|
|
22431
|
+
`run token key must be ${KEY_BYTES} bytes, got ${bytes.length}`
|
|
22432
|
+
);
|
|
22433
|
+
const id2 = createHmac("sha256", "tacho.run-token-key-id").update(bytes).digest("hex").slice(0, 16);
|
|
22434
|
+
return { bytes, id: id2 };
|
|
22435
|
+
}
|
|
22436
|
+
function generateRunTokenKey() {
|
|
22437
|
+
return keyFromBytes(randomBytes4(KEY_BYTES));
|
|
22438
|
+
}
|
|
22439
|
+
function runTokenKeyFromHex(hex) {
|
|
22440
|
+
const trimmed = hex.trim();
|
|
22441
|
+
if (!/^[0-9a-f]{64}$/i.test(trimmed))
|
|
22442
|
+
throw new Error("run token key file does not hold 64 hex characters");
|
|
22443
|
+
return keyFromBytes(Buffer.from(trimmed, "hex"));
|
|
22444
|
+
}
|
|
22445
|
+
function loadOrCreateRunTokenKey(path2) {
|
|
22446
|
+
try {
|
|
22447
|
+
return {
|
|
22448
|
+
key: runTokenKeyFromHex(readFileSync6(path2, "utf8")),
|
|
22449
|
+
created: false
|
|
22450
|
+
};
|
|
22451
|
+
} catch (error) {
|
|
22452
|
+
if (error.code !== "ENOENT") throw error;
|
|
22453
|
+
}
|
|
22454
|
+
const key = generateRunTokenKey();
|
|
22455
|
+
writeSensitiveFileAtomic(path2, `${key.bytes.toString("hex")}
|
|
22456
|
+
`);
|
|
22457
|
+
return { key, created: true };
|
|
22458
|
+
}
|
|
22459
|
+
function readRunTokenKey(path2) {
|
|
22460
|
+
const version2 = fileVersion(path2);
|
|
22461
|
+
if (version2 === void 0) {
|
|
22462
|
+
keysSeen.delete(path2);
|
|
22463
|
+
return void 0;
|
|
22464
|
+
}
|
|
22465
|
+
const seen = keysSeen.get(path2);
|
|
22466
|
+
if (seen?.version === version2) return seen.key;
|
|
22467
|
+
let key;
|
|
22468
|
+
try {
|
|
22469
|
+
key = runTokenKeyFromHex(readFileSync6(path2, "utf8"));
|
|
22470
|
+
} catch (error) {
|
|
22471
|
+
if (error.code === "ENOENT") return void 0;
|
|
22472
|
+
throw error;
|
|
22473
|
+
}
|
|
22474
|
+
keysSeen.set(path2, { version: version2, key });
|
|
22475
|
+
return key;
|
|
22476
|
+
}
|
|
22477
|
+
function b64url(bytes) {
|
|
22478
|
+
return bytes.toString("base64url");
|
|
22479
|
+
}
|
|
22480
|
+
function sign(key, claimsText) {
|
|
22481
|
+
return createHmac("sha256", key.bytes).update(claimsText, "utf8").digest();
|
|
22482
|
+
}
|
|
22483
|
+
function mintRunToken(options) {
|
|
22484
|
+
const ceiling = options.placement === "static" ? RUN_TOKEN_STATIC_MAX_TTL_MS : RUN_TOKEN_MAX_TTL_MS;
|
|
22485
|
+
const asked = options.ttlMs === void 0 ? options.placement === "static" ? RUN_TOKEN_STATIC_MAX_TTL_MS : RUN_TOKEN_DEFAULT_TTL_MS : options.ttlMs;
|
|
22486
|
+
if (!Number.isFinite(asked) || asked <= 0)
|
|
22487
|
+
throw new Error(`run token ttl must be positive, got ${String(asked)}`);
|
|
22488
|
+
let exp = options.now + Math.min(asked, ceiling);
|
|
22489
|
+
if (options.notAfter !== void 0) exp = Math.min(exp, options.notAfter);
|
|
22490
|
+
if (exp <= options.now)
|
|
22491
|
+
throw new Error("run token would already be expired when minted");
|
|
22492
|
+
const claims = {
|
|
22493
|
+
v: 1,
|
|
22494
|
+
tid: `rt_${randomBytes4(10).toString("hex")}`,
|
|
22495
|
+
host: options.host,
|
|
22496
|
+
harness: options.harness,
|
|
22497
|
+
provider: options.provider,
|
|
22498
|
+
placement: options.placement,
|
|
22499
|
+
iat: options.now,
|
|
22500
|
+
exp
|
|
22501
|
+
};
|
|
22502
|
+
const text5 = jcs(claims);
|
|
22503
|
+
const token = `${RUN_TOKEN_PREFIX}${b64url(Buffer.from(text5, "utf8"))}.${b64url(sign(options.key, text5))}`;
|
|
22504
|
+
return { token, claims };
|
|
22505
|
+
}
|
|
22506
|
+
function looksLikeRunToken(value) {
|
|
22507
|
+
return typeof value === "string" && value.startsWith(RUN_TOKEN_PREFIX) && value.length < 2048;
|
|
22508
|
+
}
|
|
22509
|
+
function peekRunTokenClaims(token) {
|
|
22510
|
+
if (!looksLikeRunToken(token)) return void 0;
|
|
22511
|
+
const body2 = token.slice(RUN_TOKEN_PREFIX.length);
|
|
22512
|
+
const dot = body2.indexOf(".");
|
|
22513
|
+
if (dot <= 0) return void 0;
|
|
22514
|
+
try {
|
|
22515
|
+
const parsed2 = JSON.parse(
|
|
22516
|
+
Buffer.from(body2.slice(0, dot), "base64url").toString("utf8")
|
|
22517
|
+
);
|
|
22518
|
+
const claims = runTokenClaimsSchema.safeParse(parsed2);
|
|
22519
|
+
return claims.success ? claims.data : void 0;
|
|
22520
|
+
} catch {
|
|
22521
|
+
return void 0;
|
|
22522
|
+
}
|
|
22523
|
+
}
|
|
22524
|
+
function verifyRunToken(token, options) {
|
|
22525
|
+
if (!looksLikeRunToken(token))
|
|
22526
|
+
return { ok: false, code: "run_token_malformed" };
|
|
22527
|
+
const body2 = token.slice(RUN_TOKEN_PREFIX.length);
|
|
22528
|
+
const dot = body2.indexOf(".");
|
|
22529
|
+
if (dot <= 0 || dot === body2.length - 1)
|
|
22530
|
+
return { ok: false, code: "run_token_malformed" };
|
|
22531
|
+
const bodyText = body2.slice(0, dot);
|
|
22532
|
+
let text5;
|
|
22533
|
+
try {
|
|
22534
|
+
text5 = Buffer.from(bodyText, "base64url").toString("utf8");
|
|
22535
|
+
} catch {
|
|
22536
|
+
return { ok: false, code: "run_token_malformed" };
|
|
22537
|
+
}
|
|
22538
|
+
const presented = Buffer.from(body2.slice(dot + 1), "utf8");
|
|
22539
|
+
const expected = Buffer.from(
|
|
22540
|
+
sign(options.key, text5).toString("base64url"),
|
|
22541
|
+
"utf8"
|
|
22542
|
+
);
|
|
22543
|
+
if (presented.length !== expected.length || !timingSafeEqual(presented, expected) || Buffer.from(text5, "utf8").toString("base64url") !== bodyText) {
|
|
22544
|
+
return { ok: false, code: "run_token_invalid", ...peeked(text5) };
|
|
22545
|
+
}
|
|
22546
|
+
let parsed2;
|
|
22547
|
+
try {
|
|
22548
|
+
parsed2 = JSON.parse(text5);
|
|
22549
|
+
} catch {
|
|
22550
|
+
return { ok: false, code: "run_token_malformed" };
|
|
22551
|
+
}
|
|
22552
|
+
const claims = runTokenClaimsSchema.safeParse(parsed2);
|
|
22553
|
+
if (!claims.success) return { ok: false, code: "run_token_malformed" };
|
|
22554
|
+
if (jcs(claims.data) !== text5)
|
|
22555
|
+
return { ok: false, code: "run_token_invalid" };
|
|
22556
|
+
if (claims.data.exp <= options.now)
|
|
22557
|
+
return { ok: false, code: "run_token_expired", claims: claims.data };
|
|
22558
|
+
if (claims.data.host !== options.host || claims.data.provider !== options.provider)
|
|
22559
|
+
return { ok: false, code: "run_token_mismatch", claims: claims.data };
|
|
22560
|
+
return { ok: true, claims: claims.data };
|
|
22561
|
+
}
|
|
22562
|
+
function peeked(text5) {
|
|
22563
|
+
try {
|
|
22564
|
+
const claims = runTokenClaimsSchema.safeParse(JSON.parse(text5));
|
|
22565
|
+
return claims.success ? { claims: claims.data } : {};
|
|
22566
|
+
} catch {
|
|
22567
|
+
return {};
|
|
22568
|
+
}
|
|
22569
|
+
}
|
|
22570
|
+
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;
|
|
22571
|
+
var init_run_token = __esm({
|
|
22572
|
+
"../../packages/tacho/src/host/run-token.ts"() {
|
|
22573
|
+
"use strict";
|
|
22574
|
+
init_zod();
|
|
22575
|
+
init_digest();
|
|
22576
|
+
init_fs();
|
|
22577
|
+
RUN_TOKEN_PREFIX = "oxrt_";
|
|
22578
|
+
RUN_TOKEN_MAX_TTL_MS = 15 * 6e4;
|
|
22579
|
+
RUN_TOKEN_DEFAULT_TTL_MS = RUN_TOKEN_MAX_TTL_MS;
|
|
22580
|
+
RUN_TOKEN_STATIC_MAX_TTL_MS = 30 * 24 * 60 * 6e4;
|
|
22581
|
+
RUN_TOKEN_PROVIDERS = ["anthropic", "openai"];
|
|
22582
|
+
RUN_TOKEN_PLACEMENTS = ["helper", "static"];
|
|
22583
|
+
runTokenClaimsSchema = external_exports.object({
|
|
22584
|
+
v: external_exports.literal(1),
|
|
22585
|
+
/** `rt_` + 20 hex: cited on frames in place of the token. */
|
|
22586
|
+
tid: external_exports.string().regex(/^rt_[0-9a-f]{20}$/),
|
|
22587
|
+
/** The host enrollment the token was minted for. */
|
|
22588
|
+
host: external_exports.string().min(1).max(64),
|
|
22589
|
+
/** The harness it was handed to. */
|
|
22590
|
+
harness: external_exports.string().min(1).max(32),
|
|
22591
|
+
provider: external_exports.enum(RUN_TOKEN_PROVIDERS),
|
|
22592
|
+
placement: external_exports.enum(RUN_TOKEN_PLACEMENTS),
|
|
22593
|
+
/** Epoch milliseconds. */
|
|
22594
|
+
iat: external_exports.number().int().nonnegative(),
|
|
22595
|
+
exp: external_exports.number().int().nonnegative()
|
|
22596
|
+
}).strict();
|
|
22597
|
+
KEY_BYTES = 32;
|
|
22598
|
+
keysSeen = /* @__PURE__ */ new Map();
|
|
22599
|
+
}
|
|
22600
|
+
});
|
|
22601
|
+
|
|
22602
|
+
// ../../packages/tacho/src/host/credential-store.ts
|
|
22603
|
+
import { createCipheriv, createDecipheriv, randomBytes as randomBytes5 } from "node:crypto";
|
|
22604
|
+
import {
|
|
22605
|
+
closeSync as closeSync4,
|
|
22606
|
+
existsSync as existsSync5,
|
|
22607
|
+
fsyncSync as fsyncSync3,
|
|
22608
|
+
openSync as openSync4,
|
|
22609
|
+
readFileSync as readFileSync7,
|
|
22610
|
+
statSync as statSync3,
|
|
22611
|
+
unlinkSync as unlinkSync4,
|
|
22612
|
+
writeSync as writeSync3
|
|
22613
|
+
} from "node:fs";
|
|
22614
|
+
function anthropicCredentialKind(secret, fallback) {
|
|
22615
|
+
return secret.trim().startsWith(CLAUDE_OAUTH_TOKEN_PREFIX) ? "oauth" : fallback;
|
|
22616
|
+
}
|
|
22617
|
+
function readKey(path2) {
|
|
22618
|
+
try {
|
|
22619
|
+
const hex = readFileSync7(path2, "utf8").trim();
|
|
22620
|
+
if (!/^[0-9a-f]{64}$/i.test(hex))
|
|
22621
|
+
throw new Error(`${path2} does not hold a 32-byte key`);
|
|
22622
|
+
return Buffer.from(hex, "hex");
|
|
22623
|
+
} catch (error) {
|
|
22624
|
+
if (error.code === "ENOENT") return void 0;
|
|
22625
|
+
throw error;
|
|
22626
|
+
}
|
|
22627
|
+
}
|
|
22628
|
+
function loadOrCreateKey(path2) {
|
|
22629
|
+
const existing = readKey(path2);
|
|
22630
|
+
if (existing !== void 0) return existing;
|
|
22631
|
+
const key = randomBytes5(KEY_BYTES2);
|
|
22632
|
+
writeSensitiveFileAtomic(path2, `${key.toString("hex")}
|
|
22633
|
+
`);
|
|
22634
|
+
return key;
|
|
22635
|
+
}
|
|
22636
|
+
function requireKey(path2) {
|
|
22637
|
+
const key = readKey(path2);
|
|
22638
|
+
if (key === void 0)
|
|
22639
|
+
throw new Error(
|
|
22640
|
+
`${path2} is missing, so the credentials in custody cannot be opened`
|
|
22641
|
+
);
|
|
22642
|
+
return key;
|
|
22643
|
+
}
|
|
22644
|
+
function overwriteInPlace(path2) {
|
|
22645
|
+
let fd2;
|
|
22646
|
+
try {
|
|
22647
|
+
const size = statSync3(path2).size;
|
|
22648
|
+
fd2 = openSync4(path2, "r+");
|
|
22649
|
+
writeSync3(fd2, randomBytes5(Math.max(size, KEY_BYTES2 * 2)), 0, void 0, 0);
|
|
22650
|
+
fsyncSync3(fd2);
|
|
22651
|
+
} catch (error) {
|
|
22652
|
+
if (error.code !== "ENOENT") throw error;
|
|
22653
|
+
} finally {
|
|
22654
|
+
if (fd2 !== void 0) closeSync4(fd2);
|
|
22655
|
+
}
|
|
22656
|
+
}
|
|
22657
|
+
function seal(key, secret, aad) {
|
|
22658
|
+
const nonce = randomBytes5(12);
|
|
22659
|
+
const cipher = createCipheriv("aes-256-gcm", key, nonce);
|
|
22660
|
+
cipher.setAAD(Buffer.from(aad, "utf8"));
|
|
22661
|
+
const ciphertext = Buffer.concat([
|
|
22662
|
+
cipher.update(secret, "utf8"),
|
|
22663
|
+
cipher.final()
|
|
22664
|
+
]);
|
|
22665
|
+
return {
|
|
22666
|
+
nonce: nonce.toString("base64"),
|
|
22667
|
+
ciphertext: ciphertext.toString("base64"),
|
|
22668
|
+
tag: cipher.getAuthTag().toString("base64")
|
|
22669
|
+
};
|
|
22670
|
+
}
|
|
22671
|
+
function open(key, sealed, aad) {
|
|
22672
|
+
const decipher = createDecipheriv(
|
|
22673
|
+
"aes-256-gcm",
|
|
22674
|
+
key,
|
|
22675
|
+
Buffer.from(sealed.nonce, "base64")
|
|
22676
|
+
);
|
|
22677
|
+
decipher.setAAD(Buffer.from(aad, "utf8"));
|
|
22678
|
+
decipher.setAuthTag(Buffer.from(sealed.tag, "base64"));
|
|
22679
|
+
return Buffer.concat([
|
|
22680
|
+
decipher.update(Buffer.from(sealed.ciphertext, "base64")),
|
|
22681
|
+
decipher.final()
|
|
22682
|
+
]).toString("utf8");
|
|
22683
|
+
}
|
|
22684
|
+
function credentialPrefix(secret) {
|
|
22685
|
+
const head2 = secret.slice(0, Math.min(8, Math.max(0, secret.length - 4)));
|
|
22686
|
+
return head2.length > 0 ? `${head2}\u2026` : "";
|
|
22687
|
+
}
|
|
22688
|
+
function custodyOf(entry2) {
|
|
22689
|
+
return {
|
|
22690
|
+
provider: entry2.provider,
|
|
22691
|
+
kind: entry2.kind,
|
|
22692
|
+
source: entry2.source,
|
|
22693
|
+
taken_at: entry2.taken_at,
|
|
22694
|
+
prefix: entry2.prefix
|
|
22695
|
+
};
|
|
22696
|
+
}
|
|
22697
|
+
function openCredentialStore(paths) {
|
|
22698
|
+
let entriesSeen;
|
|
22699
|
+
let keySeen;
|
|
22700
|
+
const keyForWrite = () => loadOrCreateKey(paths.key);
|
|
22701
|
+
function forgetKey() {
|
|
22702
|
+
keySeen?.key.fill(0);
|
|
22703
|
+
keySeen = void 0;
|
|
22704
|
+
}
|
|
22705
|
+
function keyForRead() {
|
|
22706
|
+
const version2 = fileVersion(paths.key);
|
|
22707
|
+
if (version2 !== void 0 && keySeen?.version === version2)
|
|
22708
|
+
return keySeen.key;
|
|
22709
|
+
forgetKey();
|
|
22710
|
+
const key = requireKey(paths.key);
|
|
22711
|
+
if (version2 !== void 0) keySeen = { version: version2, key };
|
|
22712
|
+
return key;
|
|
22713
|
+
}
|
|
22714
|
+
function readAll() {
|
|
22715
|
+
const version2 = fileVersion(paths.file);
|
|
22716
|
+
if (version2 === void 0) {
|
|
22717
|
+
entriesSeen = void 0;
|
|
22718
|
+
forgetKey();
|
|
22719
|
+
return [];
|
|
22720
|
+
}
|
|
22721
|
+
if (entriesSeen?.version === version2) return entriesSeen.entries;
|
|
22722
|
+
let text5;
|
|
22723
|
+
try {
|
|
22724
|
+
text5 = readFileSync7(paths.file, "utf8");
|
|
22725
|
+
} catch (error) {
|
|
22726
|
+
if (error.code === "ENOENT") return [];
|
|
22727
|
+
throw error;
|
|
22728
|
+
}
|
|
22729
|
+
let raw;
|
|
22730
|
+
try {
|
|
22731
|
+
raw = JSON.parse(text5);
|
|
22732
|
+
} catch (error) {
|
|
22733
|
+
throw new Error(
|
|
22734
|
+
`${paths.file} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`
|
|
22735
|
+
);
|
|
22736
|
+
}
|
|
22737
|
+
const parsed2 = fileSchema.safeParse(raw);
|
|
22738
|
+
if (!parsed2.success)
|
|
22739
|
+
throw new Error(
|
|
22740
|
+
`${paths.file} is not a credential store this build can read: ${parsed2.error.issues[0]?.message ?? "invalid"}`
|
|
22741
|
+
);
|
|
22742
|
+
entriesSeen = { version: version2, entries: parsed2.data.entries };
|
|
22743
|
+
return parsed2.data.entries;
|
|
22744
|
+
}
|
|
22745
|
+
function writeAll2(entries2) {
|
|
22746
|
+
if (entries2.length === 0) {
|
|
22747
|
+
if (existsSync5(paths.file)) unlinkSync4(paths.file);
|
|
22748
|
+
return;
|
|
22749
|
+
}
|
|
22750
|
+
writeSensitiveFileAtomic(
|
|
22751
|
+
paths.file,
|
|
22752
|
+
`${JSON.stringify({ schema: CREDENTIAL_STORE_SCHEMA, entries: entries2 }, null, 2)}
|
|
22753
|
+
`
|
|
22754
|
+
);
|
|
22755
|
+
}
|
|
22756
|
+
return {
|
|
22757
|
+
has: (provider) => readAll().some((e) => e.provider === provider),
|
|
22758
|
+
read: (provider) => {
|
|
22759
|
+
const entry2 = readAll().find((e) => e.provider === provider);
|
|
22760
|
+
if (entry2 === void 0) return void 0;
|
|
22761
|
+
return {
|
|
22762
|
+
kind: entry2.kind,
|
|
22763
|
+
secret: open(
|
|
22764
|
+
keyForRead(),
|
|
22765
|
+
entry2.sealed,
|
|
22766
|
+
`${CREDENTIAL_STORE_SCHEMA}:${provider}`
|
|
22767
|
+
)
|
|
22768
|
+
};
|
|
22769
|
+
},
|
|
22770
|
+
take: (provider, { kind, secret }, source, now) => {
|
|
22771
|
+
if (secret.trim().length === 0)
|
|
22772
|
+
throw new Error("refusing to take an empty credential into custody");
|
|
22773
|
+
const entry2 = {
|
|
22774
|
+
provider,
|
|
22775
|
+
kind,
|
|
22776
|
+
source,
|
|
22777
|
+
taken_at: new Date(now).toISOString(),
|
|
22778
|
+
// A ChatGPT login is JSON, whose head says nothing; it is named.
|
|
22779
|
+
prefix: kind === "chatgpt" ? "login" : credentialPrefix(secret),
|
|
22780
|
+
sealed: seal(
|
|
22781
|
+
keyForWrite(),
|
|
22782
|
+
secret,
|
|
22783
|
+
`${CREDENTIAL_STORE_SCHEMA}:${provider}`
|
|
22784
|
+
)
|
|
22785
|
+
};
|
|
22786
|
+
writeAll2([...readAll().filter((e) => e.provider !== provider), entry2]);
|
|
22787
|
+
return custodyOf(entry2);
|
|
22788
|
+
},
|
|
22789
|
+
release: (provider) => {
|
|
22790
|
+
const entries2 = readAll();
|
|
22791
|
+
const entry2 = entries2.find((e) => e.provider === provider);
|
|
22792
|
+
if (entry2 === void 0) return void 0;
|
|
22793
|
+
const secret = open(
|
|
22794
|
+
keyForRead(),
|
|
22795
|
+
entry2.sealed,
|
|
22796
|
+
`${CREDENTIAL_STORE_SCHEMA}:${provider}`
|
|
22797
|
+
);
|
|
22798
|
+
writeAll2(entries2.filter((e) => e.provider !== provider));
|
|
22799
|
+
return { kind: entry2.kind, secret };
|
|
22800
|
+
},
|
|
22801
|
+
status: () => readAll().map(custodyOf),
|
|
22802
|
+
shred: () => {
|
|
22803
|
+
let overwrite;
|
|
22804
|
+
try {
|
|
22805
|
+
overwriteInPlace(paths.key);
|
|
22806
|
+
} catch (error) {
|
|
22807
|
+
overwrite = error;
|
|
22808
|
+
}
|
|
22809
|
+
for (const path2 of [paths.file, paths.key])
|
|
22810
|
+
if (existsSync5(path2)) unlinkSync4(path2);
|
|
22811
|
+
entriesSeen = void 0;
|
|
22812
|
+
forgetKey();
|
|
22813
|
+
if (overwrite !== void 0)
|
|
22814
|
+
throw new Error(
|
|
22815
|
+
`${paths.key} was deleted but could not be overwritten first: ${overwrite instanceof Error ? overwrite.message : String(overwrite)}`
|
|
22816
|
+
);
|
|
22817
|
+
}
|
|
22818
|
+
};
|
|
22819
|
+
}
|
|
22820
|
+
var CREDENTIAL_STORE_SCHEMA, CREDENTIAL_SOURCES, CREDENTIAL_KINDS, CLAUDE_OAUTH_TOKEN_PREFIX, sealedSchema, entrySchema, fileSchema, KEY_BYTES2;
|
|
22821
|
+
var init_credential_store = __esm({
|
|
22822
|
+
"../../packages/tacho/src/host/credential-store.ts"() {
|
|
22823
|
+
"use strict";
|
|
22824
|
+
init_zod();
|
|
22825
|
+
init_fs();
|
|
22826
|
+
init_run_token();
|
|
22827
|
+
CREDENTIAL_STORE_SCHEMA = "tacho.credentials.v1";
|
|
22828
|
+
CREDENTIAL_SOURCES = [
|
|
22829
|
+
/** `env.ANTHROPIC_API_KEY` in Claude Code's user settings. */
|
|
22830
|
+
"claude-code:settings.env",
|
|
22831
|
+
/** `OPENAI_API_KEY`, or the ChatGPT login's `tokens`, in Codex's `auth.json`. */
|
|
22832
|
+
"codex:auth.json",
|
|
22833
|
+
/** A ChatGPT login the gateway refreshed, replacing the one it took. */
|
|
22834
|
+
"chatgpt:refresh",
|
|
22835
|
+
/**
|
|
22836
|
+
* `TACHO_BROKER_<PROVIDER>_API_KEY`, or `CLAUDE_CODE_OAUTH_TOKEN`, in the
|
|
22837
|
+
* enrolling shell.
|
|
22838
|
+
*/
|
|
22839
|
+
"enroll:env",
|
|
22840
|
+
/**
|
|
22841
|
+
* The subscription token `claude setup-token` printed, which
|
|
22842
|
+
* `oxagen credential login` took straight into custody.
|
|
22843
|
+
*/
|
|
22844
|
+
"claude:setup-token",
|
|
22845
|
+
/**
|
|
22846
|
+
* The run token in an Oxagen Agent Runners sandbox's `launch` message. It
|
|
22847
|
+
* is spent at the cloud gateway, which attaches the operator's model
|
|
22848
|
+
* credential. It is not a model credential itself.
|
|
22849
|
+
*/
|
|
22850
|
+
"sandbox:launch"
|
|
22851
|
+
];
|
|
22852
|
+
CREDENTIAL_KINDS = [
|
|
22853
|
+
"api_key",
|
|
22854
|
+
"bearer",
|
|
22855
|
+
"oauth",
|
|
22856
|
+
"chatgpt"
|
|
22857
|
+
];
|
|
22858
|
+
CLAUDE_OAUTH_TOKEN_PREFIX = "sk-ant-oat";
|
|
22859
|
+
sealedSchema = external_exports.object({
|
|
22860
|
+
/** AES-256-GCM: 12-byte nonce, ciphertext, 16-byte tag, all base64. */
|
|
22861
|
+
nonce: external_exports.string().min(1),
|
|
22862
|
+
ciphertext: external_exports.string().min(1),
|
|
22863
|
+
tag: external_exports.string().min(1)
|
|
22864
|
+
}).strict();
|
|
22865
|
+
entrySchema = external_exports.object({
|
|
22866
|
+
provider: external_exports.enum(RUN_TOKEN_PROVIDERS),
|
|
22867
|
+
kind: external_exports.enum(CREDENTIAL_KINDS),
|
|
22868
|
+
source: external_exports.enum(CREDENTIAL_SOURCES),
|
|
22869
|
+
taken_at: external_exports.string(),
|
|
22870
|
+
/** The first few characters, the way a vendor console shows a key. */
|
|
22871
|
+
prefix: external_exports.string().max(12),
|
|
22872
|
+
sealed: sealedSchema
|
|
22873
|
+
}).strict();
|
|
22874
|
+
fileSchema = external_exports.object({
|
|
22875
|
+
schema: external_exports.literal(CREDENTIAL_STORE_SCHEMA),
|
|
22876
|
+
entries: external_exports.array(entrySchema)
|
|
22877
|
+
}).strict();
|
|
22878
|
+
KEY_BYTES2 = 32;
|
|
22879
|
+
}
|
|
22880
|
+
});
|
|
22881
|
+
|
|
22882
|
+
// ../../packages/tacho/src/host/claude-setup-token.ts
|
|
22883
|
+
import { spawn } from "node:child_process";
|
|
22884
|
+
import { accessSync as accessSync2, constants as constants2 } from "node:fs";
|
|
22885
|
+
import { delimiter, join as join13 } from "node:path";
|
|
22886
|
+
function isSubscriptionToken(value) {
|
|
22887
|
+
return TOKEN.test(value.trim());
|
|
22888
|
+
}
|
|
22889
|
+
function extractSetupToken(output) {
|
|
22890
|
+
const lines = output.replace(ANSI, "").split(/\r?\n|\r/).map((line) => line.trim());
|
|
22891
|
+
let found;
|
|
22892
|
+
for (let i2 = 0; i2 < lines.length; i2++) {
|
|
22893
|
+
const line = lines[i2];
|
|
22894
|
+
const start = line.lastIndexOf(CLAUDE_OAUTH_TOKEN_PREFIX);
|
|
22895
|
+
if (start < 0) continue;
|
|
22896
|
+
let token = "";
|
|
22897
|
+
for (const char of line.slice(start)) {
|
|
22898
|
+
if (!TOKEN_CHAR.test(char)) break;
|
|
22899
|
+
token += char;
|
|
22900
|
+
}
|
|
22901
|
+
if (token.length === line.length - start)
|
|
22902
|
+
for (let j = i2 + 1; j < lines.length; j++) {
|
|
22903
|
+
const next = lines[j];
|
|
22904
|
+
if (next.length === 0 || ![...next].every((c) => TOKEN_CHAR.test(c)))
|
|
22905
|
+
break;
|
|
22906
|
+
token += next;
|
|
22907
|
+
}
|
|
22908
|
+
if (isSubscriptionToken(token)) found = token;
|
|
22909
|
+
}
|
|
22910
|
+
return found;
|
|
22911
|
+
}
|
|
22912
|
+
function findClaudeBinary(env, home) {
|
|
22913
|
+
return findHarnessBinary("claude", env, home);
|
|
22914
|
+
}
|
|
22915
|
+
function findHarnessBinary(name, env, home) {
|
|
22916
|
+
const file = process.platform === "win32" ? `${name}.exe` : name;
|
|
22917
|
+
const candidates = [
|
|
22918
|
+
...(env["PATH"] ?? "").split(delimiter).filter((d) => d.length > 0),
|
|
22919
|
+
join13(home, ".local", "bin"),
|
|
22920
|
+
join13(home, ".claude", "local"),
|
|
22921
|
+
join13(home, ".npm-global", "bin"),
|
|
22922
|
+
"/opt/homebrew/bin",
|
|
22923
|
+
"/usr/local/bin"
|
|
22924
|
+
].map((dir) => join13(dir, file));
|
|
22925
|
+
for (const path2 of candidates) {
|
|
22926
|
+
try {
|
|
22927
|
+
accessSync2(path2, constants2.X_OK);
|
|
22928
|
+
return path2;
|
|
22929
|
+
} catch {
|
|
22930
|
+
}
|
|
22931
|
+
}
|
|
22932
|
+
return void 0;
|
|
22933
|
+
}
|
|
22934
|
+
function setupTokenCommand(claude, platform) {
|
|
22935
|
+
const quoted3 = `'${claude.replace(/'/g, `'\\''`)}'`;
|
|
22936
|
+
const inner = `stty cols 1000 2>/dev/null; exec ${quoted3} setup-token`;
|
|
22937
|
+
if (platform === "darwin")
|
|
22938
|
+
return { file: "script", args: ["-q", "/dev/null", "sh", "-c", inner] };
|
|
22939
|
+
if (platform === "linux")
|
|
22940
|
+
return { file: "script", args: ["-q", "-e", "-c", inner, "/dev/null"] };
|
|
22941
|
+
return void 0;
|
|
22942
|
+
}
|
|
22943
|
+
function runClaudeSetupToken(options) {
|
|
22944
|
+
const command2 = setupTokenCommand(
|
|
22945
|
+
options.claude,
|
|
22946
|
+
options.platform ?? process.platform
|
|
22947
|
+
);
|
|
22948
|
+
return new Promise((resolve25, reject) => {
|
|
22949
|
+
if (command2 === void 0) {
|
|
22950
|
+
const child2 = spawn(options.claude, ["setup-token"], {
|
|
22951
|
+
stdio: "inherit",
|
|
22952
|
+
env: options.env ?? process.env
|
|
22953
|
+
});
|
|
22954
|
+
child2.on("error", reject);
|
|
22955
|
+
child2.on(
|
|
22956
|
+
"close",
|
|
22957
|
+
(code) => resolve25({ token: void 0, code: code ?? 1, captured: false })
|
|
22958
|
+
);
|
|
22959
|
+
return;
|
|
22960
|
+
}
|
|
22961
|
+
const child = spawn(command2.file, command2.args, {
|
|
22962
|
+
stdio: [options.interactive ? "inherit" : "pipe", "pipe", "inherit"],
|
|
22963
|
+
env: options.env ?? process.env
|
|
22964
|
+
});
|
|
22965
|
+
let output = "";
|
|
22966
|
+
child.stdout?.setEncoding("utf8");
|
|
22967
|
+
child.stdout?.on("data", (chunk2) => {
|
|
22968
|
+
output += chunk2;
|
|
22969
|
+
options.write(chunk2);
|
|
22970
|
+
});
|
|
22971
|
+
child.on("error", reject);
|
|
22972
|
+
child.on("close", (code) => {
|
|
22973
|
+
child.stdin?.destroy();
|
|
22974
|
+
resolve25({
|
|
22975
|
+
token: extractSetupToken(output),
|
|
22976
|
+
code: code ?? 1,
|
|
22977
|
+
captured: true
|
|
22978
|
+
});
|
|
22979
|
+
});
|
|
22980
|
+
});
|
|
22981
|
+
}
|
|
22982
|
+
var TOKEN, TOKEN_CHAR, ANSI;
|
|
22983
|
+
var init_claude_setup_token = __esm({
|
|
22984
|
+
"../../packages/tacho/src/host/claude-setup-token.ts"() {
|
|
22985
|
+
"use strict";
|
|
22986
|
+
init_credential_store();
|
|
22987
|
+
TOKEN = /^sk-ant-oat\d{2}-[A-Za-z0-9_-]{20,}$/;
|
|
22988
|
+
TOKEN_CHAR = /[A-Za-z0-9_-]/;
|
|
22989
|
+
ANSI = // biome-ignore lint/suspicious/noControlCharactersInRegex: terminal escapes
|
|
22990
|
+
/\u001b\][^\u0007\u001b]*(?:\u0007|\u001b\\)|\u001b\[[0-?]*[ -/]*[@-~]|\u001b[@-Z\\-_]/g;
|
|
22991
|
+
}
|
|
22992
|
+
});
|
|
22993
|
+
|
|
22425
22994
|
// ../../packages/tacho/src/host/model-base-url-toml.ts
|
|
22426
22995
|
function splitLines(text5) {
|
|
22427
22996
|
const lines = [];
|
|
@@ -22539,8 +23108,8 @@ var init_model_base_url_toml = __esm({
|
|
|
22539
23108
|
});
|
|
22540
23109
|
|
|
22541
23110
|
// ../../packages/tacho/src/host/model-base-url.ts
|
|
22542
|
-
import { chmodSync as chmodSync3, existsSync as
|
|
22543
|
-
import { basename as basename4, dirname as dirname7, join as
|
|
23111
|
+
import { chmodSync as chmodSync3, existsSync as existsSync6, readFileSync as readFileSync8, unlinkSync as unlinkSync5 } from "node:fs";
|
|
23112
|
+
import { basename as basename4, dirname as dirname7, join as join14 } from "node:path";
|
|
22544
23113
|
function claudeToolSearchEnabled(value) {
|
|
22545
23114
|
return typeof value === "string" && /^(true|auto(:\d+)?)$/i.test(value);
|
|
22546
23115
|
}
|
|
@@ -22554,19 +23123,19 @@ function isModelProxyBaseUrl(harness, value) {
|
|
|
22554
23123
|
}
|
|
22555
23124
|
function modelBaseUrlFile(harness, homes) {
|
|
22556
23125
|
if (harness === "claude-code")
|
|
22557
|
-
return
|
|
23126
|
+
return join14(
|
|
22558
23127
|
homes.claudeConfigDir ?? harnessConfigDirs(homes.home).claudeConfigDir,
|
|
22559
23128
|
"settings.json"
|
|
22560
23129
|
);
|
|
22561
23130
|
if (harness === "codex")
|
|
22562
|
-
return
|
|
23131
|
+
return join14(
|
|
22563
23132
|
homes.codexHome ?? harnessConfigDirs(homes.home).codexHome,
|
|
22564
23133
|
"config.toml"
|
|
22565
23134
|
);
|
|
22566
|
-
const stellaHome = homes.stellaHome ??
|
|
22567
|
-
const toml =
|
|
22568
|
-
const json2 =
|
|
22569
|
-
return !
|
|
23135
|
+
const stellaHome = homes.stellaHome ?? join14(homes.home, ".stella");
|
|
23136
|
+
const toml = join14(stellaHome, "stella.toml");
|
|
23137
|
+
const json2 = join14(stellaHome, "settings.json");
|
|
23138
|
+
return !existsSync6(toml) && existsSync6(json2) ? json2 : toml;
|
|
22570
23139
|
}
|
|
22571
23140
|
function keyLabel(harness) {
|
|
22572
23141
|
if (harness === "claude-code") return `env.${CLAUDE_KEY}`;
|
|
@@ -22576,7 +23145,7 @@ function isJsonFile(file) {
|
|
|
22576
23145
|
return file.endsWith(".json");
|
|
22577
23146
|
}
|
|
22578
23147
|
function sidecarBeside(file, contract) {
|
|
22579
|
-
return
|
|
23148
|
+
return join14(dirname7(file), `.${basename4(file)}.${contract}.json`);
|
|
22580
23149
|
}
|
|
22581
23150
|
function sidecarFor(file) {
|
|
22582
23151
|
return sidecarBeside(file, "oxagen-model-base-url");
|
|
@@ -22707,9 +23276,9 @@ function stellaManagedSettingsPath(platform = process.platform, env = process.en
|
|
|
22707
23276
|
const named = env["STELLA_MANAGED_SETTINGS"];
|
|
22708
23277
|
if (named !== void 0 && named.length > 0) return named;
|
|
22709
23278
|
const dir = platform === "darwin" ? "/Library/Application Support/stella" : "/etc/stella";
|
|
22710
|
-
const toml =
|
|
22711
|
-
const json2 =
|
|
22712
|
-
return !
|
|
23279
|
+
const toml = join14(dir, "stella.toml");
|
|
23280
|
+
const json2 = join14(dir, "settings.json");
|
|
23281
|
+
return !existsSync6(toml) && existsSync6(json2) ? json2 : toml;
|
|
22713
23282
|
}
|
|
22714
23283
|
function managedShadow(harness, managedFile, expected) {
|
|
22715
23284
|
try {
|
|
@@ -22917,7 +23486,7 @@ function describe3(harness, options, { changed, text: text5, sidecar, unreadable
|
|
|
22917
23486
|
}
|
|
22918
23487
|
function readBytesIfExists(path2) {
|
|
22919
23488
|
try {
|
|
22920
|
-
return
|
|
23489
|
+
return readFileSync8(path2);
|
|
22921
23490
|
} catch (error) {
|
|
22922
23491
|
if (error.code === "ENOENT") return void 0;
|
|
22923
23492
|
throw error;
|
|
@@ -23031,7 +23600,7 @@ function restoreOne(harness, options) {
|
|
|
23031
23600
|
const { sidecar, unreadable } = sidecarOrWhy(backup, harness);
|
|
23032
23601
|
const text5 = readTextIfExists(file);
|
|
23033
23602
|
const dropSidecar = () => {
|
|
23034
|
-
if (
|
|
23603
|
+
if (existsSync6(backup)) unlinkSync5(backup);
|
|
23035
23604
|
};
|
|
23036
23605
|
const after = (changed, left) => ({
|
|
23037
23606
|
changed,
|
|
@@ -23050,7 +23619,7 @@ function restoreOne(harness, options) {
|
|
|
23050
23619
|
writeFileAtomicPreserving(file, original);
|
|
23051
23620
|
left = original.toString("utf8");
|
|
23052
23621
|
} else {
|
|
23053
|
-
|
|
23622
|
+
unlinkSync5(file);
|
|
23054
23623
|
}
|
|
23055
23624
|
dropSidecar();
|
|
23056
23625
|
return after(true, left);
|
|
@@ -23163,186 +23732,66 @@ var init_model_base_url = __esm({
|
|
|
23163
23732
|
}
|
|
23164
23733
|
});
|
|
23165
23734
|
|
|
23166
|
-
// ../../packages/tacho/src/host/
|
|
23167
|
-
import {
|
|
23168
|
-
import {
|
|
23169
|
-
function
|
|
23170
|
-
|
|
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"));
|
|
23735
|
+
// ../../packages/tacho/src/host/model-credential.ts
|
|
23736
|
+
import { chmodSync as chmodSync4, existsSync as existsSync7, lstatSync as lstatSync2, unlinkSync as unlinkSync6 } from "node:fs";
|
|
23737
|
+
import { join as join15 } from "node:path";
|
|
23738
|
+
function claudeMemberFor(kind) {
|
|
23739
|
+
return kind === "oauth" ? CLAUDE_OAUTH_TOKEN : kind === "bearer" ? CLAUDE_AUTH_TOKEN : CLAUDE_API_KEY;
|
|
23185
23740
|
}
|
|
23186
|
-
function
|
|
23187
|
-
|
|
23188
|
-
|
|
23189
|
-
|
|
23190
|
-
|
|
23191
|
-
|
|
23192
|
-
|
|
23193
|
-
|
|
23741
|
+
function claudeEnvCredentials(env) {
|
|
23742
|
+
const found = [];
|
|
23743
|
+
for (const [member3, kind] of CLAUDE_MEMBERS) {
|
|
23744
|
+
const value = env[member3];
|
|
23745
|
+
if (isSecret(value))
|
|
23746
|
+
found.push({
|
|
23747
|
+
member: member3,
|
|
23748
|
+
credential: {
|
|
23749
|
+
kind: anthropicCredentialKind(value, kind),
|
|
23750
|
+
secret: value
|
|
23751
|
+
}
|
|
23752
|
+
});
|
|
23194
23753
|
}
|
|
23195
|
-
|
|
23196
|
-
writeSensitiveFileAtomic(path2, `${key.bytes.toString("hex")}
|
|
23197
|
-
`);
|
|
23198
|
-
return { key, created: true };
|
|
23754
|
+
return found;
|
|
23199
23755
|
}
|
|
23200
|
-
function
|
|
23201
|
-
const
|
|
23202
|
-
if (
|
|
23203
|
-
keysSeen.delete(path2);
|
|
23756
|
+
function chatGptTokensOf(auth) {
|
|
23757
|
+
const tokens = auth[CODEX_TOKENS];
|
|
23758
|
+
if (typeof tokens !== "object" || tokens === null || Array.isArray(tokens))
|
|
23204
23759
|
return void 0;
|
|
23205
|
-
|
|
23206
|
-
|
|
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();
|
|
23760
|
+
const record = tokens;
|
|
23761
|
+
return isSecret(record["access_token"]) ? record : void 0;
|
|
23223
23762
|
}
|
|
23224
|
-
function
|
|
23225
|
-
const
|
|
23226
|
-
|
|
23227
|
-
|
|
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
|
|
23763
|
+
function encodeChatGptLogin(tokens) {
|
|
23764
|
+
const login = {
|
|
23765
|
+
access_token: tokens["access_token"],
|
|
23766
|
+
refresh_token: typeof tokens["refresh_token"] === "string" ? tokens["refresh_token"] : ""
|
|
23242
23767
|
};
|
|
23243
|
-
|
|
23244
|
-
|
|
23245
|
-
|
|
23246
|
-
|
|
23247
|
-
|
|
23248
|
-
return typeof value === "string" && value.startsWith(RUN_TOKEN_PREFIX) && value.length < 2048;
|
|
23768
|
+
if (typeof tokens["id_token"] === "string")
|
|
23769
|
+
login.id_token = tokens["id_token"];
|
|
23770
|
+
if (typeof tokens["account_id"] === "string")
|
|
23771
|
+
login.account_id = tokens["account_id"];
|
|
23772
|
+
return JSON.stringify(login);
|
|
23249
23773
|
}
|
|
23250
|
-
function
|
|
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;
|
|
23774
|
+
function decodeChatGptLogin(secret) {
|
|
23255
23775
|
try {
|
|
23256
|
-
const
|
|
23257
|
-
|
|
23258
|
-
|
|
23259
|
-
|
|
23260
|
-
|
|
23776
|
+
const raw = JSON.parse(secret);
|
|
23777
|
+
if (typeof raw.access_token !== "string" || raw.access_token.length === 0)
|
|
23778
|
+
return void 0;
|
|
23779
|
+
return {
|
|
23780
|
+
access_token: raw.access_token,
|
|
23781
|
+
refresh_token: typeof raw.refresh_token === "string" ? raw.refresh_token : "",
|
|
23782
|
+
...typeof raw.id_token === "string" ? { id_token: raw.id_token } : {},
|
|
23783
|
+
...typeof raw.account_id === "string" ? { account_id: raw.account_id } : {}
|
|
23784
|
+
};
|
|
23261
23785
|
} catch {
|
|
23262
23786
|
return void 0;
|
|
23263
23787
|
}
|
|
23264
23788
|
}
|
|
23265
|
-
function
|
|
23266
|
-
|
|
23267
|
-
|
|
23268
|
-
const
|
|
23269
|
-
|
|
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
|
-
}
|
|
23789
|
+
function codexTokenMember(auth) {
|
|
23790
|
+
const tokens = chatGptTokensOf(auth);
|
|
23791
|
+
if (tokens !== void 0) return tokens["access_token"];
|
|
23792
|
+
const key = auth[CODEX_KEY2];
|
|
23793
|
+
return typeof key === "string" ? key : void 0;
|
|
23310
23794
|
}
|
|
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
23795
|
function isTachoHelper(value) {
|
|
23347
23796
|
return typeof value === "string" && HELPER_MARK.test(value);
|
|
23348
23797
|
}
|
|
@@ -23350,10 +23799,10 @@ function helperCommandFor(tachoCommand) {
|
|
|
23350
23799
|
return `${tachoCommand} credential issue --harness claude-code`;
|
|
23351
23800
|
}
|
|
23352
23801
|
function fileFor2(harness, homes) {
|
|
23353
|
-
return harness === "claude-code" ?
|
|
23802
|
+
return harness === "claude-code" ? join15(
|
|
23354
23803
|
homes.claudeConfigDir ?? harnessConfigDirs(homes.home).claudeConfigDir,
|
|
23355
23804
|
"settings.json"
|
|
23356
|
-
) :
|
|
23805
|
+
) : join15(
|
|
23357
23806
|
homes.codexHome ?? harnessConfigDirs(homes.home).codexHome,
|
|
23358
23807
|
"auth.json"
|
|
23359
23808
|
);
|
|
@@ -23396,7 +23845,9 @@ function readSidecar2(path2, harness) {
|
|
|
23396
23845
|
existed: parsed2["existed"] === true,
|
|
23397
23846
|
written_sha256: written2,
|
|
23398
23847
|
taken: Array.isArray(taken) ? taken.filter(
|
|
23399
|
-
(t) => typeof t === "object" && t !== null && typeof t.member === "string" && (
|
|
23848
|
+
(t) => typeof t === "object" && t !== null && typeof t.member === "string" && CREDENTIAL_KINDS.includes(
|
|
23849
|
+
t.kind
|
|
23850
|
+
)
|
|
23400
23851
|
) : []
|
|
23401
23852
|
};
|
|
23402
23853
|
if (harness === "codex") return { ...common, harness };
|
|
@@ -23419,7 +23870,7 @@ function isSecret(value) {
|
|
|
23419
23870
|
return typeof value === "string" && value.length > 0;
|
|
23420
23871
|
}
|
|
23421
23872
|
function holdsBothClaudeMembers(env) {
|
|
23422
|
-
return
|
|
23873
|
+
return CLAUDE_MEMBERS.filter(([member3]) => isSecret(env[member3])).length > 1;
|
|
23423
23874
|
}
|
|
23424
23875
|
function managedHelperShadow(managedFile, expected) {
|
|
23425
23876
|
try {
|
|
@@ -23469,7 +23920,7 @@ function describe4(harness, options, { changed, text: text5, reason: reason3, un
|
|
|
23469
23920
|
const current = settings[HELPER_KEY];
|
|
23470
23921
|
helper = typeof current === "string" ? current : null;
|
|
23471
23922
|
const env = envOf(settings) ?? {};
|
|
23472
|
-
brokered = isTachoHelper(current) &&
|
|
23923
|
+
brokered = isTachoHelper(current) && CLAUDE_MEMBERS.every(([member3]) => typeof env[member3] !== "string");
|
|
23473
23924
|
if (!brokered && holdsBothClaudeMembers(env)) why ??= "two_credentials";
|
|
23474
23925
|
const managed = managedHelperShadow(
|
|
23475
23926
|
internals.managedSettingsFile ?? claudeManagedSettingsPath(),
|
|
@@ -23479,14 +23930,14 @@ function describe4(harness, options, { changed, text: text5, reason: reason3, un
|
|
|
23479
23930
|
if (managed.unreadable !== void 0) unreadable.push(managed.unreadable);
|
|
23480
23931
|
} else {
|
|
23481
23932
|
const auth = parseForReport(text5, file, unreadable);
|
|
23482
|
-
const key = auth
|
|
23483
|
-
brokered = looksLikeRunToken(
|
|
23933
|
+
const key = codexTokenMember(auth);
|
|
23934
|
+
brokered = looksLikeRunToken(key);
|
|
23484
23935
|
if (brokered) {
|
|
23485
23936
|
const claims = peekRunTokenClaims(key);
|
|
23486
23937
|
if (claims !== void 0)
|
|
23487
23938
|
tokenExpiresAt = new Date(claims.exp).toISOString();
|
|
23488
23939
|
}
|
|
23489
|
-
if (!brokered && why === void 0 && auth[
|
|
23940
|
+
if (!brokered && why === void 0 && auth[CODEX_TOKENS] !== void 0)
|
|
23490
23941
|
why = "subscription_login";
|
|
23491
23942
|
}
|
|
23492
23943
|
return {
|
|
@@ -23519,21 +23970,15 @@ function applyClaude(options, taken) {
|
|
|
23519
23970
|
return { changed: false, text: text5, reason: "two_credentials" };
|
|
23520
23971
|
const rest = { ...env ?? {} };
|
|
23521
23972
|
const took = [];
|
|
23522
|
-
for (const
|
|
23523
|
-
|
|
23524
|
-
|
|
23525
|
-
|
|
23526
|
-
|
|
23527
|
-
|
|
23528
|
-
|
|
23529
|
-
|
|
23530
|
-
|
|
23531
|
-
credential: { kind, secret: value },
|
|
23532
|
-
member: `env.${member3}`
|
|
23533
|
-
});
|
|
23534
|
-
took.push({ member: member3, kind });
|
|
23535
|
-
delete rest[member3];
|
|
23536
|
-
}
|
|
23973
|
+
for (const { member: member3, credential } of claudeEnvCredentials(rest)) {
|
|
23974
|
+
taken.push({
|
|
23975
|
+
harness: "claude-code",
|
|
23976
|
+
provider: "anthropic",
|
|
23977
|
+
credential,
|
|
23978
|
+
member: `env.${member3}`
|
|
23979
|
+
});
|
|
23980
|
+
took.push({ member: member3, kind: credential.kind });
|
|
23981
|
+
delete rest[member3];
|
|
23537
23982
|
}
|
|
23538
23983
|
const helperCommand = options.helperCommand;
|
|
23539
23984
|
if (helperCommand === void 0)
|
|
@@ -23581,7 +24026,49 @@ function applyCodex(options, taken) {
|
|
|
23581
24026
|
const existing = readSidecar2(backup, "codex");
|
|
23582
24027
|
const current = auth[CODEX_KEY2];
|
|
23583
24028
|
const hasKey = typeof current === "string" && current.length > 0;
|
|
23584
|
-
|
|
24029
|
+
const tokens = chatGptTokensOf(auth);
|
|
24030
|
+
if (tokens !== void 0) {
|
|
24031
|
+
const access2 = tokens["access_token"];
|
|
24032
|
+
const ours = looksLikeRunToken(access2);
|
|
24033
|
+
if (!ours)
|
|
24034
|
+
taken.push({
|
|
24035
|
+
harness: "codex",
|
|
24036
|
+
provider: "openai",
|
|
24037
|
+
credential: { kind: "chatgpt", secret: encodeChatGptLogin(tokens) },
|
|
24038
|
+
member: CODEX_TOKENS
|
|
24039
|
+
});
|
|
24040
|
+
if (token === void 0) {
|
|
24041
|
+
if (!ours) taken.pop();
|
|
24042
|
+
return { changed: false, text: text5, reason: "no_token" };
|
|
24043
|
+
}
|
|
24044
|
+
if (access2 === token && existing !== void 0)
|
|
24045
|
+
return { changed: false, text: text5 };
|
|
24046
|
+
auth[CODEX_TOKENS] = {
|
|
24047
|
+
...tokens,
|
|
24048
|
+
access_token: token,
|
|
24049
|
+
refresh_token: CHATGPT_REFRESH_HELD
|
|
24050
|
+
};
|
|
24051
|
+
auth[CODEX_LAST_REFRESH] = (/* @__PURE__ */ new Date()).toISOString();
|
|
24052
|
+
const next2 = serializeJsonLike(text5, auth);
|
|
24053
|
+
const sidecar2 = existing ? {
|
|
24054
|
+
...existing,
|
|
24055
|
+
written_sha256: sha256Hex(next2),
|
|
24056
|
+
taken: [
|
|
24057
|
+
...existing.taken.filter((t) => t.member !== CODEX_TOKENS),
|
|
24058
|
+
{ member: CODEX_TOKENS, kind: "chatgpt" }
|
|
24059
|
+
]
|
|
24060
|
+
} : {
|
|
24061
|
+
schema: SIDECAR_SCHEMA2,
|
|
24062
|
+
harness: "codex",
|
|
24063
|
+
existed: true,
|
|
24064
|
+
written_sha256: sha256Hex(next2),
|
|
24065
|
+
taken: [{ member: CODEX_TOKENS, kind: "chatgpt" }]
|
|
24066
|
+
};
|
|
24067
|
+
writeSidecar(backup, sidecar2);
|
|
24068
|
+
writeFileAtomicPreserving(file, next2);
|
|
24069
|
+
return { changed: true, text: next2 };
|
|
24070
|
+
}
|
|
24071
|
+
if (auth[CODEX_TOKENS] !== void 0 && !looksLikeRunToken(typeof current === "string" ? current : void 0)) {
|
|
23585
24072
|
return { changed: false, text: text5, reason: "subscription_login" };
|
|
23586
24073
|
}
|
|
23587
24074
|
if (hasKey && !looksLikeRunToken(current)) {
|
|
@@ -23616,11 +24103,11 @@ function restoreClaude(options, released, sidecar) {
|
|
|
23616
24103
|
const backup = sidecarFor2(file);
|
|
23617
24104
|
const text5 = readTextIfExists(file);
|
|
23618
24105
|
const dropSidecar = () => {
|
|
23619
|
-
if (
|
|
24106
|
+
if (existsSync7(backup)) unlinkSync6(backup);
|
|
23620
24107
|
};
|
|
23621
24108
|
if (text5 === void 0) {
|
|
23622
24109
|
if (released !== void 0) {
|
|
23623
|
-
const member3 = released.kind
|
|
24110
|
+
const member3 = claudeMemberFor(released.kind);
|
|
23624
24111
|
const written2 = serializeJsonLike(void 0, {
|
|
23625
24112
|
env: { [member3]: released.secret }
|
|
23626
24113
|
});
|
|
@@ -23640,11 +24127,11 @@ function restoreClaude(options, released, sidecar) {
|
|
|
23640
24127
|
touched = true;
|
|
23641
24128
|
}
|
|
23642
24129
|
const current = envOf(settings);
|
|
23643
|
-
const foreignKey = current !== void 0 && (
|
|
24130
|
+
const foreignKey = current !== void 0 && CLAUDE_MEMBERS.some(([member3]) => isSecret(current[member3]));
|
|
23644
24131
|
const why = foreignKey ? { reason: "foreign_key_present" } : {};
|
|
23645
24132
|
let secretRestored = false;
|
|
23646
24133
|
if (released !== void 0 && !foreignKey) {
|
|
23647
|
-
const member3 = sidecar?.taken.find((t) => t.kind === released.kind)?.member ?? (released.kind
|
|
24134
|
+
const member3 = sidecar?.taken.find((t) => t.kind === released.kind)?.member ?? claudeMemberFor(released.kind);
|
|
23648
24135
|
const env = { ...current ?? {} };
|
|
23649
24136
|
env[member3] = released.secret;
|
|
23650
24137
|
settings["env"] = env;
|
|
@@ -23674,7 +24161,7 @@ function restoreCodex(options, released, sidecar) {
|
|
|
23674
24161
|
const backup = sidecarFor2(file);
|
|
23675
24162
|
const text5 = readTextIfExists(file);
|
|
23676
24163
|
const dropSidecar = () => {
|
|
23677
|
-
if (
|
|
24164
|
+
if (existsSync7(backup)) unlinkSync6(backup);
|
|
23678
24165
|
};
|
|
23679
24166
|
if (text5 === void 0) {
|
|
23680
24167
|
if (released !== void 0) {
|
|
@@ -23689,6 +24176,18 @@ function restoreCodex(options, released, sidecar) {
|
|
|
23689
24176
|
return { changed: false, text: text5, secretRestored: false };
|
|
23690
24177
|
}
|
|
23691
24178
|
const auth = parseJsonObject(text5, file);
|
|
24179
|
+
const tokens = chatGptTokensOf(auth);
|
|
24180
|
+
if (tokens !== void 0 && looksLikeRunToken(tokens["access_token"])) {
|
|
24181
|
+
const login = released?.kind === "chatgpt" ? decodeChatGptLogin(released.secret) : void 0;
|
|
24182
|
+
if (login !== void 0) {
|
|
24183
|
+
auth[CODEX_TOKENS] = { ...tokens, ...login };
|
|
24184
|
+
auth[CODEX_LAST_REFRESH] = (/* @__PURE__ */ new Date()).toISOString();
|
|
24185
|
+
} else delete auth[CODEX_TOKENS];
|
|
24186
|
+
const next2 = serializeJsonLike(text5, auth);
|
|
24187
|
+
writeFileAtomicPreserving(file, next2);
|
|
24188
|
+
dropSidecar();
|
|
24189
|
+
return { changed: true, text: next2, secretRestored: login !== void 0 };
|
|
24190
|
+
}
|
|
23692
24191
|
const current = auth[CODEX_KEY2];
|
|
23693
24192
|
if (!looksLikeRunToken(typeof current === "string" ? current : void 0)) {
|
|
23694
24193
|
dropSidecar();
|
|
@@ -23702,7 +24201,7 @@ function restoreCodex(options, released, sidecar) {
|
|
|
23702
24201
|
if (released !== void 0) auth[CODEX_KEY2] = released.secret;
|
|
23703
24202
|
else delete auth[CODEX_KEY2];
|
|
23704
24203
|
if (sidecar !== void 0 && !sidecar.existed && Object.keys(auth).length === 0) {
|
|
23705
|
-
|
|
24204
|
+
unlinkSync6(file);
|
|
23706
24205
|
dropSidecar();
|
|
23707
24206
|
return {
|
|
23708
24207
|
changed: true,
|
|
@@ -23765,22 +24264,30 @@ async function peekModelCredentials(options) {
|
|
|
23765
24264
|
if (harness === "claude-code") {
|
|
23766
24265
|
const env = envOf(document) ?? {};
|
|
23767
24266
|
if (holdsBothClaudeMembers(env)) continue;
|
|
23768
|
-
for (const
|
|
23769
|
-
|
|
23770
|
-
|
|
23771
|
-
|
|
23772
|
-
|
|
23773
|
-
|
|
24267
|
+
for (const { member: member3, credential } of claudeEnvCredentials(env))
|
|
24268
|
+
taken.push({
|
|
24269
|
+
harness,
|
|
24270
|
+
provider: "anthropic",
|
|
24271
|
+
credential,
|
|
24272
|
+
member: `env.${member3}`
|
|
24273
|
+
});
|
|
24274
|
+
} else {
|
|
24275
|
+
const tokens = chatGptTokensOf(document);
|
|
24276
|
+
if (tokens !== void 0) {
|
|
24277
|
+
if (!looksLikeRunToken(tokens["access_token"]))
|
|
23774
24278
|
taken.push({
|
|
23775
24279
|
harness,
|
|
23776
|
-
provider: "
|
|
23777
|
-
credential: {
|
|
23778
|
-
|
|
24280
|
+
provider: "openai",
|
|
24281
|
+
credential: {
|
|
24282
|
+
kind: "chatgpt",
|
|
24283
|
+
secret: encodeChatGptLogin(tokens)
|
|
24284
|
+
},
|
|
24285
|
+
member: CODEX_TOKENS
|
|
23779
24286
|
});
|
|
24287
|
+
continue;
|
|
23780
24288
|
}
|
|
23781
|
-
} else {
|
|
23782
24289
|
const current = document[CODEX_KEY2];
|
|
23783
|
-
if (document[
|
|
24290
|
+
if (document[CODEX_TOKENS] === void 0 && typeof current === "string" && current.length > 0 && !looksLikeRunToken(current))
|
|
23784
24291
|
taken.push({
|
|
23785
24292
|
harness,
|
|
23786
24293
|
provider: "openai",
|
|
@@ -23806,8 +24313,8 @@ function hasOrphanedModelCredential(harness, home, dirs = {}) {
|
|
|
23806
24313
|
try {
|
|
23807
24314
|
const document = parseJsonObject(text5, file);
|
|
23808
24315
|
if (harness === "claude-code") return isTachoHelper(document[HELPER_KEY]);
|
|
23809
|
-
const key = document
|
|
23810
|
-
return looksLikeRunToken(
|
|
24316
|
+
const key = codexTokenMember(document);
|
|
24317
|
+
return looksLikeRunToken(key);
|
|
23811
24318
|
} catch {
|
|
23812
24319
|
return text5.includes("credential issue --harness") || text5.includes("oxrt_");
|
|
23813
24320
|
}
|
|
@@ -23829,24 +24336,46 @@ function staticTokenStillGood(token, host, keyPath2, now) {
|
|
|
23829
24336
|
});
|
|
23830
24337
|
return verdict.ok && verdict.claims.exp - now > staticTokenRenewWindowMs(host, now);
|
|
23831
24338
|
}
|
|
24339
|
+
function restateCodexLastRefresh(home, now, dirs = {}) {
|
|
24340
|
+
const file = fileFor2("codex", { ...dirs, home });
|
|
24341
|
+
const text5 = readTextIfExists(file);
|
|
24342
|
+
if (text5 === void 0 || isSymlink(file)) return false;
|
|
24343
|
+
const auth = parseJsonObject(text5, file);
|
|
24344
|
+
const tokens = chatGptTokensOf(auth);
|
|
24345
|
+
if (tokens === void 0 || !looksLikeRunToken(tokens["access_token"]))
|
|
24346
|
+
return false;
|
|
24347
|
+
const last = Date.parse(
|
|
24348
|
+
typeof auth[CODEX_LAST_REFRESH] === "string" ? auth[CODEX_LAST_REFRESH] : ""
|
|
24349
|
+
);
|
|
24350
|
+
if (Number.isFinite(last) && now - last < CODEX_LAST_REFRESH_RESTATE_MS)
|
|
24351
|
+
return false;
|
|
24352
|
+
auth[CODEX_LAST_REFRESH] = new Date(now).toISOString();
|
|
24353
|
+
const next = serializeJsonLike(text5, auth);
|
|
24354
|
+
const backup = sidecarFor2(file);
|
|
24355
|
+
const sidecar = readSidecar2(backup, "codex");
|
|
24356
|
+
if (sidecar !== void 0)
|
|
24357
|
+
writeSidecar(backup, { ...sidecar, written_sha256: sha256Hex(next) });
|
|
24358
|
+
writeFileAtomicPreserving(file, next);
|
|
24359
|
+
return true;
|
|
24360
|
+
}
|
|
23832
24361
|
function readCodexApiKeyMember(home, dirs = {}) {
|
|
23833
24362
|
const file = fileFor2("codex", { ...dirs, home });
|
|
23834
24363
|
try {
|
|
23835
24364
|
const text5 = readTextIfExists(file);
|
|
23836
24365
|
if (text5 === void 0) return void 0;
|
|
23837
|
-
|
|
23838
|
-
return typeof value === "string" ? value : void 0;
|
|
24366
|
+
return codexTokenMember(parseJsonObject(text5, file));
|
|
23839
24367
|
} catch {
|
|
23840
24368
|
return void 0;
|
|
23841
24369
|
}
|
|
23842
24370
|
}
|
|
23843
|
-
var HARNESS_PROVIDER, SIDECAR_SCHEMA2, HELPER_KEY, CLAUDE_API_KEY, CLAUDE_AUTH_TOKEN, CODEX_KEY2, HELPER_MARK, STATIC_TOKEN_RENEW_WINDOW_MS;
|
|
24371
|
+
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
24372
|
var init_model_credential = __esm({
|
|
23845
24373
|
"../../packages/tacho/src/host/model-credential.ts"() {
|
|
23846
24374
|
"use strict";
|
|
23847
24375
|
init_digest();
|
|
23848
24376
|
init_fs();
|
|
23849
24377
|
init_wire();
|
|
24378
|
+
init_credential_store();
|
|
23850
24379
|
init_model_base_url();
|
|
23851
24380
|
init_paths();
|
|
23852
24381
|
init_run_token();
|
|
@@ -23855,14 +24384,24 @@ var init_model_credential = __esm({
|
|
|
23855
24384
|
HELPER_KEY = "apiKeyHelper";
|
|
23856
24385
|
CLAUDE_API_KEY = "ANTHROPIC_API_KEY";
|
|
23857
24386
|
CLAUDE_AUTH_TOKEN = "ANTHROPIC_AUTH_TOKEN";
|
|
24387
|
+
CLAUDE_OAUTH_TOKEN = "CLAUDE_CODE_OAUTH_TOKEN";
|
|
24388
|
+
CLAUDE_MEMBERS = [
|
|
24389
|
+
[CLAUDE_API_KEY, "api_key"],
|
|
24390
|
+
[CLAUDE_AUTH_TOKEN, "bearer"],
|
|
24391
|
+
[CLAUDE_OAUTH_TOKEN, "oauth"]
|
|
24392
|
+
];
|
|
23858
24393
|
CODEX_KEY2 = "OPENAI_API_KEY";
|
|
24394
|
+
CODEX_TOKENS = "tokens";
|
|
24395
|
+
CODEX_LAST_REFRESH = "last_refresh";
|
|
24396
|
+
CHATGPT_REFRESH_HELD = "held-by-oxagen-gateway";
|
|
23859
24397
|
HELPER_MARK = /\bcredential issue --harness claude-code\s*$/;
|
|
23860
24398
|
STATIC_TOKEN_RENEW_WINDOW_MS = 7 * 24 * 60 * 6e4;
|
|
24399
|
+
CODEX_LAST_REFRESH_RESTATE_MS = 5 * 24 * 60 * 6e4;
|
|
23861
24400
|
}
|
|
23862
24401
|
});
|
|
23863
24402
|
|
|
23864
24403
|
// ../../packages/tacho/src/cli/credential.ts
|
|
23865
|
-
import { existsSync as
|
|
24404
|
+
import { existsSync as existsSync8 } from "node:fs";
|
|
23866
24405
|
import { dirname as dirname8 } from "node:path";
|
|
23867
24406
|
function harnessDirsOf(deps) {
|
|
23868
24407
|
return {
|
|
@@ -23982,15 +24521,15 @@ function describeHarness(entry2) {
|
|
|
23982
24521
|
}
|
|
23983
24522
|
switch (entry2.reason) {
|
|
23984
24523
|
case "subscription_login":
|
|
23985
|
-
return `${label2}: signed in with a ChatGPT login
|
|
24524
|
+
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
24525
|
case "symlink":
|
|
23987
24526
|
return `${label2}: ${entry2.file} is a symbolic link, so it was left alone; its own credential crosses the proxy`;
|
|
23988
24527
|
case "no_file":
|
|
23989
24528
|
return `${label2}: no ${entry2.file} yet; its own credential crosses the proxy`;
|
|
23990
24529
|
case "two_credentials":
|
|
23991
|
-
return `${label2}: ${entry2.file} sets
|
|
24530
|
+
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
24531
|
default:
|
|
23993
|
-
return `${label2}: holds its own credential, which crosses the proxy (run \`oxagen agent enroll\` to broker it)`;
|
|
24532
|
+
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
24533
|
}
|
|
23995
24534
|
}
|
|
23996
24535
|
async function brokerCredentials(host, harnesses, deps) {
|
|
@@ -24018,11 +24557,17 @@ async function brokerCredentials(host, harnesses, deps) {
|
|
|
24018
24557
|
if (!offered.has(provider) && typeof fromEnv === "string" && fromEnv.trim().length > 0)
|
|
24019
24558
|
offered.set(provider, {
|
|
24020
24559
|
credential: {
|
|
24021
|
-
kind: provider === "anthropic" ? "api_key" : "bearer",
|
|
24560
|
+
kind: provider === "anthropic" ? anthropicCredentialKind(fromEnv, "api_key") : "bearer",
|
|
24022
24561
|
secret: fromEnv.trim()
|
|
24023
24562
|
},
|
|
24024
24563
|
source: "enroll:env"
|
|
24025
24564
|
});
|
|
24565
|
+
const oauth = deps.env[CLAUDE_OAUTH_TOKEN_ENV]?.trim();
|
|
24566
|
+
if (provider === "anthropic" && !offered.has(provider) && oauth !== void 0 && isSubscriptionToken(oauth))
|
|
24567
|
+
offered.set(provider, {
|
|
24568
|
+
credential: { kind: "oauth", secret: oauth },
|
|
24569
|
+
source: "enroll:env"
|
|
24570
|
+
});
|
|
24026
24571
|
}
|
|
24027
24572
|
const takenNow = [];
|
|
24028
24573
|
const staticTokens = {};
|
|
@@ -24033,8 +24578,7 @@ async function brokerCredentials(host, harnesses, deps) {
|
|
|
24033
24578
|
takenNow.push(provider);
|
|
24034
24579
|
}
|
|
24035
24580
|
if (targets.includes("codex") && store.has("openai")) {
|
|
24036
|
-
|
|
24037
|
-
if (before?.reason !== "subscription_login") {
|
|
24581
|
+
{
|
|
24038
24582
|
const current = readCodexApiKeyMember(deps.home, harnessDirsOf(deps));
|
|
24039
24583
|
if (!staticTokenStillGood(
|
|
24040
24584
|
current,
|
|
@@ -24085,7 +24629,7 @@ async function brokerCredentials(host, harnesses, deps) {
|
|
|
24085
24629
|
reason: "no_token"
|
|
24086
24630
|
};
|
|
24087
24631
|
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
|
|
24632
|
+
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
24633
|
);
|
|
24090
24634
|
}
|
|
24091
24635
|
continue;
|
|
@@ -24131,7 +24675,7 @@ async function restoreCredentials(host, deps, mode = "unenroll", only) {
|
|
|
24131
24675
|
try {
|
|
24132
24676
|
if (host !== void 0 && !host.harnesses.includes(harness)) {
|
|
24133
24677
|
const dirs = harnessDirsOf(deps);
|
|
24134
|
-
const hasReceipt =
|
|
24678
|
+
const hasReceipt = existsSync8(
|
|
24135
24679
|
modelCredentialBackupPath(harness, deps.home, dirs)
|
|
24136
24680
|
);
|
|
24137
24681
|
if (!hasReceipt && !hasOrphanedModelCredential(harness, deps.home, dirs))
|
|
@@ -24141,8 +24685,13 @@ async function restoreCredentials(host, deps, mode = "unenroll", only) {
|
|
|
24141
24685
|
const label2 = TACHO_HARNESS_LABELS[harness];
|
|
24142
24686
|
let released;
|
|
24143
24687
|
let unreadable;
|
|
24688
|
+
let fromLogin = false;
|
|
24144
24689
|
try {
|
|
24145
|
-
|
|
24690
|
+
fromLogin = store?.status().some(
|
|
24691
|
+
(c) => c.provider === provider && c.source === "claude:setup-token"
|
|
24692
|
+
) === true;
|
|
24693
|
+
if (fromLogin) store?.release(provider);
|
|
24694
|
+
else released = store?.read(provider);
|
|
24146
24695
|
} catch (error) {
|
|
24147
24696
|
unreadable = error instanceof Error ? error.message : String(error);
|
|
24148
24697
|
}
|
|
@@ -24186,10 +24735,200 @@ async function restoreCredentials(host, deps, mode = "unenroll", only) {
|
|
|
24186
24735
|
}
|
|
24187
24736
|
return { restored, failed: failed3, warnings, custodyUnreadable };
|
|
24188
24737
|
}
|
|
24189
|
-
|
|
24738
|
+
async function acquireSubscriptionToken(options, deps) {
|
|
24739
|
+
const io = deps.subscriptionLogin;
|
|
24740
|
+
if (options.tokenStdin === true) {
|
|
24741
|
+
const text5 = (await io?.readStdin())?.trim() ?? "";
|
|
24742
|
+
return isSubscriptionToken(text5) ? { token: text5, source: "claude:setup-token" } : {
|
|
24743
|
+
detail: "stdin did not hold a Claude subscription token (sk-ant-oat\u2026). Pipe in what `claude setup-token` printed"
|
|
24744
|
+
};
|
|
24745
|
+
}
|
|
24746
|
+
const fromEnv = deps.env[CLAUDE_OAUTH_TOKEN_ENV]?.trim();
|
|
24747
|
+
if (fromEnv !== void 0 && isSubscriptionToken(fromEnv))
|
|
24748
|
+
return { token: fromEnv, source: "enroll:env" };
|
|
24749
|
+
if (io === void 0)
|
|
24750
|
+
return {
|
|
24751
|
+
detail: `no Claude subscription token: set ${CLAUDE_OAUTH_TOKEN_ENV} or pipe one in with --token-stdin`
|
|
24752
|
+
};
|
|
24753
|
+
const claude = io.findClaude();
|
|
24754
|
+
if (claude === void 0)
|
|
24755
|
+
return {
|
|
24756
|
+
detail: "Claude Code is not installed, so `claude setup-token` cannot run. Install it, or pipe a token in with --token-stdin"
|
|
24757
|
+
};
|
|
24758
|
+
deps.out(
|
|
24759
|
+
"Signing in to your Claude subscription with `claude setup-token`. Finish the sign-in in your browser."
|
|
24760
|
+
);
|
|
24761
|
+
const run3 = await io.runSetupToken(
|
|
24762
|
+
claude,
|
|
24763
|
+
(chunk2) => process.stdout.write(
|
|
24764
|
+
chunk2.replace(/sk-ant-oat[A-Za-z0-9_-]*/g, "sk-ant-oat\u2026 (sent to Oxagen)")
|
|
24765
|
+
)
|
|
24766
|
+
);
|
|
24767
|
+
if (run3.token !== void 0)
|
|
24768
|
+
return { token: run3.token, source: "claude:setup-token" };
|
|
24769
|
+
if (io.interactive) {
|
|
24770
|
+
const pasted = await io.promptSecret(
|
|
24771
|
+
"Paste the token `claude setup-token` printed (sk-ant-oat\u2026): "
|
|
24772
|
+
);
|
|
24773
|
+
if (pasted !== void 0 && isSubscriptionToken(pasted))
|
|
24774
|
+
return { token: pasted, source: "claude:setup-token" };
|
|
24775
|
+
return {
|
|
24776
|
+
detail: pasted === void 0 || pasted.length === 0 ? "no token was pasted" : "that is not a Claude subscription token (sk-ant-oat\u2026)"
|
|
24777
|
+
};
|
|
24778
|
+
}
|
|
24779
|
+
return {
|
|
24780
|
+
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`
|
|
24781
|
+
};
|
|
24782
|
+
}
|
|
24783
|
+
async function signInIfNoCredential(harnesses, deps) {
|
|
24784
|
+
const store = deps.credentialStore;
|
|
24785
|
+
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({
|
|
24786
|
+
home: deps.home,
|
|
24787
|
+
harnesses: ["codex"]
|
|
24788
|
+
}) ?? []).length === 0) {
|
|
24789
|
+
const why = await ensureCodexLogin(deps);
|
|
24790
|
+
if (why !== void 0)
|
|
24791
|
+
deps.err(
|
|
24792
|
+
`warning: ChatGPT sign-in for Codex did not finish (${why}). Run \`oxagen credential login --harness codex\` to try again`
|
|
24793
|
+
);
|
|
24794
|
+
}
|
|
24795
|
+
if (!harnesses.includes("claude-code") || store === void 0 || deps.subscriptionLogin?.interactive !== true || store.has("anthropic"))
|
|
24796
|
+
return;
|
|
24797
|
+
if ([brokerEnvVar("anthropic"), CLAUDE_OAUTH_TOKEN_ENV].some(
|
|
24798
|
+
(name) => (deps.env[name]?.trim() ?? "").length > 0
|
|
24799
|
+
))
|
|
24800
|
+
return;
|
|
24801
|
+
const inFile = await deps.modelCredentials?.peek({
|
|
24802
|
+
home: deps.home,
|
|
24803
|
+
harnesses: ["claude-code"],
|
|
24804
|
+
helperCommand: deps.runtime.credentialHelperCommand
|
|
24805
|
+
});
|
|
24806
|
+
if ((inFile ?? []).some((t) => t.provider === "anthropic")) return;
|
|
24807
|
+
const acquired = await acquireSubscriptionToken({}, deps);
|
|
24808
|
+
if (acquired.token === void 0) {
|
|
24809
|
+
deps.err(
|
|
24810
|
+
`warning: Claude subscription sign-in did not finish (${acquired.detail}). Run \`oxagen credential login\` to try again`
|
|
24811
|
+
);
|
|
24812
|
+
return;
|
|
24813
|
+
}
|
|
24814
|
+
const custody = store.take(
|
|
24815
|
+
"anthropic",
|
|
24816
|
+
{ kind: "oauth", secret: acquired.token },
|
|
24817
|
+
acquired.source,
|
|
24818
|
+
deps.now()
|
|
24819
|
+
);
|
|
24820
|
+
deps.out(
|
|
24821
|
+
` Claude subscription ${custody.prefix} taken into the gateway's custody`
|
|
24822
|
+
);
|
|
24823
|
+
}
|
|
24824
|
+
async function routedToGateway(host, harness, deps) {
|
|
24825
|
+
if (deps.modelBaseUrls === void 0) return false;
|
|
24826
|
+
try {
|
|
24827
|
+
const state = await deps.modelBaseUrls.read({
|
|
24828
|
+
home: deps.home,
|
|
24829
|
+
stellaHome: dirname8(deps.paths.stellaToml),
|
|
24830
|
+
port: modelProxyPortFor(host),
|
|
24831
|
+
harnesses: [harness]
|
|
24832
|
+
});
|
|
24833
|
+
const entry2 = state.harnesses.find((h) => h.harness === harness);
|
|
24834
|
+
return entry2?.ours === true && entry2.shadowedBy === void 0;
|
|
24835
|
+
} catch {
|
|
24836
|
+
return false;
|
|
24837
|
+
}
|
|
24838
|
+
}
|
|
24839
|
+
async function codexHasChatGptLogin(deps) {
|
|
24840
|
+
const offered = await deps.modelCredentials?.peek({
|
|
24841
|
+
home: deps.home,
|
|
24842
|
+
harnesses: ["codex"]
|
|
24843
|
+
});
|
|
24844
|
+
return (offered ?? []).some((t) => t.credential.kind === "chatgpt");
|
|
24845
|
+
}
|
|
24846
|
+
async function ensureCodexLogin(deps) {
|
|
24847
|
+
if (await codexHasChatGptLogin(deps)) return void 0;
|
|
24848
|
+
const io = deps.subscriptionLogin;
|
|
24849
|
+
const codex = io?.findCodex();
|
|
24850
|
+
if (io === void 0 || codex === void 0)
|
|
24851
|
+
return "Codex is not installed, so `codex login` cannot run. Install it and try again";
|
|
24852
|
+
deps.out(
|
|
24853
|
+
"Signing in to ChatGPT with `codex login`. Finish the sign-in in your browser."
|
|
24854
|
+
);
|
|
24855
|
+
const code = await io.runCodexLogin(codex);
|
|
24856
|
+
if (code !== 0) return `\`codex login\` exited with ${code}`;
|
|
24857
|
+
return await codexHasChatGptLogin(deps) ? void 0 : "`codex login` finished, but ~/.codex/auth.json holds no ChatGPT login";
|
|
24858
|
+
}
|
|
24859
|
+
async function codexLogin(deps) {
|
|
24860
|
+
const store = deps.credentialStore;
|
|
24861
|
+
const held = store?.status().some(
|
|
24862
|
+
(c) => c.provider === "openai" && c.kind === "chatgpt"
|
|
24863
|
+
);
|
|
24864
|
+
if (held !== true) {
|
|
24865
|
+
const why = await ensureCodexLogin(deps);
|
|
24866
|
+
if (why !== void 0)
|
|
24867
|
+
return { ok: false, harnesses: [], warnings: [], detail: why };
|
|
24868
|
+
}
|
|
24869
|
+
const host = readHostFileLenient(deps.paths.hostFile).host;
|
|
24870
|
+
if (host === void 0 || !host.harnesses.includes("codex") || !await routedToGateway(host, "codex", deps))
|
|
24871
|
+
return {
|
|
24872
|
+
ok: true,
|
|
24873
|
+
harnesses: [],
|
|
24874
|
+
warnings: [],
|
|
24875
|
+
detail: "Codex is signed in to ChatGPT. Run `oxagen agent enroll --harness codex` to route it through the gateway, which then holds the login"
|
|
24876
|
+
};
|
|
24877
|
+
const outcome = await brokerCredentials(host, ["codex"], deps);
|
|
24878
|
+
return {
|
|
24879
|
+
ok: true,
|
|
24880
|
+
source: "codex:auth.json",
|
|
24881
|
+
harnesses: outcome.harnesses,
|
|
24882
|
+
warnings: outcome.warnings,
|
|
24883
|
+
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"
|
|
24884
|
+
};
|
|
24885
|
+
}
|
|
24886
|
+
async function credentialLogin(options, deps) {
|
|
24887
|
+
const store = deps.credentialStore;
|
|
24888
|
+
if (store === void 0)
|
|
24889
|
+
return {
|
|
24890
|
+
ok: false,
|
|
24891
|
+
harnesses: [],
|
|
24892
|
+
warnings: [],
|
|
24893
|
+
detail: "this build holds no credential store"
|
|
24894
|
+
};
|
|
24895
|
+
if (options.harness === "codex") return codexLogin(deps);
|
|
24896
|
+
const acquired = await acquireSubscriptionToken(options, deps);
|
|
24897
|
+
if (acquired.token === void 0)
|
|
24898
|
+
return { ok: false, harnesses: [], warnings: [], detail: acquired.detail };
|
|
24899
|
+
const custody = store.take(
|
|
24900
|
+
"anthropic",
|
|
24901
|
+
{ kind: "oauth", secret: acquired.token },
|
|
24902
|
+
acquired.source,
|
|
24903
|
+
deps.now()
|
|
24904
|
+
);
|
|
24905
|
+
deps.out(
|
|
24906
|
+
`Claude subscription ${custody.prefix} taken into the gateway's custody (${deps.paths.credentials})`
|
|
24907
|
+
);
|
|
24908
|
+
const host = readHostFileLenient(deps.paths.hostFile).host;
|
|
24909
|
+
if (host === void 0 || !host.harnesses.includes("claude-code") || !await routedToGateway(host, "claude-code", deps))
|
|
24910
|
+
return {
|
|
24911
|
+
ok: true,
|
|
24912
|
+
source: acquired.source,
|
|
24913
|
+
harnesses: [],
|
|
24914
|
+
warnings: [],
|
|
24915
|
+
detail: "Run `oxagen agent enroll` to route Claude Code through the gateway. It will use this subscription"
|
|
24916
|
+
};
|
|
24917
|
+
const outcome = await brokerCredentials(host, ["claude-code"], deps);
|
|
24918
|
+
return {
|
|
24919
|
+
ok: true,
|
|
24920
|
+
source: acquired.source,
|
|
24921
|
+
harnesses: outcome.harnesses,
|
|
24922
|
+
warnings: outcome.warnings,
|
|
24923
|
+
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"
|
|
24924
|
+
};
|
|
24925
|
+
}
|
|
24926
|
+
var MODEL_CREDENTIAL_HARNESSES, CREDENTIAL_MODES, CLAUDE_OAUTH_TOKEN_ENV;
|
|
24190
24927
|
var init_credential = __esm({
|
|
24191
24928
|
"../../packages/tacho/src/cli/credential.ts"() {
|
|
24192
24929
|
"use strict";
|
|
24930
|
+
init_claude_setup_token();
|
|
24931
|
+
init_credential_store();
|
|
24193
24932
|
init_host_file();
|
|
24194
24933
|
init_model_credential();
|
|
24195
24934
|
init_agents();
|
|
@@ -24202,11 +24941,12 @@ var init_credential = __esm({
|
|
|
24202
24941
|
"brokered",
|
|
24203
24942
|
"passthrough"
|
|
24204
24943
|
];
|
|
24944
|
+
CLAUDE_OAUTH_TOKEN_ENV = "CLAUDE_CODE_OAUTH_TOKEN";
|
|
24205
24945
|
}
|
|
24206
24946
|
});
|
|
24207
24947
|
|
|
24208
24948
|
// ../../packages/tacho/src/host/codex-app-server.ts
|
|
24209
|
-
import { spawn } from "node:child_process";
|
|
24949
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
24210
24950
|
function cmdArgument(value) {
|
|
24211
24951
|
let quoted3 = "";
|
|
24212
24952
|
let slashes = 0;
|
|
@@ -24244,7 +24984,7 @@ function codexAppServerClient(options) {
|
|
|
24244
24984
|
let child;
|
|
24245
24985
|
try {
|
|
24246
24986
|
const invocation = spawnInvocation(options.binary, ["app-server"]);
|
|
24247
|
-
child =
|
|
24987
|
+
child = spawn2(invocation.command, invocation.args, {
|
|
24248
24988
|
cwd: options.cwd,
|
|
24249
24989
|
env: options.env,
|
|
24250
24990
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -24377,266 +25117,6 @@ var init_codex_app_server = __esm({
|
|
|
24377
25117
|
}
|
|
24378
25118
|
});
|
|
24379
25119
|
|
|
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
25120
|
// ../../packages/tacho/src/host/claude-config-lock.ts
|
|
24641
25121
|
import { mkdirSync as mkdirSync4, rmdirSync as rmdirSync3, statSync as statSync4 } from "node:fs";
|
|
24642
25122
|
function sleepSync(ms) {
|
|
@@ -24709,7 +25189,7 @@ var init_claude_config_lock = __esm({
|
|
|
24709
25189
|
});
|
|
24710
25190
|
|
|
24711
25191
|
// ../../packages/tacho/src/host/service.ts
|
|
24712
|
-
import { join as
|
|
25192
|
+
import { join as join16 } from "node:path";
|
|
24713
25193
|
import {
|
|
24714
25194
|
existsSync as existsSync9,
|
|
24715
25195
|
readdirSync as readdirSync6,
|
|
@@ -24794,8 +25274,8 @@ function blockingSleep(ms) {
|
|
|
24794
25274
|
}
|
|
24795
25275
|
function launchdManager(options) {
|
|
24796
25276
|
const sleep2 = options.sleep ?? blockingSleep;
|
|
24797
|
-
const dir =
|
|
24798
|
-
const unitPath =
|
|
25277
|
+
const dir = join16(options.home, "Library", "LaunchAgents");
|
|
25278
|
+
const unitPath = join16(dir, `${SERVICE_LABEL}.plist`);
|
|
24799
25279
|
const domain = `gui/${options.uid ?? process.getuid?.() ?? 501}`;
|
|
24800
25280
|
const target2 = `${domain}/${SERVICE_LABEL}`;
|
|
24801
25281
|
const loaded = () => options.exec("launchctl", ["print", target2]).status === 0;
|
|
@@ -24900,9 +25380,9 @@ function stopByPidFile(options) {
|
|
|
24900
25380
|
);
|
|
24901
25381
|
}
|
|
24902
25382
|
function systemdManager(options) {
|
|
24903
|
-
const dir =
|
|
24904
|
-
const unitPath =
|
|
24905
|
-
const wants =
|
|
25383
|
+
const dir = join16(options.home, ".config", "systemd", "user");
|
|
25384
|
+
const unitPath = join16(dir, "tachod.service");
|
|
25385
|
+
const wants = join16(dir, "default.target.wants");
|
|
24906
25386
|
return {
|
|
24907
25387
|
kind: "systemd",
|
|
24908
25388
|
unitPath,
|
|
@@ -25053,8 +25533,8 @@ function windowsCreatedMs(exec4, pid) {
|
|
|
25053
25533
|
return result2.status === 0 && /^\d+$/.test(text5) ? Number(text5) : void 0;
|
|
25054
25534
|
}
|
|
25055
25535
|
function schtasksManager(options) {
|
|
25056
|
-
const launcher = options.launcherPath ??
|
|
25057
|
-
const pidPath = options.pidPath ??
|
|
25536
|
+
const launcher = options.launcherPath ?? join16(options.home, "tachod.cmd");
|
|
25537
|
+
const pidPath = options.pidPath ?? join16(launcher, "..", "tachod.pid");
|
|
25058
25538
|
const liveRecord = () => {
|
|
25059
25539
|
if (!existsSync9(pidPath)) return void 0;
|
|
25060
25540
|
const record = parseDaemonPid(readFileSync9(pidPath, "utf8"));
|
|
@@ -25099,7 +25579,7 @@ function schtasksManager(options) {
|
|
|
25099
25579
|
unitPath: launcher,
|
|
25100
25580
|
install: (spec) => {
|
|
25101
25581
|
stopDaemon();
|
|
25102
|
-
ensureDir(
|
|
25582
|
+
ensureDir(join16(launcher, ".."), 493);
|
|
25103
25583
|
writeSensitiveFileAtomic(
|
|
25104
25584
|
launcher,
|
|
25105
25585
|
renderWindowsLauncher(
|
|
@@ -25231,7 +25711,7 @@ import { readFileSync as readFileSync10 } from "node:fs";
|
|
|
25231
25711
|
import { dirname as dirname9, resolve as resolve3 } from "node:path";
|
|
25232
25712
|
import { fileURLToPath } from "node:url";
|
|
25233
25713
|
function readVersion() {
|
|
25234
|
-
if (true) return "2.1.4-
|
|
25714
|
+
if (true) return "2.1.4-965";
|
|
25235
25715
|
try {
|
|
25236
25716
|
const here = dirname9(fileURLToPath(import.meta.url));
|
|
25237
25717
|
const pkg = JSON.parse(
|
|
@@ -25251,7 +25731,7 @@ var init_version = __esm({
|
|
|
25251
25731
|
});
|
|
25252
25732
|
|
|
25253
25733
|
// ../../packages/tacho/src/cli/deps.ts
|
|
25254
|
-
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
25734
|
+
import { spawn as spawn3, spawnSync as spawnSync4 } from "node:child_process";
|
|
25255
25735
|
import { randomBytes as randomBytes7 } from "node:crypto";
|
|
25256
25736
|
import { existsSync as existsSync10 } from "node:fs";
|
|
25257
25737
|
import { get as httpGet, request as httpRequest } from "node:http";
|
|
@@ -25550,6 +26030,63 @@ function settleOrThrow(harnessFiles) {
|
|
|
25550
26030
|
);
|
|
25551
26031
|
return outcomes;
|
|
25552
26032
|
}
|
|
26033
|
+
function promptHidden(question) {
|
|
26034
|
+
const stdin = process.stdin;
|
|
26035
|
+
if (!stdin.isTTY) return Promise.resolve(void 0);
|
|
26036
|
+
return new Promise((resolve25) => {
|
|
26037
|
+
process.stderr.write(question);
|
|
26038
|
+
let value = "";
|
|
26039
|
+
stdin.setRawMode(true);
|
|
26040
|
+
stdin.resume();
|
|
26041
|
+
stdin.setEncoding("utf8");
|
|
26042
|
+
const done = (answer) => {
|
|
26043
|
+
stdin.setRawMode(false);
|
|
26044
|
+
stdin.pause();
|
|
26045
|
+
stdin.off("data", onData);
|
|
26046
|
+
process.stderr.write("\n");
|
|
26047
|
+
resolve25(answer);
|
|
26048
|
+
};
|
|
26049
|
+
const onData = (chunk2) => {
|
|
26050
|
+
for (const char of chunk2) {
|
|
26051
|
+
if (char === "\r" || char === "\n") return done(value.trim());
|
|
26052
|
+
if (char === "" || char === "") return done(void 0);
|
|
26053
|
+
if (char === "\x7F" || char === "\b") value = value.slice(0, -1);
|
|
26054
|
+
else value += char;
|
|
26055
|
+
}
|
|
26056
|
+
};
|
|
26057
|
+
stdin.on("data", onData);
|
|
26058
|
+
});
|
|
26059
|
+
}
|
|
26060
|
+
function realSubscriptionLogin(env, home) {
|
|
26061
|
+
return {
|
|
26062
|
+
interactive: process.stdin.isTTY === true && process.stderr.isTTY === true,
|
|
26063
|
+
findClaude: () => findClaudeBinary(env, home),
|
|
26064
|
+
runSetupToken: (claude, write) => runClaudeSetupToken({
|
|
26065
|
+
claude,
|
|
26066
|
+
interactive: process.stdin.isTTY === true,
|
|
26067
|
+
write
|
|
26068
|
+
}),
|
|
26069
|
+
promptSecret: promptHidden,
|
|
26070
|
+
findCodex: () => findHarnessBinary("codex", env, home),
|
|
26071
|
+
runCodexLogin: (codex) => new Promise((resolve25, reject) => {
|
|
26072
|
+
const child = spawn3(codex, ["login"], {
|
|
26073
|
+
stdio: [process.stdin.isTTY ? "inherit" : "pipe", "inherit", "inherit"],
|
|
26074
|
+
env: process.env
|
|
26075
|
+
});
|
|
26076
|
+
child.on("error", reject);
|
|
26077
|
+
child.on("close", (code) => {
|
|
26078
|
+
child.stdin?.destroy();
|
|
26079
|
+
resolve25(code ?? 1);
|
|
26080
|
+
});
|
|
26081
|
+
}),
|
|
26082
|
+
readStdin: async () => {
|
|
26083
|
+
let text5 = "";
|
|
26084
|
+
process.stdin.setEncoding("utf8");
|
|
26085
|
+
for await (const chunk2 of process.stdin) text5 += chunk2;
|
|
26086
|
+
return text5;
|
|
26087
|
+
}
|
|
26088
|
+
};
|
|
26089
|
+
}
|
|
25553
26090
|
function defaultCliDeps(overrides = {}, managed = {}) {
|
|
25554
26091
|
const env = overrides.env ?? process.env;
|
|
25555
26092
|
const home = overrides.home ?? homedir3();
|
|
@@ -25739,6 +26276,7 @@ function defaultCliDeps(overrides = {}, managed = {}) {
|
|
|
25739
26276
|
file: paths.credentials,
|
|
25740
26277
|
key: paths.credentialsKey
|
|
25741
26278
|
}),
|
|
26279
|
+
subscriptionLogin: realSubscriptionLogin(env, home),
|
|
25742
26280
|
daemonPost: async (path2, body2) => {
|
|
25743
26281
|
const host = readHostFile(paths.hostFile);
|
|
25744
26282
|
if (host === void 0) return void 0;
|
|
@@ -25832,6 +26370,7 @@ var init_deps = __esm({
|
|
|
25832
26370
|
"../../packages/tacho/src/cli/deps.ts"() {
|
|
25833
26371
|
"use strict";
|
|
25834
26372
|
init_hook_client();
|
|
26373
|
+
init_claude_setup_token();
|
|
25835
26374
|
init_codex_app_server();
|
|
25836
26375
|
init_credential_store();
|
|
25837
26376
|
init_claude_config_lock();
|
|
@@ -26657,7 +27196,7 @@ import {
|
|
|
26657
27196
|
unlinkSync as unlinkSync8
|
|
26658
27197
|
} from "node:fs";
|
|
26659
27198
|
import { open as open2 } from "node:fs/promises";
|
|
26660
|
-
import { join as
|
|
27199
|
+
import { join as join17 } from "node:path";
|
|
26661
27200
|
function parseStoredBody(text5) {
|
|
26662
27201
|
let value;
|
|
26663
27202
|
try {
|
|
@@ -26858,7 +27397,7 @@ var init_wal_index = __esm({
|
|
|
26858
27397
|
/** The scan `ensureAsync` has running for a session, shared by callers. */
|
|
26859
27398
|
building = /* @__PURE__ */ new Map();
|
|
26860
27399
|
sidecarFor(sessionUuid2) {
|
|
26861
|
-
return
|
|
27400
|
+
return join17(this.dir, `${sessionUuid2}${SIDECAR_SUFFIX}`);
|
|
26862
27401
|
}
|
|
26863
27402
|
/** Whether a name in the WAL directory is one of these sidecars. */
|
|
26864
27403
|
static isSidecar(name) {
|
|
@@ -27090,7 +27629,7 @@ import {
|
|
|
27090
27629
|
writeSync as writeSync4
|
|
27091
27630
|
} from "node:fs";
|
|
27092
27631
|
import { randomUUID } from "node:crypto";
|
|
27093
|
-
import { join as
|
|
27632
|
+
import { join as join18 } from "node:path";
|
|
27094
27633
|
function activityAt(event) {
|
|
27095
27634
|
const at2 = Date.parse(event.ts);
|
|
27096
27635
|
return Number.isFinite(at2) ? at2 : Number.NEGATIVE_INFINITY;
|
|
@@ -27154,7 +27693,7 @@ var init_wal = __esm({
|
|
|
27154
27693
|
this.dir = dir;
|
|
27155
27694
|
ensureDir(dir);
|
|
27156
27695
|
this.bodyIndexes = new BodyIndexStore(dir);
|
|
27157
|
-
this.cursorPath =
|
|
27696
|
+
this.cursorPath = join18(dir, "cursor.json");
|
|
27158
27697
|
let raw;
|
|
27159
27698
|
if (onCursorSetAside !== void 0)
|
|
27160
27699
|
raw = readJsonStateFile(this.cursorPath, onCursorSetAside);
|
|
@@ -27234,10 +27773,10 @@ var init_wal = __esm({
|
|
|
27234
27773
|
*/
|
|
27235
27774
|
dirtyPaths = /* @__PURE__ */ new Set();
|
|
27236
27775
|
fileFor(sessionUuid2) {
|
|
27237
|
-
return
|
|
27776
|
+
return join18(this.dir, `${sessionUuid2}.ndjson`);
|
|
27238
27777
|
}
|
|
27239
27778
|
bodyFileFor(sessionUuid2) {
|
|
27240
|
-
return
|
|
27779
|
+
return join18(this.dir, `${sessionUuid2}.bodies.jsonl`);
|
|
27241
27780
|
}
|
|
27242
27781
|
persistCursor() {
|
|
27243
27782
|
this.flush();
|
|
@@ -28666,7 +29205,7 @@ ${lines.join("\n")}
|
|
|
28666
29205
|
for (const name of readdirSync7(this.dir)) {
|
|
28667
29206
|
if (abandonedRewrite.test(name)) {
|
|
28668
29207
|
try {
|
|
28669
|
-
unlinkSync9(
|
|
29208
|
+
unlinkSync9(join18(this.dir, name));
|
|
28670
29209
|
} catch (error) {
|
|
28671
29210
|
this.bodyFailure(name.slice(0, 36), "cleanup", error);
|
|
28672
29211
|
}
|
|
@@ -29029,6 +29568,70 @@ var init_github = __esm({
|
|
|
29029
29568
|
}
|
|
29030
29569
|
});
|
|
29031
29570
|
|
|
29571
|
+
// ../../packages/tacho/src/host/harness-path.ts
|
|
29572
|
+
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
29573
|
+
import { delimiter as delimiter2, join as join19 } from "node:path";
|
|
29574
|
+
function knownDirs(home) {
|
|
29575
|
+
return [
|
|
29576
|
+
join19(home, ".local", "bin"),
|
|
29577
|
+
join19(home, ".bun", "bin"),
|
|
29578
|
+
join19(home, ".npm-global", "bin"),
|
|
29579
|
+
join19(home, ".volta", "bin"),
|
|
29580
|
+
join19(home, ".cargo", "bin"),
|
|
29581
|
+
join19(home, "bin"),
|
|
29582
|
+
"/opt/homebrew/bin",
|
|
29583
|
+
"/usr/local/bin",
|
|
29584
|
+
"/usr/bin",
|
|
29585
|
+
"/bin",
|
|
29586
|
+
"/usr/sbin",
|
|
29587
|
+
"/sbin"
|
|
29588
|
+
];
|
|
29589
|
+
}
|
|
29590
|
+
function loginShellPath(env, run3 = spawnSync5) {
|
|
29591
|
+
const shell = env["SHELL"] ?? "/bin/zsh";
|
|
29592
|
+
try {
|
|
29593
|
+
const result2 = run3(
|
|
29594
|
+
shell,
|
|
29595
|
+
["-ilc", `printf '%s%s%s' '${MARK}' "$PATH" '${MARK}'`],
|
|
29596
|
+
{
|
|
29597
|
+
encoding: "utf8",
|
|
29598
|
+
timeout: LOGIN_SHELL_TIMEOUT_MS,
|
|
29599
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
29600
|
+
env: { ...env, TERM: env["TERM"] ?? "dumb" }
|
|
29601
|
+
}
|
|
29602
|
+
);
|
|
29603
|
+
const out = typeof result2.stdout === "string" ? result2.stdout : "";
|
|
29604
|
+
const start = out.indexOf(MARK);
|
|
29605
|
+
const end = out.indexOf(MARK, start + MARK.length);
|
|
29606
|
+
if (start < 0 || end < 0) return void 0;
|
|
29607
|
+
const path2 = out.slice(start + MARK.length, end).trim();
|
|
29608
|
+
return path2.length > 0 ? path2 : void 0;
|
|
29609
|
+
} catch {
|
|
29610
|
+
return void 0;
|
|
29611
|
+
}
|
|
29612
|
+
}
|
|
29613
|
+
function harnessPath(env, home, loginPath) {
|
|
29614
|
+
const seen = /* @__PURE__ */ new Set();
|
|
29615
|
+
const dirs = [];
|
|
29616
|
+
const add2 = (dir) => {
|
|
29617
|
+
if (dir.length === 0 || seen.has(dir)) return;
|
|
29618
|
+
seen.add(dir);
|
|
29619
|
+
dirs.push(dir);
|
|
29620
|
+
};
|
|
29621
|
+
for (const dir of (loginPath ?? "").split(delimiter2)) add2(dir);
|
|
29622
|
+
for (const dir of (env["PATH"] ?? "").split(delimiter2)) add2(dir);
|
|
29623
|
+
for (const dir of knownDirs(home)) add2(dir);
|
|
29624
|
+
return dirs.join(delimiter2);
|
|
29625
|
+
}
|
|
29626
|
+
var MARK, LOGIN_SHELL_TIMEOUT_MS;
|
|
29627
|
+
var init_harness_path = __esm({
|
|
29628
|
+
"../../packages/tacho/src/host/harness-path.ts"() {
|
|
29629
|
+
"use strict";
|
|
29630
|
+
MARK = "__OXAGEN_PATH__";
|
|
29631
|
+
LOGIN_SHELL_TIMEOUT_MS = 5e3;
|
|
29632
|
+
}
|
|
29633
|
+
});
|
|
29634
|
+
|
|
29032
29635
|
// ../../packages/tacho/src/cli/daemon-service.ts
|
|
29033
29636
|
function daemonServiceSpec(daemonCommand, deps) {
|
|
29034
29637
|
return {
|
|
@@ -29043,7 +29646,11 @@ function daemonServiceSpec(daemonCommand, deps) {
|
|
|
29043
29646
|
return value !== void 0 ? [[key, value]] : [];
|
|
29044
29647
|
})
|
|
29045
29648
|
),
|
|
29046
|
-
|
|
29649
|
+
// The login shell's PATH, so the daemon's git calls find their
|
|
29650
|
+
// credential helpers and a work order's harness is found. A desktop app
|
|
29651
|
+
// installs the service from a GUI process whose PATH is the bare system
|
|
29652
|
+
// path (#5936).
|
|
29653
|
+
PATH: harnessPath(deps.env, deps.home, loginShellPath(deps.env)),
|
|
29047
29654
|
HOME: deps.home
|
|
29048
29655
|
},
|
|
29049
29656
|
// One tachod serves every agent, so its log and working directory are
|
|
@@ -29056,6 +29663,7 @@ var HARNESS_HOME_VARS;
|
|
|
29056
29663
|
var init_daemon_service = __esm({
|
|
29057
29664
|
"../../packages/tacho/src/cli/daemon-service.ts"() {
|
|
29058
29665
|
"use strict";
|
|
29666
|
+
init_harness_path();
|
|
29059
29667
|
HARNESS_HOME_VARS = [
|
|
29060
29668
|
"CLAUDE_CONFIG_DIR",
|
|
29061
29669
|
"CODEX_HOME",
|
|
@@ -29090,7 +29698,7 @@ var init_policy_mode = __esm({
|
|
|
29090
29698
|
|
|
29091
29699
|
// ../../packages/tacho/src/host/wal-ceiling.ts
|
|
29092
29700
|
import { statfsSync } from "node:fs";
|
|
29093
|
-
import { join as
|
|
29701
|
+
import { join as join20 } from "node:path";
|
|
29094
29702
|
function freeBytesOn(dir) {
|
|
29095
29703
|
try {
|
|
29096
29704
|
const stats2 = statfsSync(dir);
|
|
@@ -29137,7 +29745,7 @@ function isDrop(value) {
|
|
|
29137
29745
|
function readWalCeilingState(walDir) {
|
|
29138
29746
|
let raw;
|
|
29139
29747
|
try {
|
|
29140
|
-
raw = readJsonFileIfExists(
|
|
29748
|
+
raw = readJsonFileIfExists(join20(walDir, STATE_FILE));
|
|
29141
29749
|
} catch (error) {
|
|
29142
29750
|
if (error instanceof SyntaxError) return void 0;
|
|
29143
29751
|
throw error;
|
|
@@ -29337,7 +29945,7 @@ var init_wal_ceiling = __esm({
|
|
|
29337
29945
|
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);
|
|
29338
29946
|
this.state = next;
|
|
29339
29947
|
if (!changed) return;
|
|
29340
|
-
const path2 =
|
|
29948
|
+
const path2 = join20(this.walDir, STATE_FILE);
|
|
29341
29949
|
try {
|
|
29342
29950
|
writeSensitiveFileAtomic(path2, JSON.stringify(next));
|
|
29343
29951
|
this.unsaved = false;
|
|
@@ -29841,7 +30449,7 @@ import {
|
|
|
29841
30449
|
rmdirSync as rmdirSync5,
|
|
29842
30450
|
rmSync as rmSync2
|
|
29843
30451
|
} from "node:fs";
|
|
29844
|
-
import { dirname as dirname12, join as
|
|
30452
|
+
import { dirname as dirname12, join as join21 } from "node:path";
|
|
29845
30453
|
async function revokeOnControlPlane(host, options, deps, warnings) {
|
|
29846
30454
|
const resolved = resolveCredentials(
|
|
29847
30455
|
{
|
|
@@ -30452,7 +31060,7 @@ async function unenrollLocked(options, deps) {
|
|
|
30452
31060
|
];
|
|
30453
31061
|
const purged = parts.filter(([, path2, recursive]) => remove2(path2, recursive)).map(([name]) => name);
|
|
30454
31062
|
let failed3 = purged.length < parts.length;
|
|
30455
|
-
if (!existsSync15(
|
|
31063
|
+
if (!existsSync15(join21(deps.paths.dir, HARNESS_RECEIPTS)) && !remove2(join21(deps.paths.dir, HARNESS_BACKUPS), true))
|
|
30456
31064
|
failed3 = true;
|
|
30457
31065
|
const logShared = otherLiveAgents(deps.paths, deps.paths.dir).length > 0;
|
|
30458
31066
|
if (!logShared) {
|
|
@@ -30510,7 +31118,7 @@ var init_unenroll = __esm({
|
|
|
30510
31118
|
|
|
30511
31119
|
// ../../packages/tacho/src/cli/enroll.ts
|
|
30512
31120
|
import { existsSync as existsSync16, lstatSync as lstatSync4, rmSync as rmSync3 } from "node:fs";
|
|
30513
|
-
import { dirname as dirname13, isAbsolute, join as
|
|
31121
|
+
import { dirname as dirname13, isAbsolute, join as join22 } from "node:path";
|
|
30514
31122
|
function rootRefusal(command2, deps, allowRoot) {
|
|
30515
31123
|
if (allowRoot === true || deps.getuid?.() !== 0) return void 0;
|
|
30516
31124
|
const user = deps.env["SUDO_USER"] ?? "<user>";
|
|
@@ -30536,7 +31144,7 @@ function runtimeOf(host) {
|
|
|
30536
31144
|
if (first === void 0 || !files2.every((file) => existsSync16(file)))
|
|
30537
31145
|
return void 0;
|
|
30538
31146
|
const binDir = dirname13(first);
|
|
30539
|
-
const tacho = host.daemon_command[0] === first ? shellQuote(first) : `${host.daemon_command[0]} ${shellQuote(
|
|
31147
|
+
const tacho = host.daemon_command[0] === first ? shellQuote(first) : `${host.daemon_command[0]} ${shellQuote(join22(binDir, "tacho.mjs"))}`;
|
|
30540
31148
|
return {
|
|
30541
31149
|
hookCommand: host.hook_command,
|
|
30542
31150
|
credentialHelperCommand: helperCommandFor(tacho),
|
|
@@ -31630,6 +32238,7 @@ ${problems.map((problem) => ` ${problem}`).join("\n")}`
|
|
|
31630
32238
|
const mode = options.credentials ?? "brokered";
|
|
31631
32239
|
try {
|
|
31632
32240
|
if (mode === "brokered") {
|
|
32241
|
+
await signInIfNoCredential(reaching, deps);
|
|
31633
32242
|
const outcome = await brokerCredentials(host, reaching, deps);
|
|
31634
32243
|
for (const entry2 of outcome.harnesses)
|
|
31635
32244
|
deps.out(` ${describeHarness(entry2)}`);
|
|
@@ -32792,21 +33401,21 @@ import {
|
|
|
32792
33401
|
statSync as statSync7,
|
|
32793
33402
|
unlinkSync as unlinkSync10
|
|
32794
33403
|
} from "node:fs";
|
|
32795
|
-
import { dirname as dirname14, isAbsolute as isAbsolute2, join as
|
|
33404
|
+
import { dirname as dirname14, isAbsolute as isAbsolute2, join as join23, relative, resolve as resolve7, sep } from "node:path";
|
|
32796
33405
|
function dataLocalDir(home, env, platform) {
|
|
32797
33406
|
if (platform === "darwin")
|
|
32798
|
-
return
|
|
33407
|
+
return join23(home, "Library", "Application Support");
|
|
32799
33408
|
if (platform === "win32")
|
|
32800
|
-
return env["LOCALAPPDATA"] ??
|
|
33409
|
+
return env["LOCALAPPDATA"] ?? join23(home, "AppData", "Local");
|
|
32801
33410
|
const xdg = env["XDG_DATA_HOME"];
|
|
32802
|
-
return xdg !== void 0 && isAbsolute2(xdg) ? xdg :
|
|
33411
|
+
return xdg !== void 0 && isAbsolute2(xdg) ? xdg : join23(home, ".local", "share");
|
|
32803
33412
|
}
|
|
32804
33413
|
function desktopPlaces(deps) {
|
|
32805
|
-
const oxagenDir =
|
|
33414
|
+
const oxagenDir = join23(deps.home, ".config", "oxagen");
|
|
32806
33415
|
return {
|
|
32807
33416
|
oxagenDir,
|
|
32808
|
-
desktopConfig:
|
|
32809
|
-
copies:
|
|
33417
|
+
desktopConfig: join23(oxagenDir, "desktop.json"),
|
|
33418
|
+
copies: join23(
|
|
32810
33419
|
dataLocalDir(deps.home, deps.env, deps.platform),
|
|
32811
33420
|
"oxagen",
|
|
32812
33421
|
"bin"
|
|
@@ -33051,7 +33660,7 @@ function undoEntry(entry2, deps, tally2) {
|
|
|
33051
33660
|
}
|
|
33052
33661
|
function versionDirs(copies) {
|
|
33053
33662
|
try {
|
|
33054
|
-
return readdirSync9(copies, { withFileTypes: true }).filter((entry2) => entry2.isDirectory() && !entry2.name.startsWith(".")).map((entry2) =>
|
|
33663
|
+
return readdirSync9(copies, { withFileTypes: true }).filter((entry2) => entry2.isDirectory() && !entry2.name.startsWith(".")).map((entry2) => join23(copies, entry2.name)).sort();
|
|
33055
33664
|
} catch {
|
|
33056
33665
|
return [];
|
|
33057
33666
|
}
|
|
@@ -33087,7 +33696,7 @@ function journaledCopies(journal, copies, tally2) {
|
|
|
33087
33696
|
function removeSidecars(dir, platform, tally2) {
|
|
33088
33697
|
const note = platform === "win32" ? `. Windows keeps a running program's file, so delete ${dir} after this command exits` : "";
|
|
33089
33698
|
for (const name of ["oxagen", "tacho"]) {
|
|
33090
|
-
const file =
|
|
33699
|
+
const file = join23(dir, platform === "win32" ? `${name}.exe` : name);
|
|
33091
33700
|
removeFile(file, tally2, note);
|
|
33092
33701
|
}
|
|
33093
33702
|
}
|
|
@@ -33175,7 +33784,7 @@ async function uninstall(options, deps) {
|
|
|
33175
33784
|
tally2.left.push(`cannot remove ${dir}: ${reasonOf3(error)}`);
|
|
33176
33785
|
}
|
|
33177
33786
|
}
|
|
33178
|
-
const configDir =
|
|
33787
|
+
const configDir = join23(deps.home, ".config");
|
|
33179
33788
|
if (record.configDirCreated && removeDirIfEmpty(configDir))
|
|
33180
33789
|
tally2.removed.push(configDir);
|
|
33181
33790
|
for (const path2 of tally2.removed) deps.out(` removed ${path2}`);
|
|
@@ -33589,9 +34198,9 @@ var init_run = __esm({
|
|
|
33589
34198
|
});
|
|
33590
34199
|
|
|
33591
34200
|
// ../../packages/tacho/src/cli/agent-run.ts
|
|
33592
|
-
import { spawn as
|
|
34201
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
33593
34202
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
33594
|
-
import { constants as
|
|
34203
|
+
import { constants as constants3 } from "node:os";
|
|
33595
34204
|
import { posix as posix3, win32 as win324 } from "node:path";
|
|
33596
34205
|
function programName(program2) {
|
|
33597
34206
|
const base2 = (program2.includes("\\") ? win324 : posix3).basename(program2);
|
|
@@ -33617,7 +34226,7 @@ function sessionRefusal(stdout) {
|
|
|
33617
34226
|
function exitCodeOf(exit) {
|
|
33618
34227
|
if (exit.error !== void 0) return 1;
|
|
33619
34228
|
if (exit.code !== null) return exit.code;
|
|
33620
|
-
const number2 = exit.signal !== null ?
|
|
34229
|
+
const number2 = exit.signal !== null ? constants3.signals[exit.signal] : void 0;
|
|
33621
34230
|
return number2 !== void 0 ? 128 + number2 : 1;
|
|
33622
34231
|
}
|
|
33623
34232
|
function spawnAgent(command2, args, options) {
|
|
@@ -33628,7 +34237,7 @@ function spawnAgent(command2, args, options) {
|
|
|
33628
34237
|
options.env
|
|
33629
34238
|
);
|
|
33630
34239
|
return new Promise((resolve25) => {
|
|
33631
|
-
const child =
|
|
34240
|
+
const child = spawn4(invocation.command, invocation.args, {
|
|
33632
34241
|
cwd: options.cwd,
|
|
33633
34242
|
env: options.env,
|
|
33634
34243
|
stdio: "inherit",
|
|
@@ -33853,11 +34462,11 @@ var init_work_order_start = __esm({
|
|
|
33853
34462
|
|
|
33854
34463
|
// ../../packages/tacho/src/host/work-orders.ts
|
|
33855
34464
|
import { readdirSync as readdirSync10, rmSync as rmSync5 } from "node:fs";
|
|
33856
|
-
import { join as
|
|
34465
|
+
import { join as join24 } from "node:path";
|
|
33857
34466
|
function orderFile(paths, id2) {
|
|
33858
34467
|
if (!WORK_ORDER_ID_PATTERN.test(id2))
|
|
33859
34468
|
throw new Error(`${JSON.stringify(id2)} is not a work order id`);
|
|
33860
|
-
return
|
|
34469
|
+
return join24(paths.workOrders, `${id2}.json`);
|
|
33861
34470
|
}
|
|
33862
34471
|
function readKept(path2) {
|
|
33863
34472
|
try {
|
|
@@ -33907,7 +34516,7 @@ function removeWorkOrder(paths, id2) {
|
|
|
33907
34516
|
function runningFile(paths, id2) {
|
|
33908
34517
|
if (!WORK_ORDER_ID_PATTERN.test(id2))
|
|
33909
34518
|
throw new Error(`${JSON.stringify(id2)} is not a work order id`);
|
|
33910
|
-
return
|
|
34519
|
+
return join24(paths.workOrders, `${id2}.running`);
|
|
33911
34520
|
}
|
|
33912
34521
|
function processIsAlive(pid) {
|
|
33913
34522
|
try {
|
|
@@ -34000,7 +34609,7 @@ var init_work_orders = __esm({
|
|
|
34000
34609
|
});
|
|
34001
34610
|
|
|
34002
34611
|
// ../../packages/tacho/src/cli/work.ts
|
|
34003
|
-
import { spawnSync as
|
|
34612
|
+
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
34004
34613
|
function liveAgents(deps) {
|
|
34005
34614
|
return listAgents(homeOf(deps.paths)).filter(agentIsLive);
|
|
34006
34615
|
}
|
|
@@ -34188,7 +34797,7 @@ async function workStart(id2, deps) {
|
|
|
34188
34797
|
return exitCodeOf(exit);
|
|
34189
34798
|
}
|
|
34190
34799
|
function gitHeadIn(cwd) {
|
|
34191
|
-
const result2 =
|
|
34800
|
+
const result2 = spawnSync6("git", ["-C", cwd, "rev-parse", "HEAD"], {
|
|
34192
34801
|
encoding: "utf8",
|
|
34193
34802
|
stdio: ["ignore", "pipe", "pipe"],
|
|
34194
34803
|
timeout: 1e4
|
|
@@ -34309,10 +34918,12 @@ var init_work = __esm({
|
|
|
34309
34918
|
var cli_exports = {};
|
|
34310
34919
|
__export(cli_exports, {
|
|
34311
34920
|
BACKFILL_EXIT: () => BACKFILL_EXIT,
|
|
34921
|
+
CLAUDE_OAUTH_TOKEN_ENV: () => CLAUDE_OAUTH_TOKEN_ENV,
|
|
34312
34922
|
CONTAINED_AGENTS: () => CONTAINED_AGENTS,
|
|
34313
34923
|
CURSOR_COVERAGE_NOTE: () => CURSOR_COVERAGE_NOTE,
|
|
34314
34924
|
MODEL_CREDENTIAL_HARNESSES: () => MODEL_CREDENTIAL_HARNESSES,
|
|
34315
34925
|
SHIPPING_STALL_MS: () => SHIPPING_STALL_MS,
|
|
34926
|
+
acquireSubscriptionToken: () => acquireSubscriptionToken,
|
|
34316
34927
|
addMissingClaudeCodeMcp: () => addMissingClaudeCodeMcp,
|
|
34317
34928
|
agentNameFromCommand: () => agentNameFromCommand,
|
|
34318
34929
|
backfillCommand: () => backfillCommand,
|
|
@@ -34320,6 +34931,7 @@ __export(cli_exports, {
|
|
|
34320
34931
|
canServeOxagenTools: () => canServeOxagenTools,
|
|
34321
34932
|
claudeFacts: () => claudeFacts,
|
|
34322
34933
|
credentialIssue: () => credentialIssue,
|
|
34934
|
+
credentialLogin: () => credentialLogin,
|
|
34323
34935
|
credentialStatus: () => credentialStatus,
|
|
34324
34936
|
cursorAppFacts: () => cursorAppFacts,
|
|
34325
34937
|
cursorFacts: () => cursorFacts,
|
|
@@ -34370,6 +34982,7 @@ __export(cli_exports, {
|
|
|
34370
34982
|
shellQuote: () => shellQuote,
|
|
34371
34983
|
shimError: () => shimError,
|
|
34372
34984
|
shippingHealth: () => shippingHealth,
|
|
34985
|
+
signInIfNoCredential: () => signInIfNoCredential,
|
|
34373
34986
|
spawnAgent: () => spawnAgent,
|
|
34374
34987
|
stableExecutablePath: () => stableExecutablePath,
|
|
34375
34988
|
status: () => status,
|
|
@@ -38104,6 +38717,7 @@ function containedBridgeHandler(options) {
|
|
|
38104
38717
|
const modelPaths = options.harness === "claude-code" ? ["/model/v1/messages", "/model/v1/messages/count_tokens"] : ["/model/v1/responses", "/model/v1/chat/completions"];
|
|
38105
38718
|
if (request3.method === "POST" && modelPaths.includes(path2)) {
|
|
38106
38719
|
const credential = options.issueCredential();
|
|
38720
|
+
const chatgpt = options.harness === "codex" && options.chatgptLogin?.() === true;
|
|
38107
38721
|
request3.headers = {
|
|
38108
38722
|
"content-type": "application/json",
|
|
38109
38723
|
...request3.headers["content-length"] ? { "content-length": request3.headers["content-length"] } : {},
|
|
@@ -38111,9 +38725,12 @@ function containedBridgeHandler(options) {
|
|
|
38111
38725
|
...request3.headers["anthropic-beta"] ? { "anthropic-beta": request3.headers["anthropic-beta"] } : {},
|
|
38112
38726
|
host: `127.0.0.1:${options.modelPort}`,
|
|
38113
38727
|
"x-oxagen-session": options.sessionId,
|
|
38114
|
-
...options.harness === "claude-code" ? { "x-api-key": credential } : { authorization: `Bearer ${credential}` }
|
|
38728
|
+
...options.harness === "claude-code" ? { "x-api-key": credential } : { authorization: `Bearer ${credential}` },
|
|
38729
|
+
// Marks the call as a ChatGPT login's; the gateway puts the
|
|
38730
|
+
// login's own account in its place.
|
|
38731
|
+
...chatgpt ? { "chatgpt-account-id": "custody" } : {}
|
|
38115
38732
|
};
|
|
38116
|
-
request3.url = options.harness === "claude-code" ? path2.replace("/model", "/anthropic") : path2.replace("/model", "/openai");
|
|
38733
|
+
request3.url = options.harness === "claude-code" ? path2.replace("/model", "/anthropic") : chatgpt ? path2.replace("/model/v1", "/backend-api/codex") : path2.replace("/model", "/openai");
|
|
38117
38734
|
options.model(request3, response);
|
|
38118
38735
|
return;
|
|
38119
38736
|
}
|
|
@@ -38265,7 +38882,7 @@ var init_bridge = __esm({
|
|
|
38265
38882
|
|
|
38266
38883
|
// ../../packages/tacho/src/contained/workspace.ts
|
|
38267
38884
|
import { lstatSync as lstatSync6, readFileSync as readFileSync14, readdirSync as readdirSync11, realpathSync as realpathSync3 } from "node:fs";
|
|
38268
|
-
import { isAbsolute as isAbsolute3, join as
|
|
38885
|
+
import { isAbsolute as isAbsolute3, join as join25, relative as relative2, resolve as resolve9, sep as sep2 } from "node:path";
|
|
38269
38886
|
function within(root, path2) {
|
|
38270
38887
|
const rel = relative2(root, path2);
|
|
38271
38888
|
return rel === "" || !isAbsolute3(rel) && rel !== ".." && !rel.startsWith(`..${sep2}`);
|
|
@@ -38295,7 +38912,7 @@ function validateContainedWorkspace(workspace, sessionDirectory, mountInfo = rea
|
|
|
38295
38912
|
}
|
|
38296
38913
|
const visit2 = (directory) => {
|
|
38297
38914
|
for (const entry2 of readdirSync11(directory)) {
|
|
38298
|
-
const path2 =
|
|
38915
|
+
const path2 = join25(directory, entry2);
|
|
38299
38916
|
if (CREDENTIAL_PATHS.has(entry2) || isEnvFile(entry2))
|
|
38300
38917
|
throw new Error(
|
|
38301
38918
|
`Remove local credential files from the contained checkout before launch: ${named(path2)}`
|
|
@@ -38329,7 +38946,7 @@ function validateContainedWorkspace(workspace, sessionDirectory, mountInfo = rea
|
|
|
38329
38946
|
}
|
|
38330
38947
|
function gitDirectoryMounts(workspace) {
|
|
38331
38948
|
const root = realpathSync3(workspace);
|
|
38332
|
-
const dotGit =
|
|
38949
|
+
const dotGit = join25(root, ".git");
|
|
38333
38950
|
let stat7;
|
|
38334
38951
|
try {
|
|
38335
38952
|
stat7 = lstatSync6(dotGit);
|
|
@@ -38367,7 +38984,7 @@ function gitDirectoryMounts(workspace) {
|
|
|
38367
38984
|
if (gitDir !== void 0) {
|
|
38368
38985
|
let common;
|
|
38369
38986
|
try {
|
|
38370
|
-
common = readFileSync14(
|
|
38987
|
+
common = readFileSync14(join25(gitDir, "commondir"), "utf8").trim();
|
|
38371
38988
|
} catch {
|
|
38372
38989
|
common = void 0;
|
|
38373
38990
|
}
|
|
@@ -38394,7 +39011,7 @@ var init_workspace = __esm({
|
|
|
38394
39011
|
// ../../packages/tacho/src/collector/hardened-git.ts
|
|
38395
39012
|
import { execFile as execFile2 } from "node:child_process";
|
|
38396
39013
|
import { lstatSync as lstatSync7, readFileSync as readFileSync15, statSync as statSync8 } from "node:fs";
|
|
38397
|
-
import { dirname as dirname15, join as
|
|
39014
|
+
import { dirname as dirname15, join as join26, resolve as resolve10 } from "node:path";
|
|
38398
39015
|
function hardenedGitArgs(cwd, args, globals = []) {
|
|
38399
39016
|
const subcommand = args[0];
|
|
38400
39017
|
const end = args.indexOf("--");
|
|
@@ -38433,7 +39050,7 @@ function gitIdentity(repository, deps = DEFAULT_IDENTITY_DEPS) {
|
|
|
38433
39050
|
};
|
|
38434
39051
|
}
|
|
38435
39052
|
for (let at2 = directory; ; at2 = dirname15(at2)) {
|
|
38436
|
-
const marker =
|
|
39053
|
+
const marker = join26(at2, ".git");
|
|
38437
39054
|
const link = tryStat(deps.lstat, marker);
|
|
38438
39055
|
if (link !== void 0) {
|
|
38439
39056
|
owners.push(link);
|
|
@@ -38441,7 +39058,7 @@ function gitIdentity(repository, deps = DEFAULT_IDENTITY_DEPS) {
|
|
|
38441
39058
|
if (target2 !== void 0) {
|
|
38442
39059
|
owners.push(target2);
|
|
38443
39060
|
if (target2.isDirectory()) {
|
|
38444
|
-
const config = tryStat(deps.stat,
|
|
39061
|
+
const config = tryStat(deps.stat, join26(marker, "config"));
|
|
38445
39062
|
if (config !== void 0) owners.push(config);
|
|
38446
39063
|
}
|
|
38447
39064
|
}
|
|
@@ -38593,7 +39210,7 @@ var init_hardened_git = __esm({
|
|
|
38593
39210
|
|
|
38594
39211
|
// ../../packages/tacho/src/contained/profile.ts
|
|
38595
39212
|
import { createHash as createHash6 } from "node:crypto";
|
|
38596
|
-
import { isAbsolute as isAbsolute4, join as
|
|
39213
|
+
import { isAbsolute as isAbsolute4, join as join27, relative as relative3, sep as sep3 } from "node:path";
|
|
38597
39214
|
function containerPath(workspace, path2) {
|
|
38598
39215
|
const inside2 = relative3(workspace, path2);
|
|
38599
39216
|
if (inside2 === "" || isAbsolute4(inside2) || inside2 === ".." || inside2.startsWith(`..${sep3}`))
|
|
@@ -38603,7 +39220,7 @@ function containerPath(workspace, path2) {
|
|
|
38603
39220
|
return `/workspace/${inside2.split(sep3).join("/")}`;
|
|
38604
39221
|
}
|
|
38605
39222
|
function gitMountPairs(spec) {
|
|
38606
|
-
if (!spec.gitMounts.includes(
|
|
39223
|
+
if (!spec.gitMounts.includes(join27(spec.workspace, ".git")))
|
|
38607
39224
|
throw new Error(
|
|
38608
39225
|
"Contained execution must mount the repository's .git read-only"
|
|
38609
39226
|
);
|
|
@@ -38760,7 +39377,7 @@ var init_profile = __esm({
|
|
|
38760
39377
|
});
|
|
38761
39378
|
|
|
38762
39379
|
// ../../packages/tacho/src/contained/launcher.ts
|
|
38763
|
-
import { execFile as execFile3, spawn as
|
|
39380
|
+
import { execFile as execFile3, spawn as spawn5 } from "node:child_process";
|
|
38764
39381
|
import { randomBytes as randomBytes8 } from "node:crypto";
|
|
38765
39382
|
import {
|
|
38766
39383
|
chmodSync as chmodSync7,
|
|
@@ -38770,7 +39387,7 @@ import {
|
|
|
38770
39387
|
writeFileSync as writeFileSync2
|
|
38771
39388
|
} from "node:fs";
|
|
38772
39389
|
import { tmpdir } from "node:os";
|
|
38773
|
-
import { isAbsolute as isAbsolute5, join as
|
|
39390
|
+
import { isAbsolute as isAbsolute5, join as join28 } from "node:path";
|
|
38774
39391
|
import { promisify } from "node:util";
|
|
38775
39392
|
function reason(error) {
|
|
38776
39393
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -38809,7 +39426,7 @@ async function launchContainedAgent(options) {
|
|
|
38809
39426
|
if (digest6 === void 0)
|
|
38810
39427
|
throw new Error("The operator's contained image is not installed");
|
|
38811
39428
|
const sessionId = `contained-${randomBytes8(16).toString("hex")}`;
|
|
38812
|
-
const directory = mkdtempSync(
|
|
39429
|
+
const directory = mkdtempSync(join28(tmpdir(), "oxagen-contained-"));
|
|
38813
39430
|
chmodSync7(directory, 448);
|
|
38814
39431
|
let prepared;
|
|
38815
39432
|
let containerCreated = false;
|
|
@@ -38830,7 +39447,7 @@ async function launchContainedAgent(options) {
|
|
|
38830
39447
|
for (const [name2, contents] of entries2) {
|
|
38831
39448
|
if (!/^[a-z0-9.-]+$/.test(name2))
|
|
38832
39449
|
throw new Error("Invalid contained configuration filename");
|
|
38833
|
-
writeFileSync2(
|
|
39450
|
+
writeFileSync2(join28(directory, name2), contents, {
|
|
38834
39451
|
mode: 256,
|
|
38835
39452
|
flag: "wx"
|
|
38836
39453
|
});
|
|
@@ -38861,7 +39478,7 @@ async function launchContainedAgent(options) {
|
|
|
38861
39478
|
if (options.signal?.aborted)
|
|
38862
39479
|
throw new Error("Contained run cancelled before start");
|
|
38863
39480
|
exitCode = await new Promise((resolve25, reject) => {
|
|
38864
|
-
const child =
|
|
39481
|
+
const child = spawn5("docker", ["start", "--attach", name], {
|
|
38865
39482
|
stdio: ["ignore", "pipe", "pipe"]
|
|
38866
39483
|
});
|
|
38867
39484
|
const stop = () => {
|
|
@@ -39229,7 +39846,7 @@ var init_privilege = __esm({
|
|
|
39229
39846
|
|
|
39230
39847
|
// ../../packages/tacho/src/contained/sandbox/launcher.ts
|
|
39231
39848
|
import { randomBytes as randomBytes9 } from "node:crypto";
|
|
39232
|
-
import { join as
|
|
39849
|
+
import { join as join29 } from "node:path";
|
|
39233
39850
|
function shellQuote3(value) {
|
|
39234
39851
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
39235
39852
|
}
|
|
@@ -39319,7 +39936,7 @@ async function launchSandboxAgent(options) {
|
|
|
39319
39936
|
{ ...asAgent, cwd: SANDBOX_AGENT_HOME, timeoutMs: 15 * 6e4 }
|
|
39320
39937
|
);
|
|
39321
39938
|
for (const [name, contents] of Object.entries(claudeCodeUserState())) {
|
|
39322
|
-
const path2 =
|
|
39939
|
+
const path2 = join29(SANDBOX_AGENT_HOME, name);
|
|
39323
39940
|
system.writeFile(path2, contents, 384);
|
|
39324
39941
|
system.chown(path2, SANDBOX_AGENT_UID, SANDBOX_AGENT_GID);
|
|
39325
39942
|
}
|
|
@@ -39443,7 +40060,7 @@ var init_request = __esm({
|
|
|
39443
40060
|
});
|
|
39444
40061
|
|
|
39445
40062
|
// ../../packages/tacho/src/contained/sandbox/system.ts
|
|
39446
|
-
import { execFile as execFile4, spawn as
|
|
40063
|
+
import { execFile as execFile4, spawn as spawn6 } from "node:child_process";
|
|
39447
40064
|
import {
|
|
39448
40065
|
chmodSync as chmodSync8,
|
|
39449
40066
|
chownSync as chownSync2,
|
|
@@ -39474,7 +40091,7 @@ var init_system = __esm({
|
|
|
39474
40091
|
return { stdout: String(answer.stdout), stderr: String(answer.stderr) };
|
|
39475
40092
|
},
|
|
39476
40093
|
spawn: (file, args, options) => {
|
|
39477
|
-
const child =
|
|
40094
|
+
const child = spawn6(file, [...args], {
|
|
39478
40095
|
...options.uid !== void 0 ? { uid: options.uid } : {},
|
|
39479
40096
|
...options.gid !== void 0 ? { gid: options.gid } : {},
|
|
39480
40097
|
...options.cwd !== void 0 ? { cwd: options.cwd } : {},
|
|
@@ -39525,10 +40142,10 @@ var init_system = __esm({
|
|
|
39525
40142
|
});
|
|
39526
40143
|
|
|
39527
40144
|
// ../../packages/tacho/src/contained/runner.ts
|
|
39528
|
-
import { join as
|
|
40145
|
+
import { join as join30 } from "node:path";
|
|
39529
40146
|
function containedHookEnv(harness, workspace) {
|
|
39530
|
-
const home =
|
|
39531
|
-
return harness === "codex" ? { CODEX_HOME:
|
|
40147
|
+
const home = join30(workspace, ".oxagen-contained", "home");
|
|
40148
|
+
return harness === "codex" ? { CODEX_HOME: join30(home, ".codex") } : { CLAUDE_CONFIG_DIR: join30(home, ".claude") };
|
|
39532
40149
|
}
|
|
39533
40150
|
function containedLaunchEndpoint(host) {
|
|
39534
40151
|
const ingest = new URL(host.endpoints.ingest);
|
|
@@ -39624,6 +40241,7 @@ function createContainedRunner(options) {
|
|
|
39624
40241
|
throw new Error("Credential custody unavailable");
|
|
39625
40242
|
return answer.body.token;
|
|
39626
40243
|
},
|
|
40244
|
+
...options.chatgptLogin !== void 0 ? { chatgptLogin: options.chatgptLogin } : {},
|
|
39627
40245
|
model: (request3, response) => options.model.handle(request3, response),
|
|
39628
40246
|
hook: options.hook,
|
|
39629
40247
|
opening: route.opening,
|
|
@@ -39726,7 +40344,7 @@ function createContainedRunner(options) {
|
|
|
39726
40344
|
sessionUuid2 = started.recorder.sessionUuid;
|
|
39727
40345
|
active2.set(sessionUuid2, controller);
|
|
39728
40346
|
const bridge = await startContainedBridge({
|
|
39729
|
-
socketPath:
|
|
40347
|
+
socketPath: join30(directory, "bridge.sock"),
|
|
39730
40348
|
...bridgeRoutes({
|
|
39731
40349
|
sessionId,
|
|
39732
40350
|
workspace,
|
|
@@ -39810,7 +40428,7 @@ function createContainedRunner(options) {
|
|
|
39810
40428
|
const abort = () => controller.abort();
|
|
39811
40429
|
signal?.addEventListener("abort", abort, { once: true });
|
|
39812
40430
|
if (signal?.aborted) abort();
|
|
39813
|
-
const env = { CLAUDE_CONFIG_DIR:
|
|
40431
|
+
const env = { CLAUDE_CONFIG_DIR: join30(SANDBOX_AGENT_HOME, ".claude") };
|
|
39814
40432
|
let sessionUuid2;
|
|
39815
40433
|
let launchedSessionId;
|
|
39816
40434
|
let opened = false;
|
|
@@ -39943,14 +40561,96 @@ var init_runner = __esm({
|
|
|
39943
40561
|
}
|
|
39944
40562
|
});
|
|
39945
40563
|
|
|
40564
|
+
// ../../packages/tacho/src/host/chatgpt-refresh.ts
|
|
40565
|
+
function jwtExpiryMs(token) {
|
|
40566
|
+
const payload = token.split(".")[1];
|
|
40567
|
+
if (payload === void 0) return void 0;
|
|
40568
|
+
try {
|
|
40569
|
+
const claims = JSON.parse(
|
|
40570
|
+
Buffer.from(payload, "base64url").toString("utf8")
|
|
40571
|
+
);
|
|
40572
|
+
return typeof claims.exp === "number" ? claims.exp * 1e3 : void 0;
|
|
40573
|
+
} catch {
|
|
40574
|
+
return void 0;
|
|
40575
|
+
}
|
|
40576
|
+
}
|
|
40577
|
+
function chatGptLoginDue(login, takenAt, now) {
|
|
40578
|
+
const exp = jwtExpiryMs(login.access_token);
|
|
40579
|
+
if (exp !== void 0) return exp - now < CHATGPT_REFRESH_MARGIN_MS;
|
|
40580
|
+
return now - takenAt > CHATGPT_REFRESH_MAX_AGE_MS;
|
|
40581
|
+
}
|
|
40582
|
+
async function refreshChatGptLogin(login, fetchImpl) {
|
|
40583
|
+
if (login.refresh_token.length === 0)
|
|
40584
|
+
throw new Error("the ChatGPT login in custody has no refresh token");
|
|
40585
|
+
const response = await fetchImpl(CHATGPT_TOKEN_URL, {
|
|
40586
|
+
method: "POST",
|
|
40587
|
+
headers: { "Content-Type": "application/json" },
|
|
40588
|
+
body: JSON.stringify({
|
|
40589
|
+
client_id: CODEX_OAUTH_CLIENT_ID,
|
|
40590
|
+
grant_type: "refresh_token",
|
|
40591
|
+
refresh_token: login.refresh_token,
|
|
40592
|
+
scope: "openid profile email"
|
|
40593
|
+
})
|
|
40594
|
+
});
|
|
40595
|
+
if (!response.ok)
|
|
40596
|
+
throw new Error(
|
|
40597
|
+
`auth.openai.com refused to refresh the ChatGPT login (${response.status}); run \`codex login\`, then \`oxagen agent enroll\``
|
|
40598
|
+
);
|
|
40599
|
+
let body2;
|
|
40600
|
+
try {
|
|
40601
|
+
body2 = JSON.parse(await response.text());
|
|
40602
|
+
} catch {
|
|
40603
|
+
throw new Error("auth.openai.com answered with something other than JSON");
|
|
40604
|
+
}
|
|
40605
|
+
if (typeof body2.access_token !== "string" || body2.access_token.length === 0)
|
|
40606
|
+
throw new Error("auth.openai.com answered without an access token");
|
|
40607
|
+
return {
|
|
40608
|
+
...login,
|
|
40609
|
+
access_token: body2.access_token,
|
|
40610
|
+
refresh_token: typeof body2.refresh_token === "string" ? body2.refresh_token : login.refresh_token,
|
|
40611
|
+
...typeof body2.id_token === "string" ? { id_token: body2.id_token } : {}
|
|
40612
|
+
};
|
|
40613
|
+
}
|
|
40614
|
+
async function refreshChatGptCustody(store, fetchImpl, now) {
|
|
40615
|
+
const entry2 = store.status().find((c) => c.provider === "openai" && c.kind === "chatgpt");
|
|
40616
|
+
if (entry2 === void 0) return "none";
|
|
40617
|
+
const held = store.read("openai");
|
|
40618
|
+
const login = held?.kind === "chatgpt" ? decodeChatGptLogin(held.secret) : void 0;
|
|
40619
|
+
if (login === void 0) return { failed: "custody holds no ChatGPT login" };
|
|
40620
|
+
if (!chatGptLoginDue(login, Date.parse(entry2.taken_at), now)) return "fresh";
|
|
40621
|
+
try {
|
|
40622
|
+
const next = await refreshChatGptLogin(login, fetchImpl);
|
|
40623
|
+
store.take(
|
|
40624
|
+
"openai",
|
|
40625
|
+
{ kind: "chatgpt", secret: JSON.stringify(next) },
|
|
40626
|
+
"chatgpt:refresh",
|
|
40627
|
+
now
|
|
40628
|
+
);
|
|
40629
|
+
return "refreshed";
|
|
40630
|
+
} catch (error) {
|
|
40631
|
+
return { failed: error instanceof Error ? error.message : String(error) };
|
|
40632
|
+
}
|
|
40633
|
+
}
|
|
40634
|
+
var CODEX_OAUTH_CLIENT_ID, CHATGPT_TOKEN_URL, CHATGPT_REFRESH_MARGIN_MS, CHATGPT_REFRESH_MAX_AGE_MS;
|
|
40635
|
+
var init_chatgpt_refresh = __esm({
|
|
40636
|
+
"../../packages/tacho/src/host/chatgpt-refresh.ts"() {
|
|
40637
|
+
"use strict";
|
|
40638
|
+
init_model_credential();
|
|
40639
|
+
CODEX_OAUTH_CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
|
|
40640
|
+
CHATGPT_TOKEN_URL = "https://auth.openai.com/oauth/token";
|
|
40641
|
+
CHATGPT_REFRESH_MARGIN_MS = 60 * 6e4;
|
|
40642
|
+
CHATGPT_REFRESH_MAX_AGE_MS = 7 * 24 * 60 * 6e4;
|
|
40643
|
+
}
|
|
40644
|
+
});
|
|
40645
|
+
|
|
39946
40646
|
// ../../packages/tacho/src/host/repositories.ts
|
|
39947
|
-
import { existsSync as existsSync18 } from "node:fs";
|
|
39948
|
-
import { join as
|
|
40647
|
+
import { existsSync as existsSync18, readFileSync as readFileSync17, statSync as statSync10 } from "node:fs";
|
|
40648
|
+
import { dirname as dirname17, join as join31, resolve as resolve11, sep as sep4 } from "node:path";
|
|
39949
40649
|
function repositoriesFile(home) {
|
|
39950
|
-
return
|
|
40650
|
+
return join31(home.tachoDir, "repositories.json");
|
|
39951
40651
|
}
|
|
39952
40652
|
function workTreesDir(home) {
|
|
39953
|
-
return
|
|
40653
|
+
return join31(home.tachoDir, "work");
|
|
39954
40654
|
}
|
|
39955
40655
|
function readIndex(home) {
|
|
39956
40656
|
let raw;
|
|
@@ -39974,6 +40674,7 @@ function latest(checkouts) {
|
|
|
39974
40674
|
function recordCheckout(home, canonical3, root, seenAt) {
|
|
39975
40675
|
if (canonical3.length === 0 || root.length === 0) return false;
|
|
39976
40676
|
if (isUnder(root, workTreesDir(home))) return false;
|
|
40677
|
+
root = mainCheckoutOf(root);
|
|
39977
40678
|
const key = canonical3.toLowerCase();
|
|
39978
40679
|
const index = readIndex(home);
|
|
39979
40680
|
const kept = index.repositories[key] ?? [];
|
|
@@ -40000,8 +40701,24 @@ function recordCheckout(home, canonical3, root, seenAt) {
|
|
|
40000
40701
|
);
|
|
40001
40702
|
return true;
|
|
40002
40703
|
}
|
|
40704
|
+
function mainCheckoutOf(root) {
|
|
40705
|
+
const dotGit = join31(root, ".git");
|
|
40706
|
+
try {
|
|
40707
|
+
if (!statSync10(dotGit).isFile()) return root;
|
|
40708
|
+
const line = readFileSync17(dotGit, "utf8").trim();
|
|
40709
|
+
const match = /^gitdir:\s*(.+)$/m.exec(line);
|
|
40710
|
+
if (match === null) return root;
|
|
40711
|
+
const gitdir = resolve11(root, match[1].trim());
|
|
40712
|
+
const worktrees = dirname17(gitdir);
|
|
40713
|
+
if (!worktrees.endsWith(`${sep4}.git${sep4}worktrees`)) return root;
|
|
40714
|
+
const clone4 = dirname17(dirname17(worktrees));
|
|
40715
|
+
return existsSync18(join31(clone4, ".git")) ? clone4 : root;
|
|
40716
|
+
} catch {
|
|
40717
|
+
return root;
|
|
40718
|
+
}
|
|
40719
|
+
}
|
|
40003
40720
|
function defaultIsCheckout(root) {
|
|
40004
|
-
return existsSync18(
|
|
40721
|
+
return existsSync18(join31(root, ".git"));
|
|
40005
40722
|
}
|
|
40006
40723
|
function findCheckout(home, repository, host, deps = {}) {
|
|
40007
40724
|
const isCheckout = deps.isCheckout ?? defaultIsCheckout;
|
|
@@ -40049,7 +40766,7 @@ var init_repositories = __esm({
|
|
|
40049
40766
|
|
|
40050
40767
|
// ../../packages/tacho/src/collector/detector.ts
|
|
40051
40768
|
import { promises as fs3 } from "node:fs";
|
|
40052
|
-
import { basename as basename5, join as
|
|
40769
|
+
import { basename as basename5, join as join32 } from "node:path";
|
|
40053
40770
|
async function eachLimited(items, limit, task) {
|
|
40054
40771
|
let next = 0;
|
|
40055
40772
|
const workers = Array.from(
|
|
@@ -40075,7 +40792,7 @@ async function scanProject(dir) {
|
|
|
40075
40792
|
await eachLimited(names2, SCAN_CONCURRENCY, async (name) => {
|
|
40076
40793
|
const match = SESSION_FILE.exec(name);
|
|
40077
40794
|
if (match === null) return;
|
|
40078
|
-
const path2 =
|
|
40795
|
+
const path2 = join32(dir, name);
|
|
40079
40796
|
try {
|
|
40080
40797
|
const st = await fs3.stat(path2);
|
|
40081
40798
|
out.push({ sessionId: match[1], path: path2, mtimeMs: st.mtimeMs });
|
|
@@ -40116,7 +40833,7 @@ var init_detector = __esm({
|
|
|
40116
40833
|
continue;
|
|
40117
40834
|
}
|
|
40118
40835
|
await eachLimited(names2, SCAN_CONCURRENCY, async (name) => {
|
|
40119
|
-
const dir =
|
|
40836
|
+
const dir = join32(root, name);
|
|
40120
40837
|
try {
|
|
40121
40838
|
const st = await fs3.stat(dir);
|
|
40122
40839
|
if (st.isDirectory()) dirs.push({ dir, mtimeMs: st.mtimeMs });
|
|
@@ -40356,7 +41073,7 @@ var init_detector = __esm({
|
|
|
40356
41073
|
transcript_path: transcript.path,
|
|
40357
41074
|
transcript_mtime: new Date(transcript.mtimeMs).toISOString(),
|
|
40358
41075
|
claude_pids: processes.map((p) => p.pid),
|
|
40359
|
-
project: basename5(
|
|
41076
|
+
project: basename5(join32(transcript.path, ".."))
|
|
40360
41077
|
}
|
|
40361
41078
|
})
|
|
40362
41079
|
);
|
|
@@ -40726,9 +41443,9 @@ var init_git_facts = __esm({
|
|
|
40726
41443
|
});
|
|
40727
41444
|
|
|
40728
41445
|
// ../../packages/tacho/src/collector/work-order-autostart.ts
|
|
40729
|
-
import { spawn as
|
|
41446
|
+
import { spawn as spawn7 } from "node:child_process";
|
|
40730
41447
|
import { closeSync as closeSync7, existsSync as existsSync19, openSync as openSync7 } from "node:fs";
|
|
40731
|
-
import { dirname as
|
|
41448
|
+
import { dirname as dirname18, join as join33 } from "node:path";
|
|
40732
41449
|
function asError(error) {
|
|
40733
41450
|
return error instanceof Error ? error : new Error(String(error));
|
|
40734
41451
|
}
|
|
@@ -40741,6 +41458,14 @@ function createWorkOrderAutostart(deps) {
|
|
|
40741
41458
|
const { paths, log } = deps;
|
|
40742
41459
|
const isAlive = deps.isAlive ?? processIsAlive;
|
|
40743
41460
|
const spawnHarness = deps.spawn ?? spawnDetached;
|
|
41461
|
+
let searchPath;
|
|
41462
|
+
const pathForHarness = () => {
|
|
41463
|
+
if (searchPath === void 0) {
|
|
41464
|
+
const login = (deps.loginPath ?? (() => loginShellPath(deps.env)))();
|
|
41465
|
+
searchPath = harnessPath(deps.env, deps.env["HOME"] ?? "", login);
|
|
41466
|
+
}
|
|
41467
|
+
return searchPath;
|
|
41468
|
+
};
|
|
40744
41469
|
const lookup = deps.findCheckout ?? ((repository) => findCheckout(paths, repository, deps.host()));
|
|
40745
41470
|
const retry = /* @__PURE__ */ new Map();
|
|
40746
41471
|
const cleanups = /* @__PURE__ */ new Set();
|
|
@@ -40773,7 +41498,7 @@ function createWorkOrderAutostart(deps) {
|
|
|
40773
41498
|
}
|
|
40774
41499
|
async function abandon(id2) {
|
|
40775
41500
|
forget(id2);
|
|
40776
|
-
const worktree =
|
|
41501
|
+
const worktree = join33(workTreesDir(paths), id2);
|
|
40777
41502
|
if (!existsSync19(worktree)) return;
|
|
40778
41503
|
const [common, branch, head2] = await Promise.all([
|
|
40779
41504
|
git6(worktree, ["rev-parse", "--path-format=absolute", "--git-common-dir"]),
|
|
@@ -40789,7 +41514,7 @@ function createWorkOrderAutostart(deps) {
|
|
|
40789
41514
|
await cleanUp(
|
|
40790
41515
|
{
|
|
40791
41516
|
work_order: id2,
|
|
40792
|
-
root:
|
|
41517
|
+
root: dirname18(common.out),
|
|
40793
41518
|
worktree,
|
|
40794
41519
|
branch: branch.out,
|
|
40795
41520
|
base_sha: head2.out
|
|
@@ -40811,7 +41536,7 @@ function createWorkOrderAutostart(deps) {
|
|
|
40811
41536
|
return waitMs;
|
|
40812
41537
|
}
|
|
40813
41538
|
async function prepareWorktree(root, id2, itemNumber) {
|
|
40814
|
-
const worktree =
|
|
41539
|
+
const worktree = join33(workTreesDir(paths), id2);
|
|
40815
41540
|
const logPath = `${worktree}.log`;
|
|
40816
41541
|
if (existsSync19(worktree)) {
|
|
40817
41542
|
const [branch2, head2] = await Promise.all([
|
|
@@ -40963,7 +41688,12 @@ function createWorkOrderAutostart(deps) {
|
|
|
40963
41688
|
headlessArgs(harness, claim.prompt),
|
|
40964
41689
|
{
|
|
40965
41690
|
cwd: workspace.worktree,
|
|
40966
|
-
env: {
|
|
41691
|
+
env: {
|
|
41692
|
+
...deps.env,
|
|
41693
|
+
PATH: pathForHarness(),
|
|
41694
|
+
...headlessEnv(harness),
|
|
41695
|
+
[WORK_ORDER_ENV]: id2
|
|
41696
|
+
},
|
|
40967
41697
|
logPath: workspace.log
|
|
40968
41698
|
}
|
|
40969
41699
|
);
|
|
@@ -41060,6 +41790,7 @@ var init_work_order_autostart = __esm({
|
|
|
41060
41790
|
"../../packages/tacho/src/collector/work-order-autostart.ts"() {
|
|
41061
41791
|
"use strict";
|
|
41062
41792
|
init_fs();
|
|
41793
|
+
init_harness_path();
|
|
41063
41794
|
init_repositories();
|
|
41064
41795
|
init_work_order_start();
|
|
41065
41796
|
init_work_orders();
|
|
@@ -41071,7 +41802,7 @@ var init_work_order_autostart = __esm({
|
|
|
41071
41802
|
spawnDetached = (command2, args, options) => new Promise((resolve25) => {
|
|
41072
41803
|
let fd2;
|
|
41073
41804
|
try {
|
|
41074
|
-
ensureDir(
|
|
41805
|
+
ensureDir(dirname18(options.logPath));
|
|
41075
41806
|
fd2 = openSync7(options.logPath, "a", 384);
|
|
41076
41807
|
} catch (error) {
|
|
41077
41808
|
resolve25({ ok: false, error: asError(error) });
|
|
@@ -41088,7 +41819,7 @@ var init_work_order_autostart = __esm({
|
|
|
41088
41819
|
};
|
|
41089
41820
|
let settled2 = false;
|
|
41090
41821
|
try {
|
|
41091
|
-
const child =
|
|
41822
|
+
const child = spawn7(command2, args, {
|
|
41092
41823
|
cwd: options.cwd,
|
|
41093
41824
|
env: options.env,
|
|
41094
41825
|
// Its own process group, so a daemon restart does not stop the run.
|
|
@@ -41175,7 +41906,7 @@ import {
|
|
|
41175
41906
|
rm,
|
|
41176
41907
|
unlink
|
|
41177
41908
|
} from "node:fs/promises";
|
|
41178
|
-
import { dirname as
|
|
41909
|
+
import { dirname as dirname19, join as join34 } from "node:path";
|
|
41179
41910
|
function byPath(a, b3) {
|
|
41180
41911
|
return a.path < b3.path ? -1 : a.path > b3.path ? 1 : 0;
|
|
41181
41912
|
}
|
|
@@ -41218,7 +41949,7 @@ async function contentHash(absolutePath, kind, keep) {
|
|
|
41218
41949
|
if (keep !== void 0) {
|
|
41219
41950
|
try {
|
|
41220
41951
|
await mkdir(keep.dir, { recursive: true, mode: 448 });
|
|
41221
|
-
const temp2 =
|
|
41952
|
+
const temp2 = join34(keep.dir, `.partial-${randomUUID3()}`);
|
|
41222
41953
|
copy = {
|
|
41223
41954
|
temp: temp2,
|
|
41224
41955
|
handle: await open3(temp2, "wx", keep.executable ? 448 : 384)
|
|
@@ -41262,7 +41993,7 @@ async function settleCopy(temp, name) {
|
|
|
41262
41993
|
if (temp === void 0) return;
|
|
41263
41994
|
if (name !== void 0)
|
|
41264
41995
|
try {
|
|
41265
|
-
await rename(temp,
|
|
41996
|
+
await rename(temp, join34(dirname19(temp), name));
|
|
41266
41997
|
return;
|
|
41267
41998
|
} catch {
|
|
41268
41999
|
}
|
|
@@ -41278,7 +42009,7 @@ async function copiedBytes(dir) {
|
|
|
41278
42009
|
let total2 = 0;
|
|
41279
42010
|
for (const name of names2) {
|
|
41280
42011
|
try {
|
|
41281
|
-
total2 += (await lstat(
|
|
42012
|
+
total2 += (await lstat(join34(dir, name))).size;
|
|
41282
42013
|
} catch {
|
|
41283
42014
|
}
|
|
41284
42015
|
}
|
|
@@ -41294,7 +42025,7 @@ async function removeCopiesOutside(root, live) {
|
|
|
41294
42025
|
const keep = new Set(live());
|
|
41295
42026
|
await Promise.all(
|
|
41296
42027
|
names2.filter((name) => !keep.has(name)).map(
|
|
41297
|
-
(name) => rm(
|
|
42028
|
+
(name) => rm(join34(root, name), { recursive: true, force: true }).catch(
|
|
41298
42029
|
() => void 0
|
|
41299
42030
|
)
|
|
41300
42031
|
)
|
|
@@ -41316,7 +42047,7 @@ async function readPreexistingPaths(exec4, root, startedAtMs, copies) {
|
|
|
41316
42047
|
if (found === void 0) return;
|
|
41317
42048
|
if (found === "absent") {
|
|
41318
42049
|
if (!deletedIn(entry2.code)) return;
|
|
41319
|
-
const parent = await directoryChangedAt(
|
|
42050
|
+
const parent = await directoryChangedAt(dirname19(absolute));
|
|
41320
42051
|
if (parent === void 0 || parent >= startedAtMs) return;
|
|
41321
42052
|
paths[entry2.path] = null;
|
|
41322
42053
|
return;
|
|
@@ -41401,7 +42132,7 @@ async function contributionOf(exec4, cwd, root, repoRelative, entry2, copies) {
|
|
|
41401
42132
|
let copy = null;
|
|
41402
42133
|
if (entry2 !== null) {
|
|
41403
42134
|
if (copies === void 0 || !COPY_NAME.test(entry2[0])) return void 0;
|
|
41404
|
-
copy =
|
|
42135
|
+
copy = join34(copies, entry2[0]);
|
|
41405
42136
|
const kept = await statOf(copy);
|
|
41406
42137
|
if (kept === void 0 || kept === "absent" || kept.kind !== "file")
|
|
41407
42138
|
return void 0;
|
|
@@ -41803,7 +42534,7 @@ var init_session_changes = __esm({
|
|
|
41803
42534
|
});
|
|
41804
42535
|
|
|
41805
42536
|
// ../../packages/tacho/src/collector/session-commits.ts
|
|
41806
|
-
import { join as
|
|
42537
|
+
import { join as join35 } from "node:path";
|
|
41807
42538
|
function parseMeta(stdout) {
|
|
41808
42539
|
const out = [];
|
|
41809
42540
|
for (const record of stdout.split("\0")) {
|
|
@@ -41928,7 +42659,7 @@ async function readSessionCommits(exec4, cwd, input) {
|
|
|
41928
42659
|
const test = input.tests[commit.sha];
|
|
41929
42660
|
const toolUseId = callAt(times.get(commit.sha), calls);
|
|
41930
42661
|
const written2 = input.written;
|
|
41931
|
-
const outside = merge || written2 === void 0 || root === void 0 ? void 0 : files2.some((file) => !written2.has(
|
|
42662
|
+
const outside = merge || written2 === void 0 || root === void 0 ? void 0 : files2.some((file) => !written2.has(join35(root, file.path)));
|
|
41932
42663
|
return {
|
|
41933
42664
|
sha: commit.sha,
|
|
41934
42665
|
parent_shas: commit.parents.slice(0, MAX_COMMIT_PARENTS),
|
|
@@ -41976,7 +42707,7 @@ var init_session_commits = __esm({
|
|
|
41976
42707
|
|
|
41977
42708
|
// ../../packages/tacho/src/collector/worktree-snapshot.ts
|
|
41978
42709
|
import { lstat as lstat2 } from "node:fs/promises";
|
|
41979
|
-
import { join as
|
|
42710
|
+
import { join as join36 } from "node:path";
|
|
41980
42711
|
function headerPath(prefix, path2) {
|
|
41981
42712
|
const name = `${prefix}${path2}`;
|
|
41982
42713
|
let quoted3 = false;
|
|
@@ -42060,7 +42791,7 @@ async function worktreeFingerprint(status2, root) {
|
|
|
42060
42791
|
const path2 = statusPath(record);
|
|
42061
42792
|
if (path2 === null) return "";
|
|
42062
42793
|
try {
|
|
42063
|
-
const info = await lstat2(
|
|
42794
|
+
const info = await lstat2(join36(root, path2));
|
|
42064
42795
|
return `${info.size}:${info.mtimeMs}:${info.ctimeMs}`;
|
|
42065
42796
|
} catch {
|
|
42066
42797
|
return "absent";
|
|
@@ -42168,7 +42899,7 @@ async function readWorktreeSnapshot(exec4, cwd, baseline, measured) {
|
|
|
42168
42899
|
}
|
|
42169
42900
|
let present;
|
|
42170
42901
|
try {
|
|
42171
|
-
present = (await lstat2(
|
|
42902
|
+
present = (await lstat2(join36(root, path2))).isFile();
|
|
42172
42903
|
} catch {
|
|
42173
42904
|
present = false;
|
|
42174
42905
|
}
|
|
@@ -42271,10 +43002,10 @@ var init_worktree_snapshot = __esm({
|
|
|
42271
43002
|
});
|
|
42272
43003
|
|
|
42273
43004
|
// ../../packages/tacho/src/collector/git-lane.ts
|
|
42274
|
-
import { join as
|
|
43005
|
+
import { join as join37 } from "node:path";
|
|
42275
43006
|
function copiesDirOf(root, session) {
|
|
42276
43007
|
const uuid = session.recorder.sessionUuid;
|
|
42277
|
-
return /^[0-9a-f-]{36}$/i.test(uuid) ?
|
|
43008
|
+
return /^[0-9a-f-]{36}$/i.test(uuid) ? join37(root, uuid) : void 0;
|
|
42278
43009
|
}
|
|
42279
43010
|
function holdsBaseline(session) {
|
|
42280
43011
|
return session.baselineCommit !== void 0 || Object.keys(session.baselines ?? {}).length > 0;
|
|
@@ -43308,7 +44039,7 @@ var init_policy_run = __esm({
|
|
|
43308
44039
|
|
|
43309
44040
|
// ../../packages/tacho/src/collector/hook-handler.ts
|
|
43310
44041
|
import { homedir as homedir4 } from "node:os";
|
|
43311
|
-
import { dirname as
|
|
44042
|
+
import { dirname as dirname20, isAbsolute as isAbsolute7 } from "node:path";
|
|
43312
44043
|
function containmentUnmet(view, record) {
|
|
43313
44044
|
return view.verified && view.bundle.mode === "enforce" && view.bundle.containment?.required === true && view.launchedContained?.(record.harnessSessionId) !== true;
|
|
43314
44045
|
}
|
|
@@ -44264,7 +44995,7 @@ async function routeHook(raw, env, deps, replay, harness, agent, hookId) {
|
|
|
44264
44995
|
}
|
|
44265
44996
|
function writtenDir(input) {
|
|
44266
44997
|
const path2 = writtenPath(input);
|
|
44267
|
-
return path2 === void 0 ? void 0 :
|
|
44998
|
+
return path2 === void 0 ? void 0 : dirname20(path2);
|
|
44268
44999
|
}
|
|
44269
45000
|
function writtenPath(input) {
|
|
44270
45001
|
if (input.hook_event_name !== "PreToolUse" && input.hook_event_name !== "PostToolUse")
|
|
@@ -44490,7 +45221,7 @@ var init_steer_waiters = __esm({
|
|
|
44490
45221
|
});
|
|
44491
45222
|
|
|
44492
45223
|
// ../../packages/tacho/src/collector/hook-id-journal.ts
|
|
44493
|
-
import { appendFileSync as appendFileSync3, existsSync as existsSync20, readFileSync as
|
|
45224
|
+
import { appendFileSync as appendFileSync3, existsSync as existsSync20, readFileSync as readFileSync18, rmSync as rmSync7 } from "node:fs";
|
|
44494
45225
|
function hookIdJournalEntry(session, key, at2, events) {
|
|
44495
45226
|
const highest = /* @__PURE__ */ new Map();
|
|
44496
45227
|
for (const event of events) {
|
|
@@ -44517,7 +45248,7 @@ function isEntry(value) {
|
|
|
44517
45248
|
function readHookIdJournal(path2) {
|
|
44518
45249
|
if (!existsSync20(path2)) return [];
|
|
44519
45250
|
const entries2 = [];
|
|
44520
|
-
for (const line of
|
|
45251
|
+
for (const line of readFileSync18(path2, "utf8").split("\n")) {
|
|
44521
45252
|
if (line.trim().length === 0) continue;
|
|
44522
45253
|
try {
|
|
44523
45254
|
const value = JSON.parse(line);
|
|
@@ -45642,7 +46373,7 @@ var init_hook_queues = __esm({
|
|
|
45642
46373
|
|
|
45643
46374
|
// ../../packages/tacho/src/collector/memory-capture/memory-reader.ts
|
|
45644
46375
|
import { createRequire as createRequire2 } from "node:module";
|
|
45645
|
-
import { isAbsolute as isAbsolute8, join as
|
|
46376
|
+
import { isAbsolute as isAbsolute8, join as join38, sep as sep6 } from "node:path";
|
|
45646
46377
|
function claudeCodeLocation(projectsDir, memoryDir) {
|
|
45647
46378
|
return {
|
|
45648
46379
|
harness: "claude-code",
|
|
@@ -45654,13 +46385,13 @@ function claudeCodeLocation(projectsDir, memoryDir) {
|
|
|
45654
46385
|
}
|
|
45655
46386
|
function claudeCodeMemoryLocations(configDir, projectDirs = []) {
|
|
45656
46387
|
const locations = [
|
|
45657
|
-
claudeCodeLocation(() =>
|
|
45658
|
-
claudeCodeLocation(() =>
|
|
46388
|
+
claudeCodeLocation(() => join38(configDir, "projects"), "memory"),
|
|
46389
|
+
claudeCodeLocation(() => join38(configDir, "agent-memory"), "")
|
|
45659
46390
|
];
|
|
45660
46391
|
for (const dir of projectDirs.slice(0, MEMORY_PROJECT_DIRS_MAX))
|
|
45661
46392
|
locations.push(
|
|
45662
|
-
claudeCodeLocation(() =>
|
|
45663
|
-
claudeCodeLocation(() =>
|
|
46393
|
+
claudeCodeLocation(() => join38(dir, ".claude", "agent-memory"), ""),
|
|
46394
|
+
claudeCodeLocation(() => join38(dir, ".claude", "agent-memory-local"), "")
|
|
45664
46395
|
);
|
|
45665
46396
|
return locations;
|
|
45666
46397
|
}
|
|
@@ -45845,13 +46576,13 @@ function createMemoryReader(deps) {
|
|
|
45845
46576
|
const projects = await list2(top);
|
|
45846
46577
|
let complete = projects.complete;
|
|
45847
46578
|
for (const project2 of projects.names) {
|
|
45848
|
-
const dir = location.memoryDir === "" ?
|
|
46579
|
+
const dir = location.memoryDir === "" ? join38(top, project2) : join38(top, project2, location.memoryDir);
|
|
45849
46580
|
const files2 = await list2(dir);
|
|
45850
46581
|
if (!files2.complete) complete = false;
|
|
45851
46582
|
for (const name of files2.names) {
|
|
45852
46583
|
if (!name.endsWith(location.extension)) continue;
|
|
45853
46584
|
if (location.skip.includes(name)) continue;
|
|
45854
|
-
const path2 =
|
|
46585
|
+
const path2 = join38(dir, name);
|
|
45855
46586
|
const file = await readAt2(location.harness, path2);
|
|
45856
46587
|
if (file.kind === "absent" || file.kind === "empty") continue;
|
|
45857
46588
|
paths.push(path2);
|
|
@@ -45937,8 +46668,8 @@ var init_memory_reader = __esm({
|
|
|
45937
46668
|
MEMORY_TYPE_PATTERN = /^[a-z][a-z0-9_-]{0,31}$/;
|
|
45938
46669
|
MEMORY_PROJECT_DIRS_MAX = 200;
|
|
45939
46670
|
HARNESS_MEMORY_LOCATIONS = [
|
|
45940
|
-
claudeCodeLocation((home) =>
|
|
45941
|
-
claudeCodeLocation((home) =>
|
|
46671
|
+
claudeCodeLocation((home) => join38(home, ".claude", "projects"), "memory"),
|
|
46672
|
+
claudeCodeLocation((home) => join38(home, ".claude", "agent-memory"), "")
|
|
45942
46673
|
];
|
|
45943
46674
|
FRONTMATTER = /^---[ \t]*\r?\n(?:([\s\S]*?)\r?\n)?---[ \t]*(?:\r?\n|$)/;
|
|
45944
46675
|
FRONTMATTER_LINE = /^([ \t]*)([A-Za-z_][\w-]*)[ \t]*:[ \t]*(.*)$/;
|
|
@@ -46430,25 +47161,25 @@ var init_memory_recall = __esm({
|
|
|
46430
47161
|
});
|
|
46431
47162
|
|
|
46432
47163
|
// ../../packages/tacho/src/collector/memory-capture/memory-uses.ts
|
|
46433
|
-
import { basename as basename6, dirname as
|
|
47164
|
+
import { basename as basename6, dirname as dirname21, isAbsolute as isAbsolute9, join as join39, resolve as resolve14 } from "node:path";
|
|
46434
47165
|
function memoryFileOf(path2, locations, home) {
|
|
46435
47166
|
if (!isAbsolute9(path2)) return void 0;
|
|
46436
47167
|
const file = resolve14(path2);
|
|
46437
47168
|
const name = basename6(file);
|
|
46438
|
-
const folder =
|
|
47169
|
+
const folder = dirname21(file);
|
|
46439
47170
|
for (const location of locations) {
|
|
46440
47171
|
if (!name.endsWith(location.extension)) continue;
|
|
46441
47172
|
if (location.skip.includes(name)) continue;
|
|
46442
|
-
const projectDir = location.memoryDir === "" ? folder :
|
|
47173
|
+
const projectDir = location.memoryDir === "" ? folder : dirname21(folder);
|
|
46443
47174
|
if (location.memoryDir !== "" && basename6(folder) !== location.memoryDir)
|
|
46444
47175
|
continue;
|
|
46445
|
-
if (
|
|
47176
|
+
if (dirname21(projectDir) !== resolve14(location.projectsDir(home))) continue;
|
|
46446
47177
|
return { harness: location.harness, path: file };
|
|
46447
47178
|
}
|
|
46448
47179
|
return void 0;
|
|
46449
47180
|
}
|
|
46450
47181
|
function pathOf(word, cwd, home) {
|
|
46451
|
-
const expanded = /^(?:~|\$HOME|\$\{HOME\})\//.test(word) ?
|
|
47182
|
+
const expanded = /^(?:~|\$HOME|\$\{HOME\})\//.test(word) ? join39(home, word.slice(word.indexOf("/") + 1)) : word;
|
|
46452
47183
|
if (isAbsolute9(expanded)) return expanded;
|
|
46453
47184
|
if (cwd !== void 0 && isAbsolute9(cwd)) return resolve14(cwd, expanded);
|
|
46454
47185
|
return void 0;
|
|
@@ -46704,7 +47435,7 @@ ${use.path}`;
|
|
|
46704
47435
|
});
|
|
46705
47436
|
|
|
46706
47437
|
// ../../packages/tacho/src/collector/memory-capture/stella-store.ts
|
|
46707
|
-
import { dirname as
|
|
47438
|
+
import { dirname as dirname22, isAbsolute as isAbsolute10, join as join40, resolve as resolve15 } from "node:path";
|
|
46708
47439
|
function queryStellaStore(path2, afterSeq, limit) {
|
|
46709
47440
|
const db = new (nodeSqlite()).DatabaseSync(path2, { readOnly: true });
|
|
46710
47441
|
try {
|
|
@@ -46794,9 +47525,9 @@ async function stellaStoreOf(dir, exists) {
|
|
|
46794
47525
|
if (!isAbsolute10(dir)) return void 0;
|
|
46795
47526
|
let at2 = resolve15(dir);
|
|
46796
47527
|
for (let depth = 0; depth < WORKSPACE_SEARCH_DEPTH; depth += 1) {
|
|
46797
|
-
const candidate =
|
|
47528
|
+
const candidate = join40(at2, STELLA_CONTEXT_DB);
|
|
46798
47529
|
if (await exists(candidate)) return candidate;
|
|
46799
|
-
const up =
|
|
47530
|
+
const up = dirname22(at2);
|
|
46800
47531
|
if (up === at2) return void 0;
|
|
46801
47532
|
at2 = up;
|
|
46802
47533
|
}
|
|
@@ -46807,7 +47538,7 @@ var init_stella_store = __esm({
|
|
|
46807
47538
|
"../../packages/tacho/src/collector/memory-capture/stella-store.ts"() {
|
|
46808
47539
|
"use strict";
|
|
46809
47540
|
init_memory_reader();
|
|
46810
|
-
STELLA_CONTEXT_DB =
|
|
47541
|
+
STELLA_CONTEXT_DB = join40(".stella", "private", "context.db");
|
|
46811
47542
|
STELLA_MEMORIES_VIEW = "export_memories_v1";
|
|
46812
47543
|
STELLA_USES_VIEW = "export_memory_uses_v1";
|
|
46813
47544
|
STELLA_USES_PER_READ = 5e3;
|
|
@@ -47469,7 +48200,7 @@ var init_cloud_link = __esm({
|
|
|
47469
48200
|
|
|
47470
48201
|
// ../../packages/tacho/src/collector/local-servers/digest.ts
|
|
47471
48202
|
import { createHash as createHash10 } from "node:crypto";
|
|
47472
|
-
import { join as
|
|
48203
|
+
import { join as join41 } from "node:path";
|
|
47473
48204
|
function rememberBounded(map, key, value) {
|
|
47474
48205
|
if (!map.has(key) && map.size >= MAX_REMEMBERED_DIGESTS) {
|
|
47475
48206
|
const oldest = map.keys().next();
|
|
@@ -47506,7 +48237,7 @@ function npmNameSegment(name) {
|
|
|
47506
48237
|
return name.startsWith("@") ? `@${encodeURIComponent(name.slice(1))}` : encodeURIComponent(name);
|
|
47507
48238
|
}
|
|
47508
48239
|
async function whichOnPath(command2, pathValue, search) {
|
|
47509
|
-
const candidates = command2.includes("/") || command2.includes("\\") ? [command2] : (pathValue ?? "").split(search.delimiter).filter((dir) => dir.length > 0).map((dir) =>
|
|
48240
|
+
const candidates = command2.includes("/") || command2.includes("\\") ? [command2] : (pathValue ?? "").split(search.delimiter).filter((dir) => dir.length > 0).map((dir) => join41(dir, command2));
|
|
47510
48241
|
for (const candidate of candidates) {
|
|
47511
48242
|
for (const extension of search.extensions) {
|
|
47512
48243
|
if (await search.isExecutable(candidate + extension))
|
|
@@ -48509,7 +49240,7 @@ var init_local_servers = __esm({
|
|
|
48509
49240
|
|
|
48510
49241
|
// ../../packages/tacho/src/collector/local-servers/machine.ts
|
|
48511
49242
|
import { spawn as nodeSpawn } from "node:child_process";
|
|
48512
|
-
import { access, constants as
|
|
49243
|
+
import { access, constants as constants4, readFile, realpath, stat } from "node:fs/promises";
|
|
48513
49244
|
function machineParked(host) {
|
|
48514
49245
|
if (host.revoked_at !== null || host.host_status === "revoked")
|
|
48515
49246
|
return "the enrollment is revoked";
|
|
@@ -48534,7 +49265,7 @@ function createMachineLink(host, fetch2, env) {
|
|
|
48534
49265
|
async function isExecutable(path2) {
|
|
48535
49266
|
try {
|
|
48536
49267
|
if (!(await stat(path2)).isFile()) return false;
|
|
48537
|
-
await access(path2,
|
|
49268
|
+
await access(path2, constants4.X_OK);
|
|
48538
49269
|
return true;
|
|
48539
49270
|
} catch {
|
|
48540
49271
|
return false;
|
|
@@ -48802,9 +49533,9 @@ import {
|
|
|
48802
49533
|
writeFile
|
|
48803
49534
|
} from "node:fs/promises";
|
|
48804
49535
|
import { homedir as homedir5 } from "node:os";
|
|
48805
|
-
import { dirname as
|
|
49536
|
+
import { dirname as dirname23, join as join42 } from "node:path";
|
|
48806
49537
|
function stagingFolder(root, name) {
|
|
48807
|
-
return
|
|
49538
|
+
return join42(root, `.${name}${STAGING_SUFFIX}`);
|
|
48808
49539
|
}
|
|
48809
49540
|
function isStagingName(name) {
|
|
48810
49541
|
return name.startsWith(".") && name.endsWith(STAGING_SUFFIX);
|
|
@@ -48847,17 +49578,17 @@ function envDir(env, key) {
|
|
|
48847
49578
|
function skillsRoot(harness, env = process.env, home = homedir5()) {
|
|
48848
49579
|
switch (harness) {
|
|
48849
49580
|
case "claude-code":
|
|
48850
|
-
return
|
|
48851
|
-
envDir(env, "CLAUDE_CONFIG_DIR") ??
|
|
49581
|
+
return join42(
|
|
49582
|
+
envDir(env, "CLAUDE_CONFIG_DIR") ?? join42(home, ".claude"),
|
|
48852
49583
|
"skills"
|
|
48853
49584
|
);
|
|
48854
49585
|
case "codex": {
|
|
48855
49586
|
const codexHome = envDir(env, "CODEX_HOME");
|
|
48856
|
-
return codexHome === null ?
|
|
49587
|
+
return codexHome === null ? join42(home, ".agents", "skills") : join42(codexHome, "skills");
|
|
48857
49588
|
}
|
|
48858
49589
|
case "stella":
|
|
48859
|
-
return
|
|
48860
|
-
envDir(env, "STELLA_HOME") ??
|
|
49590
|
+
return join42(
|
|
49591
|
+
envDir(env, "STELLA_HOME") ?? join42(home, ".stella"),
|
|
48861
49592
|
"skills"
|
|
48862
49593
|
);
|
|
48863
49594
|
case "cursor":
|
|
@@ -48918,7 +49649,7 @@ async function readMarker(folder) {
|
|
|
48918
49649
|
if (!entries2.includes(SESSION_MARKER)) return { state: "foreign" };
|
|
48919
49650
|
try {
|
|
48920
49651
|
const parsed2 = JSON.parse(
|
|
48921
|
-
await readFile2(
|
|
49652
|
+
await readFile2(join42(folder, SESSION_MARKER), "utf8")
|
|
48922
49653
|
);
|
|
48923
49654
|
return isMarker(parsed2) ? { state: "ours", marker: parsed2 } : { state: "foreign" };
|
|
48924
49655
|
} catch {
|
|
@@ -48935,23 +49666,23 @@ function liveSessions(marker, now) {
|
|
|
48935
49666
|
return live;
|
|
48936
49667
|
}
|
|
48937
49668
|
async function writeMarker(folder, marker) {
|
|
48938
|
-
const temp =
|
|
49669
|
+
const temp = join42(folder, MARKER_TEMP);
|
|
48939
49670
|
await writeFile(temp, `${JSON.stringify(marker, null, 2)}
|
|
48940
49671
|
`);
|
|
48941
|
-
await rename2(temp,
|
|
49672
|
+
await rename2(temp, join42(folder, SESSION_MARKER));
|
|
48942
49673
|
}
|
|
48943
49674
|
async function writeSkill(root, skill, marker) {
|
|
48944
|
-
const folder =
|
|
49675
|
+
const folder = join42(root, skill.name);
|
|
48945
49676
|
const staging = stagingFolder(root, skill.name);
|
|
48946
49677
|
await rm2(folder, { recursive: true, force: true });
|
|
48947
49678
|
await rm2(staging, { recursive: true, force: true });
|
|
48948
49679
|
await mkdir2(staging);
|
|
48949
49680
|
await writeMarker(staging, { digest: UNFINISHED_DIGEST, sessions: {} });
|
|
48950
49681
|
await rename2(staging, folder);
|
|
48951
|
-
await writeFile(
|
|
49682
|
+
await writeFile(join42(folder, "SKILL.md"), skillMarkdown(skill));
|
|
48952
49683
|
for (const file of skill.files) {
|
|
48953
|
-
const target2 =
|
|
48954
|
-
await mkdir2(
|
|
49684
|
+
const target2 = join42(folder, file.path);
|
|
49685
|
+
await mkdir2(dirname23(target2), { recursive: true });
|
|
48955
49686
|
await writeFile(target2, file.content);
|
|
48956
49687
|
}
|
|
48957
49688
|
await writeMarker(folder, marker);
|
|
@@ -48979,7 +49710,7 @@ async function placeSkills(root, sessionId, skills, now = /* @__PURE__ */ new Da
|
|
|
48979
49710
|
result2.warnings.push(refusal);
|
|
48980
49711
|
continue;
|
|
48981
49712
|
}
|
|
48982
|
-
const folder =
|
|
49713
|
+
const folder = join42(root, skill.name);
|
|
48983
49714
|
if (taken.has(skill.name)) {
|
|
48984
49715
|
result2.skipped.push(skill.name);
|
|
48985
49716
|
result2.warnings.push(
|
|
@@ -49044,7 +49775,7 @@ async function removeSkills(root, sessionId, now = /* @__PURE__ */ new Date()) {
|
|
|
49044
49775
|
throw error;
|
|
49045
49776
|
}
|
|
49046
49777
|
for (const name of names2.sort(compareText)) {
|
|
49047
|
-
const folder =
|
|
49778
|
+
const folder = join42(root, name);
|
|
49048
49779
|
if (isStagingName(name)) {
|
|
49049
49780
|
await rm2(folder, { recursive: true, force: true });
|
|
49050
49781
|
continue;
|
|
@@ -49966,13 +50697,27 @@ function connectionTokens(raw) {
|
|
|
49966
50697
|
}
|
|
49967
50698
|
return named;
|
|
49968
50699
|
}
|
|
50700
|
+
function withOAuthBeta(value) {
|
|
50701
|
+
const flags = (value ?? "").split(",").map((flag2) => flag2.trim()).filter((flag2) => flag2.length > 0);
|
|
50702
|
+
if (!flags.includes(ANTHROPIC_OAUTH_BETA)) flags.push(ANTHROPIC_OAUTH_BETA);
|
|
50703
|
+
return flags.join(",");
|
|
50704
|
+
}
|
|
49969
50705
|
function upstreamRequestHeaders(raw, host, bodyLength, dropContentEncoding, attach) {
|
|
49970
50706
|
const named = connectionTokens(raw);
|
|
49971
50707
|
const out = ["Host", host];
|
|
50708
|
+
const oauth = attach?.kind === "oauth";
|
|
50709
|
+
let beta;
|
|
49972
50710
|
for (let i2 = 0; i2 + 1 < raw.length; i2 += 2) {
|
|
49973
50711
|
const name = raw[i2];
|
|
49974
50712
|
const lower = name.toLowerCase();
|
|
49975
50713
|
if (HOP_BY_HOP.has(lower) || named.has(lower)) continue;
|
|
50714
|
+
if (attach?.kind === "chatgpt" && attach.accountId !== void 0 && lower === CHATGPT_ACCOUNT_HEADER)
|
|
50715
|
+
continue;
|
|
50716
|
+
if (oauth && lower === "anthropic-beta") {
|
|
50717
|
+
const value = raw[i2 + 1];
|
|
50718
|
+
beta = beta === void 0 ? value : `${beta},${value}`;
|
|
50719
|
+
continue;
|
|
50720
|
+
}
|
|
49976
50721
|
if (lower === "host" || lower === "content-length") continue;
|
|
49977
50722
|
if (lower === "accept-encoding" || lower === "expect") continue;
|
|
49978
50723
|
if (lower === TACHO_MODEL_SESSION_HEADER) continue;
|
|
@@ -49984,6 +50729,9 @@ function upstreamRequestHeaders(raw, host, bodyLength, dropContentEncoding, atta
|
|
|
49984
50729
|
if (attach !== void 0) {
|
|
49985
50730
|
if (attach.kind === "api_key") out.push("X-Api-Key", attach.secret);
|
|
49986
50731
|
else out.push("Authorization", `Bearer ${attach.secret}`);
|
|
50732
|
+
if (oauth) out.push("anthropic-beta", withOAuthBeta(beta));
|
|
50733
|
+
if (attach.kind === "chatgpt" && attach.accountId !== void 0)
|
|
50734
|
+
out.push("ChatGPT-Account-ID", attach.accountId);
|
|
49987
50735
|
}
|
|
49988
50736
|
out.push("Accept-Encoding", "identity");
|
|
49989
50737
|
if (bodyLength > 0 || raw.some((h, i2) => i2 % 2 === 0 && /^content-length$/i.test(h)))
|
|
@@ -50017,7 +50765,7 @@ function providerError(provider, status2, code, message) {
|
|
|
50017
50765
|
};
|
|
50018
50766
|
return { status: status2, body: JSON.stringify(body2) };
|
|
50019
50767
|
}
|
|
50020
|
-
var DEFAULT_MODEL_UPSTREAMS, MODEL_PROXY_ROUTES, HOP_BY_HOP, CREDENTIAL_HEADERS;
|
|
50768
|
+
var DEFAULT_MODEL_UPSTREAMS, MODEL_PROXY_ROUTES, HOP_BY_HOP, CREDENTIAL_HEADERS, CHATGPT_ACCOUNT_HEADER, ANTHROPIC_OAUTH_BETA;
|
|
50021
50769
|
var init_model_routes = __esm({
|
|
50022
50770
|
"../../packages/tacho/src/collector/model-routes.ts"() {
|
|
50023
50771
|
"use strict";
|
|
@@ -50046,6 +50794,8 @@ var init_model_routes = __esm({
|
|
|
50046
50794
|
"upgrade"
|
|
50047
50795
|
]);
|
|
50048
50796
|
CREDENTIAL_HEADERS = ["authorization", "x-api-key"];
|
|
50797
|
+
CHATGPT_ACCOUNT_HEADER = "chatgpt-account-id";
|
|
50798
|
+
ANTHROPIC_OAUTH_BETA = "oauth-2025-04-20";
|
|
50049
50799
|
}
|
|
50050
50800
|
});
|
|
50051
50801
|
|
|
@@ -50777,7 +51527,7 @@ function createModelProxy(deps) {
|
|
|
50777
51527
|
function resolveCredential(req, route) {
|
|
50778
51528
|
const broker = deps.credentials;
|
|
50779
51529
|
const presented = presentedCredential(req);
|
|
50780
|
-
const brokered = broker !== void 0 && route.
|
|
51530
|
+
const brokered = broker !== void 0 && route.harness !== "stella" && broker.brokered(route.provider) && route.upstream === "chatgpt" === (broker.kind?.(route.provider) === "chatgpt");
|
|
50781
51531
|
if (broker === void 0 || !brokered) {
|
|
50782
51532
|
if (presented !== void 0 && looksLikeRunToken(presented.value)) {
|
|
50783
51533
|
const claims = peekRunTokenClaims(presented.value);
|
|
@@ -50832,6 +51582,27 @@ function createModelProxy(deps) {
|
|
|
50832
51582
|
}
|
|
50833
51583
|
};
|
|
50834
51584
|
}
|
|
51585
|
+
if (held2.kind === "chatgpt") {
|
|
51586
|
+
const login = decodeChatGptLogin(held2.secret);
|
|
51587
|
+
if (login === void 0)
|
|
51588
|
+
return {
|
|
51589
|
+
basis: TACHO_CREDENTIAL_GATEWAY_BROKERED,
|
|
51590
|
+
claims: verdict.claims,
|
|
51591
|
+
refusal: {
|
|
51592
|
+
code: "credential_unavailable",
|
|
51593
|
+
message: CREDENTIAL_MESSAGES.credential_unavailable
|
|
51594
|
+
}
|
|
51595
|
+
};
|
|
51596
|
+
return {
|
|
51597
|
+
basis: TACHO_CREDENTIAL_GATEWAY_BROKERED,
|
|
51598
|
+
claims: verdict.claims,
|
|
51599
|
+
attach: {
|
|
51600
|
+
kind: "chatgpt",
|
|
51601
|
+
secret: login.access_token,
|
|
51602
|
+
...login.account_id !== void 0 ? { accountId: login.account_id } : {}
|
|
51603
|
+
}
|
|
51604
|
+
};
|
|
51605
|
+
}
|
|
50835
51606
|
return {
|
|
50836
51607
|
basis: TACHO_CREDENTIAL_GATEWAY_BROKERED,
|
|
50837
51608
|
claims: verdict.claims,
|
|
@@ -51522,6 +52293,15 @@ function createModelProxy(deps) {
|
|
|
51522
52293
|
if (result2.path !== path2 && result2.path.startsWith("/"))
|
|
51523
52294
|
path2 = result2.path;
|
|
51524
52295
|
}
|
|
52296
|
+
if (credential.attach?.kind === "chatgpt") {
|
|
52297
|
+
const sent2 = injected ? injectedJson : json2();
|
|
52298
|
+
if (sent2 !== void 0 && sent2["store"] !== false) {
|
|
52299
|
+
const unstored = { ...sent2, store: false };
|
|
52300
|
+
if (injected) injectedJson = unstored;
|
|
52301
|
+
body2 = Buffer.from(JSON.stringify(unstored), "utf8");
|
|
52302
|
+
dropContentEncoding = true;
|
|
52303
|
+
}
|
|
52304
|
+
}
|
|
51525
52305
|
const requestModel = askedModel;
|
|
51526
52306
|
const requestEffort = requestEffortOf(injected ? injectedJson : json2());
|
|
51527
52307
|
const sent = injected ? body2 : readable();
|
|
@@ -52086,6 +52866,7 @@ var init_model_proxy = __esm({
|
|
|
52086
52866
|
init_frame_body();
|
|
52087
52867
|
init_replay_grade();
|
|
52088
52868
|
init_bundle();
|
|
52869
|
+
init_model_credential();
|
|
52089
52870
|
init_run_token();
|
|
52090
52871
|
init_wire();
|
|
52091
52872
|
init_cache_keep_alive();
|
|
@@ -52287,7 +53068,7 @@ var init_model_proxy_listener = __esm({
|
|
|
52287
53068
|
import {
|
|
52288
53069
|
createServer as createServer5
|
|
52289
53070
|
} from "node:http";
|
|
52290
|
-
import { chmodSync as chmodSync9, existsSync as existsSync21, statSync as
|
|
53071
|
+
import { chmodSync as chmodSync9, existsSync as existsSync21, statSync as statSync11, unlinkSync as unlinkSync11 } from "node:fs";
|
|
52291
53072
|
import { randomBytes as randomBytes11, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
52292
53073
|
import { createConnection } from "node:net";
|
|
52293
53074
|
function isExportFormat(value) {
|
|
@@ -52652,7 +53433,7 @@ function createRequestHandler(api, log, options = {}) {
|
|
|
52652
53433
|
}
|
|
52653
53434
|
async function removeStaleSocket(socketPath) {
|
|
52654
53435
|
if (!existsSync21(socketPath)) return;
|
|
52655
|
-
if (!
|
|
53436
|
+
if (!statSync11(socketPath).isSocket()) {
|
|
52656
53437
|
throw new Error(`collector socket path is not a socket: ${socketPath}`);
|
|
52657
53438
|
}
|
|
52658
53439
|
const stale = await new Promise((resolve25, reject) => {
|
|
@@ -52820,13 +53601,13 @@ var init_server = __esm({
|
|
|
52820
53601
|
});
|
|
52821
53602
|
|
|
52822
53603
|
// ../../packages/tacho/src/collector/refused.ts
|
|
52823
|
-
import { readdirSync as readdirSync12, readFileSync as
|
|
52824
|
-
import { join as
|
|
53604
|
+
import { readdirSync as readdirSync12, readFileSync as readFileSync19, statSync as statSync12 } from "node:fs";
|
|
53605
|
+
import { join as join43 } from "node:path";
|
|
52825
53606
|
function refusalRetryable(refusal) {
|
|
52826
53607
|
return refusal === "malformed" || refusal === "parked";
|
|
52827
53608
|
}
|
|
52828
53609
|
function refusedRecordPath(dir, event) {
|
|
52829
|
-
return
|
|
53610
|
+
return join43(dir, `${event.session_uuid}-${String(event.seq).padStart(8, "0")}.json`);
|
|
52830
53611
|
}
|
|
52831
53612
|
function newRefusedRecord(event, reason3, refusal, at2, body2) {
|
|
52832
53613
|
const retryable = refusalRetryable(refusal);
|
|
@@ -52869,8 +53650,8 @@ function readRefusedEntry(file) {
|
|
|
52869
53650
|
let record;
|
|
52870
53651
|
let mtimeMs;
|
|
52871
53652
|
try {
|
|
52872
|
-
record = JSON.parse(
|
|
52873
|
-
mtimeMs =
|
|
53653
|
+
record = JSON.parse(readFileSync19(file, "utf8"));
|
|
53654
|
+
mtimeMs = statSync12(file).mtimeMs;
|
|
52874
53655
|
} catch {
|
|
52875
53656
|
return void 0;
|
|
52876
53657
|
}
|
|
@@ -52902,7 +53683,7 @@ function scanRefused(dir, now, limit = MAX_REFUSED_RETRIES_PER_PASS) {
|
|
|
52902
53683
|
};
|
|
52903
53684
|
const due = [];
|
|
52904
53685
|
for (const name of names2) {
|
|
52905
|
-
const entry2 = readRefusedEntry(
|
|
53686
|
+
const entry2 = readRefusedEntry(join43(dir, name));
|
|
52906
53687
|
if (entry2 === void 0) continue;
|
|
52907
53688
|
summary.total += 1;
|
|
52908
53689
|
if (summary.lastRefusedAt === void 0 || entry2.refusedAt > summary.lastRefusedAt)
|
|
@@ -52938,8 +53719,8 @@ var init_refused = __esm({
|
|
|
52938
53719
|
});
|
|
52939
53720
|
|
|
52940
53721
|
// ../../packages/tacho/src/collector/spool.ts
|
|
52941
|
-
import { existsSync as existsSync22, readFileSync as
|
|
52942
|
-
import { join as
|
|
53722
|
+
import { existsSync as existsSync22, readFileSync as readFileSync20, unlinkSync as unlinkSync12 } from "node:fs";
|
|
53723
|
+
import { join as join44 } from "node:path";
|
|
52943
53724
|
function sessionOwnedElsewhere(error) {
|
|
52944
53725
|
return error.status === 403 && error.body.includes(SESSION_OWNED_ELSEWHERE);
|
|
52945
53726
|
}
|
|
@@ -53172,12 +53953,12 @@ var init_spool = __esm({
|
|
|
53172
53953
|
}
|
|
53173
53954
|
/** Add a body to a quarantine record that was written without one. */
|
|
53174
53955
|
stashBodyBeside(event, body2) {
|
|
53175
|
-
const path2 =
|
|
53956
|
+
const path2 = join44(
|
|
53176
53957
|
this.options.quarantineDir,
|
|
53177
53958
|
`${event.session_uuid}-${String(event.seq).padStart(8, "0")}.json`
|
|
53178
53959
|
);
|
|
53179
53960
|
try {
|
|
53180
|
-
const record = JSON.parse(
|
|
53961
|
+
const record = JSON.parse(readFileSync20(path2, "utf8"));
|
|
53181
53962
|
if (record["body"] !== void 0) return;
|
|
53182
53963
|
writeSensitiveFileAtomic(
|
|
53183
53964
|
path2,
|
|
@@ -53821,15 +54602,15 @@ var init_session_heads = __esm({
|
|
|
53821
54602
|
import {
|
|
53822
54603
|
existsSync as existsSync23,
|
|
53823
54604
|
readdirSync as readdirSync13,
|
|
53824
|
-
readFileSync as
|
|
54605
|
+
readFileSync as readFileSync21,
|
|
53825
54606
|
renameSync as renameSync4,
|
|
53826
|
-
statSync as
|
|
54607
|
+
statSync as statSync13,
|
|
53827
54608
|
unlinkSync as unlinkSync13
|
|
53828
54609
|
} from "node:fs";
|
|
53829
54610
|
import { readdir as readdir3, readFile as readFile3, stat as stat2 } from "node:fs/promises";
|
|
53830
54611
|
import { homedir as homedir7, hostname as osHostname2 } from "node:os";
|
|
53831
|
-
import { dirname as
|
|
53832
|
-
import { spawnSync as
|
|
54612
|
+
import { dirname as dirname24, join as join45 } from "node:path";
|
|
54613
|
+
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
53833
54614
|
function cloudGatewayUpstreams(origin = CLOUD_GATEWAY_ORIGIN) {
|
|
53834
54615
|
const base2 = new URL(origin).origin;
|
|
53835
54616
|
const openai = `${base2}${CLOUD_GATEWAY_BASE_PATH}/openai/v1`;
|
|
@@ -53859,7 +54640,7 @@ function cloudGatewayCredentialStore(disk, runToken) {
|
|
|
53859
54640
|
}
|
|
53860
54641
|
function readTextOrUndefined(path2) {
|
|
53861
54642
|
try {
|
|
53862
|
-
return
|
|
54643
|
+
return readFileSync21(path2, "utf8");
|
|
53863
54644
|
} catch {
|
|
53864
54645
|
return void 0;
|
|
53865
54646
|
}
|
|
@@ -53880,7 +54661,7 @@ function parseOtlpPayload(payload) {
|
|
|
53880
54661
|
return otlpPayloadSchema.parse(payload);
|
|
53881
54662
|
}
|
|
53882
54663
|
function defaultExec(command2, args) {
|
|
53883
|
-
const result2 =
|
|
54664
|
+
const result2 = spawnSync7(command2, args, {
|
|
53884
54665
|
encoding: "utf8",
|
|
53885
54666
|
maxBuffer: 4 * 1024 * 1024,
|
|
53886
54667
|
timeout: 1e4
|
|
@@ -54060,7 +54841,7 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
54060
54841
|
}) : void 0;
|
|
54061
54842
|
const memoryHome = options.home ?? homedir7();
|
|
54062
54843
|
const memoryLocations = () => claudeCodeMemoryLocations(
|
|
54063
|
-
|
|
54844
|
+
dirname24(paths.claudeProjects),
|
|
54064
54845
|
projectDirsOf(registry2.list())
|
|
54065
54846
|
);
|
|
54066
54847
|
const memoryUses = options.listen ?? true ? createMemoryUses({
|
|
@@ -54171,7 +54952,7 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
54171
54952
|
processStarts: hookProcessStarts,
|
|
54172
54953
|
adoptedChain: (sessionUuid2) => backfillLedger.chainHead(sessionUuid2)
|
|
54173
54954
|
});
|
|
54174
|
-
const priorStateWrittenAt = existsSync23(paths.daemonState) ?
|
|
54955
|
+
const priorStateWrittenAt = existsSync23(paths.daemonState) ? statSync13(paths.daemonState).mtimeMs : void 0;
|
|
54175
54956
|
const sealedState = parseSealedState(
|
|
54176
54957
|
readJsonStateFile(
|
|
54177
54958
|
paths.daemonSealedState,
|
|
@@ -54572,7 +55353,7 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
54572
55353
|
controlReachable: lastControlAt !== void 0 && now() - lastControlAt < 2 * timers.bundleRefreshMs
|
|
54573
55354
|
};
|
|
54574
55355
|
}
|
|
54575
|
-
const bodyPurgeOwedPath =
|
|
55356
|
+
const bodyPurgeOwedPath = join45(paths.wal, "body-purge-owed");
|
|
54576
55357
|
function markBodyPurgeOwed(retention, dropped) {
|
|
54577
55358
|
try {
|
|
54578
55359
|
ensureDir(paths.wal);
|
|
@@ -54594,7 +55375,7 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
54594
55375
|
if (!existsSync23(bodyPurgeOwedPath)) return void 0;
|
|
54595
55376
|
let text5;
|
|
54596
55377
|
try {
|
|
54597
|
-
text5 =
|
|
55378
|
+
text5 = readFileSync21(bodyPurgeOwedPath, "utf8");
|
|
54598
55379
|
} catch (error) {
|
|
54599
55380
|
log(
|
|
54600
55381
|
`cannot read the owed body purge at ${bodyPurgeOwedPath}: ${error instanceof Error ? error.message : String(error)}; the retry sweeps against the clause in force. Check the file's permissions`
|
|
@@ -54849,7 +55630,7 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
54849
55630
|
}
|
|
54850
55631
|
void workOrderAutostart.reconcile();
|
|
54851
55632
|
}
|
|
54852
|
-
const lastIngestFile =
|
|
55633
|
+
const lastIngestFile = join45(paths.dir, "last-ingest.json");
|
|
54853
55634
|
const shipper = new Shipper({
|
|
54854
55635
|
wal,
|
|
54855
55636
|
client,
|
|
@@ -54890,7 +55671,7 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
54890
55671
|
read: () => {
|
|
54891
55672
|
try {
|
|
54892
55673
|
const at2 = Date.parse(
|
|
54893
|
-
JSON.parse(
|
|
55674
|
+
JSON.parse(readFileSync21(lastIngestFile, "utf8")).at ?? ""
|
|
54894
55675
|
);
|
|
54895
55676
|
return Number.isFinite(at2) ? at2 : void 0;
|
|
54896
55677
|
} catch {
|
|
@@ -55371,7 +56152,7 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
55371
56152
|
async function readSpoolFile(name) {
|
|
55372
56153
|
try {
|
|
55373
56154
|
const file = parseSpoolFile(
|
|
55374
|
-
await readFile3(
|
|
56155
|
+
await readFile3(join45(paths.spool, name), "utf8")
|
|
55375
56156
|
);
|
|
55376
56157
|
spoolFacts.set(name, spoolFactsOf(file));
|
|
55377
56158
|
return file;
|
|
@@ -55560,7 +56341,7 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
55560
56341
|
function setAsideConflictingTerminal(uuid, pending, conflict) {
|
|
55561
56342
|
const name = `${uuid}-terminal-conflict-${String(conflict.seq).padStart(8, "0")}.json`;
|
|
55562
56343
|
writeSensitiveFileAtomic(
|
|
55563
|
-
|
|
56344
|
+
join45(paths.quarantine, name),
|
|
55564
56345
|
JSON.stringify(
|
|
55565
56346
|
{
|
|
55566
56347
|
reason: conflict.message,
|
|
@@ -55640,8 +56421,8 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
55640
56421
|
function moveToFailedSpool(path2, name, reason3) {
|
|
55641
56422
|
log(`spool file ${name} moved to spool/failed/: ${reason3}`);
|
|
55642
56423
|
try {
|
|
55643
|
-
ensureDir(
|
|
55644
|
-
renameSync4(path2,
|
|
56424
|
+
ensureDir(join45(paths.spool, "failed"));
|
|
56425
|
+
renameSync4(path2, join45(paths.spool, "failed", name));
|
|
55645
56426
|
} catch (error) {
|
|
55646
56427
|
log(
|
|
55647
56428
|
`spool file ${name} could not be moved to spool/failed/: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -55694,7 +56475,7 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
55694
56475
|
continue;
|
|
55695
56476
|
}
|
|
55696
56477
|
reads += 1;
|
|
55697
|
-
const path2 =
|
|
56478
|
+
const path2 = join45(paths.spool, name);
|
|
55698
56479
|
let file;
|
|
55699
56480
|
try {
|
|
55700
56481
|
file = await readSpoolFile(name);
|
|
@@ -55979,7 +56760,7 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
55979
56760
|
const state = await readModelBaseUrlState({
|
|
55980
56761
|
home: options.home ?? homedir7(),
|
|
55981
56762
|
port: modelProxyPortFor(host),
|
|
55982
|
-
stellaHome:
|
|
56763
|
+
stellaHome: dirname24(options.paths.stellaToml),
|
|
55983
56764
|
harnesses: ["claude-code", "codex", "stella"]
|
|
55984
56765
|
});
|
|
55985
56766
|
const next = {};
|
|
@@ -56083,6 +56864,13 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
56083
56864
|
...options.pauseHold,
|
|
56084
56865
|
credentials: {
|
|
56085
56866
|
brokered: (provider) => inCustody(provider),
|
|
56867
|
+
kind: (provider) => {
|
|
56868
|
+
try {
|
|
56869
|
+
return credentialStore.status().find((entry2) => entry2.provider === provider)?.kind;
|
|
56870
|
+
} catch {
|
|
56871
|
+
return void 0;
|
|
56872
|
+
}
|
|
56873
|
+
},
|
|
56086
56874
|
custody: (provider) => {
|
|
56087
56875
|
try {
|
|
56088
56876
|
return credentialStore.read(provider);
|
|
@@ -56147,6 +56935,13 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
56147
56935
|
record,
|
|
56148
56936
|
model: modelProxy,
|
|
56149
56937
|
modelPort: () => modelProxyListener.port(),
|
|
56938
|
+
chatgptLogin: () => {
|
|
56939
|
+
try {
|
|
56940
|
+
return credentialStore.status().some((c) => c.provider === "openai" && c.kind === "chatgpt");
|
|
56941
|
+
} catch {
|
|
56942
|
+
return false;
|
|
56943
|
+
}
|
|
56944
|
+
},
|
|
56150
56945
|
issueCredential: (harness) => issueRunToken(
|
|
56151
56946
|
{ harness },
|
|
56152
56947
|
{
|
|
@@ -56521,9 +57316,9 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
56521
57316
|
let removed = 0;
|
|
56522
57317
|
for (const name of readdirSync13(paths.quarantine)) {
|
|
56523
57318
|
if (!name.endsWith(".json")) continue;
|
|
56524
|
-
const file =
|
|
57319
|
+
const file = join45(paths.quarantine, name);
|
|
56525
57320
|
try {
|
|
56526
|
-
const refusedAt = readRefusedEntry(file)?.refusedAt ??
|
|
57321
|
+
const refusedAt = readRefusedEntry(file)?.refusedAt ?? statSync13(file).mtimeMs;
|
|
56527
57322
|
if (at2 - refusedAt < retainMs) continue;
|
|
56528
57323
|
unlinkSync13(file);
|
|
56529
57324
|
removed += 1;
|
|
@@ -56777,8 +57572,29 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
56777
57572
|
});
|
|
56778
57573
|
}
|
|
56779
57574
|
let lastStaticRenewalAt = 0;
|
|
57575
|
+
let lastLoginRefreshAt = 0;
|
|
56780
57576
|
async function renewStaticTokens() {
|
|
56781
57577
|
if (!host.harnesses.includes("codex")) return;
|
|
57578
|
+
if (now() - lastLoginRefreshAt >= CHATGPT_LOGIN_CHECK_MS) {
|
|
57579
|
+
lastLoginRefreshAt = now();
|
|
57580
|
+
try {
|
|
57581
|
+
const refreshed = await refreshChatGptCustody(
|
|
57582
|
+
credentialStore,
|
|
57583
|
+
options.fetch ?? fetch,
|
|
57584
|
+
now()
|
|
57585
|
+
);
|
|
57586
|
+
if (refreshed === "refreshed")
|
|
57587
|
+
log("refreshed the ChatGPT login in custody");
|
|
57588
|
+
else if (typeof refreshed === "object")
|
|
57589
|
+
log(`ChatGPT login refresh: ${refreshed.failed}`);
|
|
57590
|
+
if (refreshed !== "none")
|
|
57591
|
+
restateCodexLastRefresh(options.home ?? homedir7(), now());
|
|
57592
|
+
} catch (error) {
|
|
57593
|
+
log(
|
|
57594
|
+
`ChatGPT login refresh: ${error instanceof Error ? error.message : String(error)}`
|
|
57595
|
+
);
|
|
57596
|
+
}
|
|
57597
|
+
}
|
|
56782
57598
|
if (now() - lastStaticRenewalAt < STATIC_TOKEN_RENEWAL_CHECK_MS) return;
|
|
56783
57599
|
lastStaticRenewalAt = now();
|
|
56784
57600
|
if (host.host_status !== "active" || !inCustody("openai")) return;
|
|
@@ -56851,7 +57667,7 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
56851
57667
|
let memoryScan;
|
|
56852
57668
|
if (options.listen ?? true) {
|
|
56853
57669
|
const codexMemories = createCodexMemoryStore({
|
|
56854
|
-
path:
|
|
57670
|
+
path: join45(dirname24(paths.codexHooks), CODEX_MEMORY_STORE_FILE),
|
|
56855
57671
|
stat: (path2) => stat2(path2),
|
|
56856
57672
|
log
|
|
56857
57673
|
});
|
|
@@ -56996,7 +57812,7 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
56996
57812
|
}
|
|
56997
57813
|
};
|
|
56998
57814
|
}
|
|
56999
|
-
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;
|
|
57815
|
+
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;
|
|
57000
57816
|
var init_daemon = __esm({
|
|
57001
57817
|
"../../packages/tacho/src/collector/daemon.ts"() {
|
|
57002
57818
|
"use strict";
|
|
@@ -57018,6 +57834,7 @@ var init_daemon = __esm({
|
|
|
57018
57834
|
init_claude_code_mcp_writer();
|
|
57019
57835
|
init_model_base_url();
|
|
57020
57836
|
init_model_credential();
|
|
57837
|
+
init_chatgpt_refresh();
|
|
57021
57838
|
init_run_token();
|
|
57022
57839
|
init_process_scan();
|
|
57023
57840
|
init_retention();
|
|
@@ -57090,6 +57907,7 @@ var init_daemon = __esm({
|
|
|
57090
57907
|
hookBundleWaitMs: 2e3
|
|
57091
57908
|
};
|
|
57092
57909
|
STATIC_TOKEN_RENEWAL_CHECK_MS = 60 * 6e4;
|
|
57910
|
+
CHATGPT_LOGIN_CHECK_MS = 10 * 6e4;
|
|
57093
57911
|
MEMORY_SCAN_MS = 5 * 6e4;
|
|
57094
57912
|
CLOUD_GATEWAY_ORIGIN = "https://api.oxagen.sh";
|
|
57095
57913
|
CLOUD_GATEWAY_BASE_PATH = "/v1/gateway";
|
|
@@ -57139,7 +57957,7 @@ var init_daemon = __esm({
|
|
|
57139
57957
|
});
|
|
57140
57958
|
|
|
57141
57959
|
// ../../packages/tacho/src/collector/run.ts
|
|
57142
|
-
import { readFileSync as
|
|
57960
|
+
import { readFileSync as readFileSync22, unlinkSync as unlinkSync14 } from "node:fs";
|
|
57143
57961
|
function stopWithin(stop, graceMs, exit, log) {
|
|
57144
57962
|
const timer = setTimeout(() => {
|
|
57145
57963
|
log(`tachod: stop did not finish within ${graceMs} ms, exiting
|
|
@@ -57207,14 +58025,14 @@ function ownProcStart() {
|
|
|
57207
58025
|
}
|
|
57208
58026
|
function readPidFile(path2) {
|
|
57209
58027
|
try {
|
|
57210
|
-
return
|
|
58028
|
+
return readFileSync22(path2, "utf8");
|
|
57211
58029
|
} catch {
|
|
57212
58030
|
return void 0;
|
|
57213
58031
|
}
|
|
57214
58032
|
}
|
|
57215
58033
|
function releaseDaemonPid(path2, previous) {
|
|
57216
58034
|
try {
|
|
57217
|
-
if (parseDaemonPid(
|
|
58035
|
+
if (parseDaemonPid(readFileSync22(path2, "utf8"))?.pid !== process.pid) return;
|
|
57218
58036
|
if (previous === void 0) unlinkSync14(path2);
|
|
57219
58037
|
else writeSensitiveFileAtomic(path2, previous, 420);
|
|
57220
58038
|
} catch {
|
|
@@ -57354,7 +58172,7 @@ var init_run2 = __esm({
|
|
|
57354
58172
|
// ../../packages/tacho/src/arp/bundle.ts
|
|
57355
58173
|
import {
|
|
57356
58174
|
closeSync as closeSync8,
|
|
57357
|
-
constants as
|
|
58175
|
+
constants as constants5,
|
|
57358
58176
|
fstatSync as fstatSync2,
|
|
57359
58177
|
lstatSync as lstatSync8,
|
|
57360
58178
|
mkdirSync as mkdirSync6,
|
|
@@ -57363,7 +58181,7 @@ import {
|
|
|
57363
58181
|
realpathSync as realpathSync5,
|
|
57364
58182
|
writeFileSync as writeFileSync4
|
|
57365
58183
|
} from "node:fs";
|
|
57366
|
-
import { dirname as
|
|
58184
|
+
import { dirname as dirname25, join as join46, resolve as resolve17 } from "node:path";
|
|
57367
58185
|
function bundlePath(root, relative11, create2 = false) {
|
|
57368
58186
|
const absolute = resolve17(root);
|
|
57369
58187
|
if (create2) mkdirSync6(absolute, { recursive: true, mode: 448 });
|
|
@@ -57374,7 +58192,7 @@ function bundlePath(root, relative11, create2 = false) {
|
|
|
57374
58192
|
let current = base2;
|
|
57375
58193
|
const parts = relative11.split("/");
|
|
57376
58194
|
for (let i2 = 0; i2 < parts.length; i2++) {
|
|
57377
|
-
current =
|
|
58195
|
+
current = join46(current, parts[i2]);
|
|
57378
58196
|
try {
|
|
57379
58197
|
const stat7 = lstatSync8(current);
|
|
57380
58198
|
if (stat7.isSymbolicLink() || i2 < parts.length - 1 && !stat7.isDirectory()) {
|
|
@@ -57388,14 +58206,14 @@ function bundlePath(root, relative11, create2 = false) {
|
|
|
57388
58206
|
else if (i2 < parts.length - 1) throw error;
|
|
57389
58207
|
}
|
|
57390
58208
|
}
|
|
57391
|
-
if (realpathSync5(
|
|
58209
|
+
if (realpathSync5(dirname25(current)) !== dirname25(current)) {
|
|
57392
58210
|
arpFail(`The bundle directory changed while ${relative11} was read.`);
|
|
57393
58211
|
}
|
|
57394
58212
|
return current;
|
|
57395
58213
|
}
|
|
57396
58214
|
function readBounded(root, relative11, limit = ARP_MAX_BLOB_BYTES) {
|
|
57397
58215
|
const path2 = bundlePath(root, relative11);
|
|
57398
|
-
const fd2 = openSync8(path2,
|
|
58216
|
+
const fd2 = openSync8(path2, constants5.O_RDONLY | constants5.O_NOFOLLOW);
|
|
57399
58217
|
try {
|
|
57400
58218
|
const stat7 = fstatSync2(fd2);
|
|
57401
58219
|
if (!stat7.isFile() || stat7.size > limit)
|
|
@@ -57420,7 +58238,7 @@ function writeNew(root, relative11, bytes) {
|
|
|
57420
58238
|
const path2 = bundlePath(root, relative11, true);
|
|
57421
58239
|
const fd2 = openSync8(
|
|
57422
58240
|
path2,
|
|
57423
|
-
|
|
58241
|
+
constants5.O_WRONLY | constants5.O_CREAT | constants5.O_EXCL | constants5.O_NOFOLLOW,
|
|
57424
58242
|
384
|
|
57425
58243
|
);
|
|
57426
58244
|
try {
|
|
@@ -58325,7 +59143,7 @@ var init_oracles = __esm({
|
|
|
58325
59143
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
58326
59144
|
import {
|
|
58327
59145
|
closeSync as closeSync9,
|
|
58328
|
-
constants as
|
|
59146
|
+
constants as constants6,
|
|
58329
59147
|
fstatSync as fstatSync3,
|
|
58330
59148
|
lstatSync as lstatSync9,
|
|
58331
59149
|
mkdirSync as mkdirSync7,
|
|
@@ -58335,7 +59153,7 @@ import {
|
|
|
58335
59153
|
rmSync as rmSync8,
|
|
58336
59154
|
writeFileSync as writeFileSync5
|
|
58337
59155
|
} from "node:fs";
|
|
58338
|
-
import { dirname as
|
|
59156
|
+
import { dirname as dirname26, isAbsolute as isAbsolute11, join as join47, relative as relative5, resolve as resolve18, sep as sep7 } from "node:path";
|
|
58339
59157
|
function outsideProfile(path2) {
|
|
58340
59158
|
return HARNESS_CONFIG_PATH.test(path2) || CREDENTIAL_PATH.test(path2);
|
|
58341
59159
|
}
|
|
@@ -58346,7 +59164,7 @@ function sameJson(bytes, expected) {
|
|
|
58346
59164
|
return jcs(JSON.parse(bytes.toString("utf8"))) === jcs(expected);
|
|
58347
59165
|
}
|
|
58348
59166
|
function readRegular(label2, path2, limit) {
|
|
58349
|
-
const fd2 = openSync9(path2,
|
|
59167
|
+
const fd2 = openSync9(path2, constants6.O_RDONLY | constants6.O_NOFOLLOW);
|
|
58350
59168
|
try {
|
|
58351
59169
|
const before = fstatSync3(fd2);
|
|
58352
59170
|
if (!before.isFile() || before.size > limit)
|
|
@@ -58391,9 +59209,9 @@ function within2(root, path2) {
|
|
|
58391
59209
|
}
|
|
58392
59210
|
function newPath(path2) {
|
|
58393
59211
|
const full = resolve18(path2);
|
|
58394
|
-
return
|
|
58395
|
-
realpathSync6(
|
|
58396
|
-
full.slice(
|
|
59212
|
+
return join47(
|
|
59213
|
+
realpathSync6(dirname26(full)),
|
|
59214
|
+
full.slice(dirname26(full).length + 1)
|
|
58397
59215
|
);
|
|
58398
59216
|
}
|
|
58399
59217
|
function sourcePath(root, path2) {
|
|
@@ -58405,7 +59223,7 @@ function sourcePath(root, path2) {
|
|
|
58405
59223
|
}
|
|
58406
59224
|
let current = root;
|
|
58407
59225
|
for (const part2 of path2.split("/")) {
|
|
58408
|
-
current =
|
|
59226
|
+
current = join47(current, part2);
|
|
58409
59227
|
if (lstatSync9(current).isSymbolicLink())
|
|
58410
59228
|
arpFail(
|
|
58411
59229
|
`${path2} is a symlink or passes through one. Symlinks require a resource adapter.`
|
|
@@ -58672,23 +59490,23 @@ function prepareCheckpoint(options) {
|
|
|
58672
59490
|
});
|
|
58673
59491
|
mkdirSync7(destination, { mode: 448 });
|
|
58674
59492
|
try {
|
|
58675
|
-
const restored =
|
|
59493
|
+
const restored = join47(destination, "workspace");
|
|
58676
59494
|
mkdirSync7(restored, { mode: 448 });
|
|
58677
59495
|
for (const item of restore) {
|
|
58678
|
-
const path2 =
|
|
59496
|
+
const path2 = join47(restored, item.path);
|
|
58679
59497
|
if (item.kind === "directory")
|
|
58680
59498
|
mkdirSync7(path2, { recursive: true, mode: 448 });
|
|
58681
59499
|
else {
|
|
58682
|
-
mkdirSync7(
|
|
59500
|
+
mkdirSync7(dirname26(path2), { recursive: true, mode: 448 });
|
|
58683
59501
|
writeFileSync5(path2, item.bytes, {
|
|
58684
59502
|
flag: "wx",
|
|
58685
59503
|
mode: item.executable ? 448 : 384
|
|
58686
59504
|
});
|
|
58687
59505
|
}
|
|
58688
59506
|
}
|
|
58689
|
-
const promptDir =
|
|
59507
|
+
const promptDir = join47(restored, ".arp");
|
|
58690
59508
|
mkdirSync7(promptDir, { mode: 448 });
|
|
58691
|
-
const promptFile =
|
|
59509
|
+
const promptFile = join47(promptDir, "handoff.json");
|
|
58692
59510
|
const prompt = {
|
|
58693
59511
|
checkpoint_digest: checkpointDigest,
|
|
58694
59512
|
task: task.data.request,
|
|
@@ -58705,7 +59523,7 @@ function prepareCheckpoint(options) {
|
|
|
58705
59523
|
flag: "wx",
|
|
58706
59524
|
mode: 384
|
|
58707
59525
|
});
|
|
58708
|
-
const reportPath =
|
|
59526
|
+
const reportPath = join47(destination, "report.json");
|
|
58709
59527
|
writeFileSync5(
|
|
58710
59528
|
reportPath,
|
|
58711
59529
|
jcs(
|
|
@@ -58890,7 +59708,7 @@ __export(main_exports, {
|
|
|
58890
59708
|
recordedCliDeps: () => recordedCliDeps,
|
|
58891
59709
|
tokenOption: () => tokenOption
|
|
58892
59710
|
});
|
|
58893
|
-
import { readFileSync as
|
|
59711
|
+
import { readFileSync as readFileSync23 } from "node:fs";
|
|
58894
59712
|
function parsePort(value) {
|
|
58895
59713
|
const port = Number(value);
|
|
58896
59714
|
if (!/^\d+$/.test(value) || port < 1024 || port > 65535)
|
|
@@ -58927,7 +59745,7 @@ function parseOneHarness(value) {
|
|
|
58927
59745
|
throw new InvalidArgumentError("name one harness");
|
|
58928
59746
|
return harness;
|
|
58929
59747
|
}
|
|
58930
|
-
function tokenOption(opts, err2, readStdin3 = () =>
|
|
59748
|
+
function tokenOption(opts, err2, readStdin3 = () => readFileSync23(0, "utf8")) {
|
|
58931
59749
|
const flag2 = opts.token;
|
|
58932
59750
|
if (opts.tokenStdin !== true) {
|
|
58933
59751
|
if (flag2 !== void 0)
|
|
@@ -59082,6 +59900,41 @@ function buildTachoProgram(options = {}) {
|
|
|
59082
59900
|
deps.err(`${name} credential: ${result2.detail}`);
|
|
59083
59901
|
process.exitCode = 1;
|
|
59084
59902
|
});
|
|
59903
|
+
credential.command("login").description(
|
|
59904
|
+
"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`)"
|
|
59905
|
+
).option("--harness <name>", "claude-code (default) | codex").option(
|
|
59906
|
+
"--token-stdin",
|
|
59907
|
+
"Claude Code only: read a token `claude setup-token` printed from stdin instead of signing in"
|
|
59908
|
+
).option("--json", "Print the outcome as JSON").action(
|
|
59909
|
+
async (opts) => {
|
|
59910
|
+
const harness = opts.harness ?? "claude-code";
|
|
59911
|
+
if (harness !== "claude-code" && harness !== "codex") {
|
|
59912
|
+
deps.err(
|
|
59913
|
+
`${name} credential login: --harness takes claude-code or codex; got "${harness}"`
|
|
59914
|
+
);
|
|
59915
|
+
process.exitCode = 1;
|
|
59916
|
+
return;
|
|
59917
|
+
}
|
|
59918
|
+
const outcome = await credentialLogin(
|
|
59919
|
+
{
|
|
59920
|
+
harness,
|
|
59921
|
+
...opts.tokenStdin === true ? { tokenStdin: true } : {}
|
|
59922
|
+
},
|
|
59923
|
+
deps
|
|
59924
|
+
);
|
|
59925
|
+
if (opts.json === true) deps.out(JSON.stringify(outcome, null, 2));
|
|
59926
|
+
else {
|
|
59927
|
+
for (const entry2 of outcome.harnesses)
|
|
59928
|
+
deps.out(` ${describeHarness(entry2)}`);
|
|
59929
|
+
for (const warning of outcome.warnings)
|
|
59930
|
+
deps.err(`warning: ${warning}`);
|
|
59931
|
+
(outcome.ok ? deps.out : deps.err)(
|
|
59932
|
+
`${outcome.ok ? "" : `${name} credential login: `}${outcome.detail}`
|
|
59933
|
+
);
|
|
59934
|
+
}
|
|
59935
|
+
if (!outcome.ok) process.exitCode = 1;
|
|
59936
|
+
}
|
|
59937
|
+
);
|
|
59085
59938
|
credential.command("status").description(
|
|
59086
59939
|
"Which providers the gateway holds, and how each harness gets its credential"
|
|
59087
59940
|
).option("--json", "Machine-readable output").action(async (opts) => {
|
|
@@ -59346,7 +60199,7 @@ var init_package = __esm({
|
|
|
59346
60199
|
"package.json"() {
|
|
59347
60200
|
package_default = {
|
|
59348
60201
|
name: "@oxagen/cli",
|
|
59349
|
-
version: "2.1.4-
|
|
60202
|
+
version: "2.1.4-965",
|
|
59350
60203
|
description: "Oxagen governance CLI \u2014 spend, lineage, grounding, credentials, and audit (agentic coding lives in the stella CLI)",
|
|
59351
60204
|
type: "module",
|
|
59352
60205
|
main: "./dist/index.js",
|
|
@@ -59413,10 +60266,10 @@ var init_package = __esm({
|
|
|
59413
60266
|
|
|
59414
60267
|
// src/lib/atomic-write.ts
|
|
59415
60268
|
import { writeFileSync as writeFileSync6, renameSync as renameSync5, unlinkSync as unlinkSync15, existsSync as existsSync24 } from "node:fs";
|
|
59416
|
-
import { dirname as
|
|
60269
|
+
import { dirname as dirname27, join as join48 } from "node:path";
|
|
59417
60270
|
function atomicWriteFileSync(path2, data, mode) {
|
|
59418
|
-
const dir =
|
|
59419
|
-
const tmp =
|
|
60271
|
+
const dir = dirname27(path2);
|
|
60272
|
+
const tmp = join48(
|
|
59420
60273
|
dir,
|
|
59421
60274
|
`.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`
|
|
59422
60275
|
);
|
|
@@ -59441,8 +60294,8 @@ var init_atomic_write = __esm({
|
|
|
59441
60294
|
|
|
59442
60295
|
// src/lib/config.ts
|
|
59443
60296
|
import { homedir as homedir8 } from "os";
|
|
59444
|
-
import { join as
|
|
59445
|
-
import { readFileSync as
|
|
60297
|
+
import { join as join49 } from "path";
|
|
60298
|
+
import { readFileSync as readFileSync24, mkdirSync as mkdirSync8, existsSync as existsSync25, statSync as statSync14 } from "fs";
|
|
59446
60299
|
function getConfigDir() {
|
|
59447
60300
|
return CONFIG_DIR;
|
|
59448
60301
|
}
|
|
@@ -59472,7 +60325,7 @@ function parseConfig(raw) {
|
|
|
59472
60325
|
function readConfig() {
|
|
59473
60326
|
let identity;
|
|
59474
60327
|
try {
|
|
59475
|
-
const info =
|
|
60328
|
+
const info = statSync14(CONFIG_FILE);
|
|
59476
60329
|
identity = `${info.ino}:${info.size}:${info.mtimeMs}`;
|
|
59477
60330
|
} catch {
|
|
59478
60331
|
cached2 = void 0;
|
|
@@ -59480,7 +60333,7 @@ function readConfig() {
|
|
|
59480
60333
|
}
|
|
59481
60334
|
if (cached2?.identity === identity) return structuredClone(cached2.config);
|
|
59482
60335
|
try {
|
|
59483
|
-
const config = parseConfig(JSON.parse(
|
|
60336
|
+
const config = parseConfig(JSON.parse(readFileSync24(CONFIG_FILE, "utf8")));
|
|
59484
60337
|
cached2 = { identity, config };
|
|
59485
60338
|
return structuredClone(config);
|
|
59486
60339
|
} catch (err2) {
|
|
@@ -59528,8 +60381,8 @@ var CONFIG_DIR, CONFIG_FILE, STRING_FIELDS, TELEMETRY_FIELDS, cached2;
|
|
|
59528
60381
|
var init_config = __esm({
|
|
59529
60382
|
"src/lib/config.ts"() {
|
|
59530
60383
|
init_atomic_write();
|
|
59531
|
-
CONFIG_DIR =
|
|
59532
|
-
CONFIG_FILE =
|
|
60384
|
+
CONFIG_DIR = join49(homedir8(), ".config", "oxagen");
|
|
60385
|
+
CONFIG_FILE = join49(CONFIG_DIR, "config.json");
|
|
59533
60386
|
STRING_FIELDS = [
|
|
59534
60387
|
"token",
|
|
59535
60388
|
"orgSlug",
|
|
@@ -59574,16 +60427,16 @@ import {
|
|
|
59574
60427
|
writeFile as writeFile2
|
|
59575
60428
|
} from "node:fs/promises";
|
|
59576
60429
|
import { homedir as homedir9 } from "node:os";
|
|
59577
|
-
import { join as
|
|
60430
|
+
import { join as join50 } from "node:path";
|
|
59578
60431
|
function isDebugEnabled() {
|
|
59579
60432
|
const v = process.env[DEBUG_ENV];
|
|
59580
60433
|
return v === "1" || v === "true";
|
|
59581
60434
|
}
|
|
59582
60435
|
function logsDir() {
|
|
59583
|
-
return
|
|
60436
|
+
return join50(homedir9(), ".oxagen", "logs");
|
|
59584
60437
|
}
|
|
59585
60438
|
function debugLogFile() {
|
|
59586
|
-
return
|
|
60439
|
+
return join50(logsDir(), "cli.output");
|
|
59587
60440
|
}
|
|
59588
60441
|
function sanitize(value, depth = 0) {
|
|
59589
60442
|
if (value === null || value === void 0) return value;
|
|
@@ -62878,9 +63731,9 @@ var init_git = __esm({
|
|
|
62878
63731
|
|
|
62879
63732
|
// ../../packages/steering-freshness/src/cache.ts
|
|
62880
63733
|
import { mkdir as mkdir4, readFile as readFile6, writeFile as writeFile4 } from "node:fs/promises";
|
|
62881
|
-
import { dirname as
|
|
63734
|
+
import { dirname as dirname28, join as join51 } from "node:path";
|
|
62882
63735
|
function stampPath(gitCommonDir) {
|
|
62883
|
-
return
|
|
63736
|
+
return join51(gitCommonDir, "oxagen", "steering-freshness.json");
|
|
62884
63737
|
}
|
|
62885
63738
|
async function readFetchStamp(gitCommonDir, io = defaultIo) {
|
|
62886
63739
|
try {
|
|
@@ -62901,7 +63754,7 @@ async function readFetchStamp(gitCommonDir, io = defaultIo) {
|
|
|
62901
63754
|
async function writeFetchStamp(gitCommonDir, stamp, io = defaultIo) {
|
|
62902
63755
|
const path2 = stampPath(gitCommonDir);
|
|
62903
63756
|
try {
|
|
62904
|
-
await io.mkdirp(
|
|
63757
|
+
await io.mkdirp(dirname28(path2));
|
|
62905
63758
|
await io.write(path2, `${JSON.stringify(stamp)}
|
|
62906
63759
|
`, "utf8");
|
|
62907
63760
|
} catch {
|
|
@@ -62932,24 +63785,24 @@ var init_cache = __esm({
|
|
|
62932
63785
|
// ../../packages/steering-freshness/src/hooks.ts
|
|
62933
63786
|
import { mkdir as mkdir5, readFile as readFile7, writeFile as writeFile5 } from "node:fs/promises";
|
|
62934
63787
|
import { homedir as homedir10 } from "node:os";
|
|
62935
|
-
import { dirname as
|
|
63788
|
+
import { dirname as dirname29, join as join52 } from "node:path";
|
|
62936
63789
|
function hookCommand(harness) {
|
|
62937
63790
|
return `oxagen steering gate --harness ${harness}`;
|
|
62938
63791
|
}
|
|
62939
63792
|
function hookConfigPath(projectRoot, harness, env = process.env, home = homedir10()) {
|
|
62940
63793
|
switch (harness) {
|
|
62941
63794
|
case "claude-code":
|
|
62942
|
-
return
|
|
63795
|
+
return join52(projectRoot, ".claude", "settings.json");
|
|
62943
63796
|
case "codex":
|
|
62944
|
-
return
|
|
63797
|
+
return join52(env["CODEX_HOME"] ?? join52(home, ".codex"), "hooks.json");
|
|
62945
63798
|
case "cursor":
|
|
62946
|
-
return
|
|
63799
|
+
return join52(home, ".cursor", "hooks.json");
|
|
62947
63800
|
case "stella":
|
|
62948
|
-
return
|
|
63801
|
+
return join52(env["STELLA_HOME"] ?? join52(home, ".stella"), "stella.toml");
|
|
62949
63802
|
}
|
|
62950
63803
|
}
|
|
62951
63804
|
function stellaJsonPath(env, home) {
|
|
62952
|
-
return
|
|
63805
|
+
return join52(env["STELLA_HOME"] ?? join52(home, ".stella"), "settings.json");
|
|
62953
63806
|
}
|
|
62954
63807
|
function isRecord7(v) {
|
|
62955
63808
|
return v !== null && typeof v === "object" && !Array.isArray(v);
|
|
@@ -63036,7 +63889,7 @@ async function installJsonGroupHook(path2, harness, entry2, io) {
|
|
|
63036
63889
|
};
|
|
63037
63890
|
}
|
|
63038
63891
|
const had = hasGroupHook(loaded.config);
|
|
63039
|
-
await io.mkdirp(
|
|
63892
|
+
await io.mkdirp(dirname29(path2));
|
|
63040
63893
|
await io.write(
|
|
63041
63894
|
path2,
|
|
63042
63895
|
`${JSON.stringify(withGroupHook(loaded.config, entry2), null, 2)}
|
|
@@ -63138,7 +63991,7 @@ async function installCursorHook(path2, io) {
|
|
|
63138
63991
|
];
|
|
63139
63992
|
const next = { ...config, hooks };
|
|
63140
63993
|
if (next.version === void 0) next.version = 1;
|
|
63141
|
-
await io.mkdirp(
|
|
63994
|
+
await io.mkdirp(dirname29(path2));
|
|
63142
63995
|
await io.write(path2, `${JSON.stringify(next, null, 2)}
|
|
63143
63996
|
`, "utf8");
|
|
63144
63997
|
return {
|
|
@@ -63321,7 +64174,7 @@ async function installStellaHook(projectRoot, io, env, home) {
|
|
|
63321
64174
|
}
|
|
63322
64175
|
const separator = base2.length === 0 ? "" : eol;
|
|
63323
64176
|
const next = `${base2}${separator}${renderStellaBlock(eol)}`;
|
|
63324
|
-
await io.mkdirp(
|
|
64177
|
+
await io.mkdirp(dirname29(path2));
|
|
63325
64178
|
await io.write(path2, next, "utf8");
|
|
63326
64179
|
return {
|
|
63327
64180
|
harness: "stella",
|
|
@@ -63609,7 +64462,7 @@ var init_policy = __esm({
|
|
|
63609
64462
|
// ../../packages/steering-freshness/src/settings.ts
|
|
63610
64463
|
import { readFile as readFile8 } from "node:fs/promises";
|
|
63611
64464
|
import { homedir as homedir11 } from "node:os";
|
|
63612
|
-
import { join as
|
|
64465
|
+
import { join as join53 } from "node:path";
|
|
63613
64466
|
async function readLayer(scope, path2, read2) {
|
|
63614
64467
|
let text5;
|
|
63615
64468
|
try {
|
|
@@ -63661,14 +64514,14 @@ function parseLayer(scope, path2, text5) {
|
|
|
63661
64514
|
}
|
|
63662
64515
|
async function loadSteeringSettings({
|
|
63663
64516
|
projectRoot,
|
|
63664
|
-
userSettingsPath =
|
|
64517
|
+
userSettingsPath = join53(homedir11(), USER_SETTINGS_RELATIVE),
|
|
63665
64518
|
read: read2 = readFile8,
|
|
63666
64519
|
workspacePolicy = null
|
|
63667
64520
|
}) {
|
|
63668
64521
|
const targets = [
|
|
63669
64522
|
["user", userSettingsPath],
|
|
63670
|
-
["project",
|
|
63671
|
-
["local",
|
|
64523
|
+
["project", join53(projectRoot, PROJECT_DIR_NAME, PROJECT_SETTINGS_FILE)],
|
|
64524
|
+
["local", join53(projectRoot, PROJECT_DIR_NAME, LOCAL_SETTINGS_FILE)]
|
|
63672
64525
|
];
|
|
63673
64526
|
const layers = [];
|
|
63674
64527
|
const warnings = [];
|
|
@@ -63731,7 +64584,7 @@ var init_settings = __esm({
|
|
|
63731
64584
|
"use strict";
|
|
63732
64585
|
init_git();
|
|
63733
64586
|
init_policy();
|
|
63734
|
-
USER_SETTINGS_RELATIVE =
|
|
64587
|
+
USER_SETTINGS_RELATIVE = join53(
|
|
63735
64588
|
".config",
|
|
63736
64589
|
"oxagen",
|
|
63737
64590
|
"settings.json"
|
|
@@ -63744,7 +64597,7 @@ var init_settings = __esm({
|
|
|
63744
64597
|
|
|
63745
64598
|
// ../../packages/steering-freshness/src/check.ts
|
|
63746
64599
|
import { lstat as lstat3 } from "node:fs/promises";
|
|
63747
|
-
import { isAbsolute as isAbsolute12, join as
|
|
64600
|
+
import { isAbsolute as isAbsolute12, join as join54, resolve as resolve19 } from "node:path";
|
|
63748
64601
|
function publishedCommits(platform) {
|
|
63749
64602
|
if (platform.headCommits && platform.headCommits.length > 0)
|
|
63750
64603
|
return platform.headCommits;
|
|
@@ -64081,7 +64934,7 @@ async function absentFromDisk(root, paths) {
|
|
|
64081
64934
|
const flags = await Promise.all(
|
|
64082
64935
|
paths.map(async (path2) => {
|
|
64083
64936
|
try {
|
|
64084
|
-
await lstat3(
|
|
64937
|
+
await lstat3(join54(root, path2));
|
|
64085
64938
|
return false;
|
|
64086
64939
|
} catch {
|
|
64087
64940
|
return true;
|
|
@@ -64140,7 +64993,7 @@ var init_check = __esm({
|
|
|
64140
64993
|
// ../../packages/steering-freshness/src/sync.ts
|
|
64141
64994
|
import { mkdtemp, rm as rm3, writeFile as writeFile6 } from "node:fs/promises";
|
|
64142
64995
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
64143
|
-
import { join as
|
|
64996
|
+
import { join as join55 } from "node:path";
|
|
64144
64997
|
function refuse3(refusal, message) {
|
|
64145
64998
|
return {
|
|
64146
64999
|
applied: false,
|
|
@@ -64321,9 +65174,9 @@ async function syncSteering(opts) {
|
|
|
64321
65174
|
};
|
|
64322
65175
|
}
|
|
64323
65176
|
async function commitPaths(ctx, message, paths) {
|
|
64324
|
-
const dir = await mkdtemp(
|
|
65177
|
+
const dir = await mkdtemp(join55(tmpdir2(), "oxagen-steering-sync-"));
|
|
64325
65178
|
try {
|
|
64326
|
-
const list2 =
|
|
65179
|
+
const list2 = join55(dir, "pathspec");
|
|
64327
65180
|
await writeFile6(list2, `${paths.join("\0")}\0`, "utf8");
|
|
64328
65181
|
await git3(
|
|
64329
65182
|
ctx,
|
|
@@ -64850,10 +65703,10 @@ var init_paths2 = __esm({
|
|
|
64850
65703
|
});
|
|
64851
65704
|
|
|
64852
65705
|
// src/commands/workspace-link.ts
|
|
64853
|
-
import { existsSync as existsSync26, mkdirSync as mkdirSync9, readFileSync as
|
|
64854
|
-
import { dirname as
|
|
65706
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync9, readFileSync as readFileSync25 } from "node:fs";
|
|
65707
|
+
import { dirname as dirname30, join as join56 } from "node:path";
|
|
64855
65708
|
function workspaceLinkPath(cwd) {
|
|
64856
|
-
return
|
|
65709
|
+
return join56(cwd, WORKSPACE_LINK_PATH);
|
|
64857
65710
|
}
|
|
64858
65711
|
function isRecord8(value) {
|
|
64859
65712
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -64886,7 +65739,7 @@ function readWorkspaceLink(cwd) {
|
|
|
64886
65739
|
if (!existsSync26(filePath)) return null;
|
|
64887
65740
|
let parsed2;
|
|
64888
65741
|
try {
|
|
64889
|
-
parsed2 = JSON.parse(
|
|
65742
|
+
parsed2 = JSON.parse(readFileSync25(filePath, "utf8"));
|
|
64890
65743
|
} catch (err2) {
|
|
64891
65744
|
const detail = err2 instanceof Error ? err2.message : String(err2);
|
|
64892
65745
|
process.stderr.write(
|
|
@@ -64907,7 +65760,7 @@ function readWorkspaceLink(cwd) {
|
|
|
64907
65760
|
}
|
|
64908
65761
|
function writeWorkspaceLink(cwd, link) {
|
|
64909
65762
|
const filePath = workspaceLinkPath(cwd);
|
|
64910
|
-
mkdirSync9(
|
|
65763
|
+
mkdirSync9(dirname30(filePath), { recursive: true });
|
|
64911
65764
|
atomicWriteFileSync(filePath, JSON.stringify(link, null, 2));
|
|
64912
65765
|
}
|
|
64913
65766
|
var LINK_STRING_FIELDS;
|
|
@@ -64943,7 +65796,7 @@ __export(steering_exports, {
|
|
|
64943
65796
|
});
|
|
64944
65797
|
import { execFileSync } from "node:child_process";
|
|
64945
65798
|
import { existsSync as existsSync27, realpathSync as realpathSync7 } from "node:fs";
|
|
64946
|
-
import { dirname as
|
|
65799
|
+
import { dirname as dirname31, join as join57, normalize, parse as parsePath } from "node:path";
|
|
64947
65800
|
function findProjectRoot(start) {
|
|
64948
65801
|
const { root } = parsePath(start);
|
|
64949
65802
|
const rawGitRoot = gitRootOr(start);
|
|
@@ -64952,9 +65805,9 @@ function findProjectRoot(start) {
|
|
|
64952
65805
|
if (gitRoot !== null) return gitRoot;
|
|
64953
65806
|
let dir = from;
|
|
64954
65807
|
for (; ; ) {
|
|
64955
|
-
if (existsSync27(
|
|
65808
|
+
if (existsSync27(join57(dir, PROJECT_DIR_NAME))) return dir;
|
|
64956
65809
|
if (dir === root) return from;
|
|
64957
|
-
const parent =
|
|
65810
|
+
const parent = dirname31(dir);
|
|
64958
65811
|
if (parent === dir) return from;
|
|
64959
65812
|
dir = parent;
|
|
64960
65813
|
}
|
|
@@ -81317,7 +82170,7 @@ function findSecretsAndPii(text5) {
|
|
|
81317
82170
|
const findings = [];
|
|
81318
82171
|
if (/-----BEGIN [A-Z ]*PRIVATE KEY-----/.test(text5))
|
|
81319
82172
|
findings.push("private key block");
|
|
81320
|
-
for (const token of text5.match(
|
|
82173
|
+
for (const token of text5.match(TOKEN2) ?? []) {
|
|
81321
82174
|
if (isSecretToken(token)) {
|
|
81322
82175
|
findings.push("credential token");
|
|
81323
82176
|
break;
|
|
@@ -81344,7 +82197,7 @@ function findSecretsAndPii(text5) {
|
|
|
81344
82197
|
}
|
|
81345
82198
|
return findings;
|
|
81346
82199
|
}
|
|
81347
|
-
var SECRET_PREFIXES, SENSITIVE_KEY_MARKERS,
|
|
82200
|
+
var SECRET_PREFIXES, SENSITIVE_KEY_MARKERS, TOKEN2;
|
|
81348
82201
|
var init_secrets = __esm({
|
|
81349
82202
|
"../../packages/steering-check/src/secrets.ts"() {
|
|
81350
82203
|
"use strict";
|
|
@@ -81395,7 +82248,7 @@ var init_secrets = __esm({
|
|
|
81395
82248
|
"session_id",
|
|
81396
82249
|
"client_secret"
|
|
81397
82250
|
];
|
|
81398
|
-
|
|
82251
|
+
TOKEN2 = /[A-Za-z0-9_\-./+~]+/g;
|
|
81399
82252
|
}
|
|
81400
82253
|
});
|
|
81401
82254
|
|
|
@@ -82044,7 +82897,7 @@ var init_memory_client = __esm({
|
|
|
82044
82897
|
import { readFile as readFile9 } from "node:fs/promises";
|
|
82045
82898
|
import {
|
|
82046
82899
|
basename as basename7,
|
|
82047
|
-
dirname as
|
|
82900
|
+
dirname as dirname32,
|
|
82048
82901
|
isAbsolute as isAbsolute13,
|
|
82049
82902
|
relative as relative6,
|
|
82050
82903
|
resolve as resolve20,
|
|
@@ -82056,7 +82909,7 @@ function inside(rel) {
|
|
|
82056
82909
|
function importFilename(path2, folder) {
|
|
82057
82910
|
let rel = relative6(process.cwd(), path2);
|
|
82058
82911
|
if (!inside(rel) && folder !== void 0) {
|
|
82059
|
-
rel = relative6(
|
|
82912
|
+
rel = relative6(dirname32(resolve20(folder)), resolve20(path2));
|
|
82060
82913
|
}
|
|
82061
82914
|
const name = inside(rel) ? rel.split(sep8).join("/") : basename7(path2);
|
|
82062
82915
|
return name.length > 256 ? basename7(path2).slice(-256) : name;
|
|
@@ -82343,7 +83196,7 @@ __export(steering_import_exports, {
|
|
|
82343
83196
|
});
|
|
82344
83197
|
import { readdir as readdir4, realpath as realpath2, stat as stat4 } from "node:fs/promises";
|
|
82345
83198
|
import { homedir as homedir12 } from "node:os";
|
|
82346
|
-
import { basename as basename8, extname, join as
|
|
83199
|
+
import { basename as basename8, extname, join as join58, relative as relative7, sep as sep9 } from "node:path";
|
|
82347
83200
|
function envDir2(env, key) {
|
|
82348
83201
|
const value = env[key];
|
|
82349
83202
|
return value === void 0 || value.trim() === "" ? null : value;
|
|
@@ -82351,34 +83204,34 @@ function envDir2(env, key) {
|
|
|
82351
83204
|
function harnessHome(harness, env = process.env, home = homedir12()) {
|
|
82352
83205
|
switch (harness) {
|
|
82353
83206
|
case "claude-code": {
|
|
82354
|
-
const config = envDir2(env, "CLAUDE_CONFIG_DIR") ??
|
|
83207
|
+
const config = envDir2(env, "CLAUDE_CONFIG_DIR") ?? join58(home, ".claude");
|
|
82355
83208
|
return {
|
|
82356
83209
|
harness,
|
|
82357
83210
|
folders: [
|
|
82358
83211
|
{
|
|
82359
|
-
dir: skillsRoot("claude-code", env, home) ??
|
|
83212
|
+
dir: skillsRoot("claude-code", env, home) ?? join58(config, "skills"),
|
|
82360
83213
|
mount: ".claude/skills"
|
|
82361
83214
|
},
|
|
82362
|
-
{ dir:
|
|
82363
|
-
{ dir:
|
|
83215
|
+
{ dir: join58(config, "commands"), mount: ".claude/commands" },
|
|
83216
|
+
{ dir: join58(config, "agents"), mount: ".claude/agents" }
|
|
82364
83217
|
],
|
|
82365
83218
|
instructions: [
|
|
82366
|
-
{ file:
|
|
83219
|
+
{ file: join58(config, "CLAUDE.md"), filename: ".claude/CLAUDE.md" }
|
|
82367
83220
|
]
|
|
82368
83221
|
};
|
|
82369
83222
|
}
|
|
82370
83223
|
case "codex": {
|
|
82371
|
-
const codexHome = envDir2(env, "CODEX_HOME") ??
|
|
83224
|
+
const codexHome = envDir2(env, "CODEX_HOME") ?? join58(home, ".codex");
|
|
82372
83225
|
return {
|
|
82373
83226
|
harness,
|
|
82374
83227
|
folders: [
|
|
82375
83228
|
{
|
|
82376
|
-
dir: skillsRoot("codex", env, home) ??
|
|
83229
|
+
dir: skillsRoot("codex", env, home) ?? join58(home, ".agents", "skills"),
|
|
82377
83230
|
mount: ".agents/skills"
|
|
82378
83231
|
}
|
|
82379
83232
|
],
|
|
82380
83233
|
instructions: ["AGENTS.override.md", "AGENTS.md"].map((name) => ({
|
|
82381
|
-
file:
|
|
83234
|
+
file: join58(codexHome, name),
|
|
82382
83235
|
filename: `.codex/${name}`
|
|
82383
83236
|
}))
|
|
82384
83237
|
};
|
|
@@ -82387,8 +83240,8 @@ function harnessHome(harness, env = process.env, home = homedir12()) {
|
|
|
82387
83240
|
return {
|
|
82388
83241
|
harness,
|
|
82389
83242
|
folders: [
|
|
82390
|
-
{ dir:
|
|
82391
|
-
{ dir:
|
|
83243
|
+
{ dir: join58(home, ".cursor", "skills"), mount: ".cursor/skills" },
|
|
83244
|
+
{ dir: join58(home, ".cursor", "commands"), mount: ".cursor/commands" }
|
|
82392
83245
|
],
|
|
82393
83246
|
instructions: []
|
|
82394
83247
|
};
|
|
@@ -82434,7 +83287,7 @@ async function findMarkdownFiles(paths, harness) {
|
|
|
82434
83287
|
}
|
|
82435
83288
|
const found = [];
|
|
82436
83289
|
for (const entry2 of entries2.sort(byName)) {
|
|
82437
|
-
const path2 =
|
|
83290
|
+
const path2 = join58(dir, entry2.name);
|
|
82438
83291
|
if (entry2.isDirectory()) {
|
|
82439
83292
|
if (!entry2.name.startsWith(".") && entry2.name !== "node_modules")
|
|
82440
83293
|
found.push(...await filesUnder(path2, from));
|
|
@@ -82456,7 +83309,7 @@ async function findMarkdownFiles(paths, harness) {
|
|
|
82456
83309
|
const { folder } = frame;
|
|
82457
83310
|
const named = (rel) => frame.fixedNames ? { filename: rel } : {};
|
|
82458
83311
|
for (const entry2 of entries2) {
|
|
82459
|
-
const path2 =
|
|
83312
|
+
const path2 = join58(dir, entry2.name);
|
|
82460
83313
|
const rel = frame.relOf(path2);
|
|
82461
83314
|
if (entry2.isDirectory()) {
|
|
82462
83315
|
if (entry2.name === "node_modules") continue;
|
|
@@ -82515,7 +83368,7 @@ async function findMarkdownFiles(paths, harness) {
|
|
|
82515
83368
|
}
|
|
82516
83369
|
if (folderGiven) {
|
|
82517
83370
|
const catalogue = CATALOGUE_FOLDERS.has(basename8(path2));
|
|
82518
|
-
const root = catalogue ?
|
|
83371
|
+
const root = catalogue ? join58(path2, "..") : path2;
|
|
82519
83372
|
await walk2(path2, {
|
|
82520
83373
|
relOf: (p) => under(root, p),
|
|
82521
83374
|
folder: path2,
|
|
@@ -84174,12 +85027,12 @@ __export(verify_exports, {
|
|
|
84174
85027
|
readBundle: () => readBundle,
|
|
84175
85028
|
verifyBundle: () => verifyBundle3
|
|
84176
85029
|
});
|
|
84177
|
-
import { existsSync as existsSync28, readFileSync as
|
|
84178
|
-
import { join as
|
|
85030
|
+
import { existsSync as existsSync28, readFileSync as readFileSync26, statSync as statSync15 } from "node:fs";
|
|
85031
|
+
import { join as join59 } from "node:path";
|
|
84179
85032
|
function readDirectory(dir) {
|
|
84180
85033
|
const read2 = (name) => {
|
|
84181
|
-
const path2 =
|
|
84182
|
-
return existsSync28(path2) ?
|
|
85034
|
+
const path2 = join59(dir, name);
|
|
85035
|
+
return existsSync28(path2) ? readFileSync26(path2, "utf8") : void 0;
|
|
84183
85036
|
};
|
|
84184
85037
|
return assemble(read2, dir);
|
|
84185
85038
|
}
|
|
@@ -84189,7 +85042,7 @@ function isBundleEntry(name) {
|
|
|
84189
85042
|
function readZip(path2) {
|
|
84190
85043
|
let entries2;
|
|
84191
85044
|
try {
|
|
84192
|
-
entries2 = unzipSync(new Uint8Array(
|
|
85045
|
+
entries2 = unzipSync(new Uint8Array(readFileSync26(path2)), {
|
|
84193
85046
|
filter: (file) => isBundleEntry(file.name)
|
|
84194
85047
|
});
|
|
84195
85048
|
} catch (err2) {
|
|
@@ -84225,7 +85078,7 @@ function readBundle(path2) {
|
|
|
84225
85078
|
if (!existsSync28(path2)) {
|
|
84226
85079
|
throw new BundleReadError(`${path2} does not exist.`);
|
|
84227
85080
|
}
|
|
84228
|
-
return
|
|
85081
|
+
return statSync15(path2).isDirectory() ? readDirectory(path2) : readZip(path2);
|
|
84229
85082
|
}
|
|
84230
85083
|
function plural3(count12, one, many) {
|
|
84231
85084
|
return `${count12} ${count12 === 1 ? one : many}`;
|
|
@@ -85133,7 +85986,7 @@ var init_conversation = __esm({
|
|
|
85133
85986
|
});
|
|
85134
85987
|
|
|
85135
85988
|
// src/auth/open-browser.ts
|
|
85136
|
-
import { spawn as
|
|
85989
|
+
import { spawn as spawn8 } from "node:child_process";
|
|
85137
85990
|
function openBrowser(url) {
|
|
85138
85991
|
try {
|
|
85139
85992
|
let cmd;
|
|
@@ -85151,7 +86004,7 @@ function openBrowser(url) {
|
|
|
85151
86004
|
cmd = "xdg-open";
|
|
85152
86005
|
args = [url];
|
|
85153
86006
|
}
|
|
85154
|
-
const child =
|
|
86007
|
+
const child = spawn8(cmd, args, { detached: true, stdio: "ignore" });
|
|
85155
86008
|
child.on("error", () => {
|
|
85156
86009
|
});
|
|
85157
86010
|
child.unref();
|
|
@@ -85301,13 +86154,13 @@ import {
|
|
|
85301
86154
|
existsSync as existsSync29,
|
|
85302
86155
|
lstatSync as lstatSync10,
|
|
85303
86156
|
mkdirSync as mkdirSync10,
|
|
85304
|
-
readFileSync as
|
|
86157
|
+
readFileSync as readFileSync27,
|
|
85305
86158
|
readdirSync as readdirSync14,
|
|
85306
86159
|
realpathSync as realpathSync8,
|
|
85307
86160
|
writeFileSync as writeFileSync7
|
|
85308
86161
|
} from "node:fs";
|
|
85309
86162
|
import { homedir as homedir13, hostname as osHostname3 } from "node:os";
|
|
85310
|
-
import { join as
|
|
86163
|
+
import { join as join60, relative as relative8, resolve as resolve22, sep as sep10 } from "node:path";
|
|
85311
86164
|
function git4(cwd, args) {
|
|
85312
86165
|
return new Promise((done) => {
|
|
85313
86166
|
try {
|
|
@@ -85354,7 +86207,7 @@ function parseRemoteRepository(url) {
|
|
|
85354
86207
|
}
|
|
85355
86208
|
function oxagenPresent(root) {
|
|
85356
86209
|
try {
|
|
85357
|
-
return readdirSync14(
|
|
86210
|
+
return readdirSync14(join60(root, ".oxagen")).some(
|
|
85358
86211
|
(name) => name !== "workspace.json"
|
|
85359
86212
|
);
|
|
85360
86213
|
} catch {
|
|
@@ -85363,18 +86216,18 @@ function oxagenPresent(root) {
|
|
|
85363
86216
|
}
|
|
85364
86217
|
function symlinkState(root) {
|
|
85365
86218
|
try {
|
|
85366
|
-
if (!lstatSync10(
|
|
86219
|
+
if (!lstatSync10(join60(root, ".stella")).isDirectory()) return "none";
|
|
85367
86220
|
} catch {
|
|
85368
86221
|
return "none";
|
|
85369
86222
|
}
|
|
85370
86223
|
let oxagenReal;
|
|
85371
86224
|
try {
|
|
85372
|
-
oxagenReal = realpathSync8(
|
|
86225
|
+
oxagenReal = realpathSync8(join60(root, ".oxagen"));
|
|
85373
86226
|
} catch {
|
|
85374
86227
|
return "missing";
|
|
85375
86228
|
}
|
|
85376
86229
|
for (const link of STELLA_LINKS) {
|
|
85377
|
-
const at2 =
|
|
86230
|
+
const at2 = join60(root, link);
|
|
85378
86231
|
try {
|
|
85379
86232
|
if (!lstatSync10(at2).isSymbolicLink()) return "missing";
|
|
85380
86233
|
const target2 = realpathSync8(at2);
|
|
@@ -85388,11 +86241,11 @@ function symlinkState(root) {
|
|
|
85388
86241
|
return "linked";
|
|
85389
86242
|
}
|
|
85390
86243
|
function machineId(configDir = getConfigDir()) {
|
|
85391
|
-
const file =
|
|
86244
|
+
const file = join60(configDir, MACHINE_ID_FILE);
|
|
85392
86245
|
let secret = null;
|
|
85393
86246
|
try {
|
|
85394
86247
|
if (existsSync29(file)) {
|
|
85395
|
-
const stored =
|
|
86248
|
+
const stored = readFileSync27(file, "utf8").trim();
|
|
85396
86249
|
if (/^[0-9a-f]{64}$/.test(stored)) secret = stored;
|
|
85397
86250
|
}
|
|
85398
86251
|
if (secret === null) {
|
|
@@ -85470,15 +86323,15 @@ async function ensureWorkspaceLinkIgnored(root) {
|
|
|
85470
86323
|
const topDir = resolve22(top);
|
|
85471
86324
|
const entry2 = relative8(
|
|
85472
86325
|
topDir,
|
|
85473
|
-
|
|
86326
|
+
join60(realpathOr2(root), ".oxagen", "workspace.json")
|
|
85474
86327
|
).split(sep10).join("/");
|
|
85475
86328
|
if (entry2.startsWith("../")) return null;
|
|
85476
86329
|
const rule = await git4(topDir, ["check-ignore", "--no-index", "-v", entry2]);
|
|
85477
86330
|
if (rule !== null) return null;
|
|
85478
|
-
const gitignore =
|
|
86331
|
+
const gitignore = join60(resolve22(top), ".gitignore");
|
|
85479
86332
|
let existing = "";
|
|
85480
86333
|
try {
|
|
85481
|
-
existing =
|
|
86334
|
+
existing = readFileSync27(gitignore, "utf8");
|
|
85482
86335
|
} catch {
|
|
85483
86336
|
}
|
|
85484
86337
|
const prefix = existing.length > 0 && !existing.endsWith("\n") ? "\n" : "";
|
|
@@ -85991,16 +86844,16 @@ import { createHash as createHash18 } from "node:crypto";
|
|
|
85991
86844
|
import {
|
|
85992
86845
|
lstatSync as lstatSync11,
|
|
85993
86846
|
mkdirSync as mkdirSync11,
|
|
85994
|
-
readFileSync as
|
|
86847
|
+
readFileSync as readFileSync28,
|
|
85995
86848
|
readdirSync as readdirSync15,
|
|
85996
86849
|
realpathSync as realpathSync9,
|
|
85997
86850
|
rmSync as rmSync10,
|
|
85998
86851
|
rmdirSync as rmdirSync7
|
|
85999
86852
|
} from "node:fs";
|
|
86000
86853
|
import {
|
|
86001
|
-
dirname as
|
|
86854
|
+
dirname as dirname33,
|
|
86002
86855
|
isAbsolute as isAbsolute14,
|
|
86003
|
-
join as
|
|
86856
|
+
join as join61,
|
|
86004
86857
|
parse as parsePath2,
|
|
86005
86858
|
posix as posix4,
|
|
86006
86859
|
sep as sep11
|
|
@@ -86113,32 +86966,32 @@ function findLinkedRoot(start) {
|
|
|
86113
86966
|
} catch {
|
|
86114
86967
|
}
|
|
86115
86968
|
if (dir === root) return null;
|
|
86116
|
-
const parent =
|
|
86969
|
+
const parent = dirname33(dir);
|
|
86117
86970
|
if (parent === dir) return null;
|
|
86118
86971
|
dir = parent;
|
|
86119
86972
|
}
|
|
86120
86973
|
}
|
|
86121
86974
|
function fsReader(root) {
|
|
86122
86975
|
return (path2) => {
|
|
86123
|
-
const abs =
|
|
86976
|
+
const abs = join61(root, ...path2.split("/"));
|
|
86124
86977
|
try {
|
|
86125
86978
|
const st = lstatSync11(abs);
|
|
86126
86979
|
if (!st.isFile()) return Buffer.from(`\0not-a-file:${abs}`);
|
|
86127
|
-
return
|
|
86980
|
+
return readFileSync28(abs);
|
|
86128
86981
|
} catch {
|
|
86129
86982
|
return null;
|
|
86130
86983
|
}
|
|
86131
86984
|
};
|
|
86132
86985
|
}
|
|
86133
86986
|
function assertInsideOxagen(root, path2) {
|
|
86134
|
-
const oxagenAbs =
|
|
86987
|
+
const oxagenAbs = join61(root, OXAGEN_DIR);
|
|
86135
86988
|
let oxagenReal;
|
|
86136
86989
|
try {
|
|
86137
86990
|
oxagenReal = realpathSync9(oxagenAbs);
|
|
86138
86991
|
} catch {
|
|
86139
86992
|
return;
|
|
86140
86993
|
}
|
|
86141
|
-
const abs =
|
|
86994
|
+
const abs = join61(root, ...path2.split("/"));
|
|
86142
86995
|
try {
|
|
86143
86996
|
if (lstatSync11(abs).isSymbolicLink()) {
|
|
86144
86997
|
throw new Error(
|
|
@@ -86148,7 +87001,7 @@ function assertInsideOxagen(root, path2) {
|
|
|
86148
87001
|
} catch (err2) {
|
|
86149
87002
|
if (err2.code !== "ENOENT") throw err2;
|
|
86150
87003
|
}
|
|
86151
|
-
let dir =
|
|
87004
|
+
let dir = dirname33(abs);
|
|
86152
87005
|
for (; ; ) {
|
|
86153
87006
|
let real = null;
|
|
86154
87007
|
try {
|
|
@@ -86162,14 +87015,14 @@ function assertInsideOxagen(root, path2) {
|
|
|
86162
87015
|
}
|
|
86163
87016
|
return;
|
|
86164
87017
|
}
|
|
86165
|
-
const parent =
|
|
87018
|
+
const parent = dirname33(dir);
|
|
86166
87019
|
if (parent === dir) return;
|
|
86167
87020
|
dir = parent;
|
|
86168
87021
|
}
|
|
86169
87022
|
}
|
|
86170
87023
|
function pruneEmptyDirs(root, path2) {
|
|
86171
|
-
const stop =
|
|
86172
|
-
let dir =
|
|
87024
|
+
const stop = join61(root, OXAGEN_DIR);
|
|
87025
|
+
let dir = dirname33(join61(root, ...path2.split("/")));
|
|
86173
87026
|
while (dir.startsWith(stop + sep11)) {
|
|
86174
87027
|
try {
|
|
86175
87028
|
if (readdirSync15(dir).length > 0) return;
|
|
@@ -86177,19 +87030,19 @@ function pruneEmptyDirs(root, path2) {
|
|
|
86177
87030
|
} catch {
|
|
86178
87031
|
return;
|
|
86179
87032
|
}
|
|
86180
|
-
dir =
|
|
87033
|
+
dir = dirname33(dir);
|
|
86181
87034
|
}
|
|
86182
87035
|
}
|
|
86183
87036
|
function applyPlan(root, plan) {
|
|
86184
87037
|
for (const w of plan.writes) assertInsideOxagen(root, w.path);
|
|
86185
87038
|
for (const d of plan.deletes) assertInsideOxagen(root, d);
|
|
86186
87039
|
for (const w of plan.writes) {
|
|
86187
|
-
const abs =
|
|
86188
|
-
mkdirSync11(
|
|
87040
|
+
const abs = join61(root, ...w.path.split("/"));
|
|
87041
|
+
mkdirSync11(dirname33(abs), { recursive: true });
|
|
86189
87042
|
atomicWriteFileSync(abs, w.content);
|
|
86190
87043
|
}
|
|
86191
87044
|
for (const d of plan.deletes) {
|
|
86192
|
-
rmSync10(
|
|
87045
|
+
rmSync10(join61(root, ...d.split("/")), { force: true });
|
|
86193
87046
|
pruneEmptyDirs(root, d);
|
|
86194
87047
|
}
|
|
86195
87048
|
}
|
|
@@ -108152,7 +109005,7 @@ function invalidArguments(message) {
|
|
|
108152
109005
|
return new BuildError("Invalid arguments", message);
|
|
108153
109006
|
}
|
|
108154
109007
|
function checkedName(parameter) {
|
|
108155
|
-
if (!
|
|
109008
|
+
if (!TOKEN3.test(parameter.name)) {
|
|
108156
109009
|
throw new BuildError(
|
|
108157
109010
|
"Invalid request",
|
|
108158
109011
|
`The ${parameter.in} parameter name ${parameter.name} is not an HTTP token.`
|
|
@@ -108234,7 +109087,7 @@ function cookiePairs(parameter, value) {
|
|
|
108234
109087
|
]
|
|
108235
109088
|
] : shape.kind === "list" ? shape.items.map((item) => [name, item]) : shape.entries;
|
|
108236
109089
|
for (const [cookie, text5] of pairs) {
|
|
108237
|
-
if (!
|
|
109090
|
+
if (!TOKEN3.test(cookie)) {
|
|
108238
109091
|
throw invalidArguments(
|
|
108239
109092
|
`The cookie ${parameter.name} holds a key that is not an HTTP token, so no cookie can take it as a name.`
|
|
108240
109093
|
);
|
|
@@ -108277,12 +109130,12 @@ function queryEntries(parameter, value) {
|
|
|
108277
109130
|
}
|
|
108278
109131
|
if (shape.items.length === 0) return [];
|
|
108279
109132
|
if (explode) return shape.items.map((item) => pair(name, item));
|
|
108280
|
-
const [raw,
|
|
109133
|
+
const [raw, delimiter3] = style === "form" ? [",", ","] : style === "spaceDelimited" ? [" ", "%20"] : ["|", "|"];
|
|
108281
109134
|
return [
|
|
108282
109135
|
entry(
|
|
108283
109136
|
name,
|
|
108284
109137
|
shape.items.join(raw),
|
|
108285
|
-
`${enc(name)}=${shape.items.map(val).join(
|
|
109138
|
+
`${enc(name)}=${shape.items.map(val).join(delimiter3)}`
|
|
108286
109139
|
)
|
|
108287
109140
|
];
|
|
108288
109141
|
}
|
|
@@ -108499,7 +109352,7 @@ function createHttpSender(options = {}) {
|
|
|
108499
109352
|
}
|
|
108500
109353
|
};
|
|
108501
109354
|
}
|
|
108502
|
-
var IDEMPOTENT_METHODS, RESERVED_HEADERS,
|
|
109355
|
+
var IDEMPOTENT_METHODS, RESERVED_HEADERS, TOKEN3, UNSAFE_HEADER_VALUE, UNSAFE_COOKIE_VALUE;
|
|
108503
109356
|
var init_http = __esm({
|
|
108504
109357
|
"../../packages/mcp-studio/src/execute/http.ts"() {
|
|
108505
109358
|
"use strict";
|
|
@@ -108527,7 +109380,7 @@ var init_http = __esm({
|
|
|
108527
109380
|
"proxy-authorization",
|
|
108528
109381
|
"cookie"
|
|
108529
109382
|
]);
|
|
108530
|
-
|
|
109383
|
+
TOKEN3 = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
|
|
108531
109384
|
UNSAFE_HEADER_VALUE = /[\r\n\0]/;
|
|
108532
109385
|
UNSAFE_COOKIE_VALUE = /[;\r\n\0]/;
|
|
108533
109386
|
}
|
|
@@ -130060,11 +130913,11 @@ import { createHash as createHash20 } from "node:crypto";
|
|
|
130060
130913
|
import {
|
|
130061
130914
|
lstatSync as lstatSync12,
|
|
130062
130915
|
mkdirSync as mkdirSync12,
|
|
130063
|
-
readFileSync as
|
|
130916
|
+
readFileSync as readFileSync29,
|
|
130064
130917
|
readlinkSync as readlinkSync4,
|
|
130065
|
-
statSync as
|
|
130918
|
+
statSync as statSync16
|
|
130066
130919
|
} from "node:fs";
|
|
130067
|
-
import { dirname as
|
|
130920
|
+
import { dirname as dirname34, isAbsolute as isAbsolute15, join as join62, relative as relative9, resolve as resolve24, sep as sep12 } from "node:path";
|
|
130068
130921
|
function git5(cwd, args, input) {
|
|
130069
130922
|
try {
|
|
130070
130923
|
return execFileSync2("git", args, {
|
|
@@ -130096,11 +130949,11 @@ function commitOf2(root, ref2) {
|
|
|
130096
130949
|
return sha2.length > 0 ? sha2 : null;
|
|
130097
130950
|
}
|
|
130098
130951
|
function readWorkingFile(root, path2) {
|
|
130099
|
-
const abs =
|
|
130952
|
+
const abs = join62(root, ...path2.split("/"));
|
|
130100
130953
|
try {
|
|
130101
130954
|
const stat7 = lstatSync12(abs);
|
|
130102
130955
|
if (stat7.isSymbolicLink()) return readlinkSync4(abs, "utf8");
|
|
130103
|
-
return stat7.isFile() ?
|
|
130956
|
+
return stat7.isFile() ? readFileSync29(abs, "utf8") : null;
|
|
130104
130957
|
} catch {
|
|
130105
130958
|
return null;
|
|
130106
130959
|
}
|
|
@@ -130175,14 +131028,14 @@ function chooseBase(root, ref2) {
|
|
|
130175
131028
|
}
|
|
130176
131029
|
function isFile(path2) {
|
|
130177
131030
|
try {
|
|
130178
|
-
return
|
|
131031
|
+
return statSync16(path2).isFile();
|
|
130179
131032
|
} catch {
|
|
130180
131033
|
return false;
|
|
130181
131034
|
}
|
|
130182
131035
|
}
|
|
130183
131036
|
function isDir(path2) {
|
|
130184
131037
|
try {
|
|
130185
|
-
return
|
|
131038
|
+
return statSync16(path2).isDirectory();
|
|
130186
131039
|
} catch {
|
|
130187
131040
|
return false;
|
|
130188
131041
|
}
|
|
@@ -130190,10 +131043,10 @@ function isDir(path2) {
|
|
|
130190
131043
|
function findSteeringRoot(start) {
|
|
130191
131044
|
let dir = resolve24(start);
|
|
130192
131045
|
for (; ; ) {
|
|
130193
|
-
if (isFile(
|
|
131046
|
+
if (isFile(join62(dir, WORKSPACE_TOML_PATH)) || isFile(join62(dir, AGENTS_MD_PATH)) && isDir(join62(dir, STEERING_DIR))) {
|
|
130194
131047
|
return dir;
|
|
130195
131048
|
}
|
|
130196
|
-
const parent =
|
|
131049
|
+
const parent = dirname34(dir);
|
|
130197
131050
|
if (parent === dir) return null;
|
|
130198
131051
|
dir = parent;
|
|
130199
131052
|
}
|
|
@@ -130270,12 +131123,12 @@ function cacheFile(cacheDir, root) {
|
|
|
130270
131123
|
key: token === void 0 ? null : createHash20("sha256").update(token).digest("hex").slice(0, 16)
|
|
130271
131124
|
};
|
|
130272
131125
|
const key = createHash20("sha256").update(JSON.stringify([root, identity])).digest("hex").slice(0, 32);
|
|
130273
|
-
return
|
|
131126
|
+
return join62(cacheDir, `${key}.json`);
|
|
130274
131127
|
}
|
|
130275
131128
|
function readCache(file, now) {
|
|
130276
131129
|
let entry2;
|
|
130277
131130
|
try {
|
|
130278
|
-
entry2 = JSON.parse(
|
|
131131
|
+
entry2 = JSON.parse(readFileSync29(file, "utf8"));
|
|
130279
131132
|
} catch {
|
|
130280
131133
|
return null;
|
|
130281
131134
|
}
|
|
@@ -130298,7 +131151,7 @@ async function publishedInputs(root, deps, refresh, out) {
|
|
|
130298
131151
|
}
|
|
130299
131152
|
if (file !== null) {
|
|
130300
131153
|
try {
|
|
130301
|
-
mkdirSync12(
|
|
131154
|
+
mkdirSync12(dirname34(file), { recursive: true });
|
|
130302
131155
|
atomicWriteFileSync(
|
|
130303
131156
|
file,
|
|
130304
131157
|
JSON.stringify({
|
|
@@ -130384,7 +131237,7 @@ function defaultDeps2() {
|
|
|
130384
131237
|
return {
|
|
130385
131238
|
fetchPublished: fetchSteeringIndex,
|
|
130386
131239
|
cedar: cedarHooks,
|
|
130387
|
-
cacheDir:
|
|
131240
|
+
cacheDir: join62(getConfigDir(), "cache", "steering-check"),
|
|
130388
131241
|
now: () => Date.now()
|
|
130389
131242
|
};
|
|
130390
131243
|
}
|
|
@@ -134267,7 +135120,7 @@ var init_src9 = __esm({
|
|
|
134267
135120
|
|
|
134268
135121
|
// src/commands/codegraph-upload/files.ts
|
|
134269
135122
|
import { readdir as readdir5, stat as stat5 } from "node:fs/promises";
|
|
134270
|
-
import { join as
|
|
135123
|
+
import { join as join63, relative as relative10, sep as sep13 } from "node:path";
|
|
134271
135124
|
function hasGlobChars(pattern) {
|
|
134272
135125
|
return /[*?[\]{}]/.test(pattern);
|
|
134273
135126
|
}
|
|
@@ -134279,7 +135132,7 @@ async function walk(root, dir, out) {
|
|
|
134279
135132
|
const entries2 = await readdir5(dir, { withFileTypes: true });
|
|
134280
135133
|
for (const entry2 of entries2) {
|
|
134281
135134
|
if (entry2.isSymbolicLink()) continue;
|
|
134282
|
-
const full =
|
|
135135
|
+
const full = join63(dir, entry2.name);
|
|
134283
135136
|
if (entry2.isDirectory()) {
|
|
134284
135137
|
if (!SKIP_DIRS.has(entry2.name)) await walk(root, full, out);
|
|
134285
135138
|
} else if (entry2.isFile()) {
|
|
@@ -134291,7 +135144,7 @@ async function expandPattern(root, pattern) {
|
|
|
134291
135144
|
const wanted = normalize2(pattern.trim());
|
|
134292
135145
|
if (!hasGlobChars(wanted)) {
|
|
134293
135146
|
try {
|
|
134294
|
-
const info = await stat5(
|
|
135147
|
+
const info = await stat5(join63(root, wanted));
|
|
134295
135148
|
return info.isFile() ? [wanted] : [];
|
|
134296
135149
|
} catch {
|
|
134297
135150
|
return [];
|
|
@@ -134442,7 +135295,7 @@ var init_token = __esm({
|
|
|
134442
135295
|
});
|
|
134443
135296
|
|
|
134444
135297
|
// src/commands/codegraph-upload/run.ts
|
|
134445
|
-
import { join as
|
|
135298
|
+
import { join as join64 } from "node:path";
|
|
134446
135299
|
function addDropped(into, more) {
|
|
134447
135300
|
into.sensitiveValues += more.sensitiveValues;
|
|
134448
135301
|
into.secretData += more.secretData;
|
|
@@ -134460,7 +135313,7 @@ async function uploadOne(deps, config, token, group, path2, totals2) {
|
|
|
134460
135313
|
const label2 = `${group.kind}/${group.source} ${path2}`;
|
|
134461
135314
|
let bytes;
|
|
134462
135315
|
try {
|
|
134463
|
-
bytes = await deps.readFile(
|
|
135316
|
+
bytes = await deps.readFile(join64(deps.cwd, path2));
|
|
134464
135317
|
} catch (error) {
|
|
134465
135318
|
totals2.failed += 1;
|
|
134466
135319
|
deps.log(`error: ${label2}: cannot read the file: ${error.message}`);
|
|
@@ -136296,7 +137149,7 @@ __export(secret_exports, {
|
|
|
136296
137149
|
handleSecretReveal: () => handleSecretReveal,
|
|
136297
137150
|
handleSecretSet: () => handleSecretSet
|
|
136298
137151
|
});
|
|
136299
|
-
import { readFileSync as
|
|
137152
|
+
import { readFileSync as readFileSync30, writeFileSync as writeFileSync8 } from "fs";
|
|
136300
137153
|
async function readStdin2() {
|
|
136301
137154
|
const chunks = [];
|
|
136302
137155
|
for await (const chunk2 of process.stdin) chunks.push(chunk2);
|
|
@@ -136409,7 +137262,7 @@ async function handleSecretReveal(key, opts, writer = stdoutWriter) {
|
|
|
136409
137262
|
async function handleSecretImport(opts, writer = stdoutWriter) {
|
|
136410
137263
|
const out = createOutput({}, writer);
|
|
136411
137264
|
try {
|
|
136412
|
-
const text5 = opts.file ?
|
|
137265
|
+
const text5 = opts.file ? readFileSync30(opts.file, "utf8") : await readStdin2();
|
|
136413
137266
|
const environmentId = opts.env ? await resolveEnvironmentId2(opts.env) : null;
|
|
136414
137267
|
const { rows, committed } = await apiPostOrThrow("secret/import-env", { text: text5, environmentId, commit: !!opts.yes });
|
|
136415
137268
|
const newCount = rows.filter((r) => r.isNewKey).length;
|