@oxagen/cli 2.1.4-957 → 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 +1527 -774
- 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
|
}
|
|
@@ -29031,15 +29570,15 @@ var init_github = __esm({
|
|
|
29031
29570
|
|
|
29032
29571
|
// ../../packages/tacho/src/host/harness-path.ts
|
|
29033
29572
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
29034
|
-
import { delimiter, join as
|
|
29573
|
+
import { delimiter as delimiter2, join as join19 } from "node:path";
|
|
29035
29574
|
function knownDirs(home) {
|
|
29036
29575
|
return [
|
|
29037
|
-
|
|
29038
|
-
|
|
29039
|
-
|
|
29040
|
-
|
|
29041
|
-
|
|
29042
|
-
|
|
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"),
|
|
29043
29582
|
"/opt/homebrew/bin",
|
|
29044
29583
|
"/usr/local/bin",
|
|
29045
29584
|
"/usr/bin",
|
|
@@ -29079,10 +29618,10 @@ function harnessPath(env, home, loginPath) {
|
|
|
29079
29618
|
seen.add(dir);
|
|
29080
29619
|
dirs.push(dir);
|
|
29081
29620
|
};
|
|
29082
|
-
for (const dir of (loginPath ?? "").split(
|
|
29083
|
-
for (const dir of (env["PATH"] ?? "").split(
|
|
29621
|
+
for (const dir of (loginPath ?? "").split(delimiter2)) add2(dir);
|
|
29622
|
+
for (const dir of (env["PATH"] ?? "").split(delimiter2)) add2(dir);
|
|
29084
29623
|
for (const dir of knownDirs(home)) add2(dir);
|
|
29085
|
-
return dirs.join(
|
|
29624
|
+
return dirs.join(delimiter2);
|
|
29086
29625
|
}
|
|
29087
29626
|
var MARK, LOGIN_SHELL_TIMEOUT_MS;
|
|
29088
29627
|
var init_harness_path = __esm({
|
|
@@ -29159,7 +29698,7 @@ var init_policy_mode = __esm({
|
|
|
29159
29698
|
|
|
29160
29699
|
// ../../packages/tacho/src/host/wal-ceiling.ts
|
|
29161
29700
|
import { statfsSync } from "node:fs";
|
|
29162
|
-
import { join as
|
|
29701
|
+
import { join as join20 } from "node:path";
|
|
29163
29702
|
function freeBytesOn(dir) {
|
|
29164
29703
|
try {
|
|
29165
29704
|
const stats2 = statfsSync(dir);
|
|
@@ -29206,7 +29745,7 @@ function isDrop(value) {
|
|
|
29206
29745
|
function readWalCeilingState(walDir) {
|
|
29207
29746
|
let raw;
|
|
29208
29747
|
try {
|
|
29209
|
-
raw = readJsonFileIfExists(
|
|
29748
|
+
raw = readJsonFileIfExists(join20(walDir, STATE_FILE));
|
|
29210
29749
|
} catch (error) {
|
|
29211
29750
|
if (error instanceof SyntaxError) return void 0;
|
|
29212
29751
|
throw error;
|
|
@@ -29406,7 +29945,7 @@ var init_wal_ceiling = __esm({
|
|
|
29406
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);
|
|
29407
29946
|
this.state = next;
|
|
29408
29947
|
if (!changed) return;
|
|
29409
|
-
const path2 =
|
|
29948
|
+
const path2 = join20(this.walDir, STATE_FILE);
|
|
29410
29949
|
try {
|
|
29411
29950
|
writeSensitiveFileAtomic(path2, JSON.stringify(next));
|
|
29412
29951
|
this.unsaved = false;
|
|
@@ -29910,7 +30449,7 @@ import {
|
|
|
29910
30449
|
rmdirSync as rmdirSync5,
|
|
29911
30450
|
rmSync as rmSync2
|
|
29912
30451
|
} from "node:fs";
|
|
29913
|
-
import { dirname as dirname12, join as
|
|
30452
|
+
import { dirname as dirname12, join as join21 } from "node:path";
|
|
29914
30453
|
async function revokeOnControlPlane(host, options, deps, warnings) {
|
|
29915
30454
|
const resolved = resolveCredentials(
|
|
29916
30455
|
{
|
|
@@ -30521,7 +31060,7 @@ async function unenrollLocked(options, deps) {
|
|
|
30521
31060
|
];
|
|
30522
31061
|
const purged = parts.filter(([, path2, recursive]) => remove2(path2, recursive)).map(([name]) => name);
|
|
30523
31062
|
let failed3 = purged.length < parts.length;
|
|
30524
|
-
if (!existsSync15(
|
|
31063
|
+
if (!existsSync15(join21(deps.paths.dir, HARNESS_RECEIPTS)) && !remove2(join21(deps.paths.dir, HARNESS_BACKUPS), true))
|
|
30525
31064
|
failed3 = true;
|
|
30526
31065
|
const logShared = otherLiveAgents(deps.paths, deps.paths.dir).length > 0;
|
|
30527
31066
|
if (!logShared) {
|
|
@@ -30579,7 +31118,7 @@ var init_unenroll = __esm({
|
|
|
30579
31118
|
|
|
30580
31119
|
// ../../packages/tacho/src/cli/enroll.ts
|
|
30581
31120
|
import { existsSync as existsSync16, lstatSync as lstatSync4, rmSync as rmSync3 } from "node:fs";
|
|
30582
|
-
import { dirname as dirname13, isAbsolute, join as
|
|
31121
|
+
import { dirname as dirname13, isAbsolute, join as join22 } from "node:path";
|
|
30583
31122
|
function rootRefusal(command2, deps, allowRoot) {
|
|
30584
31123
|
if (allowRoot === true || deps.getuid?.() !== 0) return void 0;
|
|
30585
31124
|
const user = deps.env["SUDO_USER"] ?? "<user>";
|
|
@@ -30605,7 +31144,7 @@ function runtimeOf(host) {
|
|
|
30605
31144
|
if (first === void 0 || !files2.every((file) => existsSync16(file)))
|
|
30606
31145
|
return void 0;
|
|
30607
31146
|
const binDir = dirname13(first);
|
|
30608
|
-
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"))}`;
|
|
30609
31148
|
return {
|
|
30610
31149
|
hookCommand: host.hook_command,
|
|
30611
31150
|
credentialHelperCommand: helperCommandFor(tacho),
|
|
@@ -31699,6 +32238,7 @@ ${problems.map((problem) => ` ${problem}`).join("\n")}`
|
|
|
31699
32238
|
const mode = options.credentials ?? "brokered";
|
|
31700
32239
|
try {
|
|
31701
32240
|
if (mode === "brokered") {
|
|
32241
|
+
await signInIfNoCredential(reaching, deps);
|
|
31702
32242
|
const outcome = await brokerCredentials(host, reaching, deps);
|
|
31703
32243
|
for (const entry2 of outcome.harnesses)
|
|
31704
32244
|
deps.out(` ${describeHarness(entry2)}`);
|
|
@@ -32861,21 +33401,21 @@ import {
|
|
|
32861
33401
|
statSync as statSync7,
|
|
32862
33402
|
unlinkSync as unlinkSync10
|
|
32863
33403
|
} from "node:fs";
|
|
32864
|
-
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";
|
|
32865
33405
|
function dataLocalDir(home, env, platform) {
|
|
32866
33406
|
if (platform === "darwin")
|
|
32867
|
-
return
|
|
33407
|
+
return join23(home, "Library", "Application Support");
|
|
32868
33408
|
if (platform === "win32")
|
|
32869
|
-
return env["LOCALAPPDATA"] ??
|
|
33409
|
+
return env["LOCALAPPDATA"] ?? join23(home, "AppData", "Local");
|
|
32870
33410
|
const xdg = env["XDG_DATA_HOME"];
|
|
32871
|
-
return xdg !== void 0 && isAbsolute2(xdg) ? xdg :
|
|
33411
|
+
return xdg !== void 0 && isAbsolute2(xdg) ? xdg : join23(home, ".local", "share");
|
|
32872
33412
|
}
|
|
32873
33413
|
function desktopPlaces(deps) {
|
|
32874
|
-
const oxagenDir =
|
|
33414
|
+
const oxagenDir = join23(deps.home, ".config", "oxagen");
|
|
32875
33415
|
return {
|
|
32876
33416
|
oxagenDir,
|
|
32877
|
-
desktopConfig:
|
|
32878
|
-
copies:
|
|
33417
|
+
desktopConfig: join23(oxagenDir, "desktop.json"),
|
|
33418
|
+
copies: join23(
|
|
32879
33419
|
dataLocalDir(deps.home, deps.env, deps.platform),
|
|
32880
33420
|
"oxagen",
|
|
32881
33421
|
"bin"
|
|
@@ -33120,7 +33660,7 @@ function undoEntry(entry2, deps, tally2) {
|
|
|
33120
33660
|
}
|
|
33121
33661
|
function versionDirs(copies) {
|
|
33122
33662
|
try {
|
|
33123
|
-
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();
|
|
33124
33664
|
} catch {
|
|
33125
33665
|
return [];
|
|
33126
33666
|
}
|
|
@@ -33156,7 +33696,7 @@ function journaledCopies(journal, copies, tally2) {
|
|
|
33156
33696
|
function removeSidecars(dir, platform, tally2) {
|
|
33157
33697
|
const note = platform === "win32" ? `. Windows keeps a running program's file, so delete ${dir} after this command exits` : "";
|
|
33158
33698
|
for (const name of ["oxagen", "tacho"]) {
|
|
33159
|
-
const file =
|
|
33699
|
+
const file = join23(dir, platform === "win32" ? `${name}.exe` : name);
|
|
33160
33700
|
removeFile(file, tally2, note);
|
|
33161
33701
|
}
|
|
33162
33702
|
}
|
|
@@ -33244,7 +33784,7 @@ async function uninstall(options, deps) {
|
|
|
33244
33784
|
tally2.left.push(`cannot remove ${dir}: ${reasonOf3(error)}`);
|
|
33245
33785
|
}
|
|
33246
33786
|
}
|
|
33247
|
-
const configDir =
|
|
33787
|
+
const configDir = join23(deps.home, ".config");
|
|
33248
33788
|
if (record.configDirCreated && removeDirIfEmpty(configDir))
|
|
33249
33789
|
tally2.removed.push(configDir);
|
|
33250
33790
|
for (const path2 of tally2.removed) deps.out(` removed ${path2}`);
|
|
@@ -33658,9 +34198,9 @@ var init_run = __esm({
|
|
|
33658
34198
|
});
|
|
33659
34199
|
|
|
33660
34200
|
// ../../packages/tacho/src/cli/agent-run.ts
|
|
33661
|
-
import { spawn as
|
|
34201
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
33662
34202
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
33663
|
-
import { constants as
|
|
34203
|
+
import { constants as constants3 } from "node:os";
|
|
33664
34204
|
import { posix as posix3, win32 as win324 } from "node:path";
|
|
33665
34205
|
function programName(program2) {
|
|
33666
34206
|
const base2 = (program2.includes("\\") ? win324 : posix3).basename(program2);
|
|
@@ -33686,7 +34226,7 @@ function sessionRefusal(stdout) {
|
|
|
33686
34226
|
function exitCodeOf(exit) {
|
|
33687
34227
|
if (exit.error !== void 0) return 1;
|
|
33688
34228
|
if (exit.code !== null) return exit.code;
|
|
33689
|
-
const number2 = exit.signal !== null ?
|
|
34229
|
+
const number2 = exit.signal !== null ? constants3.signals[exit.signal] : void 0;
|
|
33690
34230
|
return number2 !== void 0 ? 128 + number2 : 1;
|
|
33691
34231
|
}
|
|
33692
34232
|
function spawnAgent(command2, args, options) {
|
|
@@ -33697,7 +34237,7 @@ function spawnAgent(command2, args, options) {
|
|
|
33697
34237
|
options.env
|
|
33698
34238
|
);
|
|
33699
34239
|
return new Promise((resolve25) => {
|
|
33700
|
-
const child =
|
|
34240
|
+
const child = spawn4(invocation.command, invocation.args, {
|
|
33701
34241
|
cwd: options.cwd,
|
|
33702
34242
|
env: options.env,
|
|
33703
34243
|
stdio: "inherit",
|
|
@@ -33922,11 +34462,11 @@ var init_work_order_start = __esm({
|
|
|
33922
34462
|
|
|
33923
34463
|
// ../../packages/tacho/src/host/work-orders.ts
|
|
33924
34464
|
import { readdirSync as readdirSync10, rmSync as rmSync5 } from "node:fs";
|
|
33925
|
-
import { join as
|
|
34465
|
+
import { join as join24 } from "node:path";
|
|
33926
34466
|
function orderFile(paths, id2) {
|
|
33927
34467
|
if (!WORK_ORDER_ID_PATTERN.test(id2))
|
|
33928
34468
|
throw new Error(`${JSON.stringify(id2)} is not a work order id`);
|
|
33929
|
-
return
|
|
34469
|
+
return join24(paths.workOrders, `${id2}.json`);
|
|
33930
34470
|
}
|
|
33931
34471
|
function readKept(path2) {
|
|
33932
34472
|
try {
|
|
@@ -33976,7 +34516,7 @@ function removeWorkOrder(paths, id2) {
|
|
|
33976
34516
|
function runningFile(paths, id2) {
|
|
33977
34517
|
if (!WORK_ORDER_ID_PATTERN.test(id2))
|
|
33978
34518
|
throw new Error(`${JSON.stringify(id2)} is not a work order id`);
|
|
33979
|
-
return
|
|
34519
|
+
return join24(paths.workOrders, `${id2}.running`);
|
|
33980
34520
|
}
|
|
33981
34521
|
function processIsAlive(pid) {
|
|
33982
34522
|
try {
|
|
@@ -34378,10 +34918,12 @@ var init_work = __esm({
|
|
|
34378
34918
|
var cli_exports = {};
|
|
34379
34919
|
__export(cli_exports, {
|
|
34380
34920
|
BACKFILL_EXIT: () => BACKFILL_EXIT,
|
|
34921
|
+
CLAUDE_OAUTH_TOKEN_ENV: () => CLAUDE_OAUTH_TOKEN_ENV,
|
|
34381
34922
|
CONTAINED_AGENTS: () => CONTAINED_AGENTS,
|
|
34382
34923
|
CURSOR_COVERAGE_NOTE: () => CURSOR_COVERAGE_NOTE,
|
|
34383
34924
|
MODEL_CREDENTIAL_HARNESSES: () => MODEL_CREDENTIAL_HARNESSES,
|
|
34384
34925
|
SHIPPING_STALL_MS: () => SHIPPING_STALL_MS,
|
|
34926
|
+
acquireSubscriptionToken: () => acquireSubscriptionToken,
|
|
34385
34927
|
addMissingClaudeCodeMcp: () => addMissingClaudeCodeMcp,
|
|
34386
34928
|
agentNameFromCommand: () => agentNameFromCommand,
|
|
34387
34929
|
backfillCommand: () => backfillCommand,
|
|
@@ -34389,6 +34931,7 @@ __export(cli_exports, {
|
|
|
34389
34931
|
canServeOxagenTools: () => canServeOxagenTools,
|
|
34390
34932
|
claudeFacts: () => claudeFacts,
|
|
34391
34933
|
credentialIssue: () => credentialIssue,
|
|
34934
|
+
credentialLogin: () => credentialLogin,
|
|
34392
34935
|
credentialStatus: () => credentialStatus,
|
|
34393
34936
|
cursorAppFacts: () => cursorAppFacts,
|
|
34394
34937
|
cursorFacts: () => cursorFacts,
|
|
@@ -34439,6 +34982,7 @@ __export(cli_exports, {
|
|
|
34439
34982
|
shellQuote: () => shellQuote,
|
|
34440
34983
|
shimError: () => shimError,
|
|
34441
34984
|
shippingHealth: () => shippingHealth,
|
|
34985
|
+
signInIfNoCredential: () => signInIfNoCredential,
|
|
34442
34986
|
spawnAgent: () => spawnAgent,
|
|
34443
34987
|
stableExecutablePath: () => stableExecutablePath,
|
|
34444
34988
|
status: () => status,
|
|
@@ -38173,6 +38717,7 @@ function containedBridgeHandler(options) {
|
|
|
38173
38717
|
const modelPaths = options.harness === "claude-code" ? ["/model/v1/messages", "/model/v1/messages/count_tokens"] : ["/model/v1/responses", "/model/v1/chat/completions"];
|
|
38174
38718
|
if (request3.method === "POST" && modelPaths.includes(path2)) {
|
|
38175
38719
|
const credential = options.issueCredential();
|
|
38720
|
+
const chatgpt = options.harness === "codex" && options.chatgptLogin?.() === true;
|
|
38176
38721
|
request3.headers = {
|
|
38177
38722
|
"content-type": "application/json",
|
|
38178
38723
|
...request3.headers["content-length"] ? { "content-length": request3.headers["content-length"] } : {},
|
|
@@ -38180,9 +38725,12 @@ function containedBridgeHandler(options) {
|
|
|
38180
38725
|
...request3.headers["anthropic-beta"] ? { "anthropic-beta": request3.headers["anthropic-beta"] } : {},
|
|
38181
38726
|
host: `127.0.0.1:${options.modelPort}`,
|
|
38182
38727
|
"x-oxagen-session": options.sessionId,
|
|
38183
|
-
...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" } : {}
|
|
38184
38732
|
};
|
|
38185
|
-
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");
|
|
38186
38734
|
options.model(request3, response);
|
|
38187
38735
|
return;
|
|
38188
38736
|
}
|
|
@@ -38334,7 +38882,7 @@ var init_bridge = __esm({
|
|
|
38334
38882
|
|
|
38335
38883
|
// ../../packages/tacho/src/contained/workspace.ts
|
|
38336
38884
|
import { lstatSync as lstatSync6, readFileSync as readFileSync14, readdirSync as readdirSync11, realpathSync as realpathSync3 } from "node:fs";
|
|
38337
|
-
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";
|
|
38338
38886
|
function within(root, path2) {
|
|
38339
38887
|
const rel = relative2(root, path2);
|
|
38340
38888
|
return rel === "" || !isAbsolute3(rel) && rel !== ".." && !rel.startsWith(`..${sep2}`);
|
|
@@ -38364,7 +38912,7 @@ function validateContainedWorkspace(workspace, sessionDirectory, mountInfo = rea
|
|
|
38364
38912
|
}
|
|
38365
38913
|
const visit2 = (directory) => {
|
|
38366
38914
|
for (const entry2 of readdirSync11(directory)) {
|
|
38367
|
-
const path2 =
|
|
38915
|
+
const path2 = join25(directory, entry2);
|
|
38368
38916
|
if (CREDENTIAL_PATHS.has(entry2) || isEnvFile(entry2))
|
|
38369
38917
|
throw new Error(
|
|
38370
38918
|
`Remove local credential files from the contained checkout before launch: ${named(path2)}`
|
|
@@ -38398,7 +38946,7 @@ function validateContainedWorkspace(workspace, sessionDirectory, mountInfo = rea
|
|
|
38398
38946
|
}
|
|
38399
38947
|
function gitDirectoryMounts(workspace) {
|
|
38400
38948
|
const root = realpathSync3(workspace);
|
|
38401
|
-
const dotGit =
|
|
38949
|
+
const dotGit = join25(root, ".git");
|
|
38402
38950
|
let stat7;
|
|
38403
38951
|
try {
|
|
38404
38952
|
stat7 = lstatSync6(dotGit);
|
|
@@ -38436,7 +38984,7 @@ function gitDirectoryMounts(workspace) {
|
|
|
38436
38984
|
if (gitDir !== void 0) {
|
|
38437
38985
|
let common;
|
|
38438
38986
|
try {
|
|
38439
|
-
common = readFileSync14(
|
|
38987
|
+
common = readFileSync14(join25(gitDir, "commondir"), "utf8").trim();
|
|
38440
38988
|
} catch {
|
|
38441
38989
|
common = void 0;
|
|
38442
38990
|
}
|
|
@@ -38463,7 +39011,7 @@ var init_workspace = __esm({
|
|
|
38463
39011
|
// ../../packages/tacho/src/collector/hardened-git.ts
|
|
38464
39012
|
import { execFile as execFile2 } from "node:child_process";
|
|
38465
39013
|
import { lstatSync as lstatSync7, readFileSync as readFileSync15, statSync as statSync8 } from "node:fs";
|
|
38466
|
-
import { dirname as dirname15, join as
|
|
39014
|
+
import { dirname as dirname15, join as join26, resolve as resolve10 } from "node:path";
|
|
38467
39015
|
function hardenedGitArgs(cwd, args, globals = []) {
|
|
38468
39016
|
const subcommand = args[0];
|
|
38469
39017
|
const end = args.indexOf("--");
|
|
@@ -38502,7 +39050,7 @@ function gitIdentity(repository, deps = DEFAULT_IDENTITY_DEPS) {
|
|
|
38502
39050
|
};
|
|
38503
39051
|
}
|
|
38504
39052
|
for (let at2 = directory; ; at2 = dirname15(at2)) {
|
|
38505
|
-
const marker =
|
|
39053
|
+
const marker = join26(at2, ".git");
|
|
38506
39054
|
const link = tryStat(deps.lstat, marker);
|
|
38507
39055
|
if (link !== void 0) {
|
|
38508
39056
|
owners.push(link);
|
|
@@ -38510,7 +39058,7 @@ function gitIdentity(repository, deps = DEFAULT_IDENTITY_DEPS) {
|
|
|
38510
39058
|
if (target2 !== void 0) {
|
|
38511
39059
|
owners.push(target2);
|
|
38512
39060
|
if (target2.isDirectory()) {
|
|
38513
|
-
const config = tryStat(deps.stat,
|
|
39061
|
+
const config = tryStat(deps.stat, join26(marker, "config"));
|
|
38514
39062
|
if (config !== void 0) owners.push(config);
|
|
38515
39063
|
}
|
|
38516
39064
|
}
|
|
@@ -38662,7 +39210,7 @@ var init_hardened_git = __esm({
|
|
|
38662
39210
|
|
|
38663
39211
|
// ../../packages/tacho/src/contained/profile.ts
|
|
38664
39212
|
import { createHash as createHash6 } from "node:crypto";
|
|
38665
|
-
import { isAbsolute as isAbsolute4, join as
|
|
39213
|
+
import { isAbsolute as isAbsolute4, join as join27, relative as relative3, sep as sep3 } from "node:path";
|
|
38666
39214
|
function containerPath(workspace, path2) {
|
|
38667
39215
|
const inside2 = relative3(workspace, path2);
|
|
38668
39216
|
if (inside2 === "" || isAbsolute4(inside2) || inside2 === ".." || inside2.startsWith(`..${sep3}`))
|
|
@@ -38672,7 +39220,7 @@ function containerPath(workspace, path2) {
|
|
|
38672
39220
|
return `/workspace/${inside2.split(sep3).join("/")}`;
|
|
38673
39221
|
}
|
|
38674
39222
|
function gitMountPairs(spec) {
|
|
38675
|
-
if (!spec.gitMounts.includes(
|
|
39223
|
+
if (!spec.gitMounts.includes(join27(spec.workspace, ".git")))
|
|
38676
39224
|
throw new Error(
|
|
38677
39225
|
"Contained execution must mount the repository's .git read-only"
|
|
38678
39226
|
);
|
|
@@ -38829,7 +39377,7 @@ var init_profile = __esm({
|
|
|
38829
39377
|
});
|
|
38830
39378
|
|
|
38831
39379
|
// ../../packages/tacho/src/contained/launcher.ts
|
|
38832
|
-
import { execFile as execFile3, spawn as
|
|
39380
|
+
import { execFile as execFile3, spawn as spawn5 } from "node:child_process";
|
|
38833
39381
|
import { randomBytes as randomBytes8 } from "node:crypto";
|
|
38834
39382
|
import {
|
|
38835
39383
|
chmodSync as chmodSync7,
|
|
@@ -38839,7 +39387,7 @@ import {
|
|
|
38839
39387
|
writeFileSync as writeFileSync2
|
|
38840
39388
|
} from "node:fs";
|
|
38841
39389
|
import { tmpdir } from "node:os";
|
|
38842
|
-
import { isAbsolute as isAbsolute5, join as
|
|
39390
|
+
import { isAbsolute as isAbsolute5, join as join28 } from "node:path";
|
|
38843
39391
|
import { promisify } from "node:util";
|
|
38844
39392
|
function reason(error) {
|
|
38845
39393
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -38878,7 +39426,7 @@ async function launchContainedAgent(options) {
|
|
|
38878
39426
|
if (digest6 === void 0)
|
|
38879
39427
|
throw new Error("The operator's contained image is not installed");
|
|
38880
39428
|
const sessionId = `contained-${randomBytes8(16).toString("hex")}`;
|
|
38881
|
-
const directory = mkdtempSync(
|
|
39429
|
+
const directory = mkdtempSync(join28(tmpdir(), "oxagen-contained-"));
|
|
38882
39430
|
chmodSync7(directory, 448);
|
|
38883
39431
|
let prepared;
|
|
38884
39432
|
let containerCreated = false;
|
|
@@ -38899,7 +39447,7 @@ async function launchContainedAgent(options) {
|
|
|
38899
39447
|
for (const [name2, contents] of entries2) {
|
|
38900
39448
|
if (!/^[a-z0-9.-]+$/.test(name2))
|
|
38901
39449
|
throw new Error("Invalid contained configuration filename");
|
|
38902
|
-
writeFileSync2(
|
|
39450
|
+
writeFileSync2(join28(directory, name2), contents, {
|
|
38903
39451
|
mode: 256,
|
|
38904
39452
|
flag: "wx"
|
|
38905
39453
|
});
|
|
@@ -38930,7 +39478,7 @@ async function launchContainedAgent(options) {
|
|
|
38930
39478
|
if (options.signal?.aborted)
|
|
38931
39479
|
throw new Error("Contained run cancelled before start");
|
|
38932
39480
|
exitCode = await new Promise((resolve25, reject) => {
|
|
38933
|
-
const child =
|
|
39481
|
+
const child = spawn5("docker", ["start", "--attach", name], {
|
|
38934
39482
|
stdio: ["ignore", "pipe", "pipe"]
|
|
38935
39483
|
});
|
|
38936
39484
|
const stop = () => {
|
|
@@ -39298,7 +39846,7 @@ var init_privilege = __esm({
|
|
|
39298
39846
|
|
|
39299
39847
|
// ../../packages/tacho/src/contained/sandbox/launcher.ts
|
|
39300
39848
|
import { randomBytes as randomBytes9 } from "node:crypto";
|
|
39301
|
-
import { join as
|
|
39849
|
+
import { join as join29 } from "node:path";
|
|
39302
39850
|
function shellQuote3(value) {
|
|
39303
39851
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
39304
39852
|
}
|
|
@@ -39388,7 +39936,7 @@ async function launchSandboxAgent(options) {
|
|
|
39388
39936
|
{ ...asAgent, cwd: SANDBOX_AGENT_HOME, timeoutMs: 15 * 6e4 }
|
|
39389
39937
|
);
|
|
39390
39938
|
for (const [name, contents] of Object.entries(claudeCodeUserState())) {
|
|
39391
|
-
const path2 =
|
|
39939
|
+
const path2 = join29(SANDBOX_AGENT_HOME, name);
|
|
39392
39940
|
system.writeFile(path2, contents, 384);
|
|
39393
39941
|
system.chown(path2, SANDBOX_AGENT_UID, SANDBOX_AGENT_GID);
|
|
39394
39942
|
}
|
|
@@ -39512,7 +40060,7 @@ var init_request = __esm({
|
|
|
39512
40060
|
});
|
|
39513
40061
|
|
|
39514
40062
|
// ../../packages/tacho/src/contained/sandbox/system.ts
|
|
39515
|
-
import { execFile as execFile4, spawn as
|
|
40063
|
+
import { execFile as execFile4, spawn as spawn6 } from "node:child_process";
|
|
39516
40064
|
import {
|
|
39517
40065
|
chmodSync as chmodSync8,
|
|
39518
40066
|
chownSync as chownSync2,
|
|
@@ -39543,7 +40091,7 @@ var init_system = __esm({
|
|
|
39543
40091
|
return { stdout: String(answer.stdout), stderr: String(answer.stderr) };
|
|
39544
40092
|
},
|
|
39545
40093
|
spawn: (file, args, options) => {
|
|
39546
|
-
const child =
|
|
40094
|
+
const child = spawn6(file, [...args], {
|
|
39547
40095
|
...options.uid !== void 0 ? { uid: options.uid } : {},
|
|
39548
40096
|
...options.gid !== void 0 ? { gid: options.gid } : {},
|
|
39549
40097
|
...options.cwd !== void 0 ? { cwd: options.cwd } : {},
|
|
@@ -39594,10 +40142,10 @@ var init_system = __esm({
|
|
|
39594
40142
|
});
|
|
39595
40143
|
|
|
39596
40144
|
// ../../packages/tacho/src/contained/runner.ts
|
|
39597
|
-
import { join as
|
|
40145
|
+
import { join as join30 } from "node:path";
|
|
39598
40146
|
function containedHookEnv(harness, workspace) {
|
|
39599
|
-
const home =
|
|
39600
|
-
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") };
|
|
39601
40149
|
}
|
|
39602
40150
|
function containedLaunchEndpoint(host) {
|
|
39603
40151
|
const ingest = new URL(host.endpoints.ingest);
|
|
@@ -39693,6 +40241,7 @@ function createContainedRunner(options) {
|
|
|
39693
40241
|
throw new Error("Credential custody unavailable");
|
|
39694
40242
|
return answer.body.token;
|
|
39695
40243
|
},
|
|
40244
|
+
...options.chatgptLogin !== void 0 ? { chatgptLogin: options.chatgptLogin } : {},
|
|
39696
40245
|
model: (request3, response) => options.model.handle(request3, response),
|
|
39697
40246
|
hook: options.hook,
|
|
39698
40247
|
opening: route.opening,
|
|
@@ -39795,7 +40344,7 @@ function createContainedRunner(options) {
|
|
|
39795
40344
|
sessionUuid2 = started.recorder.sessionUuid;
|
|
39796
40345
|
active2.set(sessionUuid2, controller);
|
|
39797
40346
|
const bridge = await startContainedBridge({
|
|
39798
|
-
socketPath:
|
|
40347
|
+
socketPath: join30(directory, "bridge.sock"),
|
|
39799
40348
|
...bridgeRoutes({
|
|
39800
40349
|
sessionId,
|
|
39801
40350
|
workspace,
|
|
@@ -39879,7 +40428,7 @@ function createContainedRunner(options) {
|
|
|
39879
40428
|
const abort = () => controller.abort();
|
|
39880
40429
|
signal?.addEventListener("abort", abort, { once: true });
|
|
39881
40430
|
if (signal?.aborted) abort();
|
|
39882
|
-
const env = { CLAUDE_CONFIG_DIR:
|
|
40431
|
+
const env = { CLAUDE_CONFIG_DIR: join30(SANDBOX_AGENT_HOME, ".claude") };
|
|
39883
40432
|
let sessionUuid2;
|
|
39884
40433
|
let launchedSessionId;
|
|
39885
40434
|
let opened = false;
|
|
@@ -40012,14 +40561,96 @@ var init_runner = __esm({
|
|
|
40012
40561
|
}
|
|
40013
40562
|
});
|
|
40014
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
|
+
|
|
40015
40646
|
// ../../packages/tacho/src/host/repositories.ts
|
|
40016
40647
|
import { existsSync as existsSync18, readFileSync as readFileSync17, statSync as statSync10 } from "node:fs";
|
|
40017
|
-
import { dirname as dirname17, join as
|
|
40648
|
+
import { dirname as dirname17, join as join31, resolve as resolve11, sep as sep4 } from "node:path";
|
|
40018
40649
|
function repositoriesFile(home) {
|
|
40019
|
-
return
|
|
40650
|
+
return join31(home.tachoDir, "repositories.json");
|
|
40020
40651
|
}
|
|
40021
40652
|
function workTreesDir(home) {
|
|
40022
|
-
return
|
|
40653
|
+
return join31(home.tachoDir, "work");
|
|
40023
40654
|
}
|
|
40024
40655
|
function readIndex(home) {
|
|
40025
40656
|
let raw;
|
|
@@ -40071,7 +40702,7 @@ function recordCheckout(home, canonical3, root, seenAt) {
|
|
|
40071
40702
|
return true;
|
|
40072
40703
|
}
|
|
40073
40704
|
function mainCheckoutOf(root) {
|
|
40074
|
-
const dotGit =
|
|
40705
|
+
const dotGit = join31(root, ".git");
|
|
40075
40706
|
try {
|
|
40076
40707
|
if (!statSync10(dotGit).isFile()) return root;
|
|
40077
40708
|
const line = readFileSync17(dotGit, "utf8").trim();
|
|
@@ -40081,13 +40712,13 @@ function mainCheckoutOf(root) {
|
|
|
40081
40712
|
const worktrees = dirname17(gitdir);
|
|
40082
40713
|
if (!worktrees.endsWith(`${sep4}.git${sep4}worktrees`)) return root;
|
|
40083
40714
|
const clone4 = dirname17(dirname17(worktrees));
|
|
40084
|
-
return existsSync18(
|
|
40715
|
+
return existsSync18(join31(clone4, ".git")) ? clone4 : root;
|
|
40085
40716
|
} catch {
|
|
40086
40717
|
return root;
|
|
40087
40718
|
}
|
|
40088
40719
|
}
|
|
40089
40720
|
function defaultIsCheckout(root) {
|
|
40090
|
-
return existsSync18(
|
|
40721
|
+
return existsSync18(join31(root, ".git"));
|
|
40091
40722
|
}
|
|
40092
40723
|
function findCheckout(home, repository, host, deps = {}) {
|
|
40093
40724
|
const isCheckout = deps.isCheckout ?? defaultIsCheckout;
|
|
@@ -40135,7 +40766,7 @@ var init_repositories = __esm({
|
|
|
40135
40766
|
|
|
40136
40767
|
// ../../packages/tacho/src/collector/detector.ts
|
|
40137
40768
|
import { promises as fs3 } from "node:fs";
|
|
40138
|
-
import { basename as basename5, join as
|
|
40769
|
+
import { basename as basename5, join as join32 } from "node:path";
|
|
40139
40770
|
async function eachLimited(items, limit, task) {
|
|
40140
40771
|
let next = 0;
|
|
40141
40772
|
const workers = Array.from(
|
|
@@ -40161,7 +40792,7 @@ async function scanProject(dir) {
|
|
|
40161
40792
|
await eachLimited(names2, SCAN_CONCURRENCY, async (name) => {
|
|
40162
40793
|
const match = SESSION_FILE.exec(name);
|
|
40163
40794
|
if (match === null) return;
|
|
40164
|
-
const path2 =
|
|
40795
|
+
const path2 = join32(dir, name);
|
|
40165
40796
|
try {
|
|
40166
40797
|
const st = await fs3.stat(path2);
|
|
40167
40798
|
out.push({ sessionId: match[1], path: path2, mtimeMs: st.mtimeMs });
|
|
@@ -40202,7 +40833,7 @@ var init_detector = __esm({
|
|
|
40202
40833
|
continue;
|
|
40203
40834
|
}
|
|
40204
40835
|
await eachLimited(names2, SCAN_CONCURRENCY, async (name) => {
|
|
40205
|
-
const dir =
|
|
40836
|
+
const dir = join32(root, name);
|
|
40206
40837
|
try {
|
|
40207
40838
|
const st = await fs3.stat(dir);
|
|
40208
40839
|
if (st.isDirectory()) dirs.push({ dir, mtimeMs: st.mtimeMs });
|
|
@@ -40442,7 +41073,7 @@ var init_detector = __esm({
|
|
|
40442
41073
|
transcript_path: transcript.path,
|
|
40443
41074
|
transcript_mtime: new Date(transcript.mtimeMs).toISOString(),
|
|
40444
41075
|
claude_pids: processes.map((p) => p.pid),
|
|
40445
|
-
project: basename5(
|
|
41076
|
+
project: basename5(join32(transcript.path, ".."))
|
|
40446
41077
|
}
|
|
40447
41078
|
})
|
|
40448
41079
|
);
|
|
@@ -40812,9 +41443,9 @@ var init_git_facts = __esm({
|
|
|
40812
41443
|
});
|
|
40813
41444
|
|
|
40814
41445
|
// ../../packages/tacho/src/collector/work-order-autostart.ts
|
|
40815
|
-
import { spawn as
|
|
41446
|
+
import { spawn as spawn7 } from "node:child_process";
|
|
40816
41447
|
import { closeSync as closeSync7, existsSync as existsSync19, openSync as openSync7 } from "node:fs";
|
|
40817
|
-
import { dirname as dirname18, join as
|
|
41448
|
+
import { dirname as dirname18, join as join33 } from "node:path";
|
|
40818
41449
|
function asError(error) {
|
|
40819
41450
|
return error instanceof Error ? error : new Error(String(error));
|
|
40820
41451
|
}
|
|
@@ -40867,7 +41498,7 @@ function createWorkOrderAutostart(deps) {
|
|
|
40867
41498
|
}
|
|
40868
41499
|
async function abandon(id2) {
|
|
40869
41500
|
forget(id2);
|
|
40870
|
-
const worktree =
|
|
41501
|
+
const worktree = join33(workTreesDir(paths), id2);
|
|
40871
41502
|
if (!existsSync19(worktree)) return;
|
|
40872
41503
|
const [common, branch, head2] = await Promise.all([
|
|
40873
41504
|
git6(worktree, ["rev-parse", "--path-format=absolute", "--git-common-dir"]),
|
|
@@ -40905,7 +41536,7 @@ function createWorkOrderAutostart(deps) {
|
|
|
40905
41536
|
return waitMs;
|
|
40906
41537
|
}
|
|
40907
41538
|
async function prepareWorktree(root, id2, itemNumber) {
|
|
40908
|
-
const worktree =
|
|
41539
|
+
const worktree = join33(workTreesDir(paths), id2);
|
|
40909
41540
|
const logPath = `${worktree}.log`;
|
|
40910
41541
|
if (existsSync19(worktree)) {
|
|
40911
41542
|
const [branch2, head2] = await Promise.all([
|
|
@@ -41188,7 +41819,7 @@ var init_work_order_autostart = __esm({
|
|
|
41188
41819
|
};
|
|
41189
41820
|
let settled2 = false;
|
|
41190
41821
|
try {
|
|
41191
|
-
const child =
|
|
41822
|
+
const child = spawn7(command2, args, {
|
|
41192
41823
|
cwd: options.cwd,
|
|
41193
41824
|
env: options.env,
|
|
41194
41825
|
// Its own process group, so a daemon restart does not stop the run.
|
|
@@ -41275,7 +41906,7 @@ import {
|
|
|
41275
41906
|
rm,
|
|
41276
41907
|
unlink
|
|
41277
41908
|
} from "node:fs/promises";
|
|
41278
|
-
import { dirname as dirname19, join as
|
|
41909
|
+
import { dirname as dirname19, join as join34 } from "node:path";
|
|
41279
41910
|
function byPath(a, b3) {
|
|
41280
41911
|
return a.path < b3.path ? -1 : a.path > b3.path ? 1 : 0;
|
|
41281
41912
|
}
|
|
@@ -41318,7 +41949,7 @@ async function contentHash(absolutePath, kind, keep) {
|
|
|
41318
41949
|
if (keep !== void 0) {
|
|
41319
41950
|
try {
|
|
41320
41951
|
await mkdir(keep.dir, { recursive: true, mode: 448 });
|
|
41321
|
-
const temp2 =
|
|
41952
|
+
const temp2 = join34(keep.dir, `.partial-${randomUUID3()}`);
|
|
41322
41953
|
copy = {
|
|
41323
41954
|
temp: temp2,
|
|
41324
41955
|
handle: await open3(temp2, "wx", keep.executable ? 448 : 384)
|
|
@@ -41362,7 +41993,7 @@ async function settleCopy(temp, name) {
|
|
|
41362
41993
|
if (temp === void 0) return;
|
|
41363
41994
|
if (name !== void 0)
|
|
41364
41995
|
try {
|
|
41365
|
-
await rename(temp,
|
|
41996
|
+
await rename(temp, join34(dirname19(temp), name));
|
|
41366
41997
|
return;
|
|
41367
41998
|
} catch {
|
|
41368
41999
|
}
|
|
@@ -41378,7 +42009,7 @@ async function copiedBytes(dir) {
|
|
|
41378
42009
|
let total2 = 0;
|
|
41379
42010
|
for (const name of names2) {
|
|
41380
42011
|
try {
|
|
41381
|
-
total2 += (await lstat(
|
|
42012
|
+
total2 += (await lstat(join34(dir, name))).size;
|
|
41382
42013
|
} catch {
|
|
41383
42014
|
}
|
|
41384
42015
|
}
|
|
@@ -41394,7 +42025,7 @@ async function removeCopiesOutside(root, live) {
|
|
|
41394
42025
|
const keep = new Set(live());
|
|
41395
42026
|
await Promise.all(
|
|
41396
42027
|
names2.filter((name) => !keep.has(name)).map(
|
|
41397
|
-
(name) => rm(
|
|
42028
|
+
(name) => rm(join34(root, name), { recursive: true, force: true }).catch(
|
|
41398
42029
|
() => void 0
|
|
41399
42030
|
)
|
|
41400
42031
|
)
|
|
@@ -41501,7 +42132,7 @@ async function contributionOf(exec4, cwd, root, repoRelative, entry2, copies) {
|
|
|
41501
42132
|
let copy = null;
|
|
41502
42133
|
if (entry2 !== null) {
|
|
41503
42134
|
if (copies === void 0 || !COPY_NAME.test(entry2[0])) return void 0;
|
|
41504
|
-
copy =
|
|
42135
|
+
copy = join34(copies, entry2[0]);
|
|
41505
42136
|
const kept = await statOf(copy);
|
|
41506
42137
|
if (kept === void 0 || kept === "absent" || kept.kind !== "file")
|
|
41507
42138
|
return void 0;
|
|
@@ -41903,7 +42534,7 @@ var init_session_changes = __esm({
|
|
|
41903
42534
|
});
|
|
41904
42535
|
|
|
41905
42536
|
// ../../packages/tacho/src/collector/session-commits.ts
|
|
41906
|
-
import { join as
|
|
42537
|
+
import { join as join35 } from "node:path";
|
|
41907
42538
|
function parseMeta(stdout) {
|
|
41908
42539
|
const out = [];
|
|
41909
42540
|
for (const record of stdout.split("\0")) {
|
|
@@ -42028,7 +42659,7 @@ async function readSessionCommits(exec4, cwd, input) {
|
|
|
42028
42659
|
const test = input.tests[commit.sha];
|
|
42029
42660
|
const toolUseId = callAt(times.get(commit.sha), calls);
|
|
42030
42661
|
const written2 = input.written;
|
|
42031
|
-
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)));
|
|
42032
42663
|
return {
|
|
42033
42664
|
sha: commit.sha,
|
|
42034
42665
|
parent_shas: commit.parents.slice(0, MAX_COMMIT_PARENTS),
|
|
@@ -42076,7 +42707,7 @@ var init_session_commits = __esm({
|
|
|
42076
42707
|
|
|
42077
42708
|
// ../../packages/tacho/src/collector/worktree-snapshot.ts
|
|
42078
42709
|
import { lstat as lstat2 } from "node:fs/promises";
|
|
42079
|
-
import { join as
|
|
42710
|
+
import { join as join36 } from "node:path";
|
|
42080
42711
|
function headerPath(prefix, path2) {
|
|
42081
42712
|
const name = `${prefix}${path2}`;
|
|
42082
42713
|
let quoted3 = false;
|
|
@@ -42160,7 +42791,7 @@ async function worktreeFingerprint(status2, root) {
|
|
|
42160
42791
|
const path2 = statusPath(record);
|
|
42161
42792
|
if (path2 === null) return "";
|
|
42162
42793
|
try {
|
|
42163
|
-
const info = await lstat2(
|
|
42794
|
+
const info = await lstat2(join36(root, path2));
|
|
42164
42795
|
return `${info.size}:${info.mtimeMs}:${info.ctimeMs}`;
|
|
42165
42796
|
} catch {
|
|
42166
42797
|
return "absent";
|
|
@@ -42268,7 +42899,7 @@ async function readWorktreeSnapshot(exec4, cwd, baseline, measured) {
|
|
|
42268
42899
|
}
|
|
42269
42900
|
let present;
|
|
42270
42901
|
try {
|
|
42271
|
-
present = (await lstat2(
|
|
42902
|
+
present = (await lstat2(join36(root, path2))).isFile();
|
|
42272
42903
|
} catch {
|
|
42273
42904
|
present = false;
|
|
42274
42905
|
}
|
|
@@ -42371,10 +43002,10 @@ var init_worktree_snapshot = __esm({
|
|
|
42371
43002
|
});
|
|
42372
43003
|
|
|
42373
43004
|
// ../../packages/tacho/src/collector/git-lane.ts
|
|
42374
|
-
import { join as
|
|
43005
|
+
import { join as join37 } from "node:path";
|
|
42375
43006
|
function copiesDirOf(root, session) {
|
|
42376
43007
|
const uuid = session.recorder.sessionUuid;
|
|
42377
|
-
return /^[0-9a-f-]{36}$/i.test(uuid) ?
|
|
43008
|
+
return /^[0-9a-f-]{36}$/i.test(uuid) ? join37(root, uuid) : void 0;
|
|
42378
43009
|
}
|
|
42379
43010
|
function holdsBaseline(session) {
|
|
42380
43011
|
return session.baselineCommit !== void 0 || Object.keys(session.baselines ?? {}).length > 0;
|
|
@@ -45742,7 +46373,7 @@ var init_hook_queues = __esm({
|
|
|
45742
46373
|
|
|
45743
46374
|
// ../../packages/tacho/src/collector/memory-capture/memory-reader.ts
|
|
45744
46375
|
import { createRequire as createRequire2 } from "node:module";
|
|
45745
|
-
import { isAbsolute as isAbsolute8, join as
|
|
46376
|
+
import { isAbsolute as isAbsolute8, join as join38, sep as sep6 } from "node:path";
|
|
45746
46377
|
function claudeCodeLocation(projectsDir, memoryDir) {
|
|
45747
46378
|
return {
|
|
45748
46379
|
harness: "claude-code",
|
|
@@ -45754,13 +46385,13 @@ function claudeCodeLocation(projectsDir, memoryDir) {
|
|
|
45754
46385
|
}
|
|
45755
46386
|
function claudeCodeMemoryLocations(configDir, projectDirs = []) {
|
|
45756
46387
|
const locations = [
|
|
45757
|
-
claudeCodeLocation(() =>
|
|
45758
|
-
claudeCodeLocation(() =>
|
|
46388
|
+
claudeCodeLocation(() => join38(configDir, "projects"), "memory"),
|
|
46389
|
+
claudeCodeLocation(() => join38(configDir, "agent-memory"), "")
|
|
45759
46390
|
];
|
|
45760
46391
|
for (const dir of projectDirs.slice(0, MEMORY_PROJECT_DIRS_MAX))
|
|
45761
46392
|
locations.push(
|
|
45762
|
-
claudeCodeLocation(() =>
|
|
45763
|
-
claudeCodeLocation(() =>
|
|
46393
|
+
claudeCodeLocation(() => join38(dir, ".claude", "agent-memory"), ""),
|
|
46394
|
+
claudeCodeLocation(() => join38(dir, ".claude", "agent-memory-local"), "")
|
|
45764
46395
|
);
|
|
45765
46396
|
return locations;
|
|
45766
46397
|
}
|
|
@@ -45945,13 +46576,13 @@ function createMemoryReader(deps) {
|
|
|
45945
46576
|
const projects = await list2(top);
|
|
45946
46577
|
let complete = projects.complete;
|
|
45947
46578
|
for (const project2 of projects.names) {
|
|
45948
|
-
const dir = location.memoryDir === "" ?
|
|
46579
|
+
const dir = location.memoryDir === "" ? join38(top, project2) : join38(top, project2, location.memoryDir);
|
|
45949
46580
|
const files2 = await list2(dir);
|
|
45950
46581
|
if (!files2.complete) complete = false;
|
|
45951
46582
|
for (const name of files2.names) {
|
|
45952
46583
|
if (!name.endsWith(location.extension)) continue;
|
|
45953
46584
|
if (location.skip.includes(name)) continue;
|
|
45954
|
-
const path2 =
|
|
46585
|
+
const path2 = join38(dir, name);
|
|
45955
46586
|
const file = await readAt2(location.harness, path2);
|
|
45956
46587
|
if (file.kind === "absent" || file.kind === "empty") continue;
|
|
45957
46588
|
paths.push(path2);
|
|
@@ -46037,8 +46668,8 @@ var init_memory_reader = __esm({
|
|
|
46037
46668
|
MEMORY_TYPE_PATTERN = /^[a-z][a-z0-9_-]{0,31}$/;
|
|
46038
46669
|
MEMORY_PROJECT_DIRS_MAX = 200;
|
|
46039
46670
|
HARNESS_MEMORY_LOCATIONS = [
|
|
46040
|
-
claudeCodeLocation((home) =>
|
|
46041
|
-
claudeCodeLocation((home) =>
|
|
46671
|
+
claudeCodeLocation((home) => join38(home, ".claude", "projects"), "memory"),
|
|
46672
|
+
claudeCodeLocation((home) => join38(home, ".claude", "agent-memory"), "")
|
|
46042
46673
|
];
|
|
46043
46674
|
FRONTMATTER = /^---[ \t]*\r?\n(?:([\s\S]*?)\r?\n)?---[ \t]*(?:\r?\n|$)/;
|
|
46044
46675
|
FRONTMATTER_LINE = /^([ \t]*)([A-Za-z_][\w-]*)[ \t]*:[ \t]*(.*)$/;
|
|
@@ -46530,7 +47161,7 @@ var init_memory_recall = __esm({
|
|
|
46530
47161
|
});
|
|
46531
47162
|
|
|
46532
47163
|
// ../../packages/tacho/src/collector/memory-capture/memory-uses.ts
|
|
46533
|
-
import { basename as basename6, dirname as dirname21, isAbsolute as isAbsolute9, join as
|
|
47164
|
+
import { basename as basename6, dirname as dirname21, isAbsolute as isAbsolute9, join as join39, resolve as resolve14 } from "node:path";
|
|
46534
47165
|
function memoryFileOf(path2, locations, home) {
|
|
46535
47166
|
if (!isAbsolute9(path2)) return void 0;
|
|
46536
47167
|
const file = resolve14(path2);
|
|
@@ -46548,7 +47179,7 @@ function memoryFileOf(path2, locations, home) {
|
|
|
46548
47179
|
return void 0;
|
|
46549
47180
|
}
|
|
46550
47181
|
function pathOf(word, cwd, home) {
|
|
46551
|
-
const expanded = /^(?:~|\$HOME|\$\{HOME\})\//.test(word) ?
|
|
47182
|
+
const expanded = /^(?:~|\$HOME|\$\{HOME\})\//.test(word) ? join39(home, word.slice(word.indexOf("/") + 1)) : word;
|
|
46552
47183
|
if (isAbsolute9(expanded)) return expanded;
|
|
46553
47184
|
if (cwd !== void 0 && isAbsolute9(cwd)) return resolve14(cwd, expanded);
|
|
46554
47185
|
return void 0;
|
|
@@ -46804,7 +47435,7 @@ ${use.path}`;
|
|
|
46804
47435
|
});
|
|
46805
47436
|
|
|
46806
47437
|
// ../../packages/tacho/src/collector/memory-capture/stella-store.ts
|
|
46807
|
-
import { dirname as dirname22, isAbsolute as isAbsolute10, join as
|
|
47438
|
+
import { dirname as dirname22, isAbsolute as isAbsolute10, join as join40, resolve as resolve15 } from "node:path";
|
|
46808
47439
|
function queryStellaStore(path2, afterSeq, limit) {
|
|
46809
47440
|
const db = new (nodeSqlite()).DatabaseSync(path2, { readOnly: true });
|
|
46810
47441
|
try {
|
|
@@ -46894,7 +47525,7 @@ async function stellaStoreOf(dir, exists) {
|
|
|
46894
47525
|
if (!isAbsolute10(dir)) return void 0;
|
|
46895
47526
|
let at2 = resolve15(dir);
|
|
46896
47527
|
for (let depth = 0; depth < WORKSPACE_SEARCH_DEPTH; depth += 1) {
|
|
46897
|
-
const candidate =
|
|
47528
|
+
const candidate = join40(at2, STELLA_CONTEXT_DB);
|
|
46898
47529
|
if (await exists(candidate)) return candidate;
|
|
46899
47530
|
const up = dirname22(at2);
|
|
46900
47531
|
if (up === at2) return void 0;
|
|
@@ -46907,7 +47538,7 @@ var init_stella_store = __esm({
|
|
|
46907
47538
|
"../../packages/tacho/src/collector/memory-capture/stella-store.ts"() {
|
|
46908
47539
|
"use strict";
|
|
46909
47540
|
init_memory_reader();
|
|
46910
|
-
STELLA_CONTEXT_DB =
|
|
47541
|
+
STELLA_CONTEXT_DB = join40(".stella", "private", "context.db");
|
|
46911
47542
|
STELLA_MEMORIES_VIEW = "export_memories_v1";
|
|
46912
47543
|
STELLA_USES_VIEW = "export_memory_uses_v1";
|
|
46913
47544
|
STELLA_USES_PER_READ = 5e3;
|
|
@@ -47569,7 +48200,7 @@ var init_cloud_link = __esm({
|
|
|
47569
48200
|
|
|
47570
48201
|
// ../../packages/tacho/src/collector/local-servers/digest.ts
|
|
47571
48202
|
import { createHash as createHash10 } from "node:crypto";
|
|
47572
|
-
import { join as
|
|
48203
|
+
import { join as join41 } from "node:path";
|
|
47573
48204
|
function rememberBounded(map, key, value) {
|
|
47574
48205
|
if (!map.has(key) && map.size >= MAX_REMEMBERED_DIGESTS) {
|
|
47575
48206
|
const oldest = map.keys().next();
|
|
@@ -47606,7 +48237,7 @@ function npmNameSegment(name) {
|
|
|
47606
48237
|
return name.startsWith("@") ? `@${encodeURIComponent(name.slice(1))}` : encodeURIComponent(name);
|
|
47607
48238
|
}
|
|
47608
48239
|
async function whichOnPath(command2, pathValue, search) {
|
|
47609
|
-
const candidates = command2.includes("/") || command2.includes("\\") ? [command2] : (pathValue ?? "").split(search.delimiter).filter((dir) => dir.length > 0).map((dir) =>
|
|
48240
|
+
const candidates = command2.includes("/") || command2.includes("\\") ? [command2] : (pathValue ?? "").split(search.delimiter).filter((dir) => dir.length > 0).map((dir) => join41(dir, command2));
|
|
47610
48241
|
for (const candidate of candidates) {
|
|
47611
48242
|
for (const extension of search.extensions) {
|
|
47612
48243
|
if (await search.isExecutable(candidate + extension))
|
|
@@ -48609,7 +49240,7 @@ var init_local_servers = __esm({
|
|
|
48609
49240
|
|
|
48610
49241
|
// ../../packages/tacho/src/collector/local-servers/machine.ts
|
|
48611
49242
|
import { spawn as nodeSpawn } from "node:child_process";
|
|
48612
|
-
import { access, constants as
|
|
49243
|
+
import { access, constants as constants4, readFile, realpath, stat } from "node:fs/promises";
|
|
48613
49244
|
function machineParked(host) {
|
|
48614
49245
|
if (host.revoked_at !== null || host.host_status === "revoked")
|
|
48615
49246
|
return "the enrollment is revoked";
|
|
@@ -48634,7 +49265,7 @@ function createMachineLink(host, fetch2, env) {
|
|
|
48634
49265
|
async function isExecutable(path2) {
|
|
48635
49266
|
try {
|
|
48636
49267
|
if (!(await stat(path2)).isFile()) return false;
|
|
48637
|
-
await access(path2,
|
|
49268
|
+
await access(path2, constants4.X_OK);
|
|
48638
49269
|
return true;
|
|
48639
49270
|
} catch {
|
|
48640
49271
|
return false;
|
|
@@ -48902,9 +49533,9 @@ import {
|
|
|
48902
49533
|
writeFile
|
|
48903
49534
|
} from "node:fs/promises";
|
|
48904
49535
|
import { homedir as homedir5 } from "node:os";
|
|
48905
|
-
import { dirname as dirname23, join as
|
|
49536
|
+
import { dirname as dirname23, join as join42 } from "node:path";
|
|
48906
49537
|
function stagingFolder(root, name) {
|
|
48907
|
-
return
|
|
49538
|
+
return join42(root, `.${name}${STAGING_SUFFIX}`);
|
|
48908
49539
|
}
|
|
48909
49540
|
function isStagingName(name) {
|
|
48910
49541
|
return name.startsWith(".") && name.endsWith(STAGING_SUFFIX);
|
|
@@ -48947,17 +49578,17 @@ function envDir(env, key) {
|
|
|
48947
49578
|
function skillsRoot(harness, env = process.env, home = homedir5()) {
|
|
48948
49579
|
switch (harness) {
|
|
48949
49580
|
case "claude-code":
|
|
48950
|
-
return
|
|
48951
|
-
envDir(env, "CLAUDE_CONFIG_DIR") ??
|
|
49581
|
+
return join42(
|
|
49582
|
+
envDir(env, "CLAUDE_CONFIG_DIR") ?? join42(home, ".claude"),
|
|
48952
49583
|
"skills"
|
|
48953
49584
|
);
|
|
48954
49585
|
case "codex": {
|
|
48955
49586
|
const codexHome = envDir(env, "CODEX_HOME");
|
|
48956
|
-
return codexHome === null ?
|
|
49587
|
+
return codexHome === null ? join42(home, ".agents", "skills") : join42(codexHome, "skills");
|
|
48957
49588
|
}
|
|
48958
49589
|
case "stella":
|
|
48959
|
-
return
|
|
48960
|
-
envDir(env, "STELLA_HOME") ??
|
|
49590
|
+
return join42(
|
|
49591
|
+
envDir(env, "STELLA_HOME") ?? join42(home, ".stella"),
|
|
48961
49592
|
"skills"
|
|
48962
49593
|
);
|
|
48963
49594
|
case "cursor":
|
|
@@ -49018,7 +49649,7 @@ async function readMarker(folder) {
|
|
|
49018
49649
|
if (!entries2.includes(SESSION_MARKER)) return { state: "foreign" };
|
|
49019
49650
|
try {
|
|
49020
49651
|
const parsed2 = JSON.parse(
|
|
49021
|
-
await readFile2(
|
|
49652
|
+
await readFile2(join42(folder, SESSION_MARKER), "utf8")
|
|
49022
49653
|
);
|
|
49023
49654
|
return isMarker(parsed2) ? { state: "ours", marker: parsed2 } : { state: "foreign" };
|
|
49024
49655
|
} catch {
|
|
@@ -49035,22 +49666,22 @@ function liveSessions(marker, now) {
|
|
|
49035
49666
|
return live;
|
|
49036
49667
|
}
|
|
49037
49668
|
async function writeMarker(folder, marker) {
|
|
49038
|
-
const temp =
|
|
49669
|
+
const temp = join42(folder, MARKER_TEMP);
|
|
49039
49670
|
await writeFile(temp, `${JSON.stringify(marker, null, 2)}
|
|
49040
49671
|
`);
|
|
49041
|
-
await rename2(temp,
|
|
49672
|
+
await rename2(temp, join42(folder, SESSION_MARKER));
|
|
49042
49673
|
}
|
|
49043
49674
|
async function writeSkill(root, skill, marker) {
|
|
49044
|
-
const folder =
|
|
49675
|
+
const folder = join42(root, skill.name);
|
|
49045
49676
|
const staging = stagingFolder(root, skill.name);
|
|
49046
49677
|
await rm2(folder, { recursive: true, force: true });
|
|
49047
49678
|
await rm2(staging, { recursive: true, force: true });
|
|
49048
49679
|
await mkdir2(staging);
|
|
49049
49680
|
await writeMarker(staging, { digest: UNFINISHED_DIGEST, sessions: {} });
|
|
49050
49681
|
await rename2(staging, folder);
|
|
49051
|
-
await writeFile(
|
|
49682
|
+
await writeFile(join42(folder, "SKILL.md"), skillMarkdown(skill));
|
|
49052
49683
|
for (const file of skill.files) {
|
|
49053
|
-
const target2 =
|
|
49684
|
+
const target2 = join42(folder, file.path);
|
|
49054
49685
|
await mkdir2(dirname23(target2), { recursive: true });
|
|
49055
49686
|
await writeFile(target2, file.content);
|
|
49056
49687
|
}
|
|
@@ -49079,7 +49710,7 @@ async function placeSkills(root, sessionId, skills, now = /* @__PURE__ */ new Da
|
|
|
49079
49710
|
result2.warnings.push(refusal);
|
|
49080
49711
|
continue;
|
|
49081
49712
|
}
|
|
49082
|
-
const folder =
|
|
49713
|
+
const folder = join42(root, skill.name);
|
|
49083
49714
|
if (taken.has(skill.name)) {
|
|
49084
49715
|
result2.skipped.push(skill.name);
|
|
49085
49716
|
result2.warnings.push(
|
|
@@ -49144,7 +49775,7 @@ async function removeSkills(root, sessionId, now = /* @__PURE__ */ new Date()) {
|
|
|
49144
49775
|
throw error;
|
|
49145
49776
|
}
|
|
49146
49777
|
for (const name of names2.sort(compareText)) {
|
|
49147
|
-
const folder =
|
|
49778
|
+
const folder = join42(root, name);
|
|
49148
49779
|
if (isStagingName(name)) {
|
|
49149
49780
|
await rm2(folder, { recursive: true, force: true });
|
|
49150
49781
|
continue;
|
|
@@ -50066,13 +50697,27 @@ function connectionTokens(raw) {
|
|
|
50066
50697
|
}
|
|
50067
50698
|
return named;
|
|
50068
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
|
+
}
|
|
50069
50705
|
function upstreamRequestHeaders(raw, host, bodyLength, dropContentEncoding, attach) {
|
|
50070
50706
|
const named = connectionTokens(raw);
|
|
50071
50707
|
const out = ["Host", host];
|
|
50708
|
+
const oauth = attach?.kind === "oauth";
|
|
50709
|
+
let beta;
|
|
50072
50710
|
for (let i2 = 0; i2 + 1 < raw.length; i2 += 2) {
|
|
50073
50711
|
const name = raw[i2];
|
|
50074
50712
|
const lower = name.toLowerCase();
|
|
50075
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
|
+
}
|
|
50076
50721
|
if (lower === "host" || lower === "content-length") continue;
|
|
50077
50722
|
if (lower === "accept-encoding" || lower === "expect") continue;
|
|
50078
50723
|
if (lower === TACHO_MODEL_SESSION_HEADER) continue;
|
|
@@ -50084,6 +50729,9 @@ function upstreamRequestHeaders(raw, host, bodyLength, dropContentEncoding, atta
|
|
|
50084
50729
|
if (attach !== void 0) {
|
|
50085
50730
|
if (attach.kind === "api_key") out.push("X-Api-Key", attach.secret);
|
|
50086
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);
|
|
50087
50735
|
}
|
|
50088
50736
|
out.push("Accept-Encoding", "identity");
|
|
50089
50737
|
if (bodyLength > 0 || raw.some((h, i2) => i2 % 2 === 0 && /^content-length$/i.test(h)))
|
|
@@ -50117,7 +50765,7 @@ function providerError(provider, status2, code, message) {
|
|
|
50117
50765
|
};
|
|
50118
50766
|
return { status: status2, body: JSON.stringify(body2) };
|
|
50119
50767
|
}
|
|
50120
|
-
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;
|
|
50121
50769
|
var init_model_routes = __esm({
|
|
50122
50770
|
"../../packages/tacho/src/collector/model-routes.ts"() {
|
|
50123
50771
|
"use strict";
|
|
@@ -50146,6 +50794,8 @@ var init_model_routes = __esm({
|
|
|
50146
50794
|
"upgrade"
|
|
50147
50795
|
]);
|
|
50148
50796
|
CREDENTIAL_HEADERS = ["authorization", "x-api-key"];
|
|
50797
|
+
CHATGPT_ACCOUNT_HEADER = "chatgpt-account-id";
|
|
50798
|
+
ANTHROPIC_OAUTH_BETA = "oauth-2025-04-20";
|
|
50149
50799
|
}
|
|
50150
50800
|
});
|
|
50151
50801
|
|
|
@@ -50877,7 +51527,7 @@ function createModelProxy(deps) {
|
|
|
50877
51527
|
function resolveCredential(req, route) {
|
|
50878
51528
|
const broker = deps.credentials;
|
|
50879
51529
|
const presented = presentedCredential(req);
|
|
50880
|
-
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");
|
|
50881
51531
|
if (broker === void 0 || !brokered) {
|
|
50882
51532
|
if (presented !== void 0 && looksLikeRunToken(presented.value)) {
|
|
50883
51533
|
const claims = peekRunTokenClaims(presented.value);
|
|
@@ -50932,6 +51582,27 @@ function createModelProxy(deps) {
|
|
|
50932
51582
|
}
|
|
50933
51583
|
};
|
|
50934
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
|
+
}
|
|
50935
51606
|
return {
|
|
50936
51607
|
basis: TACHO_CREDENTIAL_GATEWAY_BROKERED,
|
|
50937
51608
|
claims: verdict.claims,
|
|
@@ -51622,6 +52293,15 @@ function createModelProxy(deps) {
|
|
|
51622
52293
|
if (result2.path !== path2 && result2.path.startsWith("/"))
|
|
51623
52294
|
path2 = result2.path;
|
|
51624
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
|
+
}
|
|
51625
52305
|
const requestModel = askedModel;
|
|
51626
52306
|
const requestEffort = requestEffortOf(injected ? injectedJson : json2());
|
|
51627
52307
|
const sent = injected ? body2 : readable();
|
|
@@ -52186,6 +52866,7 @@ var init_model_proxy = __esm({
|
|
|
52186
52866
|
init_frame_body();
|
|
52187
52867
|
init_replay_grade();
|
|
52188
52868
|
init_bundle();
|
|
52869
|
+
init_model_credential();
|
|
52189
52870
|
init_run_token();
|
|
52190
52871
|
init_wire();
|
|
52191
52872
|
init_cache_keep_alive();
|
|
@@ -52921,12 +53602,12 @@ var init_server = __esm({
|
|
|
52921
53602
|
|
|
52922
53603
|
// ../../packages/tacho/src/collector/refused.ts
|
|
52923
53604
|
import { readdirSync as readdirSync12, readFileSync as readFileSync19, statSync as statSync12 } from "node:fs";
|
|
52924
|
-
import { join as
|
|
53605
|
+
import { join as join43 } from "node:path";
|
|
52925
53606
|
function refusalRetryable(refusal) {
|
|
52926
53607
|
return refusal === "malformed" || refusal === "parked";
|
|
52927
53608
|
}
|
|
52928
53609
|
function refusedRecordPath(dir, event) {
|
|
52929
|
-
return
|
|
53610
|
+
return join43(dir, `${event.session_uuid}-${String(event.seq).padStart(8, "0")}.json`);
|
|
52930
53611
|
}
|
|
52931
53612
|
function newRefusedRecord(event, reason3, refusal, at2, body2) {
|
|
52932
53613
|
const retryable = refusalRetryable(refusal);
|
|
@@ -53002,7 +53683,7 @@ function scanRefused(dir, now, limit = MAX_REFUSED_RETRIES_PER_PASS) {
|
|
|
53002
53683
|
};
|
|
53003
53684
|
const due = [];
|
|
53004
53685
|
for (const name of names2) {
|
|
53005
|
-
const entry2 = readRefusedEntry(
|
|
53686
|
+
const entry2 = readRefusedEntry(join43(dir, name));
|
|
53006
53687
|
if (entry2 === void 0) continue;
|
|
53007
53688
|
summary.total += 1;
|
|
53008
53689
|
if (summary.lastRefusedAt === void 0 || entry2.refusedAt > summary.lastRefusedAt)
|
|
@@ -53039,7 +53720,7 @@ var init_refused = __esm({
|
|
|
53039
53720
|
|
|
53040
53721
|
// ../../packages/tacho/src/collector/spool.ts
|
|
53041
53722
|
import { existsSync as existsSync22, readFileSync as readFileSync20, unlinkSync as unlinkSync12 } from "node:fs";
|
|
53042
|
-
import { join as
|
|
53723
|
+
import { join as join44 } from "node:path";
|
|
53043
53724
|
function sessionOwnedElsewhere(error) {
|
|
53044
53725
|
return error.status === 403 && error.body.includes(SESSION_OWNED_ELSEWHERE);
|
|
53045
53726
|
}
|
|
@@ -53272,7 +53953,7 @@ var init_spool = __esm({
|
|
|
53272
53953
|
}
|
|
53273
53954
|
/** Add a body to a quarantine record that was written without one. */
|
|
53274
53955
|
stashBodyBeside(event, body2) {
|
|
53275
|
-
const path2 =
|
|
53956
|
+
const path2 = join44(
|
|
53276
53957
|
this.options.quarantineDir,
|
|
53277
53958
|
`${event.session_uuid}-${String(event.seq).padStart(8, "0")}.json`
|
|
53278
53959
|
);
|
|
@@ -53928,7 +54609,7 @@ import {
|
|
|
53928
54609
|
} from "node:fs";
|
|
53929
54610
|
import { readdir as readdir3, readFile as readFile3, stat as stat2 } from "node:fs/promises";
|
|
53930
54611
|
import { homedir as homedir7, hostname as osHostname2 } from "node:os";
|
|
53931
|
-
import { dirname as dirname24, join as
|
|
54612
|
+
import { dirname as dirname24, join as join45 } from "node:path";
|
|
53932
54613
|
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
53933
54614
|
function cloudGatewayUpstreams(origin = CLOUD_GATEWAY_ORIGIN) {
|
|
53934
54615
|
const base2 = new URL(origin).origin;
|
|
@@ -54672,7 +55353,7 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
54672
55353
|
controlReachable: lastControlAt !== void 0 && now() - lastControlAt < 2 * timers.bundleRefreshMs
|
|
54673
55354
|
};
|
|
54674
55355
|
}
|
|
54675
|
-
const bodyPurgeOwedPath =
|
|
55356
|
+
const bodyPurgeOwedPath = join45(paths.wal, "body-purge-owed");
|
|
54676
55357
|
function markBodyPurgeOwed(retention, dropped) {
|
|
54677
55358
|
try {
|
|
54678
55359
|
ensureDir(paths.wal);
|
|
@@ -54949,7 +55630,7 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
54949
55630
|
}
|
|
54950
55631
|
void workOrderAutostart.reconcile();
|
|
54951
55632
|
}
|
|
54952
|
-
const lastIngestFile =
|
|
55633
|
+
const lastIngestFile = join45(paths.dir, "last-ingest.json");
|
|
54953
55634
|
const shipper = new Shipper({
|
|
54954
55635
|
wal,
|
|
54955
55636
|
client,
|
|
@@ -55471,7 +56152,7 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
55471
56152
|
async function readSpoolFile(name) {
|
|
55472
56153
|
try {
|
|
55473
56154
|
const file = parseSpoolFile(
|
|
55474
|
-
await readFile3(
|
|
56155
|
+
await readFile3(join45(paths.spool, name), "utf8")
|
|
55475
56156
|
);
|
|
55476
56157
|
spoolFacts.set(name, spoolFactsOf(file));
|
|
55477
56158
|
return file;
|
|
@@ -55660,7 +56341,7 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
55660
56341
|
function setAsideConflictingTerminal(uuid, pending, conflict) {
|
|
55661
56342
|
const name = `${uuid}-terminal-conflict-${String(conflict.seq).padStart(8, "0")}.json`;
|
|
55662
56343
|
writeSensitiveFileAtomic(
|
|
55663
|
-
|
|
56344
|
+
join45(paths.quarantine, name),
|
|
55664
56345
|
JSON.stringify(
|
|
55665
56346
|
{
|
|
55666
56347
|
reason: conflict.message,
|
|
@@ -55740,8 +56421,8 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
55740
56421
|
function moveToFailedSpool(path2, name, reason3) {
|
|
55741
56422
|
log(`spool file ${name} moved to spool/failed/: ${reason3}`);
|
|
55742
56423
|
try {
|
|
55743
|
-
ensureDir(
|
|
55744
|
-
renameSync4(path2,
|
|
56424
|
+
ensureDir(join45(paths.spool, "failed"));
|
|
56425
|
+
renameSync4(path2, join45(paths.spool, "failed", name));
|
|
55745
56426
|
} catch (error) {
|
|
55746
56427
|
log(
|
|
55747
56428
|
`spool file ${name} could not be moved to spool/failed/: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -55794,7 +56475,7 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
55794
56475
|
continue;
|
|
55795
56476
|
}
|
|
55796
56477
|
reads += 1;
|
|
55797
|
-
const path2 =
|
|
56478
|
+
const path2 = join45(paths.spool, name);
|
|
55798
56479
|
let file;
|
|
55799
56480
|
try {
|
|
55800
56481
|
file = await readSpoolFile(name);
|
|
@@ -56183,6 +56864,13 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
56183
56864
|
...options.pauseHold,
|
|
56184
56865
|
credentials: {
|
|
56185
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
|
+
},
|
|
56186
56874
|
custody: (provider) => {
|
|
56187
56875
|
try {
|
|
56188
56876
|
return credentialStore.read(provider);
|
|
@@ -56247,6 +56935,13 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
56247
56935
|
record,
|
|
56248
56936
|
model: modelProxy,
|
|
56249
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
|
+
},
|
|
56250
56945
|
issueCredential: (harness) => issueRunToken(
|
|
56251
56946
|
{ harness },
|
|
56252
56947
|
{
|
|
@@ -56621,7 +57316,7 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
56621
57316
|
let removed = 0;
|
|
56622
57317
|
for (const name of readdirSync13(paths.quarantine)) {
|
|
56623
57318
|
if (!name.endsWith(".json")) continue;
|
|
56624
|
-
const file =
|
|
57319
|
+
const file = join45(paths.quarantine, name);
|
|
56625
57320
|
try {
|
|
56626
57321
|
const refusedAt = readRefusedEntry(file)?.refusedAt ?? statSync13(file).mtimeMs;
|
|
56627
57322
|
if (at2 - refusedAt < retainMs) continue;
|
|
@@ -56877,8 +57572,29 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
56877
57572
|
});
|
|
56878
57573
|
}
|
|
56879
57574
|
let lastStaticRenewalAt = 0;
|
|
57575
|
+
let lastLoginRefreshAt = 0;
|
|
56880
57576
|
async function renewStaticTokens() {
|
|
56881
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
|
+
}
|
|
56882
57598
|
if (now() - lastStaticRenewalAt < STATIC_TOKEN_RENEWAL_CHECK_MS) return;
|
|
56883
57599
|
lastStaticRenewalAt = now();
|
|
56884
57600
|
if (host.host_status !== "active" || !inCustody("openai")) return;
|
|
@@ -56951,7 +57667,7 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
56951
57667
|
let memoryScan;
|
|
56952
57668
|
if (options.listen ?? true) {
|
|
56953
57669
|
const codexMemories = createCodexMemoryStore({
|
|
56954
|
-
path:
|
|
57670
|
+
path: join45(dirname24(paths.codexHooks), CODEX_MEMORY_STORE_FILE),
|
|
56955
57671
|
stat: (path2) => stat2(path2),
|
|
56956
57672
|
log
|
|
56957
57673
|
});
|
|
@@ -57096,7 +57812,7 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
57096
57812
|
}
|
|
57097
57813
|
};
|
|
57098
57814
|
}
|
|
57099
|
-
var DEFAULT_TIMERS, STATIC_TOKEN_RENEWAL_CHECK_MS, MEMORY_SCAN_MS, CLOUD_GATEWAY_ORIGIN, CLOUD_GATEWAY_BASE_PATH, QUEUED_PROMPT_CLASS, RECORDER_EVENTS_KEPT, owedBodyPurgeSchema, objectSchema, spoolFileSchema, otlpResourceListSchema, otlpPayloadSchema, defaultExecAsync, STOPPING, STOPPED_EXEC, STATE_WRITE_DEFER_MS;
|
|
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;
|
|
57100
57816
|
var init_daemon = __esm({
|
|
57101
57817
|
"../../packages/tacho/src/collector/daemon.ts"() {
|
|
57102
57818
|
"use strict";
|
|
@@ -57118,6 +57834,7 @@ var init_daemon = __esm({
|
|
|
57118
57834
|
init_claude_code_mcp_writer();
|
|
57119
57835
|
init_model_base_url();
|
|
57120
57836
|
init_model_credential();
|
|
57837
|
+
init_chatgpt_refresh();
|
|
57121
57838
|
init_run_token();
|
|
57122
57839
|
init_process_scan();
|
|
57123
57840
|
init_retention();
|
|
@@ -57190,6 +57907,7 @@ var init_daemon = __esm({
|
|
|
57190
57907
|
hookBundleWaitMs: 2e3
|
|
57191
57908
|
};
|
|
57192
57909
|
STATIC_TOKEN_RENEWAL_CHECK_MS = 60 * 6e4;
|
|
57910
|
+
CHATGPT_LOGIN_CHECK_MS = 10 * 6e4;
|
|
57193
57911
|
MEMORY_SCAN_MS = 5 * 6e4;
|
|
57194
57912
|
CLOUD_GATEWAY_ORIGIN = "https://api.oxagen.sh";
|
|
57195
57913
|
CLOUD_GATEWAY_BASE_PATH = "/v1/gateway";
|
|
@@ -57454,7 +58172,7 @@ var init_run2 = __esm({
|
|
|
57454
58172
|
// ../../packages/tacho/src/arp/bundle.ts
|
|
57455
58173
|
import {
|
|
57456
58174
|
closeSync as closeSync8,
|
|
57457
|
-
constants as
|
|
58175
|
+
constants as constants5,
|
|
57458
58176
|
fstatSync as fstatSync2,
|
|
57459
58177
|
lstatSync as lstatSync8,
|
|
57460
58178
|
mkdirSync as mkdirSync6,
|
|
@@ -57463,7 +58181,7 @@ import {
|
|
|
57463
58181
|
realpathSync as realpathSync5,
|
|
57464
58182
|
writeFileSync as writeFileSync4
|
|
57465
58183
|
} from "node:fs";
|
|
57466
|
-
import { dirname as dirname25, join as
|
|
58184
|
+
import { dirname as dirname25, join as join46, resolve as resolve17 } from "node:path";
|
|
57467
58185
|
function bundlePath(root, relative11, create2 = false) {
|
|
57468
58186
|
const absolute = resolve17(root);
|
|
57469
58187
|
if (create2) mkdirSync6(absolute, { recursive: true, mode: 448 });
|
|
@@ -57474,7 +58192,7 @@ function bundlePath(root, relative11, create2 = false) {
|
|
|
57474
58192
|
let current = base2;
|
|
57475
58193
|
const parts = relative11.split("/");
|
|
57476
58194
|
for (let i2 = 0; i2 < parts.length; i2++) {
|
|
57477
|
-
current =
|
|
58195
|
+
current = join46(current, parts[i2]);
|
|
57478
58196
|
try {
|
|
57479
58197
|
const stat7 = lstatSync8(current);
|
|
57480
58198
|
if (stat7.isSymbolicLink() || i2 < parts.length - 1 && !stat7.isDirectory()) {
|
|
@@ -57495,7 +58213,7 @@ function bundlePath(root, relative11, create2 = false) {
|
|
|
57495
58213
|
}
|
|
57496
58214
|
function readBounded(root, relative11, limit = ARP_MAX_BLOB_BYTES) {
|
|
57497
58215
|
const path2 = bundlePath(root, relative11);
|
|
57498
|
-
const fd2 = openSync8(path2,
|
|
58216
|
+
const fd2 = openSync8(path2, constants5.O_RDONLY | constants5.O_NOFOLLOW);
|
|
57499
58217
|
try {
|
|
57500
58218
|
const stat7 = fstatSync2(fd2);
|
|
57501
58219
|
if (!stat7.isFile() || stat7.size > limit)
|
|
@@ -57520,7 +58238,7 @@ function writeNew(root, relative11, bytes) {
|
|
|
57520
58238
|
const path2 = bundlePath(root, relative11, true);
|
|
57521
58239
|
const fd2 = openSync8(
|
|
57522
58240
|
path2,
|
|
57523
|
-
|
|
58241
|
+
constants5.O_WRONLY | constants5.O_CREAT | constants5.O_EXCL | constants5.O_NOFOLLOW,
|
|
57524
58242
|
384
|
|
57525
58243
|
);
|
|
57526
58244
|
try {
|
|
@@ -58425,7 +59143,7 @@ var init_oracles = __esm({
|
|
|
58425
59143
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
58426
59144
|
import {
|
|
58427
59145
|
closeSync as closeSync9,
|
|
58428
|
-
constants as
|
|
59146
|
+
constants as constants6,
|
|
58429
59147
|
fstatSync as fstatSync3,
|
|
58430
59148
|
lstatSync as lstatSync9,
|
|
58431
59149
|
mkdirSync as mkdirSync7,
|
|
@@ -58435,7 +59153,7 @@ import {
|
|
|
58435
59153
|
rmSync as rmSync8,
|
|
58436
59154
|
writeFileSync as writeFileSync5
|
|
58437
59155
|
} from "node:fs";
|
|
58438
|
-
import { dirname as dirname26, isAbsolute as isAbsolute11, join as
|
|
59156
|
+
import { dirname as dirname26, isAbsolute as isAbsolute11, join as join47, relative as relative5, resolve as resolve18, sep as sep7 } from "node:path";
|
|
58439
59157
|
function outsideProfile(path2) {
|
|
58440
59158
|
return HARNESS_CONFIG_PATH.test(path2) || CREDENTIAL_PATH.test(path2);
|
|
58441
59159
|
}
|
|
@@ -58446,7 +59164,7 @@ function sameJson(bytes, expected) {
|
|
|
58446
59164
|
return jcs(JSON.parse(bytes.toString("utf8"))) === jcs(expected);
|
|
58447
59165
|
}
|
|
58448
59166
|
function readRegular(label2, path2, limit) {
|
|
58449
|
-
const fd2 = openSync9(path2,
|
|
59167
|
+
const fd2 = openSync9(path2, constants6.O_RDONLY | constants6.O_NOFOLLOW);
|
|
58450
59168
|
try {
|
|
58451
59169
|
const before = fstatSync3(fd2);
|
|
58452
59170
|
if (!before.isFile() || before.size > limit)
|
|
@@ -58491,7 +59209,7 @@ function within2(root, path2) {
|
|
|
58491
59209
|
}
|
|
58492
59210
|
function newPath(path2) {
|
|
58493
59211
|
const full = resolve18(path2);
|
|
58494
|
-
return
|
|
59212
|
+
return join47(
|
|
58495
59213
|
realpathSync6(dirname26(full)),
|
|
58496
59214
|
full.slice(dirname26(full).length + 1)
|
|
58497
59215
|
);
|
|
@@ -58505,7 +59223,7 @@ function sourcePath(root, path2) {
|
|
|
58505
59223
|
}
|
|
58506
59224
|
let current = root;
|
|
58507
59225
|
for (const part2 of path2.split("/")) {
|
|
58508
|
-
current =
|
|
59226
|
+
current = join47(current, part2);
|
|
58509
59227
|
if (lstatSync9(current).isSymbolicLink())
|
|
58510
59228
|
arpFail(
|
|
58511
59229
|
`${path2} is a symlink or passes through one. Symlinks require a resource adapter.`
|
|
@@ -58772,10 +59490,10 @@ function prepareCheckpoint(options) {
|
|
|
58772
59490
|
});
|
|
58773
59491
|
mkdirSync7(destination, { mode: 448 });
|
|
58774
59492
|
try {
|
|
58775
|
-
const restored =
|
|
59493
|
+
const restored = join47(destination, "workspace");
|
|
58776
59494
|
mkdirSync7(restored, { mode: 448 });
|
|
58777
59495
|
for (const item of restore) {
|
|
58778
|
-
const path2 =
|
|
59496
|
+
const path2 = join47(restored, item.path);
|
|
58779
59497
|
if (item.kind === "directory")
|
|
58780
59498
|
mkdirSync7(path2, { recursive: true, mode: 448 });
|
|
58781
59499
|
else {
|
|
@@ -58786,9 +59504,9 @@ function prepareCheckpoint(options) {
|
|
|
58786
59504
|
});
|
|
58787
59505
|
}
|
|
58788
59506
|
}
|
|
58789
|
-
const promptDir =
|
|
59507
|
+
const promptDir = join47(restored, ".arp");
|
|
58790
59508
|
mkdirSync7(promptDir, { mode: 448 });
|
|
58791
|
-
const promptFile =
|
|
59509
|
+
const promptFile = join47(promptDir, "handoff.json");
|
|
58792
59510
|
const prompt = {
|
|
58793
59511
|
checkpoint_digest: checkpointDigest,
|
|
58794
59512
|
task: task.data.request,
|
|
@@ -58805,7 +59523,7 @@ function prepareCheckpoint(options) {
|
|
|
58805
59523
|
flag: "wx",
|
|
58806
59524
|
mode: 384
|
|
58807
59525
|
});
|
|
58808
|
-
const reportPath =
|
|
59526
|
+
const reportPath = join47(destination, "report.json");
|
|
58809
59527
|
writeFileSync5(
|
|
58810
59528
|
reportPath,
|
|
58811
59529
|
jcs(
|
|
@@ -59182,6 +59900,41 @@ function buildTachoProgram(options = {}) {
|
|
|
59182
59900
|
deps.err(`${name} credential: ${result2.detail}`);
|
|
59183
59901
|
process.exitCode = 1;
|
|
59184
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
|
+
);
|
|
59185
59938
|
credential.command("status").description(
|
|
59186
59939
|
"Which providers the gateway holds, and how each harness gets its credential"
|
|
59187
59940
|
).option("--json", "Machine-readable output").action(async (opts) => {
|
|
@@ -59446,7 +60199,7 @@ var init_package = __esm({
|
|
|
59446
60199
|
"package.json"() {
|
|
59447
60200
|
package_default = {
|
|
59448
60201
|
name: "@oxagen/cli",
|
|
59449
|
-
version: "2.1.4-
|
|
60202
|
+
version: "2.1.4-965",
|
|
59450
60203
|
description: "Oxagen governance CLI \u2014 spend, lineage, grounding, credentials, and audit (agentic coding lives in the stella CLI)",
|
|
59451
60204
|
type: "module",
|
|
59452
60205
|
main: "./dist/index.js",
|
|
@@ -59513,10 +60266,10 @@ var init_package = __esm({
|
|
|
59513
60266
|
|
|
59514
60267
|
// src/lib/atomic-write.ts
|
|
59515
60268
|
import { writeFileSync as writeFileSync6, renameSync as renameSync5, unlinkSync as unlinkSync15, existsSync as existsSync24 } from "node:fs";
|
|
59516
|
-
import { dirname as dirname27, join as
|
|
60269
|
+
import { dirname as dirname27, join as join48 } from "node:path";
|
|
59517
60270
|
function atomicWriteFileSync(path2, data, mode) {
|
|
59518
60271
|
const dir = dirname27(path2);
|
|
59519
|
-
const tmp =
|
|
60272
|
+
const tmp = join48(
|
|
59520
60273
|
dir,
|
|
59521
60274
|
`.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`
|
|
59522
60275
|
);
|
|
@@ -59541,7 +60294,7 @@ var init_atomic_write = __esm({
|
|
|
59541
60294
|
|
|
59542
60295
|
// src/lib/config.ts
|
|
59543
60296
|
import { homedir as homedir8 } from "os";
|
|
59544
|
-
import { join as
|
|
60297
|
+
import { join as join49 } from "path";
|
|
59545
60298
|
import { readFileSync as readFileSync24, mkdirSync as mkdirSync8, existsSync as existsSync25, statSync as statSync14 } from "fs";
|
|
59546
60299
|
function getConfigDir() {
|
|
59547
60300
|
return CONFIG_DIR;
|
|
@@ -59628,8 +60381,8 @@ var CONFIG_DIR, CONFIG_FILE, STRING_FIELDS, TELEMETRY_FIELDS, cached2;
|
|
|
59628
60381
|
var init_config = __esm({
|
|
59629
60382
|
"src/lib/config.ts"() {
|
|
59630
60383
|
init_atomic_write();
|
|
59631
|
-
CONFIG_DIR =
|
|
59632
|
-
CONFIG_FILE =
|
|
60384
|
+
CONFIG_DIR = join49(homedir8(), ".config", "oxagen");
|
|
60385
|
+
CONFIG_FILE = join49(CONFIG_DIR, "config.json");
|
|
59633
60386
|
STRING_FIELDS = [
|
|
59634
60387
|
"token",
|
|
59635
60388
|
"orgSlug",
|
|
@@ -59674,16 +60427,16 @@ import {
|
|
|
59674
60427
|
writeFile as writeFile2
|
|
59675
60428
|
} from "node:fs/promises";
|
|
59676
60429
|
import { homedir as homedir9 } from "node:os";
|
|
59677
|
-
import { join as
|
|
60430
|
+
import { join as join50 } from "node:path";
|
|
59678
60431
|
function isDebugEnabled() {
|
|
59679
60432
|
const v = process.env[DEBUG_ENV];
|
|
59680
60433
|
return v === "1" || v === "true";
|
|
59681
60434
|
}
|
|
59682
60435
|
function logsDir() {
|
|
59683
|
-
return
|
|
60436
|
+
return join50(homedir9(), ".oxagen", "logs");
|
|
59684
60437
|
}
|
|
59685
60438
|
function debugLogFile() {
|
|
59686
|
-
return
|
|
60439
|
+
return join50(logsDir(), "cli.output");
|
|
59687
60440
|
}
|
|
59688
60441
|
function sanitize(value, depth = 0) {
|
|
59689
60442
|
if (value === null || value === void 0) return value;
|
|
@@ -62978,9 +63731,9 @@ var init_git = __esm({
|
|
|
62978
63731
|
|
|
62979
63732
|
// ../../packages/steering-freshness/src/cache.ts
|
|
62980
63733
|
import { mkdir as mkdir4, readFile as readFile6, writeFile as writeFile4 } from "node:fs/promises";
|
|
62981
|
-
import { dirname as dirname28, join as
|
|
63734
|
+
import { dirname as dirname28, join as join51 } from "node:path";
|
|
62982
63735
|
function stampPath(gitCommonDir) {
|
|
62983
|
-
return
|
|
63736
|
+
return join51(gitCommonDir, "oxagen", "steering-freshness.json");
|
|
62984
63737
|
}
|
|
62985
63738
|
async function readFetchStamp(gitCommonDir, io = defaultIo) {
|
|
62986
63739
|
try {
|
|
@@ -63032,24 +63785,24 @@ var init_cache = __esm({
|
|
|
63032
63785
|
// ../../packages/steering-freshness/src/hooks.ts
|
|
63033
63786
|
import { mkdir as mkdir5, readFile as readFile7, writeFile as writeFile5 } from "node:fs/promises";
|
|
63034
63787
|
import { homedir as homedir10 } from "node:os";
|
|
63035
|
-
import { dirname as dirname29, join as
|
|
63788
|
+
import { dirname as dirname29, join as join52 } from "node:path";
|
|
63036
63789
|
function hookCommand(harness) {
|
|
63037
63790
|
return `oxagen steering gate --harness ${harness}`;
|
|
63038
63791
|
}
|
|
63039
63792
|
function hookConfigPath(projectRoot, harness, env = process.env, home = homedir10()) {
|
|
63040
63793
|
switch (harness) {
|
|
63041
63794
|
case "claude-code":
|
|
63042
|
-
return
|
|
63795
|
+
return join52(projectRoot, ".claude", "settings.json");
|
|
63043
63796
|
case "codex":
|
|
63044
|
-
return
|
|
63797
|
+
return join52(env["CODEX_HOME"] ?? join52(home, ".codex"), "hooks.json");
|
|
63045
63798
|
case "cursor":
|
|
63046
|
-
return
|
|
63799
|
+
return join52(home, ".cursor", "hooks.json");
|
|
63047
63800
|
case "stella":
|
|
63048
|
-
return
|
|
63801
|
+
return join52(env["STELLA_HOME"] ?? join52(home, ".stella"), "stella.toml");
|
|
63049
63802
|
}
|
|
63050
63803
|
}
|
|
63051
63804
|
function stellaJsonPath(env, home) {
|
|
63052
|
-
return
|
|
63805
|
+
return join52(env["STELLA_HOME"] ?? join52(home, ".stella"), "settings.json");
|
|
63053
63806
|
}
|
|
63054
63807
|
function isRecord7(v) {
|
|
63055
63808
|
return v !== null && typeof v === "object" && !Array.isArray(v);
|
|
@@ -63709,7 +64462,7 @@ var init_policy = __esm({
|
|
|
63709
64462
|
// ../../packages/steering-freshness/src/settings.ts
|
|
63710
64463
|
import { readFile as readFile8 } from "node:fs/promises";
|
|
63711
64464
|
import { homedir as homedir11 } from "node:os";
|
|
63712
|
-
import { join as
|
|
64465
|
+
import { join as join53 } from "node:path";
|
|
63713
64466
|
async function readLayer(scope, path2, read2) {
|
|
63714
64467
|
let text5;
|
|
63715
64468
|
try {
|
|
@@ -63761,14 +64514,14 @@ function parseLayer(scope, path2, text5) {
|
|
|
63761
64514
|
}
|
|
63762
64515
|
async function loadSteeringSettings({
|
|
63763
64516
|
projectRoot,
|
|
63764
|
-
userSettingsPath =
|
|
64517
|
+
userSettingsPath = join53(homedir11(), USER_SETTINGS_RELATIVE),
|
|
63765
64518
|
read: read2 = readFile8,
|
|
63766
64519
|
workspacePolicy = null
|
|
63767
64520
|
}) {
|
|
63768
64521
|
const targets = [
|
|
63769
64522
|
["user", userSettingsPath],
|
|
63770
|
-
["project",
|
|
63771
|
-
["local",
|
|
64523
|
+
["project", join53(projectRoot, PROJECT_DIR_NAME, PROJECT_SETTINGS_FILE)],
|
|
64524
|
+
["local", join53(projectRoot, PROJECT_DIR_NAME, LOCAL_SETTINGS_FILE)]
|
|
63772
64525
|
];
|
|
63773
64526
|
const layers = [];
|
|
63774
64527
|
const warnings = [];
|
|
@@ -63831,7 +64584,7 @@ var init_settings = __esm({
|
|
|
63831
64584
|
"use strict";
|
|
63832
64585
|
init_git();
|
|
63833
64586
|
init_policy();
|
|
63834
|
-
USER_SETTINGS_RELATIVE =
|
|
64587
|
+
USER_SETTINGS_RELATIVE = join53(
|
|
63835
64588
|
".config",
|
|
63836
64589
|
"oxagen",
|
|
63837
64590
|
"settings.json"
|
|
@@ -63844,7 +64597,7 @@ var init_settings = __esm({
|
|
|
63844
64597
|
|
|
63845
64598
|
// ../../packages/steering-freshness/src/check.ts
|
|
63846
64599
|
import { lstat as lstat3 } from "node:fs/promises";
|
|
63847
|
-
import { isAbsolute as isAbsolute12, join as
|
|
64600
|
+
import { isAbsolute as isAbsolute12, join as join54, resolve as resolve19 } from "node:path";
|
|
63848
64601
|
function publishedCommits(platform) {
|
|
63849
64602
|
if (platform.headCommits && platform.headCommits.length > 0)
|
|
63850
64603
|
return platform.headCommits;
|
|
@@ -64181,7 +64934,7 @@ async function absentFromDisk(root, paths) {
|
|
|
64181
64934
|
const flags = await Promise.all(
|
|
64182
64935
|
paths.map(async (path2) => {
|
|
64183
64936
|
try {
|
|
64184
|
-
await lstat3(
|
|
64937
|
+
await lstat3(join54(root, path2));
|
|
64185
64938
|
return false;
|
|
64186
64939
|
} catch {
|
|
64187
64940
|
return true;
|
|
@@ -64240,7 +64993,7 @@ var init_check = __esm({
|
|
|
64240
64993
|
// ../../packages/steering-freshness/src/sync.ts
|
|
64241
64994
|
import { mkdtemp, rm as rm3, writeFile as writeFile6 } from "node:fs/promises";
|
|
64242
64995
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
64243
|
-
import { join as
|
|
64996
|
+
import { join as join55 } from "node:path";
|
|
64244
64997
|
function refuse3(refusal, message) {
|
|
64245
64998
|
return {
|
|
64246
64999
|
applied: false,
|
|
@@ -64421,9 +65174,9 @@ async function syncSteering(opts) {
|
|
|
64421
65174
|
};
|
|
64422
65175
|
}
|
|
64423
65176
|
async function commitPaths(ctx, message, paths) {
|
|
64424
|
-
const dir = await mkdtemp(
|
|
65177
|
+
const dir = await mkdtemp(join55(tmpdir2(), "oxagen-steering-sync-"));
|
|
64425
65178
|
try {
|
|
64426
|
-
const list2 =
|
|
65179
|
+
const list2 = join55(dir, "pathspec");
|
|
64427
65180
|
await writeFile6(list2, `${paths.join("\0")}\0`, "utf8");
|
|
64428
65181
|
await git3(
|
|
64429
65182
|
ctx,
|
|
@@ -64951,9 +65704,9 @@ var init_paths2 = __esm({
|
|
|
64951
65704
|
|
|
64952
65705
|
// src/commands/workspace-link.ts
|
|
64953
65706
|
import { existsSync as existsSync26, mkdirSync as mkdirSync9, readFileSync as readFileSync25 } from "node:fs";
|
|
64954
|
-
import { dirname as dirname30, join as
|
|
65707
|
+
import { dirname as dirname30, join as join56 } from "node:path";
|
|
64955
65708
|
function workspaceLinkPath(cwd) {
|
|
64956
|
-
return
|
|
65709
|
+
return join56(cwd, WORKSPACE_LINK_PATH);
|
|
64957
65710
|
}
|
|
64958
65711
|
function isRecord8(value) {
|
|
64959
65712
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -65043,7 +65796,7 @@ __export(steering_exports, {
|
|
|
65043
65796
|
});
|
|
65044
65797
|
import { execFileSync } from "node:child_process";
|
|
65045
65798
|
import { existsSync as existsSync27, realpathSync as realpathSync7 } from "node:fs";
|
|
65046
|
-
import { dirname as dirname31, join as
|
|
65799
|
+
import { dirname as dirname31, join as join57, normalize, parse as parsePath } from "node:path";
|
|
65047
65800
|
function findProjectRoot(start) {
|
|
65048
65801
|
const { root } = parsePath(start);
|
|
65049
65802
|
const rawGitRoot = gitRootOr(start);
|
|
@@ -65052,7 +65805,7 @@ function findProjectRoot(start) {
|
|
|
65052
65805
|
if (gitRoot !== null) return gitRoot;
|
|
65053
65806
|
let dir = from;
|
|
65054
65807
|
for (; ; ) {
|
|
65055
|
-
if (existsSync27(
|
|
65808
|
+
if (existsSync27(join57(dir, PROJECT_DIR_NAME))) return dir;
|
|
65056
65809
|
if (dir === root) return from;
|
|
65057
65810
|
const parent = dirname31(dir);
|
|
65058
65811
|
if (parent === dir) return from;
|
|
@@ -81417,7 +82170,7 @@ function findSecretsAndPii(text5) {
|
|
|
81417
82170
|
const findings = [];
|
|
81418
82171
|
if (/-----BEGIN [A-Z ]*PRIVATE KEY-----/.test(text5))
|
|
81419
82172
|
findings.push("private key block");
|
|
81420
|
-
for (const token of text5.match(
|
|
82173
|
+
for (const token of text5.match(TOKEN2) ?? []) {
|
|
81421
82174
|
if (isSecretToken(token)) {
|
|
81422
82175
|
findings.push("credential token");
|
|
81423
82176
|
break;
|
|
@@ -81444,7 +82197,7 @@ function findSecretsAndPii(text5) {
|
|
|
81444
82197
|
}
|
|
81445
82198
|
return findings;
|
|
81446
82199
|
}
|
|
81447
|
-
var SECRET_PREFIXES, SENSITIVE_KEY_MARKERS,
|
|
82200
|
+
var SECRET_PREFIXES, SENSITIVE_KEY_MARKERS, TOKEN2;
|
|
81448
82201
|
var init_secrets = __esm({
|
|
81449
82202
|
"../../packages/steering-check/src/secrets.ts"() {
|
|
81450
82203
|
"use strict";
|
|
@@ -81495,7 +82248,7 @@ var init_secrets = __esm({
|
|
|
81495
82248
|
"session_id",
|
|
81496
82249
|
"client_secret"
|
|
81497
82250
|
];
|
|
81498
|
-
|
|
82251
|
+
TOKEN2 = /[A-Za-z0-9_\-./+~]+/g;
|
|
81499
82252
|
}
|
|
81500
82253
|
});
|
|
81501
82254
|
|
|
@@ -82443,7 +83196,7 @@ __export(steering_import_exports, {
|
|
|
82443
83196
|
});
|
|
82444
83197
|
import { readdir as readdir4, realpath as realpath2, stat as stat4 } from "node:fs/promises";
|
|
82445
83198
|
import { homedir as homedir12 } from "node:os";
|
|
82446
|
-
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";
|
|
82447
83200
|
function envDir2(env, key) {
|
|
82448
83201
|
const value = env[key];
|
|
82449
83202
|
return value === void 0 || value.trim() === "" ? null : value;
|
|
@@ -82451,34 +83204,34 @@ function envDir2(env, key) {
|
|
|
82451
83204
|
function harnessHome(harness, env = process.env, home = homedir12()) {
|
|
82452
83205
|
switch (harness) {
|
|
82453
83206
|
case "claude-code": {
|
|
82454
|
-
const config = envDir2(env, "CLAUDE_CONFIG_DIR") ??
|
|
83207
|
+
const config = envDir2(env, "CLAUDE_CONFIG_DIR") ?? join58(home, ".claude");
|
|
82455
83208
|
return {
|
|
82456
83209
|
harness,
|
|
82457
83210
|
folders: [
|
|
82458
83211
|
{
|
|
82459
|
-
dir: skillsRoot("claude-code", env, home) ??
|
|
83212
|
+
dir: skillsRoot("claude-code", env, home) ?? join58(config, "skills"),
|
|
82460
83213
|
mount: ".claude/skills"
|
|
82461
83214
|
},
|
|
82462
|
-
{ dir:
|
|
82463
|
-
{ dir:
|
|
83215
|
+
{ dir: join58(config, "commands"), mount: ".claude/commands" },
|
|
83216
|
+
{ dir: join58(config, "agents"), mount: ".claude/agents" }
|
|
82464
83217
|
],
|
|
82465
83218
|
instructions: [
|
|
82466
|
-
{ file:
|
|
83219
|
+
{ file: join58(config, "CLAUDE.md"), filename: ".claude/CLAUDE.md" }
|
|
82467
83220
|
]
|
|
82468
83221
|
};
|
|
82469
83222
|
}
|
|
82470
83223
|
case "codex": {
|
|
82471
|
-
const codexHome = envDir2(env, "CODEX_HOME") ??
|
|
83224
|
+
const codexHome = envDir2(env, "CODEX_HOME") ?? join58(home, ".codex");
|
|
82472
83225
|
return {
|
|
82473
83226
|
harness,
|
|
82474
83227
|
folders: [
|
|
82475
83228
|
{
|
|
82476
|
-
dir: skillsRoot("codex", env, home) ??
|
|
83229
|
+
dir: skillsRoot("codex", env, home) ?? join58(home, ".agents", "skills"),
|
|
82477
83230
|
mount: ".agents/skills"
|
|
82478
83231
|
}
|
|
82479
83232
|
],
|
|
82480
83233
|
instructions: ["AGENTS.override.md", "AGENTS.md"].map((name) => ({
|
|
82481
|
-
file:
|
|
83234
|
+
file: join58(codexHome, name),
|
|
82482
83235
|
filename: `.codex/${name}`
|
|
82483
83236
|
}))
|
|
82484
83237
|
};
|
|
@@ -82487,8 +83240,8 @@ function harnessHome(harness, env = process.env, home = homedir12()) {
|
|
|
82487
83240
|
return {
|
|
82488
83241
|
harness,
|
|
82489
83242
|
folders: [
|
|
82490
|
-
{ dir:
|
|
82491
|
-
{ dir:
|
|
83243
|
+
{ dir: join58(home, ".cursor", "skills"), mount: ".cursor/skills" },
|
|
83244
|
+
{ dir: join58(home, ".cursor", "commands"), mount: ".cursor/commands" }
|
|
82492
83245
|
],
|
|
82493
83246
|
instructions: []
|
|
82494
83247
|
};
|
|
@@ -82534,7 +83287,7 @@ async function findMarkdownFiles(paths, harness) {
|
|
|
82534
83287
|
}
|
|
82535
83288
|
const found = [];
|
|
82536
83289
|
for (const entry2 of entries2.sort(byName)) {
|
|
82537
|
-
const path2 =
|
|
83290
|
+
const path2 = join58(dir, entry2.name);
|
|
82538
83291
|
if (entry2.isDirectory()) {
|
|
82539
83292
|
if (!entry2.name.startsWith(".") && entry2.name !== "node_modules")
|
|
82540
83293
|
found.push(...await filesUnder(path2, from));
|
|
@@ -82556,7 +83309,7 @@ async function findMarkdownFiles(paths, harness) {
|
|
|
82556
83309
|
const { folder } = frame;
|
|
82557
83310
|
const named = (rel) => frame.fixedNames ? { filename: rel } : {};
|
|
82558
83311
|
for (const entry2 of entries2) {
|
|
82559
|
-
const path2 =
|
|
83312
|
+
const path2 = join58(dir, entry2.name);
|
|
82560
83313
|
const rel = frame.relOf(path2);
|
|
82561
83314
|
if (entry2.isDirectory()) {
|
|
82562
83315
|
if (entry2.name === "node_modules") continue;
|
|
@@ -82615,7 +83368,7 @@ async function findMarkdownFiles(paths, harness) {
|
|
|
82615
83368
|
}
|
|
82616
83369
|
if (folderGiven) {
|
|
82617
83370
|
const catalogue = CATALOGUE_FOLDERS.has(basename8(path2));
|
|
82618
|
-
const root = catalogue ?
|
|
83371
|
+
const root = catalogue ? join58(path2, "..") : path2;
|
|
82619
83372
|
await walk2(path2, {
|
|
82620
83373
|
relOf: (p) => under(root, p),
|
|
82621
83374
|
folder: path2,
|
|
@@ -84275,10 +85028,10 @@ __export(verify_exports, {
|
|
|
84275
85028
|
verifyBundle: () => verifyBundle3
|
|
84276
85029
|
});
|
|
84277
85030
|
import { existsSync as existsSync28, readFileSync as readFileSync26, statSync as statSync15 } from "node:fs";
|
|
84278
|
-
import { join as
|
|
85031
|
+
import { join as join59 } from "node:path";
|
|
84279
85032
|
function readDirectory(dir) {
|
|
84280
85033
|
const read2 = (name) => {
|
|
84281
|
-
const path2 =
|
|
85034
|
+
const path2 = join59(dir, name);
|
|
84282
85035
|
return existsSync28(path2) ? readFileSync26(path2, "utf8") : void 0;
|
|
84283
85036
|
};
|
|
84284
85037
|
return assemble(read2, dir);
|
|
@@ -85233,7 +85986,7 @@ var init_conversation = __esm({
|
|
|
85233
85986
|
});
|
|
85234
85987
|
|
|
85235
85988
|
// src/auth/open-browser.ts
|
|
85236
|
-
import { spawn as
|
|
85989
|
+
import { spawn as spawn8 } from "node:child_process";
|
|
85237
85990
|
function openBrowser(url) {
|
|
85238
85991
|
try {
|
|
85239
85992
|
let cmd;
|
|
@@ -85251,7 +86004,7 @@ function openBrowser(url) {
|
|
|
85251
86004
|
cmd = "xdg-open";
|
|
85252
86005
|
args = [url];
|
|
85253
86006
|
}
|
|
85254
|
-
const child =
|
|
86007
|
+
const child = spawn8(cmd, args, { detached: true, stdio: "ignore" });
|
|
85255
86008
|
child.on("error", () => {
|
|
85256
86009
|
});
|
|
85257
86010
|
child.unref();
|
|
@@ -85407,7 +86160,7 @@ import {
|
|
|
85407
86160
|
writeFileSync as writeFileSync7
|
|
85408
86161
|
} from "node:fs";
|
|
85409
86162
|
import { homedir as homedir13, hostname as osHostname3 } from "node:os";
|
|
85410
|
-
import { join as
|
|
86163
|
+
import { join as join60, relative as relative8, resolve as resolve22, sep as sep10 } from "node:path";
|
|
85411
86164
|
function git4(cwd, args) {
|
|
85412
86165
|
return new Promise((done) => {
|
|
85413
86166
|
try {
|
|
@@ -85454,7 +86207,7 @@ function parseRemoteRepository(url) {
|
|
|
85454
86207
|
}
|
|
85455
86208
|
function oxagenPresent(root) {
|
|
85456
86209
|
try {
|
|
85457
|
-
return readdirSync14(
|
|
86210
|
+
return readdirSync14(join60(root, ".oxagen")).some(
|
|
85458
86211
|
(name) => name !== "workspace.json"
|
|
85459
86212
|
);
|
|
85460
86213
|
} catch {
|
|
@@ -85463,18 +86216,18 @@ function oxagenPresent(root) {
|
|
|
85463
86216
|
}
|
|
85464
86217
|
function symlinkState(root) {
|
|
85465
86218
|
try {
|
|
85466
|
-
if (!lstatSync10(
|
|
86219
|
+
if (!lstatSync10(join60(root, ".stella")).isDirectory()) return "none";
|
|
85467
86220
|
} catch {
|
|
85468
86221
|
return "none";
|
|
85469
86222
|
}
|
|
85470
86223
|
let oxagenReal;
|
|
85471
86224
|
try {
|
|
85472
|
-
oxagenReal = realpathSync8(
|
|
86225
|
+
oxagenReal = realpathSync8(join60(root, ".oxagen"));
|
|
85473
86226
|
} catch {
|
|
85474
86227
|
return "missing";
|
|
85475
86228
|
}
|
|
85476
86229
|
for (const link of STELLA_LINKS) {
|
|
85477
|
-
const at2 =
|
|
86230
|
+
const at2 = join60(root, link);
|
|
85478
86231
|
try {
|
|
85479
86232
|
if (!lstatSync10(at2).isSymbolicLink()) return "missing";
|
|
85480
86233
|
const target2 = realpathSync8(at2);
|
|
@@ -85488,7 +86241,7 @@ function symlinkState(root) {
|
|
|
85488
86241
|
return "linked";
|
|
85489
86242
|
}
|
|
85490
86243
|
function machineId(configDir = getConfigDir()) {
|
|
85491
|
-
const file =
|
|
86244
|
+
const file = join60(configDir, MACHINE_ID_FILE);
|
|
85492
86245
|
let secret = null;
|
|
85493
86246
|
try {
|
|
85494
86247
|
if (existsSync29(file)) {
|
|
@@ -85570,12 +86323,12 @@ async function ensureWorkspaceLinkIgnored(root) {
|
|
|
85570
86323
|
const topDir = resolve22(top);
|
|
85571
86324
|
const entry2 = relative8(
|
|
85572
86325
|
topDir,
|
|
85573
|
-
|
|
86326
|
+
join60(realpathOr2(root), ".oxagen", "workspace.json")
|
|
85574
86327
|
).split(sep10).join("/");
|
|
85575
86328
|
if (entry2.startsWith("../")) return null;
|
|
85576
86329
|
const rule = await git4(topDir, ["check-ignore", "--no-index", "-v", entry2]);
|
|
85577
86330
|
if (rule !== null) return null;
|
|
85578
|
-
const gitignore =
|
|
86331
|
+
const gitignore = join60(resolve22(top), ".gitignore");
|
|
85579
86332
|
let existing = "";
|
|
85580
86333
|
try {
|
|
85581
86334
|
existing = readFileSync27(gitignore, "utf8");
|
|
@@ -86100,7 +86853,7 @@ import {
|
|
|
86100
86853
|
import {
|
|
86101
86854
|
dirname as dirname33,
|
|
86102
86855
|
isAbsolute as isAbsolute14,
|
|
86103
|
-
join as
|
|
86856
|
+
join as join61,
|
|
86104
86857
|
parse as parsePath2,
|
|
86105
86858
|
posix as posix4,
|
|
86106
86859
|
sep as sep11
|
|
@@ -86220,7 +86973,7 @@ function findLinkedRoot(start) {
|
|
|
86220
86973
|
}
|
|
86221
86974
|
function fsReader(root) {
|
|
86222
86975
|
return (path2) => {
|
|
86223
|
-
const abs =
|
|
86976
|
+
const abs = join61(root, ...path2.split("/"));
|
|
86224
86977
|
try {
|
|
86225
86978
|
const st = lstatSync11(abs);
|
|
86226
86979
|
if (!st.isFile()) return Buffer.from(`\0not-a-file:${abs}`);
|
|
@@ -86231,14 +86984,14 @@ function fsReader(root) {
|
|
|
86231
86984
|
};
|
|
86232
86985
|
}
|
|
86233
86986
|
function assertInsideOxagen(root, path2) {
|
|
86234
|
-
const oxagenAbs =
|
|
86987
|
+
const oxagenAbs = join61(root, OXAGEN_DIR);
|
|
86235
86988
|
let oxagenReal;
|
|
86236
86989
|
try {
|
|
86237
86990
|
oxagenReal = realpathSync9(oxagenAbs);
|
|
86238
86991
|
} catch {
|
|
86239
86992
|
return;
|
|
86240
86993
|
}
|
|
86241
|
-
const abs =
|
|
86994
|
+
const abs = join61(root, ...path2.split("/"));
|
|
86242
86995
|
try {
|
|
86243
86996
|
if (lstatSync11(abs).isSymbolicLink()) {
|
|
86244
86997
|
throw new Error(
|
|
@@ -86268,8 +87021,8 @@ function assertInsideOxagen(root, path2) {
|
|
|
86268
87021
|
}
|
|
86269
87022
|
}
|
|
86270
87023
|
function pruneEmptyDirs(root, path2) {
|
|
86271
|
-
const stop =
|
|
86272
|
-
let dir = dirname33(
|
|
87024
|
+
const stop = join61(root, OXAGEN_DIR);
|
|
87025
|
+
let dir = dirname33(join61(root, ...path2.split("/")));
|
|
86273
87026
|
while (dir.startsWith(stop + sep11)) {
|
|
86274
87027
|
try {
|
|
86275
87028
|
if (readdirSync15(dir).length > 0) return;
|
|
@@ -86284,12 +87037,12 @@ function applyPlan(root, plan) {
|
|
|
86284
87037
|
for (const w of plan.writes) assertInsideOxagen(root, w.path);
|
|
86285
87038
|
for (const d of plan.deletes) assertInsideOxagen(root, d);
|
|
86286
87039
|
for (const w of plan.writes) {
|
|
86287
|
-
const abs =
|
|
87040
|
+
const abs = join61(root, ...w.path.split("/"));
|
|
86288
87041
|
mkdirSync11(dirname33(abs), { recursive: true });
|
|
86289
87042
|
atomicWriteFileSync(abs, w.content);
|
|
86290
87043
|
}
|
|
86291
87044
|
for (const d of plan.deletes) {
|
|
86292
|
-
rmSync10(
|
|
87045
|
+
rmSync10(join61(root, ...d.split("/")), { force: true });
|
|
86293
87046
|
pruneEmptyDirs(root, d);
|
|
86294
87047
|
}
|
|
86295
87048
|
}
|
|
@@ -108252,7 +109005,7 @@ function invalidArguments(message) {
|
|
|
108252
109005
|
return new BuildError("Invalid arguments", message);
|
|
108253
109006
|
}
|
|
108254
109007
|
function checkedName(parameter) {
|
|
108255
|
-
if (!
|
|
109008
|
+
if (!TOKEN3.test(parameter.name)) {
|
|
108256
109009
|
throw new BuildError(
|
|
108257
109010
|
"Invalid request",
|
|
108258
109011
|
`The ${parameter.in} parameter name ${parameter.name} is not an HTTP token.`
|
|
@@ -108334,7 +109087,7 @@ function cookiePairs(parameter, value) {
|
|
|
108334
109087
|
]
|
|
108335
109088
|
] : shape.kind === "list" ? shape.items.map((item) => [name, item]) : shape.entries;
|
|
108336
109089
|
for (const [cookie, text5] of pairs) {
|
|
108337
|
-
if (!
|
|
109090
|
+
if (!TOKEN3.test(cookie)) {
|
|
108338
109091
|
throw invalidArguments(
|
|
108339
109092
|
`The cookie ${parameter.name} holds a key that is not an HTTP token, so no cookie can take it as a name.`
|
|
108340
109093
|
);
|
|
@@ -108377,12 +109130,12 @@ function queryEntries(parameter, value) {
|
|
|
108377
109130
|
}
|
|
108378
109131
|
if (shape.items.length === 0) return [];
|
|
108379
109132
|
if (explode) return shape.items.map((item) => pair(name, item));
|
|
108380
|
-
const [raw,
|
|
109133
|
+
const [raw, delimiter3] = style === "form" ? [",", ","] : style === "spaceDelimited" ? [" ", "%20"] : ["|", "|"];
|
|
108381
109134
|
return [
|
|
108382
109135
|
entry(
|
|
108383
109136
|
name,
|
|
108384
109137
|
shape.items.join(raw),
|
|
108385
|
-
`${enc(name)}=${shape.items.map(val).join(
|
|
109138
|
+
`${enc(name)}=${shape.items.map(val).join(delimiter3)}`
|
|
108386
109139
|
)
|
|
108387
109140
|
];
|
|
108388
109141
|
}
|
|
@@ -108599,7 +109352,7 @@ function createHttpSender(options = {}) {
|
|
|
108599
109352
|
}
|
|
108600
109353
|
};
|
|
108601
109354
|
}
|
|
108602
|
-
var IDEMPOTENT_METHODS, RESERVED_HEADERS,
|
|
109355
|
+
var IDEMPOTENT_METHODS, RESERVED_HEADERS, TOKEN3, UNSAFE_HEADER_VALUE, UNSAFE_COOKIE_VALUE;
|
|
108603
109356
|
var init_http = __esm({
|
|
108604
109357
|
"../../packages/mcp-studio/src/execute/http.ts"() {
|
|
108605
109358
|
"use strict";
|
|
@@ -108627,7 +109380,7 @@ var init_http = __esm({
|
|
|
108627
109380
|
"proxy-authorization",
|
|
108628
109381
|
"cookie"
|
|
108629
109382
|
]);
|
|
108630
|
-
|
|
109383
|
+
TOKEN3 = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
|
|
108631
109384
|
UNSAFE_HEADER_VALUE = /[\r\n\0]/;
|
|
108632
109385
|
UNSAFE_COOKIE_VALUE = /[;\r\n\0]/;
|
|
108633
109386
|
}
|
|
@@ -130164,7 +130917,7 @@ import {
|
|
|
130164
130917
|
readlinkSync as readlinkSync4,
|
|
130165
130918
|
statSync as statSync16
|
|
130166
130919
|
} from "node:fs";
|
|
130167
|
-
import { dirname as dirname34, isAbsolute as isAbsolute15, join as
|
|
130920
|
+
import { dirname as dirname34, isAbsolute as isAbsolute15, join as join62, relative as relative9, resolve as resolve24, sep as sep12 } from "node:path";
|
|
130168
130921
|
function git5(cwd, args, input) {
|
|
130169
130922
|
try {
|
|
130170
130923
|
return execFileSync2("git", args, {
|
|
@@ -130196,7 +130949,7 @@ function commitOf2(root, ref2) {
|
|
|
130196
130949
|
return sha2.length > 0 ? sha2 : null;
|
|
130197
130950
|
}
|
|
130198
130951
|
function readWorkingFile(root, path2) {
|
|
130199
|
-
const abs =
|
|
130952
|
+
const abs = join62(root, ...path2.split("/"));
|
|
130200
130953
|
try {
|
|
130201
130954
|
const stat7 = lstatSync12(abs);
|
|
130202
130955
|
if (stat7.isSymbolicLink()) return readlinkSync4(abs, "utf8");
|
|
@@ -130290,7 +131043,7 @@ function isDir(path2) {
|
|
|
130290
131043
|
function findSteeringRoot(start) {
|
|
130291
131044
|
let dir = resolve24(start);
|
|
130292
131045
|
for (; ; ) {
|
|
130293
|
-
if (isFile(
|
|
131046
|
+
if (isFile(join62(dir, WORKSPACE_TOML_PATH)) || isFile(join62(dir, AGENTS_MD_PATH)) && isDir(join62(dir, STEERING_DIR))) {
|
|
130294
131047
|
return dir;
|
|
130295
131048
|
}
|
|
130296
131049
|
const parent = dirname34(dir);
|
|
@@ -130370,7 +131123,7 @@ function cacheFile(cacheDir, root) {
|
|
|
130370
131123
|
key: token === void 0 ? null : createHash20("sha256").update(token).digest("hex").slice(0, 16)
|
|
130371
131124
|
};
|
|
130372
131125
|
const key = createHash20("sha256").update(JSON.stringify([root, identity])).digest("hex").slice(0, 32);
|
|
130373
|
-
return
|
|
131126
|
+
return join62(cacheDir, `${key}.json`);
|
|
130374
131127
|
}
|
|
130375
131128
|
function readCache(file, now) {
|
|
130376
131129
|
let entry2;
|
|
@@ -130484,7 +131237,7 @@ function defaultDeps2() {
|
|
|
130484
131237
|
return {
|
|
130485
131238
|
fetchPublished: fetchSteeringIndex,
|
|
130486
131239
|
cedar: cedarHooks,
|
|
130487
|
-
cacheDir:
|
|
131240
|
+
cacheDir: join62(getConfigDir(), "cache", "steering-check"),
|
|
130488
131241
|
now: () => Date.now()
|
|
130489
131242
|
};
|
|
130490
131243
|
}
|
|
@@ -134367,7 +135120,7 @@ var init_src9 = __esm({
|
|
|
134367
135120
|
|
|
134368
135121
|
// src/commands/codegraph-upload/files.ts
|
|
134369
135122
|
import { readdir as readdir5, stat as stat5 } from "node:fs/promises";
|
|
134370
|
-
import { join as
|
|
135123
|
+
import { join as join63, relative as relative10, sep as sep13 } from "node:path";
|
|
134371
135124
|
function hasGlobChars(pattern) {
|
|
134372
135125
|
return /[*?[\]{}]/.test(pattern);
|
|
134373
135126
|
}
|
|
@@ -134379,7 +135132,7 @@ async function walk(root, dir, out) {
|
|
|
134379
135132
|
const entries2 = await readdir5(dir, { withFileTypes: true });
|
|
134380
135133
|
for (const entry2 of entries2) {
|
|
134381
135134
|
if (entry2.isSymbolicLink()) continue;
|
|
134382
|
-
const full =
|
|
135135
|
+
const full = join63(dir, entry2.name);
|
|
134383
135136
|
if (entry2.isDirectory()) {
|
|
134384
135137
|
if (!SKIP_DIRS.has(entry2.name)) await walk(root, full, out);
|
|
134385
135138
|
} else if (entry2.isFile()) {
|
|
@@ -134391,7 +135144,7 @@ async function expandPattern(root, pattern) {
|
|
|
134391
135144
|
const wanted = normalize2(pattern.trim());
|
|
134392
135145
|
if (!hasGlobChars(wanted)) {
|
|
134393
135146
|
try {
|
|
134394
|
-
const info = await stat5(
|
|
135147
|
+
const info = await stat5(join63(root, wanted));
|
|
134395
135148
|
return info.isFile() ? [wanted] : [];
|
|
134396
135149
|
} catch {
|
|
134397
135150
|
return [];
|
|
@@ -134542,7 +135295,7 @@ var init_token = __esm({
|
|
|
134542
135295
|
});
|
|
134543
135296
|
|
|
134544
135297
|
// src/commands/codegraph-upload/run.ts
|
|
134545
|
-
import { join as
|
|
135298
|
+
import { join as join64 } from "node:path";
|
|
134546
135299
|
function addDropped(into, more) {
|
|
134547
135300
|
into.sensitiveValues += more.sensitiveValues;
|
|
134548
135301
|
into.secretData += more.secretData;
|
|
@@ -134560,7 +135313,7 @@ async function uploadOne(deps, config, token, group, path2, totals2) {
|
|
|
134560
135313
|
const label2 = `${group.kind}/${group.source} ${path2}`;
|
|
134561
135314
|
let bytes;
|
|
134562
135315
|
try {
|
|
134563
|
-
bytes = await deps.readFile(
|
|
135316
|
+
bytes = await deps.readFile(join64(deps.cwd, path2));
|
|
134564
135317
|
} catch (error) {
|
|
134565
135318
|
totals2.failed += 1;
|
|
134566
135319
|
deps.log(`error: ${label2}: cannot read the file: ${error.message}`);
|