@archal/cli 0.9.5 → 0.9.7
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/LICENSE +8 -0
- package/dist/index.cjs +1260 -370
- package/package.json +25 -26
package/dist/index.cjs
CHANGED
|
@@ -4092,15 +4092,15 @@ var init_parseUtil = __esm({
|
|
|
4092
4092
|
message: issueData.message
|
|
4093
4093
|
};
|
|
4094
4094
|
}
|
|
4095
|
-
let
|
|
4095
|
+
let errorMessage3 = "";
|
|
4096
4096
|
const maps = errorMaps.filter((m) => !!m).slice().reverse();
|
|
4097
4097
|
for (const map2 of maps) {
|
|
4098
|
-
|
|
4098
|
+
errorMessage3 = map2(fullIssue, { data, defaultError: errorMessage3 }).message;
|
|
4099
4099
|
}
|
|
4100
4100
|
return {
|
|
4101
4101
|
...issueData,
|
|
4102
4102
|
path: fullPath,
|
|
4103
|
-
message:
|
|
4103
|
+
message: errorMessage3
|
|
4104
4104
|
};
|
|
4105
4105
|
};
|
|
4106
4106
|
ParseStatus = class _ParseStatus {
|
|
@@ -31300,12 +31300,902 @@ var init_dist2 = __esm({
|
|
|
31300
31300
|
}
|
|
31301
31301
|
});
|
|
31302
31302
|
|
|
31303
|
+
// ../packages/node-auth/dist/index.js
|
|
31304
|
+
function isPlan(value) {
|
|
31305
|
+
return value === "free" || value === "pro" || value === "enterprise";
|
|
31306
|
+
}
|
|
31307
|
+
function errorMessage2(error49) {
|
|
31308
|
+
return error49 instanceof Error ? error49.message : String(error49);
|
|
31309
|
+
}
|
|
31310
|
+
function debug(message) {
|
|
31311
|
+
if (process.env["ARCHAL_DEBUG"] !== "1") {
|
|
31312
|
+
return;
|
|
31313
|
+
}
|
|
31314
|
+
process.stderr.write(`[archal-node-auth] ${message}
|
|
31315
|
+
`);
|
|
31316
|
+
}
|
|
31317
|
+
function getWarn(options) {
|
|
31318
|
+
return options?.warn ?? console.warn;
|
|
31319
|
+
}
|
|
31320
|
+
function isExpired(expiresAt) {
|
|
31321
|
+
return expiresAt <= Math.floor(Date.now() / 1e3);
|
|
31322
|
+
}
|
|
31323
|
+
function isRunningUnderTests() {
|
|
31324
|
+
return process.env["VITEST"] === "true" || process.env["VITEST_WORKER_ID"] !== void 0 || process.env["JEST_WORKER_ID"] !== void 0 || process.env["NODE_TEST_CONTEXT"] !== void 0;
|
|
31325
|
+
}
|
|
31326
|
+
function getRealArchalDir() {
|
|
31327
|
+
return (0, import_path.join)((0, import_os.homedir)(), ARCHAL_DIR_NAME);
|
|
31328
|
+
}
|
|
31329
|
+
function getTestSandboxDir() {
|
|
31330
|
+
const workerId = process.env["VITEST_WORKER_ID"] ?? process.env["JEST_WORKER_ID"] ?? String(process.pid);
|
|
31331
|
+
return (0, import_path.join)((0, import_os.tmpdir)(), `archal-test-sandbox-${workerId}`);
|
|
31332
|
+
}
|
|
31333
|
+
function seedSandboxFromRealHomeOnce(sandboxDir) {
|
|
31334
|
+
try {
|
|
31335
|
+
if (seededSandboxes.has(sandboxDir)) {
|
|
31336
|
+
const credsIntact = (0, import_fs.existsSync)((0, import_path.join)(sandboxDir, CREDENTIALS_FILE));
|
|
31337
|
+
if (credsIntact) return;
|
|
31338
|
+
seededSandboxes.delete(sandboxDir);
|
|
31339
|
+
}
|
|
31340
|
+
const realDir = getRealArchalDir();
|
|
31341
|
+
if (!(0, import_fs.existsSync)(realDir)) {
|
|
31342
|
+
seededSandboxes.add(sandboxDir);
|
|
31343
|
+
return;
|
|
31344
|
+
}
|
|
31345
|
+
if (!(0, import_fs.existsSync)(sandboxDir)) {
|
|
31346
|
+
(0, import_fs.mkdirSync)(sandboxDir, { recursive: true, mode: 448 });
|
|
31347
|
+
}
|
|
31348
|
+
for (const filename of [CREDENTIALS_FILE, CREDENTIALS_KEY_FILE]) {
|
|
31349
|
+
const realPath = (0, import_path.join)(realDir, filename);
|
|
31350
|
+
const sandboxPath = (0, import_path.join)(sandboxDir, filename);
|
|
31351
|
+
if (!(0, import_fs.existsSync)(realPath) || (0, import_fs.existsSync)(sandboxPath)) continue;
|
|
31352
|
+
const contents = (0, import_fs.readFileSync)(realPath);
|
|
31353
|
+
(0, import_fs.writeFileSync)(sandboxPath, contents, { mode: 384 });
|
|
31354
|
+
try {
|
|
31355
|
+
(0, import_fs.chmodSync)(sandboxPath, 384);
|
|
31356
|
+
} catch {
|
|
31357
|
+
}
|
|
31358
|
+
}
|
|
31359
|
+
seededSandboxes.add(sandboxDir);
|
|
31360
|
+
} catch (err) {
|
|
31361
|
+
debug(`Sandbox seed skipped: ${errorMessage2(err)}`);
|
|
31362
|
+
}
|
|
31363
|
+
}
|
|
31364
|
+
function getArchalDir() {
|
|
31365
|
+
const explicit = process.env["ARCHAL_HOME"];
|
|
31366
|
+
if (explicit) {
|
|
31367
|
+
return explicit;
|
|
31368
|
+
}
|
|
31369
|
+
if (isRunningUnderTests()) {
|
|
31370
|
+
const sandbox = getTestSandboxDir();
|
|
31371
|
+
seedSandboxFromRealHomeOnce(sandbox);
|
|
31372
|
+
return sandbox;
|
|
31373
|
+
}
|
|
31374
|
+
return getRealArchalDir();
|
|
31375
|
+
}
|
|
31376
|
+
function ensureArchalDir() {
|
|
31377
|
+
const dir = getArchalDir();
|
|
31378
|
+
if (!(0, import_fs.existsSync)(dir)) {
|
|
31379
|
+
(0, import_fs.mkdirSync)(dir, { recursive: true });
|
|
31380
|
+
debug(`Created archal directory at ${dir}`);
|
|
31381
|
+
}
|
|
31382
|
+
return dir;
|
|
31383
|
+
}
|
|
31384
|
+
function getCredentialsPath() {
|
|
31385
|
+
return (0, import_path.join)(ensureArchalDir(), CREDENTIALS_FILE);
|
|
31386
|
+
}
|
|
31387
|
+
function getCredentialsKeyPath() {
|
|
31388
|
+
return (0, import_path.join)(ensureArchalDir(), CREDENTIALS_KEY_FILE);
|
|
31389
|
+
}
|
|
31390
|
+
function readCredentialsKeyFromEnv() {
|
|
31391
|
+
const raw = process.env[CREDENTIALS_MASTER_KEY_ENV_VAR]?.trim();
|
|
31392
|
+
if (!raw) {
|
|
31393
|
+
return null;
|
|
31394
|
+
}
|
|
31395
|
+
if (/^[a-fA-F0-9]{64}$/.test(raw)) {
|
|
31396
|
+
return Buffer.from(raw, "hex");
|
|
31397
|
+
}
|
|
31398
|
+
try {
|
|
31399
|
+
const decoded = Buffer.from(raw, "base64");
|
|
31400
|
+
if (decoded.length === 32) {
|
|
31401
|
+
return decoded;
|
|
31402
|
+
}
|
|
31403
|
+
} catch (err) {
|
|
31404
|
+
debug(`Base64 master key decode failed: ${errorMessage2(err)}`);
|
|
31405
|
+
}
|
|
31406
|
+
return (0, import_crypto2.createHash)("sha256").update(raw, "utf8").digest();
|
|
31407
|
+
}
|
|
31408
|
+
function readCredentialsKeyFromMacKeychain() {
|
|
31409
|
+
if (process.platform !== "darwin") return null;
|
|
31410
|
+
try {
|
|
31411
|
+
const result = (0, import_child_process.spawnSync)(
|
|
31412
|
+
"security",
|
|
31413
|
+
["find-generic-password", "-s", KEYCHAIN_SERVICE, "-a", KEYCHAIN_ACCOUNT, "-w"],
|
|
31414
|
+
{ encoding: "utf-8", timeout: KEYCHAIN_COMMAND_TIMEOUT_MS }
|
|
31415
|
+
);
|
|
31416
|
+
if (!result || result.error || result.status !== 0 || typeof result.stdout !== "string" || result.stdout.length === 0) {
|
|
31417
|
+
if (result?.error) {
|
|
31418
|
+
debug(`Keychain lookup failed: ${result.error.message}`);
|
|
31419
|
+
}
|
|
31420
|
+
return null;
|
|
31421
|
+
}
|
|
31422
|
+
const raw = result.stdout.trim();
|
|
31423
|
+
if (!/^[a-fA-F0-9]{64}$/.test(raw)) {
|
|
31424
|
+
return null;
|
|
31425
|
+
}
|
|
31426
|
+
return Buffer.from(raw, "hex");
|
|
31427
|
+
} catch (err) {
|
|
31428
|
+
debug(`Keychain lookup threw: ${errorMessage2(err)}`);
|
|
31429
|
+
return null;
|
|
31430
|
+
}
|
|
31431
|
+
}
|
|
31432
|
+
function readCredentialsKeyFromFile() {
|
|
31433
|
+
const keyPath = getCredentialsKeyPath();
|
|
31434
|
+
if (!(0, import_fs.existsSync)(keyPath)) {
|
|
31435
|
+
return null;
|
|
31436
|
+
}
|
|
31437
|
+
try {
|
|
31438
|
+
const raw = (0, import_fs.readFileSync)(keyPath, "utf-8").trim();
|
|
31439
|
+
const key = Buffer.from(raw, "hex");
|
|
31440
|
+
if (key.length === 32) {
|
|
31441
|
+
return key;
|
|
31442
|
+
}
|
|
31443
|
+
} catch (err) {
|
|
31444
|
+
debug(`Failed to read credentials key file: ${errorMessage2(err)}`);
|
|
31445
|
+
}
|
|
31446
|
+
return null;
|
|
31447
|
+
}
|
|
31448
|
+
function collectCredentialKeysForDecrypt() {
|
|
31449
|
+
const keys = [];
|
|
31450
|
+
for (const candidate of [
|
|
31451
|
+
readCredentialsKeyFromEnv(),
|
|
31452
|
+
readCredentialsKeyFromMacKeychain(),
|
|
31453
|
+
readCredentialsKeyFromFile()
|
|
31454
|
+
]) {
|
|
31455
|
+
if (!candidate) continue;
|
|
31456
|
+
if (!keys.some((entry) => entry.equals(candidate))) {
|
|
31457
|
+
keys.push(candidate);
|
|
31458
|
+
}
|
|
31459
|
+
}
|
|
31460
|
+
return keys;
|
|
31461
|
+
}
|
|
31462
|
+
function writeCredentialsKeyToMacKeychain(key) {
|
|
31463
|
+
if (process.platform !== "darwin") return false;
|
|
31464
|
+
try {
|
|
31465
|
+
const result = (0, import_child_process.spawnSync)(
|
|
31466
|
+
"security",
|
|
31467
|
+
[
|
|
31468
|
+
"add-generic-password",
|
|
31469
|
+
"-U",
|
|
31470
|
+
"-s",
|
|
31471
|
+
KEYCHAIN_SERVICE,
|
|
31472
|
+
"-a",
|
|
31473
|
+
KEYCHAIN_ACCOUNT,
|
|
31474
|
+
"-w",
|
|
31475
|
+
key.toString("hex")
|
|
31476
|
+
],
|
|
31477
|
+
{ encoding: "utf-8", timeout: KEYCHAIN_COMMAND_TIMEOUT_MS }
|
|
31478
|
+
);
|
|
31479
|
+
if (result?.error) {
|
|
31480
|
+
debug(`Keychain write failed: ${result.error.message}`);
|
|
31481
|
+
}
|
|
31482
|
+
return !!result && !result.error && result.status === 0;
|
|
31483
|
+
} catch (err) {
|
|
31484
|
+
debug(`Keychain write threw: ${errorMessage2(err)}`);
|
|
31485
|
+
return false;
|
|
31486
|
+
}
|
|
31487
|
+
}
|
|
31488
|
+
function getOrCreateCredentialsKey() {
|
|
31489
|
+
const envKey = readCredentialsKeyFromEnv();
|
|
31490
|
+
if (envKey) {
|
|
31491
|
+
return envKey;
|
|
31492
|
+
}
|
|
31493
|
+
const keychainKey = readCredentialsKeyFromMacKeychain();
|
|
31494
|
+
if (keychainKey) {
|
|
31495
|
+
return keychainKey;
|
|
31496
|
+
}
|
|
31497
|
+
const fileKey = readCredentialsKeyFromFile();
|
|
31498
|
+
if (fileKey) {
|
|
31499
|
+
if (writeCredentialsKeyToMacKeychain(fileKey)) {
|
|
31500
|
+
try {
|
|
31501
|
+
(0, import_fs.unlinkSync)(getCredentialsKeyPath());
|
|
31502
|
+
} catch {
|
|
31503
|
+
}
|
|
31504
|
+
}
|
|
31505
|
+
return fileKey;
|
|
31506
|
+
}
|
|
31507
|
+
const generated = (0, import_crypto2.randomBytes)(32);
|
|
31508
|
+
if (!writeCredentialsKeyToMacKeychain(generated)) {
|
|
31509
|
+
(0, import_fs.writeFileSync)(getCredentialsKeyPath(), `${generated.toString("hex")}
|
|
31510
|
+
`, {
|
|
31511
|
+
encoding: "utf-8",
|
|
31512
|
+
mode: 384
|
|
31513
|
+
});
|
|
31514
|
+
}
|
|
31515
|
+
return generated;
|
|
31516
|
+
}
|
|
31517
|
+
function encryptToken(token) {
|
|
31518
|
+
const key = getOrCreateCredentialsKey();
|
|
31519
|
+
const iv = (0, import_crypto2.randomBytes)(12);
|
|
31520
|
+
const cipher = (0, import_crypto2.createCipheriv)("aes-256-gcm", key, iv);
|
|
31521
|
+
const encrypted = Buffer.concat([cipher.update(token, "utf-8"), cipher.final()]);
|
|
31522
|
+
return `${TOKEN_ENCRYPTION_PREFIX}:${iv.toString("hex")}:${cipher.getAuthTag().toString("hex")}:${encrypted.toString("hex")}`;
|
|
31523
|
+
}
|
|
31524
|
+
function decryptToken(ciphertext) {
|
|
31525
|
+
const parts = ciphertext.split(":");
|
|
31526
|
+
if (parts.length !== 4 || parts[0] !== TOKEN_ENCRYPTION_PREFIX) {
|
|
31527
|
+
return null;
|
|
31528
|
+
}
|
|
31529
|
+
const [, ivHex, tagHex, dataHex] = parts;
|
|
31530
|
+
if (!ivHex || !tagHex || !dataHex) {
|
|
31531
|
+
return null;
|
|
31532
|
+
}
|
|
31533
|
+
const iv = Buffer.from(ivHex, "hex");
|
|
31534
|
+
const tag = Buffer.from(tagHex, "hex");
|
|
31535
|
+
const data = Buffer.from(dataHex, "hex");
|
|
31536
|
+
const keys = collectCredentialKeysForDecrypt();
|
|
31537
|
+
if (keys.length === 0) {
|
|
31538
|
+
keys.push(getOrCreateCredentialsKey());
|
|
31539
|
+
}
|
|
31540
|
+
for (const key of keys) {
|
|
31541
|
+
try {
|
|
31542
|
+
const decipher = (0, import_crypto2.createDecipheriv)("aes-256-gcm", key, iv);
|
|
31543
|
+
decipher.setAuthTag(tag);
|
|
31544
|
+
return Buffer.concat([decipher.update(data), decipher.final()]).toString("utf-8");
|
|
31545
|
+
} catch {
|
|
31546
|
+
}
|
|
31547
|
+
}
|
|
31548
|
+
debug("Token decryption failed with all available credential keys.");
|
|
31549
|
+
return null;
|
|
31550
|
+
}
|
|
31551
|
+
function decodeJwtPayload(token) {
|
|
31552
|
+
try {
|
|
31553
|
+
const payloadPart = token.split(".")[1];
|
|
31554
|
+
if (!payloadPart) return null;
|
|
31555
|
+
const normalized = payloadPart.replace(/-/g, "+").replace(/_/g, "/");
|
|
31556
|
+
const padded = normalized + "=".repeat((4 - normalized.length % 4) % 4);
|
|
31557
|
+
return JSON.parse(Buffer.from(padded, "base64").toString("utf-8"));
|
|
31558
|
+
} catch (err) {
|
|
31559
|
+
debug(`JWT payload decode failed (expected for non-JWT tokens): ${errorMessage2(err)}`);
|
|
31560
|
+
return null;
|
|
31561
|
+
}
|
|
31562
|
+
}
|
|
31563
|
+
function hasValidSelectedTwins(value) {
|
|
31564
|
+
return value === void 0 || Array.isArray(value) && value.every((twin) => typeof twin === "string");
|
|
31565
|
+
}
|
|
31566
|
+
function resolveStoredToken(parsed) {
|
|
31567
|
+
if (typeof parsed.token === "string") {
|
|
31568
|
+
const token = parsed.token.trim();
|
|
31569
|
+
return { token: token.length > 0 ? token : null, source: "legacy" };
|
|
31570
|
+
}
|
|
31571
|
+
if (typeof parsed.accessToken === "string") {
|
|
31572
|
+
const token = parsed.accessToken.trim();
|
|
31573
|
+
return { token: token.length > 0 ? token : null, source: "legacy" };
|
|
31574
|
+
}
|
|
31575
|
+
if (typeof parsed.tokenEncrypted === "string") {
|
|
31576
|
+
const token = decryptToken(parsed.tokenEncrypted)?.trim() || null;
|
|
31577
|
+
return { token: token?.length ? token : null, source: "encrypted" };
|
|
31578
|
+
}
|
|
31579
|
+
return { token: null, source: "legacy" };
|
|
31580
|
+
}
|
|
31581
|
+
function resolveStoredRefreshToken(parsed) {
|
|
31582
|
+
if (typeof parsed.refreshTokenEncrypted === "string") {
|
|
31583
|
+
const refreshToken = decryptToken(parsed.refreshTokenEncrypted)?.trim() || null;
|
|
31584
|
+
if (refreshToken !== null) {
|
|
31585
|
+
return { refreshToken, source: "encrypted" };
|
|
31586
|
+
}
|
|
31587
|
+
if (typeof parsed.refreshToken === "string") {
|
|
31588
|
+
return { refreshToken: parsed.refreshToken.trim(), source: "legacy" };
|
|
31589
|
+
}
|
|
31590
|
+
return { refreshToken: null, source: "encrypted" };
|
|
31591
|
+
}
|
|
31592
|
+
if (typeof parsed.refreshToken === "string") {
|
|
31593
|
+
return { refreshToken: parsed.refreshToken.trim(), source: "legacy" };
|
|
31594
|
+
}
|
|
31595
|
+
return { refreshToken: "", source: "none" };
|
|
31596
|
+
}
|
|
31597
|
+
function buildStoredCredentials(parsed, path, warn3) {
|
|
31598
|
+
const { token, source: tokenSource } = resolveStoredToken(parsed);
|
|
31599
|
+
const { refreshToken, source: refreshTokenSource } = resolveStoredRefreshToken(parsed);
|
|
31600
|
+
if (token === null || refreshToken === null || parsed.refreshToken !== void 0 && typeof parsed.refreshToken !== "string" || parsed.refreshTokenEncrypted !== void 0 && typeof parsed.refreshTokenEncrypted !== "string" || !hasValidSelectedTwins(parsed.selectedTwins)) {
|
|
31601
|
+
warn3(
|
|
31602
|
+
`Credentials file at ${path} has missing or invalid fields. Run \`archal login\` to re-authenticate.`
|
|
31603
|
+
);
|
|
31604
|
+
return null;
|
|
31605
|
+
}
|
|
31606
|
+
const { email: email3, plan, expiresAt } = parsed;
|
|
31607
|
+
if (typeof email3 !== "string" || !isPlan(plan) || typeof expiresAt !== "number") {
|
|
31608
|
+
warn3(
|
|
31609
|
+
`Credentials file at ${path} has missing or invalid fields. Run \`archal login\` to re-authenticate.`
|
|
31610
|
+
);
|
|
31611
|
+
return null;
|
|
31612
|
+
}
|
|
31613
|
+
const creds = {
|
|
31614
|
+
token,
|
|
31615
|
+
refreshToken,
|
|
31616
|
+
email: email3,
|
|
31617
|
+
plan,
|
|
31618
|
+
selectedTwins: parsed.selectedTwins ?? [],
|
|
31619
|
+
expiresAt
|
|
31620
|
+
};
|
|
31621
|
+
if (tokenSource === "legacy" || refreshTokenSource === "legacy") {
|
|
31622
|
+
try {
|
|
31623
|
+
saveCredentials(creds);
|
|
31624
|
+
} catch (err) {
|
|
31625
|
+
debug(`Credential migration failed: ${errorMessage2(err)}`);
|
|
31626
|
+
}
|
|
31627
|
+
}
|
|
31628
|
+
return creds;
|
|
31629
|
+
}
|
|
31630
|
+
function readCredentialsFile(options) {
|
|
31631
|
+
const path = getCredentialsPath();
|
|
31632
|
+
if (!(0, import_fs.existsSync)(path)) {
|
|
31633
|
+
return null;
|
|
31634
|
+
}
|
|
31635
|
+
try {
|
|
31636
|
+
const warn3 = getWarn(options);
|
|
31637
|
+
const parsed = JSON.parse((0, import_fs.readFileSync)(path, "utf-8"));
|
|
31638
|
+
return buildStoredCredentials(parsed, path, warn3);
|
|
31639
|
+
} catch {
|
|
31640
|
+
const warn3 = getWarn(options);
|
|
31641
|
+
warn3(
|
|
31642
|
+
`Credentials file at ${path} exists but could not be parsed. Delete it and run \`archal login\` to re-authenticate.`
|
|
31643
|
+
);
|
|
31644
|
+
return null;
|
|
31645
|
+
}
|
|
31646
|
+
}
|
|
31647
|
+
function readCredentialsFromEnv(options) {
|
|
31648
|
+
const raw = process.env[AUTH_TOKEN_ENV_VAR];
|
|
31649
|
+
if (typeof raw !== "string") {
|
|
31650
|
+
return null;
|
|
31651
|
+
}
|
|
31652
|
+
const token = raw.trim();
|
|
31653
|
+
if (token.length === 0) {
|
|
31654
|
+
return null;
|
|
31655
|
+
}
|
|
31656
|
+
const claims = decodeJwtPayload(token);
|
|
31657
|
+
const nowSeconds = Math.floor(Date.now() / 1e3);
|
|
31658
|
+
const email3 = claims !== null && typeof claims["email"] === "string" ? claims["email"] : "(from ARCHAL_TOKEN)";
|
|
31659
|
+
let plan = claims !== null && isPlan(claims["plan"]) ? claims["plan"] : void 0;
|
|
31660
|
+
if (!plan) {
|
|
31661
|
+
if (claims !== null) {
|
|
31662
|
+
getWarn(options)("JWT does not contain a valid plan claim - defaulting to free");
|
|
31663
|
+
}
|
|
31664
|
+
plan = "free";
|
|
31665
|
+
}
|
|
31666
|
+
const expiresAt = claims !== null && typeof claims["exp"] === "number" ? claims["exp"] : nowSeconds + ENV_TOKEN_FALLBACK_TTL_SECONDS;
|
|
31667
|
+
if (expiresAt <= nowSeconds) {
|
|
31668
|
+
if (options?.onExpiredEnvToken === "throw") {
|
|
31669
|
+
throw new ExpiredEnvTokenError();
|
|
31670
|
+
}
|
|
31671
|
+
debug("Ignoring expired ARCHAL_TOKEN from environment.");
|
|
31672
|
+
return null;
|
|
31673
|
+
}
|
|
31674
|
+
return {
|
|
31675
|
+
token,
|
|
31676
|
+
refreshToken: "",
|
|
31677
|
+
email: email3,
|
|
31678
|
+
plan,
|
|
31679
|
+
selectedTwins: [],
|
|
31680
|
+
expiresAt
|
|
31681
|
+
};
|
|
31682
|
+
}
|
|
31683
|
+
function getCredentials(options) {
|
|
31684
|
+
const creds = readCredentialsFromEnv(options) ?? getStoredCredentials(options);
|
|
31685
|
+
if (!creds) {
|
|
31686
|
+
return null;
|
|
31687
|
+
}
|
|
31688
|
+
return isExpired(creds.expiresAt) ? null : creds;
|
|
31689
|
+
}
|
|
31690
|
+
function getStoredCredentials(options) {
|
|
31691
|
+
const creds = readCredentialsFile(options);
|
|
31692
|
+
if (!creds) {
|
|
31693
|
+
return null;
|
|
31694
|
+
}
|
|
31695
|
+
if (options?.includeExpired) {
|
|
31696
|
+
return creds;
|
|
31697
|
+
}
|
|
31698
|
+
return isExpired(creds.expiresAt) ? null : creds;
|
|
31699
|
+
}
|
|
31700
|
+
function saveCredentials(creds) {
|
|
31701
|
+
const credPath = getCredentialsPath();
|
|
31702
|
+
const payload = {
|
|
31703
|
+
email: creds.email,
|
|
31704
|
+
plan: creds.plan,
|
|
31705
|
+
selectedTwins: creds.selectedTwins,
|
|
31706
|
+
expiresAt: creds.expiresAt,
|
|
31707
|
+
tokenEncrypted: encryptToken(creds.token.trim()),
|
|
31708
|
+
refreshTokenEncrypted: creds.refreshToken.trim().length > 0 ? encryptToken(creds.refreshToken.trim()) : void 0
|
|
31709
|
+
};
|
|
31710
|
+
const tmpPath = `${credPath}.${(0, import_crypto2.randomBytes)(4).toString("hex")}.tmp`;
|
|
31711
|
+
(0, import_fs.writeFileSync)(tmpPath, `${JSON.stringify(payload, null, 2)}
|
|
31712
|
+
`, {
|
|
31713
|
+
encoding: "utf-8",
|
|
31714
|
+
mode: 384
|
|
31715
|
+
});
|
|
31716
|
+
(0, import_fs.renameSync)(tmpPath, credPath);
|
|
31717
|
+
}
|
|
31718
|
+
function deleteCredentials() {
|
|
31719
|
+
const path = getCredentialsPath();
|
|
31720
|
+
if (!(0, import_fs.existsSync)(path)) {
|
|
31721
|
+
return false;
|
|
31722
|
+
}
|
|
31723
|
+
(0, import_fs.unlinkSync)(path);
|
|
31724
|
+
return true;
|
|
31725
|
+
}
|
|
31726
|
+
function getWarn2(options) {
|
|
31727
|
+
return options?.warn ?? console.warn;
|
|
31728
|
+
}
|
|
31729
|
+
function stripUrlCredentials(url2) {
|
|
31730
|
+
try {
|
|
31731
|
+
const parsed = new URL(url2);
|
|
31732
|
+
parsed.username = "";
|
|
31733
|
+
parsed.password = "";
|
|
31734
|
+
return parsed.toString();
|
|
31735
|
+
} catch {
|
|
31736
|
+
const atIndex = url2.indexOf("@");
|
|
31737
|
+
return atIndex >= 0 ? url2.slice(atIndex + 1) : url2;
|
|
31738
|
+
}
|
|
31739
|
+
}
|
|
31740
|
+
function normalizeAuthUrl(value) {
|
|
31741
|
+
if (typeof value !== "string") {
|
|
31742
|
+
return null;
|
|
31743
|
+
}
|
|
31744
|
+
const trimmed = value.trim().replace(/\/+$/, "");
|
|
31745
|
+
if (trimmed.length === 0) {
|
|
31746
|
+
return null;
|
|
31747
|
+
}
|
|
31748
|
+
const normalized = trimmed.endsWith("/api") ? trimmed.slice(0, -4) : trimmed;
|
|
31749
|
+
if (normalized.length === 0) {
|
|
31750
|
+
return null;
|
|
31751
|
+
}
|
|
31752
|
+
const parsed = new URL(normalized);
|
|
31753
|
+
if (parsed.protocol === "https:") {
|
|
31754
|
+
return normalized;
|
|
31755
|
+
}
|
|
31756
|
+
const isLocalHttp = parsed.protocol === "http:" && (parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1");
|
|
31757
|
+
if (!isLocalHttp) {
|
|
31758
|
+
throw new Error(
|
|
31759
|
+
`Auth URL must use HTTPS (got ${stripUrlCredentials(normalized)}). HTTP is only allowed for localhost.`
|
|
31760
|
+
);
|
|
31761
|
+
}
|
|
31762
|
+
return normalized;
|
|
31763
|
+
}
|
|
31764
|
+
function parseBooleanEnvFlag(value) {
|
|
31765
|
+
if (typeof value !== "string") {
|
|
31766
|
+
return false;
|
|
31767
|
+
}
|
|
31768
|
+
switch (value.trim().toLowerCase()) {
|
|
31769
|
+
case "1":
|
|
31770
|
+
case "true":
|
|
31771
|
+
case "yes":
|
|
31772
|
+
case "on":
|
|
31773
|
+
return true;
|
|
31774
|
+
default:
|
|
31775
|
+
return false;
|
|
31776
|
+
}
|
|
31777
|
+
}
|
|
31778
|
+
function isStrictEndpointModeEnabled() {
|
|
31779
|
+
return parseBooleanEnvFlag(process.env[STRICT_ENDPOINTS_ENV_VAR]);
|
|
31780
|
+
}
|
|
31781
|
+
function readConfiguredUrl(options, ...envKeys) {
|
|
31782
|
+
for (const key of envKeys) {
|
|
31783
|
+
try {
|
|
31784
|
+
const value = normalizeAuthUrl(process.env[key]);
|
|
31785
|
+
if (value) {
|
|
31786
|
+
return value;
|
|
31787
|
+
}
|
|
31788
|
+
} catch (err) {
|
|
31789
|
+
getWarn2(options)(
|
|
31790
|
+
`Ignoring invalid ${key}: ${err instanceof Error ? err.message : String(err)}`
|
|
31791
|
+
);
|
|
31792
|
+
}
|
|
31793
|
+
}
|
|
31794
|
+
return null;
|
|
31795
|
+
}
|
|
31796
|
+
function getConfiguredAuthBaseUrl(options) {
|
|
31797
|
+
const explicit = readConfiguredUrl(options, "ARCHAL_AUTH_URL", "ARCHAL_AUTH_BASE_URL");
|
|
31798
|
+
if (explicit) {
|
|
31799
|
+
return explicit;
|
|
31800
|
+
}
|
|
31801
|
+
return isStrictEndpointModeEnabled() ? null : HOSTED_DEFAULT_AUTH_BASE_URL;
|
|
31802
|
+
}
|
|
31803
|
+
function getConfiguredApiBaseUrl(options) {
|
|
31804
|
+
const explicit = readConfiguredUrl(options, "ARCHAL_API_URL", "ARCHAL_API_BASE_URL");
|
|
31805
|
+
if (explicit) {
|
|
31806
|
+
return explicit;
|
|
31807
|
+
}
|
|
31808
|
+
return isStrictEndpointModeEnabled() ? null : HOSTED_DEFAULT_API_BASE_URL;
|
|
31809
|
+
}
|
|
31810
|
+
function buildAuthRequestHeaders(metadata, includeContentType = false) {
|
|
31811
|
+
const headers = {};
|
|
31812
|
+
if (includeContentType) {
|
|
31813
|
+
headers["content-type"] = "application/json";
|
|
31814
|
+
}
|
|
31815
|
+
if (metadata?.userAgent) {
|
|
31816
|
+
headers["user-agent"] = metadata.userAgent;
|
|
31817
|
+
}
|
|
31818
|
+
if (metadata?.cliVersion) {
|
|
31819
|
+
headers["x-archal-cli-version"] = metadata.cliVersion;
|
|
31820
|
+
}
|
|
31821
|
+
return headers;
|
|
31822
|
+
}
|
|
31823
|
+
function isTokenDerivedIdentity(email3) {
|
|
31824
|
+
return email3 === "(from ARCHAL_TOKEN)" || email3 === "(from token)";
|
|
31825
|
+
}
|
|
31826
|
+
function getWarn3(metadata) {
|
|
31827
|
+
return metadata?.warn ?? console.warn;
|
|
31828
|
+
}
|
|
31829
|
+
function getAuthBaseUrl(metadata) {
|
|
31830
|
+
const configured = metadata?.authBaseUrl?.trim();
|
|
31831
|
+
if (configured) {
|
|
31832
|
+
return configured.replace(/\/+$/, "");
|
|
31833
|
+
}
|
|
31834
|
+
return getConfiguredAuthBaseUrl();
|
|
31835
|
+
}
|
|
31836
|
+
function logRefreshFailure(creds, reason, authBaseUrl, metadata) {
|
|
31837
|
+
const endpoint = `${authBaseUrl}/auth/me`;
|
|
31838
|
+
const warn3 = getWarn3(metadata);
|
|
31839
|
+
if (isTokenDerivedIdentity(creds.email)) {
|
|
31840
|
+
warn3(
|
|
31841
|
+
`Could not verify token with ${endpoint} (${reason}). Using token without refreshed account metadata.`
|
|
31842
|
+
);
|
|
31843
|
+
return;
|
|
31844
|
+
}
|
|
31845
|
+
warn3(
|
|
31846
|
+
`Could not refresh account metadata from ${endpoint} (${reason}). Using cached credentials.`
|
|
31847
|
+
);
|
|
31848
|
+
}
|
|
31849
|
+
async function readFailureDetail(response) {
|
|
31850
|
+
const contentType = response.headers.get("content-type")?.toLowerCase() ?? "";
|
|
31851
|
+
if (!contentType.includes("application/json")) {
|
|
31852
|
+
return null;
|
|
31853
|
+
}
|
|
31854
|
+
try {
|
|
31855
|
+
const payload = await response.json();
|
|
31856
|
+
const error49 = typeof payload.error === "string" ? payload.error.trim() : "";
|
|
31857
|
+
const message = typeof payload.message === "string" ? payload.message.trim() : "";
|
|
31858
|
+
if (error49 && message) return `${error49}: ${message}`;
|
|
31859
|
+
if (message) return message;
|
|
31860
|
+
if (error49) return error49;
|
|
31861
|
+
} catch {
|
|
31862
|
+
return null;
|
|
31863
|
+
}
|
|
31864
|
+
return null;
|
|
31865
|
+
}
|
|
31866
|
+
async function validateTokenWithServer(creds, metadata) {
|
|
31867
|
+
const authBaseUrl = getAuthBaseUrl(metadata);
|
|
31868
|
+
if (!authBaseUrl) {
|
|
31869
|
+
return {
|
|
31870
|
+
ok: false,
|
|
31871
|
+
code: "no_auth_url",
|
|
31872
|
+
status: null,
|
|
31873
|
+
reason: "no auth URL configured"
|
|
31874
|
+
};
|
|
31875
|
+
}
|
|
31876
|
+
try {
|
|
31877
|
+
const response = await fetch(`${authBaseUrl}/auth/me`, {
|
|
31878
|
+
method: "GET",
|
|
31879
|
+
headers: {
|
|
31880
|
+
authorization: `Bearer ${creds.token}`,
|
|
31881
|
+
...buildAuthRequestHeaders(metadata, false)
|
|
31882
|
+
},
|
|
31883
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
31884
|
+
});
|
|
31885
|
+
if (!response.ok) {
|
|
31886
|
+
const detail = await readFailureDetail(response);
|
|
31887
|
+
return {
|
|
31888
|
+
ok: false,
|
|
31889
|
+
code: response.status === 401 ? "auth_rejected" : "http_error",
|
|
31890
|
+
status: response.status,
|
|
31891
|
+
reason: detail ? `HTTP ${response.status} ${detail}` : `HTTP ${response.status}`
|
|
31892
|
+
};
|
|
31893
|
+
}
|
|
31894
|
+
let data;
|
|
31895
|
+
try {
|
|
31896
|
+
data = await response.json();
|
|
31897
|
+
} catch {
|
|
31898
|
+
return {
|
|
31899
|
+
ok: false,
|
|
31900
|
+
code: "invalid_payload",
|
|
31901
|
+
status: null,
|
|
31902
|
+
reason: "invalid response payload"
|
|
31903
|
+
};
|
|
31904
|
+
}
|
|
31905
|
+
if (typeof data.email !== "string" || !isPlan(data.plan)) {
|
|
31906
|
+
return {
|
|
31907
|
+
ok: false,
|
|
31908
|
+
code: "invalid_payload",
|
|
31909
|
+
status: null,
|
|
31910
|
+
reason: "invalid response payload"
|
|
31911
|
+
};
|
|
31912
|
+
}
|
|
31913
|
+
const selectedTwins = Array.isArray(data.selectedTwinIds) ? data.selectedTwinIds.filter((id) => typeof id === "string") : creds.selectedTwins;
|
|
31914
|
+
const updated = {
|
|
31915
|
+
...creds,
|
|
31916
|
+
email: data.email,
|
|
31917
|
+
plan: data.plan,
|
|
31918
|
+
selectedTwins
|
|
31919
|
+
};
|
|
31920
|
+
if ((updated.email !== creds.email || updated.plan !== creds.plan || JSON.stringify(updated.selectedTwins) !== JSON.stringify(creds.selectedTwins)) && !process.env[AUTH_TOKEN_ENV_VAR]) {
|
|
31921
|
+
saveCredentials(updated);
|
|
31922
|
+
}
|
|
31923
|
+
return { ok: true, credentials: updated };
|
|
31924
|
+
} catch (error49) {
|
|
31925
|
+
return {
|
|
31926
|
+
ok: false,
|
|
31927
|
+
code: "network_error",
|
|
31928
|
+
status: null,
|
|
31929
|
+
reason: errorMessage2(error49)
|
|
31930
|
+
};
|
|
31931
|
+
}
|
|
31932
|
+
}
|
|
31933
|
+
async function refreshAuthFromServer(creds, metadata) {
|
|
31934
|
+
const authBaseUrl = getAuthBaseUrl(metadata);
|
|
31935
|
+
if (!authBaseUrl) return creds;
|
|
31936
|
+
const result = await refreshAuthFromServerWithValidation(creds, metadata);
|
|
31937
|
+
if (!result.validation.ok) {
|
|
31938
|
+
logRefreshFailure(creds, result.validation.reason, authBaseUrl, metadata);
|
|
31939
|
+
if (result.validation.code === "auth_rejected") {
|
|
31940
|
+
throw new Error("Authentication failed. Your token may be expired or invalid. Run: archal login");
|
|
31941
|
+
}
|
|
31942
|
+
}
|
|
31943
|
+
return result.credentials;
|
|
31944
|
+
}
|
|
31945
|
+
async function refreshAuthFromServerWithValidation(creds, metadata) {
|
|
31946
|
+
const result = await validateTokenWithServer(creds, metadata);
|
|
31947
|
+
if (result.ok) {
|
|
31948
|
+
return {
|
|
31949
|
+
credentials: result.credentials,
|
|
31950
|
+
validation: result
|
|
31951
|
+
};
|
|
31952
|
+
}
|
|
31953
|
+
return {
|
|
31954
|
+
credentials: creds,
|
|
31955
|
+
validation: result
|
|
31956
|
+
};
|
|
31957
|
+
}
|
|
31958
|
+
async function resolveWhoamiAuthState(creds, metadata) {
|
|
31959
|
+
if (!creds) {
|
|
31960
|
+
return { loggedIn: false };
|
|
31961
|
+
}
|
|
31962
|
+
const refreshed = await refreshAuthFromServerWithValidation(creds, metadata);
|
|
31963
|
+
return {
|
|
31964
|
+
loggedIn: true,
|
|
31965
|
+
credentials: refreshed.credentials,
|
|
31966
|
+
validation: refreshed.validation
|
|
31967
|
+
};
|
|
31968
|
+
}
|
|
31969
|
+
function isEntitled(creds, twinName) {
|
|
31970
|
+
if (creds.plan === "pro" || creds.plan === "enterprise") return true;
|
|
31971
|
+
if (creds.selectedTwins && creds.selectedTwins.length > 0) {
|
|
31972
|
+
return creds.selectedTwins.includes(twinName);
|
|
31973
|
+
}
|
|
31974
|
+
return true;
|
|
31975
|
+
}
|
|
31976
|
+
function getJwtExpiry(token) {
|
|
31977
|
+
const claims = decodeJwtPayload(token);
|
|
31978
|
+
if (claims === null) return null;
|
|
31979
|
+
return typeof claims["exp"] === "number" ? claims["exp"] : null;
|
|
31980
|
+
}
|
|
31981
|
+
function sleep2(ms, signal) {
|
|
31982
|
+
if (!signal) {
|
|
31983
|
+
return new Promise((resolve15) => {
|
|
31984
|
+
setTimeout(resolve15, ms);
|
|
31985
|
+
});
|
|
31986
|
+
}
|
|
31987
|
+
const abortSignal = signal;
|
|
31988
|
+
if (abortSignal.aborted) {
|
|
31989
|
+
return Promise.reject(abortSignal.reason instanceof Error ? abortSignal.reason : new DOMException("The operation was aborted.", "AbortError"));
|
|
31990
|
+
}
|
|
31991
|
+
return new Promise((resolve15, reject) => {
|
|
31992
|
+
const timeout = setTimeout(() => {
|
|
31993
|
+
abortSignal.removeEventListener("abort", onAbort);
|
|
31994
|
+
resolve15();
|
|
31995
|
+
}, ms);
|
|
31996
|
+
function onAbort() {
|
|
31997
|
+
clearTimeout(timeout);
|
|
31998
|
+
reject(abortSignal.reason instanceof Error ? abortSignal.reason : new DOMException("The operation was aborted.", "AbortError"));
|
|
31999
|
+
}
|
|
32000
|
+
abortSignal.addEventListener("abort", onAbort, { once: true });
|
|
32001
|
+
});
|
|
32002
|
+
}
|
|
32003
|
+
function resolveBackoffDelay(backoffMs, attempt, fallbackMs) {
|
|
32004
|
+
const indexed = backoffMs[attempt];
|
|
32005
|
+
if (typeof indexed === "number" && Number.isFinite(indexed) && indexed >= 0) {
|
|
32006
|
+
return indexed;
|
|
32007
|
+
}
|
|
32008
|
+
const last = backoffMs.length > 0 ? backoffMs[backoffMs.length - 1] : void 0;
|
|
32009
|
+
if (typeof last === "number" && Number.isFinite(last) && last >= 0) {
|
|
32010
|
+
return last;
|
|
32011
|
+
}
|
|
32012
|
+
return fallbackMs;
|
|
32013
|
+
}
|
|
32014
|
+
async function fetchWithRetry(url2, init, options) {
|
|
32015
|
+
const maxRetries = options?.maxRetries ?? AUTH_RETRY_OPTIONS.maxRetries;
|
|
32016
|
+
const timeoutMs = options?.timeoutMs ?? AUTH_RETRY_OPTIONS.timeoutMs;
|
|
32017
|
+
const retryableStatusCodes = options?.retryableStatusCodes instanceof Set ? options.retryableStatusCodes : new Set(options?.retryableStatusCodes ?? AUTH_RETRY_OPTIONS.retryableStatusCodes);
|
|
32018
|
+
const backoffMs = options?.backoffMs ?? AUTH_RETRY_OPTIONS.backoffMs;
|
|
32019
|
+
const fetchImpl = options?.fetchImpl ?? fetch;
|
|
32020
|
+
const externalSignal = options?.signal;
|
|
32021
|
+
let lastError;
|
|
32022
|
+
for (let attempt = 0; attempt <= maxRetries; attempt += 1) {
|
|
32023
|
+
if (externalSignal?.aborted) {
|
|
32024
|
+
throw externalSignal.reason ?? new DOMException("The operation was aborted.", "AbortError");
|
|
32025
|
+
}
|
|
32026
|
+
try {
|
|
32027
|
+
const requestSignal = externalSignal ? AbortSignal.any([externalSignal, AbortSignal.timeout(timeoutMs)]) : AbortSignal.timeout(timeoutMs);
|
|
32028
|
+
const response = await fetchImpl(url2, {
|
|
32029
|
+
...init,
|
|
32030
|
+
signal: requestSignal
|
|
32031
|
+
});
|
|
32032
|
+
if (response.ok || !retryableStatusCodes.has(response.status) || attempt >= maxRetries) {
|
|
32033
|
+
return response;
|
|
32034
|
+
}
|
|
32035
|
+
lastError = new Error(`HTTP ${response.status}`);
|
|
32036
|
+
} catch (error49) {
|
|
32037
|
+
lastError = error49;
|
|
32038
|
+
if (attempt >= maxRetries) {
|
|
32039
|
+
break;
|
|
32040
|
+
}
|
|
32041
|
+
}
|
|
32042
|
+
if (attempt < maxRetries) {
|
|
32043
|
+
const delay = resolveBackoffDelay(backoffMs, attempt, 3e3);
|
|
32044
|
+
await sleep2(delay, externalSignal);
|
|
32045
|
+
}
|
|
32046
|
+
}
|
|
32047
|
+
throw lastError instanceof Error ? lastError : new Error(errorMessage2(lastError));
|
|
32048
|
+
}
|
|
32049
|
+
function isCliTokenExchangeResponse(value) {
|
|
32050
|
+
if (!value || typeof value !== "object") return false;
|
|
32051
|
+
const data = value;
|
|
32052
|
+
return typeof data["accessToken"] === "string" && typeof data["refreshToken"] === "string" && typeof data["email"] === "string" && isPlan(data["plan"]) && typeof data["expiresAt"] === "number";
|
|
32053
|
+
}
|
|
32054
|
+
function isCliRefreshResponse(value) {
|
|
32055
|
+
if (!value || typeof value !== "object") return false;
|
|
32056
|
+
const data = value;
|
|
32057
|
+
return typeof data["accessToken"] === "string" && typeof data["refreshToken"] === "string" && typeof data["expiresAt"] === "number";
|
|
32058
|
+
}
|
|
32059
|
+
function debug2(message) {
|
|
32060
|
+
if (process.env["ARCHAL_DEBUG"] !== "1") {
|
|
32061
|
+
return;
|
|
32062
|
+
}
|
|
32063
|
+
process.stderr.write(`[archal-node-auth] ${message}
|
|
32064
|
+
`);
|
|
32065
|
+
}
|
|
32066
|
+
function getAuthBaseUrl2(metadata) {
|
|
32067
|
+
const configured = metadata?.authBaseUrl?.trim();
|
|
32068
|
+
if (configured) {
|
|
32069
|
+
return configured.replace(/\/+$/, "");
|
|
32070
|
+
}
|
|
32071
|
+
return getConfiguredAuthBaseUrl();
|
|
32072
|
+
}
|
|
32073
|
+
async function exchangeCliAuthCode(input, metadata) {
|
|
32074
|
+
const authBaseUrl = getAuthBaseUrl2(metadata);
|
|
32075
|
+
if (!authBaseUrl) {
|
|
32076
|
+
throw new Error(
|
|
32077
|
+
"ARCHAL_AUTH_URL is required for browser login when ARCHAL_STRICT_ENDPOINTS=1. Set ARCHAL_AUTH_URL and run `archal login` again."
|
|
32078
|
+
);
|
|
32079
|
+
}
|
|
32080
|
+
const response = await fetchWithRetry(
|
|
32081
|
+
`${authBaseUrl}/auth/cli/token`,
|
|
32082
|
+
{
|
|
32083
|
+
method: "POST",
|
|
32084
|
+
headers: buildAuthRequestHeaders(metadata, true),
|
|
32085
|
+
body: JSON.stringify(input)
|
|
32086
|
+
},
|
|
32087
|
+
AUTH_RETRY_OPTIONS
|
|
32088
|
+
);
|
|
32089
|
+
if (!response.ok) {
|
|
32090
|
+
throw new Error(`Login failed during code exchange (${response.status})`);
|
|
32091
|
+
}
|
|
32092
|
+
const payload = await response.json();
|
|
32093
|
+
if (!isCliTokenExchangeResponse(payload)) {
|
|
32094
|
+
throw new Error("Login failed: invalid token exchange response");
|
|
32095
|
+
}
|
|
32096
|
+
const selectedTwins = Array.isArray(payload.selectedTwinIds) ? payload.selectedTwinIds.filter((id) => typeof id === "string") : [];
|
|
32097
|
+
return {
|
|
32098
|
+
token: payload.accessToken,
|
|
32099
|
+
refreshToken: payload.refreshToken,
|
|
32100
|
+
email: payload.email,
|
|
32101
|
+
plan: payload.plan,
|
|
32102
|
+
selectedTwins,
|
|
32103
|
+
expiresAt: payload.expiresAt
|
|
32104
|
+
};
|
|
32105
|
+
}
|
|
32106
|
+
async function refreshCliSession(creds, metadata) {
|
|
32107
|
+
if (!creds.refreshToken) {
|
|
32108
|
+
return null;
|
|
32109
|
+
}
|
|
32110
|
+
const authBaseUrl = getAuthBaseUrl2(metadata);
|
|
32111
|
+
if (!authBaseUrl) {
|
|
32112
|
+
return null;
|
|
32113
|
+
}
|
|
32114
|
+
const response = await fetchWithRetry(
|
|
32115
|
+
`${authBaseUrl}/auth/cli/refresh`,
|
|
32116
|
+
{
|
|
32117
|
+
method: "POST",
|
|
32118
|
+
headers: buildAuthRequestHeaders(metadata, true),
|
|
32119
|
+
body: JSON.stringify({ refreshToken: creds.refreshToken })
|
|
32120
|
+
},
|
|
32121
|
+
AUTH_RETRY_OPTIONS
|
|
32122
|
+
);
|
|
32123
|
+
if (!response.ok) {
|
|
32124
|
+
return null;
|
|
32125
|
+
}
|
|
32126
|
+
const payload = await response.json();
|
|
32127
|
+
if (!isCliRefreshResponse(payload)) {
|
|
32128
|
+
return null;
|
|
32129
|
+
}
|
|
32130
|
+
return {
|
|
32131
|
+
...creds,
|
|
32132
|
+
token: payload.accessToken,
|
|
32133
|
+
refreshToken: payload.refreshToken,
|
|
32134
|
+
expiresAt: payload.expiresAt
|
|
32135
|
+
};
|
|
32136
|
+
}
|
|
32137
|
+
async function revokeCliSession(refreshToken, metadata) {
|
|
32138
|
+
const authBaseUrl = getAuthBaseUrl2(metadata);
|
|
32139
|
+
if (!authBaseUrl) {
|
|
32140
|
+
return;
|
|
32141
|
+
}
|
|
32142
|
+
try {
|
|
32143
|
+
await fetch(`${authBaseUrl}/auth/cli/revoke`, {
|
|
32144
|
+
method: "POST",
|
|
32145
|
+
headers: buildAuthRequestHeaders(metadata, true),
|
|
32146
|
+
body: JSON.stringify({ refreshToken }),
|
|
32147
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
32148
|
+
});
|
|
32149
|
+
} catch (error49) {
|
|
32150
|
+
debug2(`Session revoke failed (best-effort): ${errorMessage2(error49)}`);
|
|
32151
|
+
}
|
|
32152
|
+
}
|
|
32153
|
+
var import_child_process, import_crypto2, import_fs, import_os, import_path, CREDENTIALS_FILE, CREDENTIALS_KEY_FILE, AUTH_TOKEN_ENV_VAR, TOKEN_ENCRYPTION_PREFIX, CREDENTIALS_MASTER_KEY_ENV_VAR, KEYCHAIN_SERVICE, KEYCHAIN_ACCOUNT, HOSTED_DEFAULT_AUTH_BASE_URL, HOSTED_DEFAULT_API_BASE_URL, STRICT_ENDPOINTS_ENV_VAR, REQUEST_TIMEOUT_MS, ENV_TOKEN_FALLBACK_TTL_SECONDS, AUTH_RETRY_OPTIONS, ExpiredEnvTokenError, KEYCHAIN_COMMAND_TIMEOUT_MS, ARCHAL_DIR_NAME, seededSandboxes;
|
|
32154
|
+
var init_dist3 = __esm({
|
|
32155
|
+
"../packages/node-auth/dist/index.js"() {
|
|
32156
|
+
"use strict";
|
|
32157
|
+
import_child_process = require("child_process");
|
|
32158
|
+
import_crypto2 = require("crypto");
|
|
32159
|
+
import_fs = require("fs");
|
|
32160
|
+
import_os = require("os");
|
|
32161
|
+
import_path = require("path");
|
|
32162
|
+
CREDENTIALS_FILE = "credentials.json";
|
|
32163
|
+
CREDENTIALS_KEY_FILE = "credentials.key";
|
|
32164
|
+
AUTH_TOKEN_ENV_VAR = "ARCHAL_TOKEN";
|
|
32165
|
+
TOKEN_ENCRYPTION_PREFIX = "enc-v1";
|
|
32166
|
+
CREDENTIALS_MASTER_KEY_ENV_VAR = "ARCHAL_CREDENTIALS_MASTER_KEY";
|
|
32167
|
+
KEYCHAIN_SERVICE = "archal-cli";
|
|
32168
|
+
KEYCHAIN_ACCOUNT = "credentials-master-key";
|
|
32169
|
+
HOSTED_DEFAULT_AUTH_BASE_URL = "https://www.archal.ai";
|
|
32170
|
+
HOSTED_DEFAULT_API_BASE_URL = "https://www.archal.ai";
|
|
32171
|
+
STRICT_ENDPOINTS_ENV_VAR = "ARCHAL_STRICT_ENDPOINTS";
|
|
32172
|
+
REQUEST_TIMEOUT_MS = 8e3;
|
|
32173
|
+
ENV_TOKEN_FALLBACK_TTL_SECONDS = 24 * 60 * 60;
|
|
32174
|
+
AUTH_RETRY_OPTIONS = {
|
|
32175
|
+
maxRetries: 2,
|
|
32176
|
+
timeoutMs: REQUEST_TIMEOUT_MS,
|
|
32177
|
+
retryableStatusCodes: /* @__PURE__ */ new Set([429, 502, 503, 504]),
|
|
32178
|
+
backoffMs: [500, 1500],
|
|
32179
|
+
label: "auth"
|
|
32180
|
+
};
|
|
32181
|
+
ExpiredEnvTokenError = class extends Error {
|
|
32182
|
+
constructor(envVar = AUTH_TOKEN_ENV_VAR) {
|
|
32183
|
+
super(`${envVar} is expired. Remove it or replace it with a valid token.`);
|
|
32184
|
+
this.name = "ExpiredEnvTokenError";
|
|
32185
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
32186
|
+
}
|
|
32187
|
+
};
|
|
32188
|
+
KEYCHAIN_COMMAND_TIMEOUT_MS = 1500;
|
|
32189
|
+
ARCHAL_DIR_NAME = ".archal";
|
|
32190
|
+
seededSandboxes = /* @__PURE__ */ new Set();
|
|
32191
|
+
}
|
|
32192
|
+
});
|
|
32193
|
+
|
|
31303
32194
|
// src/auth/types.ts
|
|
31304
|
-
var import_node_auth;
|
|
31305
32195
|
var init_types3 = __esm({
|
|
31306
32196
|
"src/auth/types.ts"() {
|
|
31307
32197
|
"use strict";
|
|
31308
|
-
|
|
32198
|
+
init_dist3();
|
|
31309
32199
|
}
|
|
31310
32200
|
});
|
|
31311
32201
|
|
|
@@ -31372,7 +32262,7 @@ function log(level, message, data) {
|
|
|
31372
32262
|
const formatted = formatLogEntry(entry);
|
|
31373
32263
|
process.stderr.write(formatted + "\n");
|
|
31374
32264
|
}
|
|
31375
|
-
function
|
|
32265
|
+
function debug3(message, data) {
|
|
31376
32266
|
log("debug", message, data);
|
|
31377
32267
|
}
|
|
31378
32268
|
function info(message, data) {
|
|
@@ -31481,34 +32371,34 @@ var init_logger = __esm({
|
|
|
31481
32371
|
});
|
|
31482
32372
|
|
|
31483
32373
|
// src/auth/url-resolver.ts
|
|
31484
|
-
function
|
|
31485
|
-
return
|
|
32374
|
+
function getConfiguredAuthBaseUrl2() {
|
|
32375
|
+
return getConfiguredAuthBaseUrl(READ_OPTIONS);
|
|
31486
32376
|
}
|
|
31487
|
-
function
|
|
31488
|
-
return
|
|
32377
|
+
function getConfiguredApiBaseUrl2() {
|
|
32378
|
+
return getConfiguredApiBaseUrl(READ_OPTIONS);
|
|
31489
32379
|
}
|
|
31490
|
-
var
|
|
32380
|
+
var READ_OPTIONS;
|
|
31491
32381
|
var init_url_resolver = __esm({
|
|
31492
32382
|
"src/auth/url-resolver.ts"() {
|
|
31493
32383
|
"use strict";
|
|
31494
|
-
|
|
32384
|
+
init_dist3();
|
|
31495
32385
|
init_logger();
|
|
31496
32386
|
READ_OPTIONS = { warn };
|
|
31497
32387
|
}
|
|
31498
32388
|
});
|
|
31499
32389
|
|
|
31500
32390
|
// src/auth/credential-store.ts
|
|
31501
|
-
function
|
|
31502
|
-
return
|
|
32391
|
+
function getCredentials2() {
|
|
32392
|
+
return getCredentials(READ_OPTIONS2);
|
|
31503
32393
|
}
|
|
31504
|
-
function
|
|
31505
|
-
return
|
|
32394
|
+
function getStoredCredentials2() {
|
|
32395
|
+
return getStoredCredentials(STORED_READ_OPTIONS);
|
|
31506
32396
|
}
|
|
31507
|
-
var
|
|
32397
|
+
var READ_OPTIONS2, STORED_READ_OPTIONS;
|
|
31508
32398
|
var init_credential_store = __esm({
|
|
31509
32399
|
"src/auth/credential-store.ts"() {
|
|
31510
32400
|
"use strict";
|
|
31511
|
-
|
|
32401
|
+
init_dist3();
|
|
31512
32402
|
init_logger();
|
|
31513
32403
|
READ_OPTIONS2 = { onExpiredEnvToken: "throw", warn };
|
|
31514
32404
|
STORED_READ_OPTIONS = { includeExpired: true, warn };
|
|
@@ -31544,12 +32434,12 @@ var init_errors4 = __esm({
|
|
|
31544
32434
|
|
|
31545
32435
|
// src/auth/require-auth.ts
|
|
31546
32436
|
function requireAuth(options = {}) {
|
|
31547
|
-
const existing =
|
|
32437
|
+
const existing = getCredentials2();
|
|
31548
32438
|
if (existing) {
|
|
31549
32439
|
return existing;
|
|
31550
32440
|
}
|
|
31551
32441
|
const canAutoLogin = process.env["ARCHAL_AUTO_LOGIN"] !== "0" && process.argv[2] !== "login" && !!process.stdin.isTTY && !!process.stdout.isTTY && !process.env["CI"];
|
|
31552
|
-
const authBaseUrl =
|
|
32442
|
+
const authBaseUrl = getConfiguredAuthBaseUrl2();
|
|
31553
32443
|
if (canAutoLogin) {
|
|
31554
32444
|
if (!authBaseUrl) {
|
|
31555
32445
|
process.stderr.write(
|
|
@@ -31568,7 +32458,7 @@ function requireAuth(options = {}) {
|
|
|
31568
32458
|
env: process.env
|
|
31569
32459
|
});
|
|
31570
32460
|
if (!result.error && result.status === 0) {
|
|
31571
|
-
const loggedIn =
|
|
32461
|
+
const loggedIn = getCredentials2();
|
|
31572
32462
|
if (loggedIn) {
|
|
31573
32463
|
return loggedIn;
|
|
31574
32464
|
}
|
|
@@ -31676,20 +32566,20 @@ var init_version = __esm({
|
|
|
31676
32566
|
});
|
|
31677
32567
|
|
|
31678
32568
|
// src/auth/token-exchange.ts
|
|
31679
|
-
function
|
|
31680
|
-
return
|
|
32569
|
+
function exchangeCliAuthCode2(input) {
|
|
32570
|
+
return exchangeCliAuthCode(input, REQUEST_METADATA);
|
|
31681
32571
|
}
|
|
31682
|
-
function
|
|
31683
|
-
return
|
|
32572
|
+
function refreshCliSession2(creds) {
|
|
32573
|
+
return refreshCliSession(creds, REQUEST_METADATA);
|
|
31684
32574
|
}
|
|
31685
|
-
function
|
|
31686
|
-
return
|
|
32575
|
+
function revokeCliSession2(refreshToken) {
|
|
32576
|
+
return revokeCliSession(refreshToken, REQUEST_METADATA);
|
|
31687
32577
|
}
|
|
31688
|
-
var
|
|
32578
|
+
var REQUEST_METADATA;
|
|
31689
32579
|
var init_token_exchange = __esm({
|
|
31690
32580
|
"src/auth/token-exchange.ts"() {
|
|
31691
32581
|
"use strict";
|
|
31692
|
-
|
|
32582
|
+
init_dist3();
|
|
31693
32583
|
init_version();
|
|
31694
32584
|
REQUEST_METADATA = {
|
|
31695
32585
|
userAgent: CLI_USER_AGENT,
|
|
@@ -31702,27 +32592,27 @@ var init_token_exchange = __esm({
|
|
|
31702
32592
|
var auth_exports = {};
|
|
31703
32593
|
__export(auth_exports, {
|
|
31704
32594
|
REQUEST_METADATA: () => REQUEST_METADATA2,
|
|
31705
|
-
decodeJwtPayload: () =>
|
|
31706
|
-
deleteCredentials: () =>
|
|
31707
|
-
exchangeCliAuthCode: () =>
|
|
31708
|
-
getArchalDir: () =>
|
|
31709
|
-
getConfiguredApiBaseUrl: () =>
|
|
31710
|
-
getConfiguredAuthBaseUrl: () =>
|
|
31711
|
-
getCredentials: () =>
|
|
31712
|
-
getJwtExpiry: () =>
|
|
31713
|
-
getStoredCredentials: () =>
|
|
31714
|
-
isEntitled: () =>
|
|
31715
|
-
isPlan: () =>
|
|
31716
|
-
refreshAuthFromServer: () =>
|
|
31717
|
-
refreshAuthFromServerWithValidation: () =>
|
|
31718
|
-
refreshCliSession: () =>
|
|
32595
|
+
decodeJwtPayload: () => decodeJwtPayload,
|
|
32596
|
+
deleteCredentials: () => deleteCredentials,
|
|
32597
|
+
exchangeCliAuthCode: () => exchangeCliAuthCode2,
|
|
32598
|
+
getArchalDir: () => getArchalDir,
|
|
32599
|
+
getConfiguredApiBaseUrl: () => getConfiguredApiBaseUrl2,
|
|
32600
|
+
getConfiguredAuthBaseUrl: () => getConfiguredAuthBaseUrl2,
|
|
32601
|
+
getCredentials: () => getCredentials2,
|
|
32602
|
+
getJwtExpiry: () => getJwtExpiry,
|
|
32603
|
+
getStoredCredentials: () => getStoredCredentials2,
|
|
32604
|
+
isEntitled: () => isEntitled,
|
|
32605
|
+
isPlan: () => isPlan,
|
|
32606
|
+
refreshAuthFromServer: () => refreshAuthFromServer,
|
|
32607
|
+
refreshAuthFromServerWithValidation: () => refreshAuthFromServerWithValidation,
|
|
32608
|
+
refreshCliSession: () => refreshCliSession2,
|
|
31719
32609
|
requireAuth: () => requireAuth,
|
|
31720
|
-
resolveWhoamiAuthState: () =>
|
|
31721
|
-
revokeCliSession: () =>
|
|
31722
|
-
saveCredentials: () =>
|
|
31723
|
-
validateTokenWithServer: () =>
|
|
32610
|
+
resolveWhoamiAuthState: () => resolveWhoamiAuthState,
|
|
32611
|
+
revokeCliSession: () => revokeCliSession2,
|
|
32612
|
+
saveCredentials: () => saveCredentials,
|
|
32613
|
+
validateTokenWithServer: () => validateTokenWithServer
|
|
31724
32614
|
});
|
|
31725
|
-
var
|
|
32615
|
+
var REQUEST_METADATA2;
|
|
31726
32616
|
var init_auth = __esm({
|
|
31727
32617
|
"src/auth/index.ts"() {
|
|
31728
32618
|
"use strict";
|
|
@@ -31731,7 +32621,7 @@ var init_auth = __esm({
|
|
|
31731
32621
|
init_credential_store();
|
|
31732
32622
|
init_require_auth();
|
|
31733
32623
|
init_token_exchange();
|
|
31734
|
-
|
|
32624
|
+
init_dist3();
|
|
31735
32625
|
init_version();
|
|
31736
32626
|
init_logger();
|
|
31737
32627
|
REQUEST_METADATA2 = {
|
|
@@ -31810,7 +32700,7 @@ function spawnWithTimeout(options) {
|
|
|
31810
32700
|
stdio: pipeStdio ? "inherit" : "pipe",
|
|
31811
32701
|
shell: process.platform === "win32"
|
|
31812
32702
|
};
|
|
31813
|
-
|
|
32703
|
+
debug3("Spawning process", { command, args: args.join(" "), timeoutMs });
|
|
31814
32704
|
let child;
|
|
31815
32705
|
try {
|
|
31816
32706
|
child = (0, import_node_child_process2.spawn)(command, args, spawnOpts);
|
|
@@ -31825,7 +32715,7 @@ function spawnWithTimeout(options) {
|
|
|
31825
32715
|
});
|
|
31826
32716
|
const timer = setTimeout(() => {
|
|
31827
32717
|
timedOut = true;
|
|
31828
|
-
|
|
32718
|
+
debug3("Process timed out, killing", { command, timeoutMs });
|
|
31829
32719
|
child.kill("SIGTERM");
|
|
31830
32720
|
setTimeout(() => {
|
|
31831
32721
|
if (!exited) {
|
|
@@ -31868,7 +32758,7 @@ function spawnWithTimeout(options) {
|
|
|
31868
32758
|
child.on("close", (exitCode) => {
|
|
31869
32759
|
clearTimeout(timer);
|
|
31870
32760
|
const durationMs = Date.now() - startTime;
|
|
31871
|
-
|
|
32761
|
+
debug3("Process exited", { command, exitCode, durationMs, timedOut, stdoutTruncated, stderrTruncated });
|
|
31872
32762
|
resolve15({
|
|
31873
32763
|
exitCode,
|
|
31874
32764
|
stdout: stdoutBuf,
|
|
@@ -31910,7 +32800,7 @@ var init_process = __esm({
|
|
|
31910
32800
|
});
|
|
31911
32801
|
|
|
31912
32802
|
// src/utils/fetch-retry.ts
|
|
31913
|
-
function
|
|
32803
|
+
function resolveBackoffDelay2(backoffMs, attempt, fallbackMs) {
|
|
31914
32804
|
const indexed = backoffMs[attempt];
|
|
31915
32805
|
if (typeof indexed === "number" && Number.isFinite(indexed) && indexed >= 0) {
|
|
31916
32806
|
return indexed;
|
|
@@ -31921,7 +32811,7 @@ function resolveBackoffDelay(backoffMs, attempt, fallbackMs) {
|
|
|
31921
32811
|
}
|
|
31922
32812
|
return fallbackMs;
|
|
31923
32813
|
}
|
|
31924
|
-
async function
|
|
32814
|
+
async function fetchWithRetry2(url2, init, options) {
|
|
31925
32815
|
const maxRetries = options?.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
31926
32816
|
const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
31927
32817
|
const retryableStatusCodes = options?.retryableStatusCodes instanceof Set ? options.retryableStatusCodes : new Set(options?.retryableStatusCodes ?? DEFAULT_RETRYABLE_STATUS_CODES);
|
|
@@ -31944,19 +32834,19 @@ async function fetchWithRetry(url2, init, options) {
|
|
|
31944
32834
|
if (response.ok || !retryableStatusCodes.has(response.status) || attempt >= maxRetries) {
|
|
31945
32835
|
return response;
|
|
31946
32836
|
}
|
|
31947
|
-
|
|
32837
|
+
debug3(
|
|
31948
32838
|
`${label}: HTTP ${response.status} (attempt ${attempt + 1}/${maxRetries + 1}), retrying`
|
|
31949
32839
|
);
|
|
31950
32840
|
lastError = new Error(`HTTP ${response.status}`);
|
|
31951
32841
|
} catch (err) {
|
|
31952
32842
|
lastError = err;
|
|
31953
32843
|
if (attempt >= maxRetries) break;
|
|
31954
|
-
|
|
32844
|
+
debug3(
|
|
31955
32845
|
`${label}: fetch failed (attempt ${attempt + 1}/${maxRetries + 1}): ${errorMessage(err)}`
|
|
31956
32846
|
);
|
|
31957
32847
|
}
|
|
31958
32848
|
if (attempt < maxRetries) {
|
|
31959
|
-
const delay =
|
|
32849
|
+
const delay = resolveBackoffDelay2(backoffMs, attempt, 3e3) + (jitter ? Math.floor(Math.random() * 500) : 0);
|
|
31960
32850
|
await abortableSleep(delay, externalSignal);
|
|
31961
32851
|
}
|
|
31962
32852
|
}
|
|
@@ -32033,7 +32923,7 @@ function isRetryableNetworkError(error49) {
|
|
|
32033
32923
|
return Boolean(causeCode && RETRYABLE_NETWORK_CODES.has(causeCode));
|
|
32034
32924
|
}
|
|
32035
32925
|
function resolveBaseUrl(_path) {
|
|
32036
|
-
const apiBase =
|
|
32926
|
+
const apiBase = getConfiguredApiBaseUrl2();
|
|
32037
32927
|
if (apiBase) {
|
|
32038
32928
|
return { ok: true, baseUrl: apiBase };
|
|
32039
32929
|
}
|
|
@@ -32060,7 +32950,7 @@ function parseErrorPayload(rawText) {
|
|
|
32060
32950
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
32061
32951
|
return parsed;
|
|
32062
32952
|
} catch (err) {
|
|
32063
|
-
|
|
32953
|
+
debug3(`parseErrorPayload: non-JSON body: ${errorMessage(err)}`);
|
|
32064
32954
|
return null;
|
|
32065
32955
|
}
|
|
32066
32956
|
}
|
|
@@ -32077,20 +32967,20 @@ function buildHttpError(status, rawText) {
|
|
|
32077
32967
|
}
|
|
32078
32968
|
async function tryRefreshToken() {
|
|
32079
32969
|
try {
|
|
32080
|
-
const creds =
|
|
32970
|
+
const creds = getStoredCredentials2();
|
|
32081
32971
|
if (!creds || !creds.refreshToken) {
|
|
32082
|
-
|
|
32972
|
+
debug3("Token refresh skipped: no stored credentials or refresh token");
|
|
32083
32973
|
return null;
|
|
32084
32974
|
}
|
|
32085
|
-
const refreshed = await
|
|
32975
|
+
const refreshed = await refreshCliSession2(creds);
|
|
32086
32976
|
if (!refreshed) {
|
|
32087
32977
|
warn(
|
|
32088
32978
|
"Token refresh failed: server returned no credentials (session may have expired \u2014 run `archal login`)"
|
|
32089
32979
|
);
|
|
32090
32980
|
return null;
|
|
32091
32981
|
}
|
|
32092
|
-
|
|
32093
|
-
|
|
32982
|
+
saveCredentials(refreshed);
|
|
32983
|
+
debug3("Token refreshed successfully");
|
|
32094
32984
|
return refreshed.token;
|
|
32095
32985
|
} catch (err) {
|
|
32096
32986
|
const msg = errorMessage(err);
|
|
@@ -32140,7 +33030,7 @@ async function request(method, path, token, body, timeoutOrOptions) {
|
|
|
32140
33030
|
method,
|
|
32141
33031
|
headers,
|
|
32142
33032
|
body: body ? JSON.stringify(body) : void 0,
|
|
32143
|
-
signal: AbortSignal.timeout(options.timeoutMs ??
|
|
33033
|
+
signal: AbortSignal.timeout(options.timeoutMs ?? REQUEST_TIMEOUT_MS2)
|
|
32144
33034
|
});
|
|
32145
33035
|
if (!response.ok) {
|
|
32146
33036
|
if (response.status === 401 && token && !refreshAttempted) {
|
|
@@ -32154,7 +33044,7 @@ async function request(method, path, token, body, timeoutOrOptions) {
|
|
|
32154
33044
|
}
|
|
32155
33045
|
if (retriesAllowed && !softAuthRetryAttempted && getMaxRetries() > 0 && token) {
|
|
32156
33046
|
softAuthRetryAttempted = true;
|
|
32157
|
-
|
|
33047
|
+
debug3(`401 on ${method} ${path}: soft-retrying once after backoff`);
|
|
32158
33048
|
await sleep(retryDelayMs(1, response.headers.get("retry-after")));
|
|
32159
33049
|
attempt -= 1;
|
|
32160
33050
|
continue;
|
|
@@ -32267,7 +33157,7 @@ function requestLlmCompletion(token, body) {
|
|
|
32267
33157
|
LLM_PROXY_TIMEOUT_MS
|
|
32268
33158
|
);
|
|
32269
33159
|
}
|
|
32270
|
-
var
|
|
33160
|
+
var REQUEST_TIMEOUT_MS2, LLM_PROXY_TIMEOUT_MS, ERROR_BODY_PREVIEW_LENGTH, RETRYABLE_STATUS_CODES, NON_RETRYABLE_ERROR_CODES, RETRYABLE_NETWORK_CODES;
|
|
32271
33161
|
var init_api_client = __esm({
|
|
32272
33162
|
"src/api-client.ts"() {
|
|
32273
33163
|
"use strict";
|
|
@@ -32275,7 +33165,7 @@ var init_api_client = __esm({
|
|
|
32275
33165
|
init_version();
|
|
32276
33166
|
init_logger();
|
|
32277
33167
|
init_auth();
|
|
32278
|
-
|
|
33168
|
+
REQUEST_TIMEOUT_MS2 = 8e3;
|
|
32279
33169
|
LLM_PROXY_TIMEOUT_MS = 9e4;
|
|
32280
33170
|
ERROR_BODY_PREVIEW_LENGTH = 200;
|
|
32281
33171
|
RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([408, 425, 429, 500, 502, 503, 504]);
|
|
@@ -32430,7 +33320,7 @@ var init_config_schemas = __esm({
|
|
|
32430
33320
|
|
|
32431
33321
|
// src/config/config-loader.ts
|
|
32432
33322
|
function getArchalDir2() {
|
|
32433
|
-
return process.env["ARCHAL_HOME"] ?? (0, import_node_path3.join)((0, import_node_os2.homedir)(),
|
|
33323
|
+
return process.env["ARCHAL_HOME"] ?? (0, import_node_path3.join)((0, import_node_os2.homedir)(), ARCHAL_DIR_NAME2);
|
|
32434
33324
|
}
|
|
32435
33325
|
function getConfigPath() {
|
|
32436
33326
|
return (0, import_node_path3.join)(getArchalDir2(), CONFIG_FILE_NAME);
|
|
@@ -32438,18 +33328,18 @@ function getConfigPath() {
|
|
|
32438
33328
|
function getProjectConfigPath(cwd = process.cwd()) {
|
|
32439
33329
|
return (0, import_node_path3.join)(cwd, ".archal.json");
|
|
32440
33330
|
}
|
|
32441
|
-
function
|
|
33331
|
+
function ensureArchalDir2() {
|
|
32442
33332
|
const dir = getArchalDir2();
|
|
32443
33333
|
if (!(0, import_node_fs5.existsSync)(dir)) {
|
|
32444
33334
|
(0, import_node_fs5.mkdirSync)(dir, { recursive: true });
|
|
32445
|
-
|
|
33335
|
+
debug3("Created archal directory", { path: dir });
|
|
32446
33336
|
}
|
|
32447
33337
|
return dir;
|
|
32448
33338
|
}
|
|
32449
33339
|
function loadConfigFile() {
|
|
32450
33340
|
const configPath = getConfigPath();
|
|
32451
33341
|
if (!(0, import_node_fs5.existsSync)(configPath)) {
|
|
32452
|
-
|
|
33342
|
+
debug3("No config file found, using defaults", { path: configPath });
|
|
32453
33343
|
return configFileSchema.parse({});
|
|
32454
33344
|
}
|
|
32455
33345
|
try {
|
|
@@ -32469,7 +33359,7 @@ Warning: evaluator.provider="${String(evaluator["provider"])}" in ${configPath}
|
|
|
32469
33359
|
}
|
|
32470
33360
|
}
|
|
32471
33361
|
const config2 = configFileSchema.parse(parsed);
|
|
32472
|
-
|
|
33362
|
+
debug3("Loaded config file", { path: configPath });
|
|
32473
33363
|
return config2;
|
|
32474
33364
|
} catch (err) {
|
|
32475
33365
|
const message = errorMessage(err);
|
|
@@ -32500,10 +33390,10 @@ function writeConfigFile(configPath, config2) {
|
|
|
32500
33390
|
encoding: "utf-8",
|
|
32501
33391
|
mode: 384
|
|
32502
33392
|
});
|
|
32503
|
-
|
|
33393
|
+
debug3("Saved config file", { path: configPath });
|
|
32504
33394
|
}
|
|
32505
33395
|
function saveConfig(config2) {
|
|
32506
|
-
const dir =
|
|
33396
|
+
const dir = ensureArchalDir2();
|
|
32507
33397
|
const configPath = (0, import_node_path3.join)(dir, CONFIG_FILE_NAME);
|
|
32508
33398
|
let existing;
|
|
32509
33399
|
if ((0, import_node_fs5.existsSync)(configPath)) {
|
|
@@ -32545,7 +33435,7 @@ function initConfig() {
|
|
|
32545
33435
|
return configPath;
|
|
32546
33436
|
}
|
|
32547
33437
|
const defaultConfig = configFileSchema.parse({});
|
|
32548
|
-
|
|
33438
|
+
ensureArchalDir2();
|
|
32549
33439
|
(0, import_node_fs5.writeFileSync)(configPath, JSON.stringify(defaultConfig, null, 2) + "\n", {
|
|
32550
33440
|
encoding: "utf-8",
|
|
32551
33441
|
mode: 384
|
|
@@ -32575,7 +33465,7 @@ function saveProjectConfig(config2, cwd = process.cwd()) {
|
|
|
32575
33465
|
});
|
|
32576
33466
|
return projectConfigPath;
|
|
32577
33467
|
}
|
|
32578
|
-
var import_node_fs5, import_node_path3, import_node_os2,
|
|
33468
|
+
var import_node_fs5, import_node_path3, import_node_os2, ARCHAL_DIR_NAME2, CONFIG_FILE_NAME;
|
|
32579
33469
|
var init_config_loader = __esm({
|
|
32580
33470
|
"src/config/config-loader.ts"() {
|
|
32581
33471
|
"use strict";
|
|
@@ -32585,7 +33475,7 @@ var init_config_loader = __esm({
|
|
|
32585
33475
|
init_dist2();
|
|
32586
33476
|
init_logger();
|
|
32587
33477
|
init_config_schemas();
|
|
32588
|
-
|
|
33478
|
+
ARCHAL_DIR_NAME2 = ".archal";
|
|
32589
33479
|
CONFIG_FILE_NAME = "config.json";
|
|
32590
33480
|
}
|
|
32591
33481
|
});
|
|
@@ -32863,7 +33753,7 @@ var init_config_display = __esm({
|
|
|
32863
33753
|
var config_exports = {};
|
|
32864
33754
|
__export(config_exports, {
|
|
32865
33755
|
bindConfigToLogin: () => bindConfigToLogin,
|
|
32866
|
-
ensureArchalDir: () =>
|
|
33756
|
+
ensureArchalDir: () => ensureArchalDir2,
|
|
32867
33757
|
formatConfiguredSecret: () => formatConfiguredSecret,
|
|
32868
33758
|
getArchalDir: () => getArchalDir2,
|
|
32869
33759
|
getConfigDisplay: () => getConfigDisplay,
|
|
@@ -32975,9 +33865,9 @@ function buildModelBackendHint() {
|
|
|
32975
33865
|
function buildOpenClawFailureMessage(parsed) {
|
|
32976
33866
|
const status = parsed.status?.trim() || "unknown";
|
|
32977
33867
|
const outputText = collectResponseText(parsed);
|
|
32978
|
-
const
|
|
33868
|
+
const errorMessage22 = parsed.error?.message?.trim();
|
|
32979
33869
|
let message = `OpenClaw returned non-success status: ${status}`;
|
|
32980
|
-
const details = [
|
|
33870
|
+
const details = [errorMessage22, outputText].filter((value) => Boolean(value && value.trim())).join(" | ");
|
|
32981
33871
|
if (details) {
|
|
32982
33872
|
message += `
|
|
32983
33873
|
Gateway output: ${details.slice(0, 500)}`;
|
|
@@ -33097,7 +33987,7 @@ ${buildModelBackendHint()}`);
|
|
|
33097
33987
|
clearTimeout(timer);
|
|
33098
33988
|
}
|
|
33099
33989
|
}
|
|
33100
|
-
async function consumeSSEStream(body, signal,
|
|
33990
|
+
async function consumeSSEStream(body, signal, debug5) {
|
|
33101
33991
|
const decoder = new TextDecoder();
|
|
33102
33992
|
const reader = body.getReader();
|
|
33103
33993
|
let buffer = "";
|
|
@@ -33132,7 +34022,7 @@ async function consumeSSEStream(body, signal, debug3) {
|
|
|
33132
34022
|
eventCount++;
|
|
33133
34023
|
const eventType = typeof event["type"] === "string" ? event["type"] : "";
|
|
33134
34024
|
if (eventType) {
|
|
33135
|
-
|
|
34025
|
+
debug5("SSE event", { type: eventType, count: eventCount });
|
|
33136
34026
|
}
|
|
33137
34027
|
if (eventType === "response.completed" && event["response"]) {
|
|
33138
34028
|
lastResponse = event["response"];
|
|
@@ -33144,7 +34034,7 @@ async function consumeSSEStream(body, signal, debug3) {
|
|
|
33144
34034
|
}
|
|
33145
34035
|
}
|
|
33146
34036
|
} catch {
|
|
33147
|
-
|
|
34037
|
+
debug5("SSE parse error", { data: jsonStr.slice(0, 200) });
|
|
33148
34038
|
}
|
|
33149
34039
|
boundary = buffer.indexOf("\n\n");
|
|
33150
34040
|
}
|
|
@@ -33167,7 +34057,7 @@ async function consumeSSEStream(body, signal, debug3) {
|
|
|
33167
34057
|
return lastResponse;
|
|
33168
34058
|
}
|
|
33169
34059
|
async function executeOpenClawRemote(remoteConfig, scenario, runId, taskMessage, twinUrls, apiRouting, openclawEvalMode, logger) {
|
|
33170
|
-
const
|
|
34060
|
+
const debug5 = logger?.debug ?? (() => {
|
|
33171
34061
|
});
|
|
33172
34062
|
const info2 = logger?.info ?? (() => {
|
|
33173
34063
|
});
|
|
@@ -33201,11 +34091,11 @@ async function executeOpenClawRemote(remoteConfig, scenario, runId, taskMessage,
|
|
|
33201
34091
|
timeout: `${remoteConfig.timeoutMs}ms`,
|
|
33202
34092
|
...remoteConfig.agentId ? { agentId: remoteConfig.agentId } : {}
|
|
33203
34093
|
});
|
|
33204
|
-
|
|
34094
|
+
debug5("Task message being sent to OpenClaw:", {
|
|
33205
34095
|
taskMessage: taskMessage.replace(/x-archal-admin-token:\s*\S+/gi, "x-archal-admin-token: [REDACTED]").replace(/Authorization:\s*Bearer\s+\S+/gi, "Authorization: Bearer [REDACTED]").slice(0, 2e3)
|
|
33206
34096
|
});
|
|
33207
|
-
|
|
33208
|
-
|
|
34097
|
+
debug5("Twin URLs:", { twinUrls: JSON.stringify(twinUrls) });
|
|
34098
|
+
debug5("API routing:", {
|
|
33209
34099
|
apiRouting: JSON.stringify({
|
|
33210
34100
|
...apiRouting,
|
|
33211
34101
|
bearerToken: apiRouting?.bearerToken ? "[REDACTED]" : void 0,
|
|
@@ -33236,7 +34126,7 @@ ${rawBody}${hint}`.trim(),
|
|
|
33236
34126
|
let parsed;
|
|
33237
34127
|
if (isSSE && response.body) {
|
|
33238
34128
|
info2("OpenClaw streaming SSE response detected");
|
|
33239
|
-
parsed = await consumeSSEStream(response.body, controller.signal,
|
|
34129
|
+
parsed = await consumeSSEStream(response.body, controller.signal, debug5);
|
|
33240
34130
|
} else {
|
|
33241
34131
|
const rawBody = await response.text();
|
|
33242
34132
|
try {
|
|
@@ -33303,7 +34193,7 @@ ${buildModelBackendHint()}` : `OpenClaw error: ${parsed.error.message}`,
|
|
|
33303
34193
|
}
|
|
33304
34194
|
}
|
|
33305
34195
|
var OPENCLAW_SUCCESS_STATUSES, OPENCLAW_BACKEND_FAILURE_PATTERNS;
|
|
33306
|
-
var
|
|
34196
|
+
var init_dist4 = __esm({
|
|
33307
34197
|
"../packages/openclaw-runtime/dist/index.js"() {
|
|
33308
34198
|
"use strict";
|
|
33309
34199
|
init_dist2();
|
|
@@ -42823,7 +43713,7 @@ function executeSeedCode(code, twinName, baseSeed, timeoutMs = DEFAULT_TIMEOUT_M
|
|
|
42823
43713
|
};
|
|
42824
43714
|
}
|
|
42825
43715
|
}
|
|
42826
|
-
function
|
|
43716
|
+
function debug4(logger, message, fields) {
|
|
42827
43717
|
logger?.debug?.(message, fields);
|
|
42828
43718
|
}
|
|
42829
43719
|
function warn2(logger, message, fields) {
|
|
@@ -42887,23 +43777,23 @@ async function runLegacySeedCodegen(options) {
|
|
|
42887
43777
|
} = options;
|
|
42888
43778
|
const initialResponse = await generateText(initialPrompt);
|
|
42889
43779
|
if (!initialResponse) {
|
|
42890
|
-
|
|
43780
|
+
debug4(logger, "Codegen: LLM returned empty response");
|
|
42891
43781
|
return null;
|
|
42892
43782
|
}
|
|
42893
43783
|
let generatedCode = extractExecutableCode(initialResponse);
|
|
42894
|
-
|
|
42895
|
-
|
|
43784
|
+
debug4(logger, "Codegen: LLM raw response", { response: initialResponse.slice(0, 500) });
|
|
43785
|
+
debug4(logger, "Codegen: executing generated code", {
|
|
42896
43786
|
length: String(generatedCode.length),
|
|
42897
43787
|
code: generatedCode.slice(0, 500)
|
|
42898
43788
|
});
|
|
42899
43789
|
let execution = executeSeedCode(generatedCode, twinName, baseSeedData);
|
|
42900
43790
|
for (let repair = 1; repair <= maxRepairAttempts && !execution.ok; repair += 1) {
|
|
42901
|
-
|
|
43791
|
+
debug4(logger, `Codegen: attempt failed (repair ${repair}/${maxRepairAttempts})`, {
|
|
42902
43792
|
type: execution.type,
|
|
42903
43793
|
message: execution.message.slice(0, 300)
|
|
42904
43794
|
});
|
|
42905
43795
|
if (execution.type === "timeout") {
|
|
42906
|
-
|
|
43796
|
+
debug4(logger, "Codegen: aborting repair loop \u2014 timeout indicates infinite loop");
|
|
42907
43797
|
return null;
|
|
42908
43798
|
}
|
|
42909
43799
|
if (deadline !== void 0 && Date.now() >= deadline) {
|
|
@@ -42912,13 +43802,13 @@ async function runLegacySeedCodegen(options) {
|
|
|
42912
43802
|
}
|
|
42913
43803
|
const repairResponse = await generateText(buildRepairPrompt2(generatedCode, execution.message));
|
|
42914
43804
|
if (!repairResponse) {
|
|
42915
|
-
|
|
43805
|
+
debug4(logger, `Codegen: repair ${repair} \u2014 LLM returned empty response`);
|
|
42916
43806
|
break;
|
|
42917
43807
|
}
|
|
42918
43808
|
generatedCode = extractExecutableCode(repairResponse);
|
|
42919
43809
|
execution = executeSeedCode(generatedCode, twinName, baseSeedData);
|
|
42920
43810
|
if (execution.ok) {
|
|
42921
|
-
|
|
43811
|
+
debug4(logger, `Codegen: repair ${repair} succeeded`);
|
|
42922
43812
|
}
|
|
42923
43813
|
}
|
|
42924
43814
|
if (!execution.ok) {
|
|
@@ -42931,7 +43821,7 @@ async function runLegacySeedCodegen(options) {
|
|
|
42931
43821
|
if (deadline !== void 0 && Date.now() >= deadline) {
|
|
42932
43822
|
return null;
|
|
42933
43823
|
}
|
|
42934
|
-
|
|
43824
|
+
debug4(logger, "Codegen: trying simplified prompt with core functions only");
|
|
42935
43825
|
const simplifiedResponse = await generateText(simplifiedPrompt);
|
|
42936
43826
|
if (!simplifiedResponse) {
|
|
42937
43827
|
return null;
|
|
@@ -42939,12 +43829,12 @@ async function runLegacySeedCodegen(options) {
|
|
|
42939
43829
|
generatedCode = extractExecutableCode(simplifiedResponse);
|
|
42940
43830
|
execution = executeSeedCode(generatedCode, twinName, baseSeedData);
|
|
42941
43831
|
if (!execution.ok) {
|
|
42942
|
-
|
|
43832
|
+
debug4(logger, "Codegen: simplified prompt also failed", {
|
|
42943
43833
|
error: execution.message.slice(0, 200)
|
|
42944
43834
|
});
|
|
42945
43835
|
return null;
|
|
42946
43836
|
}
|
|
42947
|
-
|
|
43837
|
+
debug4(logger, "Codegen: simplified prompt succeeded");
|
|
42948
43838
|
}
|
|
42949
43839
|
return {
|
|
42950
43840
|
execution,
|
|
@@ -43020,7 +43910,7 @@ ${setupDescription}
|
|
|
43020
43910
|
Write ONLY JavaScript function calls. No imports, no markdown, no prose.`;
|
|
43021
43911
|
}
|
|
43022
43912
|
function resolveManagedApiBaseUrl() {
|
|
43023
|
-
const apiBase =
|
|
43913
|
+
const apiBase = getConfiguredApiBaseUrl() ?? getConfiguredAuthBaseUrl();
|
|
43024
43914
|
if (apiBase) {
|
|
43025
43915
|
return apiBase;
|
|
43026
43916
|
}
|
|
@@ -43097,16 +43987,16 @@ async function withRetry2(fn, label) {
|
|
|
43097
43987
|
throw lastError ?? new Error(`${label}: all ${MAX_RETRIES2 + 1} attempts failed`);
|
|
43098
43988
|
}
|
|
43099
43989
|
async function tryRefreshToken2() {
|
|
43100
|
-
const stored =
|
|
43990
|
+
const stored = getStoredCredentials();
|
|
43101
43991
|
if (!stored?.refreshToken) {
|
|
43102
43992
|
return null;
|
|
43103
43993
|
}
|
|
43104
43994
|
try {
|
|
43105
|
-
const refreshed = await
|
|
43995
|
+
const refreshed = await refreshCliSession(stored);
|
|
43106
43996
|
if (!refreshed) {
|
|
43107
43997
|
return null;
|
|
43108
43998
|
}
|
|
43109
|
-
|
|
43999
|
+
saveCredentials(refreshed);
|
|
43110
44000
|
return refreshed.token;
|
|
43111
44001
|
} catch {
|
|
43112
44002
|
return null;
|
|
@@ -43158,7 +44048,7 @@ async function requestManagedSeedCompletion(token, body) {
|
|
|
43158
44048
|
}
|
|
43159
44049
|
}
|
|
43160
44050
|
async function callManagedSeedLlm(options) {
|
|
43161
|
-
const creds =
|
|
44051
|
+
const creds = getCredentials();
|
|
43162
44052
|
const token = creds?.token;
|
|
43163
44053
|
const runtimeAdminToken = process.env["ARCHAL_RUNTIME_ADMIN_TOKEN"]?.trim();
|
|
43164
44054
|
if (!token && !runtimeAdminToken) {
|
|
@@ -43289,7 +44179,7 @@ async function callSeedLlm(options) {
|
|
|
43289
44179
|
if (routing === "direct-only" || options.apiKey.trim()) {
|
|
43290
44180
|
return callDirectSeedLlm(options);
|
|
43291
44181
|
}
|
|
43292
|
-
const creds =
|
|
44182
|
+
const creds = getCredentials();
|
|
43293
44183
|
if (creds?.token || process.env["ARCHAL_RUNTIME_ADMIN_TOKEN"]?.trim()) {
|
|
43294
44184
|
try {
|
|
43295
44185
|
return await callManagedSeedLlm(options);
|
|
@@ -43581,14 +44471,14 @@ function augmentPlanFromDescription(plan, description, twinName) {
|
|
|
43581
44471
|
planTypes.add(rule.type);
|
|
43582
44472
|
}
|
|
43583
44473
|
}
|
|
43584
|
-
var import_vm,
|
|
43585
|
-
var
|
|
44474
|
+
var import_vm, MS_PER_DAY, ISSUE_TITLES, ISSUE_BODIES, PR_TITLES, CHANNEL_PURPOSES, MESSAGE_TEXTS, DEFAULT_REACTIONS, MAX_BULK_COUNT, SeedCollector, TWIN_CONTEXT_BUILDERS, FORBIDDEN_PATTERN, OBFUSCATION_PATTERNS, DEFAULT_TIMEOUT_MS2, SDK_DECLARATIONS, SDK_EXAMPLES, CODEGEN_SYSTEM_PROMPT, GEMINI_API_BASE_URL2, ANTHROPIC_API_URL2, OPENAI_API_URL2, ANTHROPIC_API_VERSION2, MANAGED_SEED_TIMEOUT_MS, DIRECT_SEED_TIMEOUT_MS, ERROR_BODY_PREVIEW_LENGTH3, RETRYABLE_STATUS_CODES3, MAX_RETRIES2, INITIAL_BACKOFF_MS2, MAX_JITTER_MS2, SeedLlmApiError, PLAN_SYSTEM_PROMPT, ENTITY_TYPE_TO_COLLECTION;
|
|
44475
|
+
var init_dist5 = __esm({
|
|
43586
44476
|
"../packages/seed-codegen-runtime/dist/index.js"() {
|
|
43587
44477
|
"use strict";
|
|
43588
44478
|
import_vm = __toESM(require("vm"), 1);
|
|
43589
44479
|
init_dist2();
|
|
43590
44480
|
init_dist2();
|
|
43591
|
-
|
|
44481
|
+
init_dist3();
|
|
43592
44482
|
MS_PER_DAY = 864e5;
|
|
43593
44483
|
ISSUE_TITLES = [
|
|
43594
44484
|
"Fix login redirect loop on Safari",
|
|
@@ -48600,14 +49490,14 @@ function applyPlanDrivenFill(seed, plan, forTwin) {
|
|
|
48600
49490
|
filled += 6;
|
|
48601
49491
|
}
|
|
48602
49492
|
if (filled > 0) {
|
|
48603
|
-
|
|
49493
|
+
debug3("Plan-driven fill: injected " + filled + " entities");
|
|
48604
49494
|
}
|
|
48605
49495
|
return filled;
|
|
48606
49496
|
}
|
|
48607
49497
|
var init_plan_fill = __esm({
|
|
48608
49498
|
"src/runner/seed/plan-fill.ts"() {
|
|
48609
49499
|
"use strict";
|
|
48610
|
-
|
|
49500
|
+
init_dist5();
|
|
48611
49501
|
init_logger();
|
|
48612
49502
|
init_fill_templates();
|
|
48613
49503
|
}
|
|
@@ -49083,7 +49973,7 @@ function autoFillMissingFKs(seed, twinName) {
|
|
|
49083
49973
|
if (needsFill) {
|
|
49084
49974
|
if (rule.optional) {
|
|
49085
49975
|
if (currentValue !== void 0 && currentValue !== null && !validTargetSet.has(String(currentValue))) {
|
|
49086
|
-
|
|
49976
|
+
debug3(
|
|
49087
49977
|
`Auto-filling ${rule.sourceCollection}.${rule.sourceField} = null (was ${String(currentValue)} \u2014 invalid optional FK)`
|
|
49088
49978
|
);
|
|
49089
49979
|
e[rule.sourceField] = null;
|
|
@@ -49092,7 +49982,7 @@ function autoFillMissingFKs(seed, twinName) {
|
|
|
49092
49982
|
}
|
|
49093
49983
|
const fillValue = targetValues[fillIndex % targetValues.length];
|
|
49094
49984
|
fillIndex++;
|
|
49095
|
-
|
|
49985
|
+
debug3(
|
|
49096
49986
|
`Auto-filling ${rule.sourceCollection}.${rule.sourceField} = ${String(fillValue)} (from ${targetValues.length} ${rule.targetCollection})` + (currentValue != null ? ` (was ${String(currentValue)} \u2014 not in targets)` : "")
|
|
49097
49987
|
);
|
|
49098
49988
|
e[rule.sourceField] = fillValue;
|
|
@@ -49156,11 +50046,11 @@ function normalizeSeedData(seed, twinName) {
|
|
|
49156
50046
|
if (wrongName in e) {
|
|
49157
50047
|
if (!(correctName in e)) {
|
|
49158
50048
|
e[correctName] = e[wrongName];
|
|
49159
|
-
|
|
50049
|
+
debug3(
|
|
49160
50050
|
`Seed normalization: renamed ${collection}.${wrongName} \u2192 ${correctName}`
|
|
49161
50051
|
);
|
|
49162
50052
|
} else {
|
|
49163
|
-
|
|
50053
|
+
debug3(
|
|
49164
50054
|
`Seed normalization: dropped duplicate ${collection}.${wrongName} (${correctName} already exists)`
|
|
49165
50055
|
);
|
|
49166
50056
|
}
|
|
@@ -49178,15 +50068,15 @@ function normalizeSeedData(seed, twinName) {
|
|
|
49178
50068
|
const obj = e[field];
|
|
49179
50069
|
const extracted = obj["login"] ?? obj["name"] ?? obj["value"] ?? obj["key"] ?? obj["id"] ?? obj["displayName"];
|
|
49180
50070
|
if (typeof extracted === "string") {
|
|
49181
|
-
|
|
50071
|
+
debug3(`Seed normalization: coerced ${collection}.${field} from object to string "${extracted}"`);
|
|
49182
50072
|
e[field] = extracted;
|
|
49183
50073
|
} else {
|
|
49184
50074
|
const firstStr2 = Object.values(obj).find((v) => typeof v === "string");
|
|
49185
50075
|
if (firstStr2) {
|
|
49186
|
-
|
|
50076
|
+
debug3(`Seed normalization: coerced ${collection}.${field} from object to string "${firstStr2}" (fallback)`);
|
|
49187
50077
|
e[field] = firstStr2;
|
|
49188
50078
|
} else {
|
|
49189
|
-
|
|
50079
|
+
debug3(`Seed normalization: could not coerce ${collection}.${field} from object to string, removing`);
|
|
49190
50080
|
delete e[field];
|
|
49191
50081
|
}
|
|
49192
50082
|
}
|
|
@@ -49212,7 +50102,7 @@ function normalizeSeedData(seed, twinName) {
|
|
|
49212
50102
|
const e = entity;
|
|
49213
50103
|
if ((!e["fullName"] || typeof e["fullName"] !== "string") && typeof e["owner"] === "string" && typeof e["name"] === "string") {
|
|
49214
50104
|
e["fullName"] = `${e["owner"]}/${e["name"]}`;
|
|
49215
|
-
|
|
50105
|
+
debug3(`Seed normalization: derived repos.fullName = "${e["fullName"]}"`);
|
|
49216
50106
|
}
|
|
49217
50107
|
}
|
|
49218
50108
|
}
|
|
@@ -51019,7 +51909,7 @@ function evictStaleEntries() {
|
|
|
51019
51909
|
const age = now - (0, import_node_fs8.statSync)(filePath).mtimeMs;
|
|
51020
51910
|
if (age > MAX_AGE_MS) {
|
|
51021
51911
|
(0, import_node_fs8.unlinkSync)(filePath);
|
|
51022
|
-
|
|
51912
|
+
debug3("Evicted stale cache entry", { file: file2 });
|
|
51023
51913
|
}
|
|
51024
51914
|
}
|
|
51025
51915
|
} catch (evictErr) {
|
|
@@ -51056,7 +51946,7 @@ function getCachedSeed(twinName, baseSeedName, setupText, scope) {
|
|
|
51056
51946
|
}
|
|
51057
51947
|
return null;
|
|
51058
51948
|
}
|
|
51059
|
-
|
|
51949
|
+
debug3("Seed cache hit", { twin: twinName, baseSeed: baseSeedName, key });
|
|
51060
51950
|
return { seed: entry.seed, patch: entry.patch };
|
|
51061
51951
|
} catch {
|
|
51062
51952
|
warn("Failed to read seed cache entry");
|
|
@@ -51077,7 +51967,7 @@ function cacheSeed(twinName, baseSeedName, setupText, seed, patch, scope, genera
|
|
|
51077
51967
|
} = cacheFilePathScoped(twinName, baseSeedName, setupText, scope);
|
|
51078
51968
|
const mismatches = verifySeedCounts(setupText, seed);
|
|
51079
51969
|
if (mismatches.length > 0) {
|
|
51080
|
-
|
|
51970
|
+
debug3("Skipping cache write \u2014 seed failed count verification", {
|
|
51081
51971
|
twin: twinName,
|
|
51082
51972
|
mismatches: mismatches.map((m) => `${m.subject}: ${m.expected} vs ${m.actual}`).join("; ")
|
|
51083
51973
|
});
|
|
@@ -51098,7 +51988,7 @@ function cacheSeed(twinName, baseSeedName, setupText, seed, patch, scope, genera
|
|
|
51098
51988
|
...generatedCode !== void 0 && { generatedCode }
|
|
51099
51989
|
};
|
|
51100
51990
|
(0, import_node_fs8.writeFileSync)(filePath, JSON.stringify(entry));
|
|
51101
|
-
|
|
51991
|
+
debug3("Seed cached", { twin: twinName, baseSeed: baseSeedName, key });
|
|
51102
51992
|
} catch {
|
|
51103
51993
|
warn("Failed to write seed cache entry");
|
|
51104
51994
|
}
|
|
@@ -51115,10 +52005,10 @@ function getNegativeSeed(twinName, baseSeedName, setupText, scope) {
|
|
|
51115
52005
|
}
|
|
51116
52006
|
const entry = JSON.parse(raw);
|
|
51117
52007
|
if (entry.version !== NEGATIVE_CACHE_VERSION) {
|
|
51118
|
-
|
|
52008
|
+
debug3("Negative seed cache version mismatch, ignoring cached entry");
|
|
51119
52009
|
return null;
|
|
51120
52010
|
}
|
|
51121
|
-
|
|
52011
|
+
debug3("Negative seed cache hit", { twin: twinName, baseSeed: baseSeedName, key });
|
|
51122
52012
|
return { missingSlots: entry.missingSlots };
|
|
51123
52013
|
} catch {
|
|
51124
52014
|
warn("Failed to read negative seed cache entry");
|
|
@@ -51149,7 +52039,7 @@ function cacheNegativeSeed(twinName, baseSeedName, setupText, missingSlots, scop
|
|
|
51149
52039
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
51150
52040
|
};
|
|
51151
52041
|
(0, import_node_fs8.writeFileSync)(filePath, JSON.stringify(entry));
|
|
51152
|
-
|
|
52042
|
+
debug3("Negative seed cached", { twin: twinName, baseSeed: baseSeedName, key });
|
|
51153
52043
|
} catch {
|
|
51154
52044
|
warn("Failed to write negative seed cache entry");
|
|
51155
52045
|
}
|
|
@@ -51163,7 +52053,7 @@ function clearSeedCache() {
|
|
|
51163
52053
|
(0, import_node_fs8.unlinkSync)((0, import_node_path6.join)(CACHE_DIR, file2));
|
|
51164
52054
|
}
|
|
51165
52055
|
}
|
|
51166
|
-
|
|
52056
|
+
debug3("Seed cache cleared");
|
|
51167
52057
|
} catch {
|
|
51168
52058
|
warn("Failed to clear seed cache");
|
|
51169
52059
|
}
|
|
@@ -51349,7 +52239,7 @@ async function callCodegenLlm(options, cooldownKey = "__global__") {
|
|
|
51349
52239
|
`ARCHAL_SEED_MODEL_OVERRIDE=${override} but ${keyEnv ?? `<unknown provider "${provider ?? ""}"`} is not set`
|
|
51350
52240
|
);
|
|
51351
52241
|
}
|
|
51352
|
-
|
|
52242
|
+
debug3(`Using seed model override: ${provider ?? ""}/${model}`);
|
|
51353
52243
|
return callSeedLlm({
|
|
51354
52244
|
...options,
|
|
51355
52245
|
provider: provider ?? "",
|
|
@@ -51360,7 +52250,7 @@ async function callCodegenLlm(options, cooldownKey = "__global__") {
|
|
|
51360
52250
|
}
|
|
51361
52251
|
const fallback = resolveDirectSeedFallback();
|
|
51362
52252
|
if (fallback && isManagedSeedBackendCoolingDown(cooldownKey)) {
|
|
51363
|
-
|
|
52253
|
+
debug3("Managed seed backend is cooling down; using direct fallback", {
|
|
51364
52254
|
provider: fallback.provider,
|
|
51365
52255
|
model: fallback.model
|
|
51366
52256
|
});
|
|
@@ -51398,7 +52288,7 @@ var MANAGED_SEED_CODEGEN_MODEL, DIRECT_SEED_FALLBACK_OPENAI_MODEL, DIRECT_SEED_F
|
|
|
51398
52288
|
var init_seed_codegen_llm = __esm({
|
|
51399
52289
|
"src/runner/seed/seed-codegen-llm.ts"() {
|
|
51400
52290
|
"use strict";
|
|
51401
|
-
|
|
52291
|
+
init_dist5();
|
|
51402
52292
|
init_logger();
|
|
51403
52293
|
init_session_context();
|
|
51404
52294
|
MANAGED_SEED_CODEGEN_MODEL = "claude-sonnet-4-6";
|
|
@@ -51548,15 +52438,15 @@ ${example}`;
|
|
|
51548
52438
|
}
|
|
51549
52439
|
async function enrichSeedWithLlm(seed, twinName, setupDescription, deadline, cooldownKey = "__global__") {
|
|
51550
52440
|
if (Date.now() >= deadline) {
|
|
51551
|
-
|
|
52441
|
+
debug3("Enrich: skipped \u2014 budget exhausted");
|
|
51552
52442
|
return 0;
|
|
51553
52443
|
}
|
|
51554
52444
|
const snapshot = buildEnrichableSnapshot(seed, twinName);
|
|
51555
52445
|
if (!snapshot) {
|
|
51556
|
-
|
|
52446
|
+
debug3("Enrich: skipped \u2014 no generic fields to enrich");
|
|
51557
52447
|
return 0;
|
|
51558
52448
|
}
|
|
51559
|
-
|
|
52449
|
+
debug3("Enrich: calling LLM to replace generic values");
|
|
51560
52450
|
try {
|
|
51561
52451
|
const response = await callCodegenLlm({
|
|
51562
52452
|
systemPrompt: ENRICH_SYSTEM_PROMPT,
|
|
@@ -51572,10 +52462,10 @@ ${snapshot}${buildFewShotExample(twinName)}`,
|
|
|
51572
52462
|
responseFormat: "json"
|
|
51573
52463
|
}, cooldownKey);
|
|
51574
52464
|
const applied = applyEnrichments(seed, response);
|
|
51575
|
-
|
|
52465
|
+
debug3("Enrich: applied " + applied + " field updates");
|
|
51576
52466
|
return applied;
|
|
51577
52467
|
} catch (error49) {
|
|
51578
|
-
|
|
52468
|
+
debug3("Enrich: LLM call failed, continuing with generic values", {
|
|
51579
52469
|
error: error49 instanceof Error ? error49.message : String(error49)
|
|
51580
52470
|
});
|
|
51581
52471
|
return 0;
|
|
@@ -51709,7 +52599,7 @@ function fixProjectKeys(seed, collectionName, issueCollectionName, fkField, issu
|
|
|
51709
52599
|
alreadyMatched
|
|
51710
52600
|
);
|
|
51711
52601
|
if (!project) {
|
|
51712
|
-
|
|
52602
|
+
debug3(`key-fixer: no project/team found to match prefix "${prefix}"`);
|
|
51713
52603
|
continue;
|
|
51714
52604
|
}
|
|
51715
52605
|
alreadyMatched.add(project["id"]);
|
|
@@ -51818,12 +52708,12 @@ function fixIssueKeys(seed, intent, twinName, options) {
|
|
|
51818
52708
|
for (const [prefix, expectedNumbers] of issueKeysByPrefix) {
|
|
51819
52709
|
const projectId = projectKeyToId.get(prefix);
|
|
51820
52710
|
if (projectId === void 0) {
|
|
51821
|
-
|
|
52711
|
+
debug3(`key-fixer: no project/team with key="${prefix}" found, skipping issue renumbering`);
|
|
51822
52712
|
continue;
|
|
51823
52713
|
}
|
|
51824
52714
|
const projectIssues = issues.filter((issue2) => issue2[fkField] === projectId);
|
|
51825
52715
|
if (projectIssues.length === 0 && !options?.fillMissing) {
|
|
51826
|
-
|
|
52716
|
+
debug3(`key-fixer: no issues found for ${fkField}=${String(projectId)} (prefix="${prefix}")`);
|
|
51827
52717
|
continue;
|
|
51828
52718
|
}
|
|
51829
52719
|
projectIssues.sort((a, b) => {
|
|
@@ -51833,7 +52723,7 @@ function fixIssueKeys(seed, intent, twinName, options) {
|
|
|
51833
52723
|
});
|
|
51834
52724
|
const pairCount = Math.min(expectedNumbers.length, projectIssues.length);
|
|
51835
52725
|
if (pairCount < expectedNumbers.length && !options?.fillMissing) {
|
|
51836
|
-
|
|
52726
|
+
debug3(
|
|
51837
52727
|
`key-fixer: expected ${expectedNumbers.length} issues for prefix "${prefix}" but only found ${projectIssues.length} in seed`
|
|
51838
52728
|
);
|
|
51839
52729
|
}
|
|
@@ -51892,7 +52782,7 @@ function fixIssueKeys(seed, intent, twinName, options) {
|
|
|
51892
52782
|
}
|
|
51893
52783
|
cloned[issueCollectionName] = issues;
|
|
51894
52784
|
if (fixes.length > 0) {
|
|
51895
|
-
|
|
52785
|
+
debug3(`key-fixer: applied ${fixes.length} fix(es)`);
|
|
51896
52786
|
}
|
|
51897
52787
|
return { seed: cloned, fixes };
|
|
51898
52788
|
}
|
|
@@ -51961,7 +52851,7 @@ function patchStripeDollarsToCents(seed, setupText) {
|
|
|
51961
52851
|
}
|
|
51962
52852
|
}
|
|
51963
52853
|
if (patches.length > 0) {
|
|
51964
|
-
|
|
52854
|
+
debug3(`Numeric patcher: applied ${patches.length} dollar\u2192cents fix(es)`);
|
|
51965
52855
|
}
|
|
51966
52856
|
return { seed: cloned, patches };
|
|
51967
52857
|
}
|
|
@@ -52128,7 +53018,7 @@ function patchStripeAmountsByContext(seed, setupText) {
|
|
|
52128
53018
|
}
|
|
52129
53019
|
}
|
|
52130
53020
|
if (patches.length > 0) {
|
|
52131
|
-
|
|
53021
|
+
debug3(`Context patcher: applied ${patches.length} context-aware amount fix(es)`);
|
|
52132
53022
|
}
|
|
52133
53023
|
return { seed: cloned, patches };
|
|
52134
53024
|
}
|
|
@@ -52223,7 +53113,7 @@ function patchIssueKeys(seed, setupText, twinName) {
|
|
|
52223
53113
|
}
|
|
52224
53114
|
}
|
|
52225
53115
|
if (patches.length > 0) {
|
|
52226
|
-
|
|
53116
|
+
debug3(`Numeric patcher: renumbered ${patches.length} issue key(s)`);
|
|
52227
53117
|
}
|
|
52228
53118
|
return { seed: cloned, patches };
|
|
52229
53119
|
}
|
|
@@ -52288,7 +53178,7 @@ function patchIssueStatuses(seed, setupText, twinName) {
|
|
|
52288
53178
|
}
|
|
52289
53179
|
if (patches.length > 0) {
|
|
52290
53180
|
cloned["statuses"] = clonedStatuses;
|
|
52291
|
-
|
|
53181
|
+
debug3(`Numeric patcher: applied ${patches.length} issue status fix(es)`);
|
|
52292
53182
|
}
|
|
52293
53183
|
return { seed: cloned, patches };
|
|
52294
53184
|
}
|
|
@@ -52368,7 +53258,7 @@ function patchGitHubPRNumbers(seed, setupText) {
|
|
|
52368
53258
|
nextIdx++;
|
|
52369
53259
|
}
|
|
52370
53260
|
if (patches.length > 0) {
|
|
52371
|
-
|
|
53261
|
+
debug3(`Numeric patcher: renumbered ${patches.length} GitHub PR(s)`);
|
|
52372
53262
|
}
|
|
52373
53263
|
return { seed: cloned, patches };
|
|
52374
53264
|
}
|
|
@@ -52655,14 +53545,14 @@ ${fkDetails}
|
|
|
52655
53545
|
if (countMismatches.length > 0) {
|
|
52656
53546
|
const trimmed = trimSeedToExpectedCounts(finalSeed, countMismatches);
|
|
52657
53547
|
if (trimmed > 0) {
|
|
52658
|
-
|
|
53548
|
+
debug3(`${prefix}: trimmed ${trimmed} excess entities to match setup counts`);
|
|
52659
53549
|
}
|
|
52660
53550
|
}
|
|
52661
53551
|
if (intent) {
|
|
52662
53552
|
const keyFixResult = fixIssueKeys(finalSeed, intent, twinName, { fillMissing: true });
|
|
52663
53553
|
if (keyFixResult.fixes.length > 0) {
|
|
52664
53554
|
finalSeed = keyFixResult.seed;
|
|
52665
|
-
|
|
53555
|
+
debug3(`${prefix}: applied ${keyFixResult.fixes.length} key fix(es)`);
|
|
52666
53556
|
finalSeed = autoFillMissingFKs(finalSeed, twinName);
|
|
52667
53557
|
}
|
|
52668
53558
|
}
|
|
@@ -52675,7 +53565,7 @@ ${fkDetails}
|
|
|
52675
53565
|
);
|
|
52676
53566
|
if (numericPatches.length > 0) {
|
|
52677
53567
|
finalSeed = patchedSeed;
|
|
52678
|
-
|
|
53568
|
+
debug3(`Numeric patcher: ${numericPatches.length} fix(es) applied`);
|
|
52679
53569
|
}
|
|
52680
53570
|
}
|
|
52681
53571
|
const finalPatch = computeSeedPatch(baseSeedData, finalSeed);
|
|
@@ -52728,7 +53618,7 @@ function buildSeedCacheContext(twinName, systemPromptHash, intent, context) {
|
|
|
52728
53618
|
async function tryCodegenPath(twinName, baseSeedData, setupDescription, intent, strictSeed, originalDescription, cooldownKey = "__global__") {
|
|
52729
53619
|
const deadline = Date.now() + CODEGEN_TOTAL_BUDGET_MS;
|
|
52730
53620
|
const planDescription = originalDescription ?? setupDescription;
|
|
52731
|
-
|
|
53621
|
+
debug3("Plan+Fill: Phase 1 \u2014 planning entity creation");
|
|
52732
53622
|
let plan = null;
|
|
52733
53623
|
try {
|
|
52734
53624
|
const planResponse = await callCodegenLlm({
|
|
@@ -52739,13 +53629,13 @@ async function tryCodegenPath(twinName, baseSeedData, setupDescription, intent,
|
|
|
52739
53629
|
}, cooldownKey);
|
|
52740
53630
|
plan = parseSeedPlan(planResponse);
|
|
52741
53631
|
} catch (error49) {
|
|
52742
|
-
|
|
53632
|
+
debug3("Plan+Fill: Phase 1 failed, falling back to legacy", {
|
|
52743
53633
|
error: error49 instanceof Error ? error49.message : String(error49)
|
|
52744
53634
|
});
|
|
52745
53635
|
}
|
|
52746
53636
|
if (!plan || plan.entities.length === 0) {
|
|
52747
53637
|
if (twinName === "supabase") {
|
|
52748
|
-
|
|
53638
|
+
debug3("Plan+Fill: Supabase \u2014 generating SQL directly from description (no plan)");
|
|
52749
53639
|
try {
|
|
52750
53640
|
const sqlResponse = await callCodegenLlm({
|
|
52751
53641
|
systemPrompt: SUPABASE_SQL_SYSTEM_PROMPT,
|
|
@@ -52764,16 +53654,16 @@ Generate the complete SQL script with CREATE TABLE, INSERT INTO, and any RLS pol
|
|
|
52764
53654
|
}
|
|
52765
53655
|
return { seed: {}, patch: { added: {}, removed: {}, modified: {} }, fromCache: false, source: "llm" };
|
|
52766
53656
|
}
|
|
52767
|
-
|
|
53657
|
+
debug3("Plan+Fill: No plan generated, falling back to legacy codegen");
|
|
52768
53658
|
return tryCodegenPathLegacy(twinName, baseSeedData, setupDescription, intent, strictSeed, planDescription, deadline, cooldownKey);
|
|
52769
53659
|
}
|
|
52770
53660
|
augmentPlanFromDescription(plan, planDescription, twinName);
|
|
52771
53661
|
plan = normalizePlan(plan);
|
|
52772
|
-
|
|
53662
|
+
debug3("Plan+Fill: plan has " + plan.entities.length + " entity types", {
|
|
52773
53663
|
types: plan.entities.map((e) => e.type).join(", ")
|
|
52774
53664
|
});
|
|
52775
53665
|
if (twinName === "supabase") {
|
|
52776
|
-
|
|
53666
|
+
debug3("Plan+Fill: Supabase \u2014 generating SQL from plan");
|
|
52777
53667
|
try {
|
|
52778
53668
|
const sqlPrompt = buildSupabaseSqlPrompt(plan, planDescription);
|
|
52779
53669
|
const sqlResponse = await callCodegenLlm({
|
|
@@ -52784,7 +53674,7 @@ Generate the complete SQL script with CREATE TABLE, INSERT INTO, and any RLS pol
|
|
|
52784
53674
|
}, cooldownKey);
|
|
52785
53675
|
const sql = extractSupabaseSql(sqlResponse);
|
|
52786
53676
|
if (sql.length > 50) {
|
|
52787
|
-
|
|
53677
|
+
debug3("Plan+Fill: Supabase SQL generated (" + sql.length + " chars)");
|
|
52788
53678
|
return {
|
|
52789
53679
|
seed: {},
|
|
52790
53680
|
patch: { added: {}, removed: {}, modified: {} },
|
|
@@ -52794,7 +53684,7 @@ Generate the complete SQL script with CREATE TABLE, INSERT INTO, and any RLS pol
|
|
|
52794
53684
|
};
|
|
52795
53685
|
}
|
|
52796
53686
|
} catch (error49) {
|
|
52797
|
-
|
|
53687
|
+
debug3("Plan+Fill: Supabase SQL generation failed", {
|
|
52798
53688
|
error: error49 instanceof Error ? error49.message : String(error49)
|
|
52799
53689
|
});
|
|
52800
53690
|
}
|
|
@@ -52812,7 +53702,7 @@ Generate the complete SQL script with CREATE TABLE, INSERT INTO, and any RLS pol
|
|
|
52812
53702
|
}
|
|
52813
53703
|
}
|
|
52814
53704
|
const filled = applyPlanDrivenFill(finalSeed, plan, twinName);
|
|
52815
|
-
|
|
53705
|
+
debug3("Plan+Fill: created " + filled + " entities deterministically");
|
|
52816
53706
|
finalSeed = normalizeSeedData(finalSeed, twinName);
|
|
52817
53707
|
finalSeed = autoFillMissingFKs(finalSeed, twinName);
|
|
52818
53708
|
await enrichSeedWithLlm(finalSeed, twinName, planDescription, deadline, cooldownKey);
|
|
@@ -52838,7 +53728,7 @@ async function tryCodegenPathLegacy(twinName, baseSeedData, setupDescription, in
|
|
|
52838
53728
|
twinName,
|
|
52839
53729
|
baseSeedData,
|
|
52840
53730
|
initialPrompt: buildCodegenUserPrompt(twinName, setupDescription),
|
|
52841
|
-
buildRepairPrompt: (generatedCode,
|
|
53731
|
+
buildRepairPrompt: (generatedCode, errorMessage3) => buildRepairPrompt(twinName, generatedCode, errorMessage3),
|
|
52842
53732
|
simplifiedPrompt,
|
|
52843
53733
|
deadline,
|
|
52844
53734
|
generateText: async (userPrompt) => callCodegenLlm({
|
|
@@ -52848,7 +53738,7 @@ async function tryCodegenPathLegacy(twinName, baseSeedData, setupDescription, in
|
|
|
52848
53738
|
responseFormat: "text"
|
|
52849
53739
|
}, cooldownKey),
|
|
52850
53740
|
logger: {
|
|
52851
|
-
debug,
|
|
53741
|
+
debug: debug3,
|
|
52852
53742
|
warn
|
|
52853
53743
|
}
|
|
52854
53744
|
});
|
|
@@ -53051,7 +53941,7 @@ async function tryCodegenPathLegacy(twinName, baseSeedData, setupDescription, in
|
|
|
53051
53941
|
}
|
|
53052
53942
|
}
|
|
53053
53943
|
if (needsFill) {
|
|
53054
|
-
|
|
53944
|
+
debug3(`Codegen: deterministic fill \u2014 ${lines.length} supplementary calls`);
|
|
53055
53945
|
const fillResult = executeSeedCode(lines.join("\n"), twinName, baseSeedData);
|
|
53056
53946
|
if (fillResult.ok) {
|
|
53057
53947
|
let merged = 0;
|
|
@@ -53070,10 +53960,10 @@ async function tryCodegenPathLegacy(twinName, baseSeedData, setupDescription, in
|
|
|
53070
53960
|
merged++;
|
|
53071
53961
|
}
|
|
53072
53962
|
}
|
|
53073
|
-
|
|
53963
|
+
debug3(`Codegen: deterministic fill merged ${merged} entities`);
|
|
53074
53964
|
finalSeed = autoFillMissingFKs(finalSeed, twinName);
|
|
53075
53965
|
} else {
|
|
53076
|
-
|
|
53966
|
+
debug3(`Codegen: deterministic fill failed: ${fillResult.message.slice(0, 200)}`);
|
|
53077
53967
|
}
|
|
53078
53968
|
}
|
|
53079
53969
|
}
|
|
@@ -53107,7 +53997,7 @@ function buildSeedPromptHashInput() {
|
|
|
53107
53997
|
async function generateDynamicSeed(twinName, baseSeedName, baseSeedData, setupDescription, config2, intent, context) {
|
|
53108
53998
|
const scopedSetupDescription = config2.skipTwinScoping ? setupDescription : scopeSetupToTwin(twinName, setupDescription);
|
|
53109
53999
|
if (scopedSetupDescription !== setupDescription) {
|
|
53110
|
-
|
|
54000
|
+
debug3("Scoped setup description to twin context", {
|
|
53111
54001
|
twin: twinName,
|
|
53112
54002
|
originalLength: String(setupDescription.length),
|
|
53113
54003
|
scopedLength: String(scopedSetupDescription.length)
|
|
@@ -53124,7 +54014,7 @@ async function generateDynamicSeed(twinName, baseSeedName, baseSeedData, setupDe
|
|
|
53124
54014
|
return { seed: cached2.seed, patch: cached2.patch, fromCache: true, source: "cache" };
|
|
53125
54015
|
}
|
|
53126
54016
|
}
|
|
53127
|
-
const creds =
|
|
54017
|
+
const creds = getCredentials();
|
|
53128
54018
|
const directFallback = resolveDirectSeedFallback();
|
|
53129
54019
|
if (!creds?.token && !directFallback) {
|
|
53130
54020
|
throw new DynamicSeedError(twinName, [
|
|
@@ -53194,13 +54084,13 @@ Hint: Dynamic seed generation failed for the "${twinName}" twin. Try adding a \`
|
|
|
53194
54084
|
Use a documented seed name for ${twinName}, or inspect the twin package assets in this repo.`
|
|
53195
54085
|
);
|
|
53196
54086
|
}
|
|
53197
|
-
var import_node_crypto5,
|
|
54087
|
+
var import_node_crypto5, SEED_CODEGEN_MAX_TOKENS, MAX_CODEGEN_ATTEMPTS, SEED_CACHE_PROMPT_TEMPLATE_VERSION, CODEGEN_TOTAL_BUDGET_MS, SYSTEM_PROMPT_HASH;
|
|
53198
54088
|
var init_dynamic_generator = __esm({
|
|
53199
54089
|
"src/runner/seed/dynamic-generator.ts"() {
|
|
53200
54090
|
"use strict";
|
|
53201
54091
|
import_node_crypto5 = require("crypto");
|
|
53202
|
-
|
|
53203
|
-
|
|
54092
|
+
init_dist3();
|
|
54093
|
+
init_dist5();
|
|
53204
54094
|
init_logger();
|
|
53205
54095
|
init_plan_fill();
|
|
53206
54096
|
init_patch();
|
|
@@ -53228,8 +54118,8 @@ __export(agent_http_exports, {
|
|
|
53228
54118
|
collectTraceFromHttp: () => collectTraceFromHttp,
|
|
53229
54119
|
pushStateToCloud: () => pushStateToCloud
|
|
53230
54120
|
});
|
|
53231
|
-
async function
|
|
53232
|
-
return
|
|
54121
|
+
async function fetchWithRetry3(url2, options, overrides) {
|
|
54122
|
+
return fetchWithRetry2(url2, options, {
|
|
53233
54123
|
maxRetries: overrides?.retries ?? HTTP_COLLECT_RETRY.maxRetries,
|
|
53234
54124
|
timeoutMs: overrides?.timeoutMs ?? HTTP_COLLECT_RETRY.timeoutMs,
|
|
53235
54125
|
retryableStatusCodes: HTTP_RETRYABLE_STATUS_CODES,
|
|
@@ -53263,7 +54153,7 @@ async function collectStateFromHttp(twinUrls, bearerToken, adminAuth) {
|
|
|
53263
54153
|
const headers = buildTwinHttpHeaders(bearerToken, adminAuth);
|
|
53264
54154
|
for (const [name, baseUrl] of Object.entries(twinUrls)) {
|
|
53265
54155
|
try {
|
|
53266
|
-
const response = await
|
|
54156
|
+
const response = await fetchWithRetry3(`${twinBasePath(baseUrl)}/state`, { headers });
|
|
53267
54157
|
if (response.ok) {
|
|
53268
54158
|
state[name] = await response.json();
|
|
53269
54159
|
} else {
|
|
@@ -53296,7 +54186,7 @@ async function pushStateToCloud(twinUrls, seedSelections, bearerToken, adminAuth
|
|
|
53296
54186
|
continue;
|
|
53297
54187
|
}
|
|
53298
54188
|
const url2 = `${twinBasePath(baseUrl)}/state`;
|
|
53299
|
-
|
|
54189
|
+
debug3(`Pushing dynamic seed to ${sel.twinName}`, { url: url2 });
|
|
53300
54190
|
const payload = JSON.stringify(sel.seedData);
|
|
53301
54191
|
let pushed = false;
|
|
53302
54192
|
for (let warmupAttempt = 0; warmupAttempt <= HTTP_PUSH_WARMUP_RETRIES; warmupAttempt++) {
|
|
@@ -53305,7 +54195,7 @@ async function pushStateToCloud(twinUrls, seedSelections, bearerToken, adminAuth
|
|
|
53305
54195
|
`Failed to push dynamic seed to twin "${sel.twinName}": run timeout exceeded during warmup`
|
|
53306
54196
|
);
|
|
53307
54197
|
}
|
|
53308
|
-
const response = await
|
|
54198
|
+
const response = await fetchWithRetry3(
|
|
53309
54199
|
url2,
|
|
53310
54200
|
{
|
|
53311
54201
|
method: "PUT",
|
|
@@ -53326,7 +54216,7 @@ async function pushStateToCloud(twinUrls, seedSelections, bearerToken, adminAuth
|
|
|
53326
54216
|
const text = await response.text().catch(() => "");
|
|
53327
54217
|
const isWarmup = isTwinWorkerWarmupResponse(response.status, text);
|
|
53328
54218
|
if (isWarmup && warmupAttempt < HTTP_PUSH_WARMUP_RETRIES) {
|
|
53329
|
-
const delay =
|
|
54219
|
+
const delay = resolveBackoffDelay2(
|
|
53330
54220
|
HTTP_PUSH_WARMUP_BACKOFF_MS,
|
|
53331
54221
|
warmupAttempt,
|
|
53332
54222
|
DEFAULT_WARMUP_BACKOFF_MS
|
|
@@ -53346,7 +54236,7 @@ async function pushStateToCloud(twinUrls, seedSelections, bearerToken, adminAuth
|
|
|
53346
54236
|
`Failed to push dynamic seed to twin "${sel.twinName}": worker warmup did not complete in time`
|
|
53347
54237
|
);
|
|
53348
54238
|
}
|
|
53349
|
-
|
|
54239
|
+
debug3(`Pushed dynamic seed to ${sel.twinName} successfully`);
|
|
53350
54240
|
}
|
|
53351
54241
|
}
|
|
53352
54242
|
async function collectTraceFromHttp(twinUrls, bearerToken, adminAuth, context) {
|
|
@@ -53356,7 +54246,7 @@ async function collectTraceFromHttp(twinUrls, bearerToken, adminAuth, context) {
|
|
|
53356
54246
|
for (const [name, baseUrl] of Object.entries(twinUrls)) {
|
|
53357
54247
|
const traceUrl = `${twinBasePath(baseUrl)}/trace`;
|
|
53358
54248
|
try {
|
|
53359
|
-
const response = await
|
|
54249
|
+
const response = await fetchWithRetry3(traceUrl, { headers });
|
|
53360
54250
|
if (response.ok) {
|
|
53361
54251
|
const entries = await response.json();
|
|
53362
54252
|
for (const entry of entries) {
|
|
@@ -53414,7 +54304,7 @@ async function collectEventsFromHttp(twinUrls, bearerToken, adminAuth) {
|
|
|
53414
54304
|
for (const [name, baseUrl] of Object.entries(twinUrls)) {
|
|
53415
54305
|
const eventsUrl = `${twinBasePath(baseUrl)}/events`;
|
|
53416
54306
|
try {
|
|
53417
|
-
const response = await
|
|
54307
|
+
const response = await fetchWithRetry3(eventsUrl, { headers });
|
|
53418
54308
|
if (response.ok) {
|
|
53419
54309
|
result[name] = await response.json();
|
|
53420
54310
|
} else {
|
|
@@ -53433,7 +54323,7 @@ function cleanupTempFiles(mcpConfigPath) {
|
|
|
53433
54323
|
} catch (err) {
|
|
53434
54324
|
const code = err instanceof Error && "code" in err ? err.code : void 0;
|
|
53435
54325
|
if (code !== "ENOENT") {
|
|
53436
|
-
|
|
54326
|
+
debug3(`Failed to clean up temp file ${file2}: ${errorMessage(err)}`);
|
|
53437
54327
|
}
|
|
53438
54328
|
}
|
|
53439
54329
|
}
|
|
@@ -53506,8 +54396,8 @@ function isStringRecord(v) {
|
|
|
53506
54396
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
53507
54397
|
}
|
|
53508
54398
|
function readPackageJson(path) {
|
|
53509
|
-
if (!(0,
|
|
53510
|
-
const content = (0,
|
|
54399
|
+
if (!(0, import_fs2.existsSync)(path)) return void 0;
|
|
54400
|
+
const content = (0, import_fs2.readFileSync)(path, "utf-8");
|
|
53511
54401
|
let parsed;
|
|
53512
54402
|
try {
|
|
53513
54403
|
parsed = JSON.parse(content);
|
|
@@ -53532,7 +54422,7 @@ function readPackageJson(path) {
|
|
|
53532
54422
|
};
|
|
53533
54423
|
}
|
|
53534
54424
|
function hasFile(repoPath, relativePath) {
|
|
53535
|
-
return (0,
|
|
54425
|
+
return (0, import_fs2.existsSync)((0, import_path2.join)(repoPath, relativePath));
|
|
53536
54426
|
}
|
|
53537
54427
|
function quoteJsonCommand(parts) {
|
|
53538
54428
|
return `[${parts.map((part) => JSON.stringify(part)).join(", ")}]`;
|
|
@@ -53588,7 +54478,7 @@ function resolveNodeLaunchCommand(repoPath, pkg, packageManager) {
|
|
|
53588
54478
|
return void 0;
|
|
53589
54479
|
}
|
|
53590
54480
|
function maybeGenerateNodeDockerfile(repoPath) {
|
|
53591
|
-
const packageJsonPath = (0,
|
|
54481
|
+
const packageJsonPath = (0, import_path2.join)(repoPath, "package.json");
|
|
53592
54482
|
const pkg = readPackageJson(packageJsonPath);
|
|
53593
54483
|
if (!pkg) return void 0;
|
|
53594
54484
|
const packageManager = detectPackageManager(pkg, repoPath);
|
|
@@ -53616,16 +54506,16 @@ function maybeGenerateNodeDockerfile(repoPath) {
|
|
|
53616
54506
|
};
|
|
53617
54507
|
}
|
|
53618
54508
|
function maybeGenerateSharedLibNodeDockerfile(repoPath) {
|
|
53619
|
-
const packageJsonPath = (0,
|
|
54509
|
+
const packageJsonPath = (0, import_path2.join)(repoPath, "package.json");
|
|
53620
54510
|
const pkg = readPackageJson(packageJsonPath);
|
|
53621
54511
|
if (!pkg) return void 0;
|
|
53622
|
-
const harnessDirName = (0,
|
|
53623
|
-
const parentDir = (0,
|
|
53624
|
-
const sharedLibDir = (0,
|
|
53625
|
-
if (!(0,
|
|
54512
|
+
const harnessDirName = (0, import_path2.basename)(repoPath);
|
|
54513
|
+
const parentDir = (0, import_path2.dirname)(repoPath);
|
|
54514
|
+
const sharedLibDir = (0, import_path2.join)(parentDir, "_lib");
|
|
54515
|
+
if (!(0, import_fs2.existsSync)(sharedLibDir)) return void 0;
|
|
53626
54516
|
let hasSharedLibFiles;
|
|
53627
54517
|
try {
|
|
53628
|
-
hasSharedLibFiles = (0,
|
|
54518
|
+
hasSharedLibFiles = (0, import_fs2.readdirSync)(sharedLibDir).some((f) => f.endsWith(".mjs") || f.endsWith(".js"));
|
|
53629
54519
|
} catch {
|
|
53630
54520
|
return void 0;
|
|
53631
54521
|
}
|
|
@@ -53736,8 +54626,8 @@ function generateDockerfile(repoPath) {
|
|
|
53736
54626
|
}
|
|
53737
54627
|
function resolveExplicitDockerfile(repoPath, rawPath) {
|
|
53738
54628
|
const trimmed = rawPath.trim();
|
|
53739
|
-
const dockerfilePath = (0,
|
|
53740
|
-
if (!(0,
|
|
54629
|
+
const dockerfilePath = (0, import_path2.resolve)(repoPath, trimmed);
|
|
54630
|
+
if (!(0, import_fs2.existsSync)(dockerfilePath) || !(0, import_fs2.statSync)(dockerfilePath).isFile()) {
|
|
53741
54631
|
throw new DockerfileError(
|
|
53742
54632
|
"invalid_path",
|
|
53743
54633
|
`Dockerfile path does not exist: ${dockerfilePath}`,
|
|
@@ -53747,7 +54637,7 @@ function resolveExplicitDockerfile(repoPath, rawPath) {
|
|
|
53747
54637
|
return dockerfilePath;
|
|
53748
54638
|
}
|
|
53749
54639
|
function resolveDockerfile(repoPathInput, options) {
|
|
53750
|
-
const repoPath = (0,
|
|
54640
|
+
const repoPath = (0, import_path2.resolve)(repoPathInput);
|
|
53751
54641
|
if (options?.explicitDockerfile?.trim()) {
|
|
53752
54642
|
const dockerfilePath = resolveExplicitDockerfile(repoPath, options.explicitDockerfile);
|
|
53753
54643
|
return {
|
|
@@ -53757,8 +54647,8 @@ function resolveDockerfile(repoPathInput, options) {
|
|
|
53757
54647
|
summary: `using explicit Dockerfile ${dockerfilePath}`
|
|
53758
54648
|
};
|
|
53759
54649
|
}
|
|
53760
|
-
const rootDockerfile = (0,
|
|
53761
|
-
if ((0,
|
|
54650
|
+
const rootDockerfile = (0, import_path2.join)(repoPath, "Dockerfile");
|
|
54651
|
+
if ((0, import_fs2.existsSync)(rootDockerfile) && (0, import_fs2.statSync)(rootDockerfile).isFile()) {
|
|
53762
54652
|
return {
|
|
53763
54653
|
source: "existing",
|
|
53764
54654
|
path: rootDockerfile,
|
|
@@ -53781,8 +54671,8 @@ function resolveDockerfile(repoPathInput, options) {
|
|
|
53781
54671
|
"Pass a generatedDockerfilePath to resolveDockerfile."
|
|
53782
54672
|
);
|
|
53783
54673
|
}
|
|
53784
|
-
const generatedPath = (0,
|
|
53785
|
-
(0,
|
|
54674
|
+
const generatedPath = (0, import_path2.resolve)(options.generatedDockerfilePath);
|
|
54675
|
+
(0, import_fs2.writeFileSync)(generatedPath, generated.contents, "utf-8");
|
|
53786
54676
|
return {
|
|
53787
54677
|
source: "generated",
|
|
53788
54678
|
path: generatedPath,
|
|
@@ -53792,29 +54682,29 @@ function resolveDockerfile(repoPathInput, options) {
|
|
|
53792
54682
|
};
|
|
53793
54683
|
}
|
|
53794
54684
|
function generateCertAuthority() {
|
|
53795
|
-
const { publicKey, privateKey } = (0,
|
|
54685
|
+
const { publicKey, privateKey } = (0, import_crypto3.generateKeyPairSync)("rsa", {
|
|
53796
54686
|
modulusLength: 2048
|
|
53797
54687
|
});
|
|
53798
54688
|
const certPem = generateSelfSignedCert(publicKey, privateKey, CA_COMMON_NAME, true);
|
|
53799
54689
|
const keyPem = privateKey.export({ type: "pkcs8", format: "pem" });
|
|
53800
|
-
const dir = (0,
|
|
53801
|
-
const certPath = (0,
|
|
53802
|
-
const keyPath = (0,
|
|
53803
|
-
(0,
|
|
53804
|
-
(0,
|
|
54690
|
+
const dir = (0, import_fs4.mkdtempSync)((0, import_path4.join)((0, import_os3.tmpdir)(), "archal-sandbox-ca-"));
|
|
54691
|
+
const certPath = (0, import_path4.join)(dir, "ca.crt");
|
|
54692
|
+
const keyPath = (0, import_path4.join)(dir, "ca.key");
|
|
54693
|
+
(0, import_fs4.writeFileSync)(certPath, certPem);
|
|
54694
|
+
(0, import_fs4.writeFileSync)(keyPath, keyPem);
|
|
53805
54695
|
return { certPem, keyPem, certPath, keyPath, dir };
|
|
53806
54696
|
}
|
|
53807
54697
|
function destroyCertAuthority(ca) {
|
|
53808
|
-
(0,
|
|
54698
|
+
(0, import_fs4.rmSync)(ca.dir, { recursive: true, force: true });
|
|
53809
54699
|
}
|
|
53810
54700
|
function caFingerprint(ca) {
|
|
53811
|
-
return (0,
|
|
54701
|
+
return (0, import_crypto3.createHash)("sha256").update(ca.certPem).digest("hex").slice(0, 16);
|
|
53812
54702
|
}
|
|
53813
54703
|
function getDomainCert(domain2, ca) {
|
|
53814
54704
|
const cacheKey2 = `${caFingerprint(ca)}:${domain2}`;
|
|
53815
54705
|
const cached2 = domainCertCache.get(cacheKey2);
|
|
53816
54706
|
if (cached2) return cached2;
|
|
53817
|
-
const { publicKey, privateKey } = (0,
|
|
54707
|
+
const { publicKey, privateKey } = (0, import_crypto3.generateKeyPairSync)("rsa", {
|
|
53818
54708
|
modulusLength: 2048
|
|
53819
54709
|
});
|
|
53820
54710
|
const certPem = generateSignedCert(publicKey, privateKey, domain2, ca);
|
|
@@ -53827,12 +54717,12 @@ function generateSelfSignedCert(publicKey, privateKey, cn, isCA) {
|
|
|
53827
54717
|
return buildMinimalX509(publicKey, privateKey, cn, isCA);
|
|
53828
54718
|
}
|
|
53829
54719
|
function generateSignedCert(publicKey, _privateKey, domain2, ca) {
|
|
53830
|
-
const caKey = (0,
|
|
54720
|
+
const caKey = (0, import_crypto3.createPrivateKey)(ca.keyPem);
|
|
53831
54721
|
return buildMinimalX509(publicKey, caKey, domain2, false);
|
|
53832
54722
|
}
|
|
53833
54723
|
function buildMinimalX509(subjectPublicKey, signingKey, cn, isCA) {
|
|
53834
54724
|
const spkiDer = subjectPublicKey.export({ type: "spki", format: "der" });
|
|
53835
|
-
const serial = (0,
|
|
54725
|
+
const serial = (0, import_crypto3.randomBytes)(16);
|
|
53836
54726
|
serial[0] = serial[0] & 127;
|
|
53837
54727
|
const now = /* @__PURE__ */ new Date();
|
|
53838
54728
|
const notBefore = new Date(now.getTime() - 6e4);
|
|
@@ -53846,7 +54736,7 @@ function buildMinimalX509(subjectPublicKey, signingKey, cn, isCA) {
|
|
|
53846
54736
|
spkiDer,
|
|
53847
54737
|
isCA
|
|
53848
54738
|
});
|
|
53849
|
-
const signer = (0,
|
|
54739
|
+
const signer = (0, import_crypto3.createSign)("SHA256");
|
|
53850
54740
|
signer.update(tbs);
|
|
53851
54741
|
const signature = signer.sign(signingKey);
|
|
53852
54742
|
const certDer = derSequence([
|
|
@@ -54726,7 +55616,7 @@ function generateHostsEntries(cloudTwinUrls) {
|
|
|
54726
55616
|
}
|
|
54727
55617
|
function isDockerAvailable() {
|
|
54728
55618
|
try {
|
|
54729
|
-
(0,
|
|
55619
|
+
(0, import_child_process2.execFileSync)("docker", ["info"], { stdio: "pipe", timeout: 1e4 });
|
|
54730
55620
|
return true;
|
|
54731
55621
|
} catch {
|
|
54732
55622
|
return false;
|
|
@@ -54743,47 +55633,47 @@ function formatExecError(err) {
|
|
|
54743
55633
|
return String(err);
|
|
54744
55634
|
}
|
|
54745
55635
|
function resolveLocalSandboxBuildTarget() {
|
|
54746
|
-
const moduleDir = typeof import_meta3?.url === "string" ? (0,
|
|
55636
|
+
const moduleDir = typeof import_meta3?.url === "string" ? (0, import_path5.dirname)((0, import_url.fileURLToPath)(import_meta3.url)) : typeof __dirname === "string" ? __dirname : process.cwd();
|
|
54747
55637
|
const candidates = [
|
|
54748
55638
|
{
|
|
54749
|
-
dockerfile: (0,
|
|
54750
|
-
contextDir: (0,
|
|
55639
|
+
dockerfile: (0, import_path5.resolve)(process.cwd(), "packages/sandbox-runtime/docker/sandbox/Dockerfile"),
|
|
55640
|
+
contextDir: (0, import_path5.resolve)(process.cwd(), "packages/sandbox-runtime")
|
|
54751
55641
|
},
|
|
54752
55642
|
{
|
|
54753
|
-
dockerfile: (0,
|
|
54754
|
-
contextDir: (0,
|
|
55643
|
+
dockerfile: (0, import_path5.resolve)(process.cwd(), "cli/docker/sandbox/Dockerfile"),
|
|
55644
|
+
contextDir: (0, import_path5.resolve)(process.cwd(), "cli")
|
|
54755
55645
|
},
|
|
54756
55646
|
{
|
|
54757
|
-
dockerfile: (0,
|
|
55647
|
+
dockerfile: (0, import_path5.resolve)(process.cwd(), "docker/sandbox/Dockerfile"),
|
|
54758
55648
|
contextDir: process.cwd()
|
|
54759
55649
|
},
|
|
54760
55650
|
{
|
|
54761
|
-
dockerfile: (0,
|
|
54762
|
-
contextDir: (0,
|
|
55651
|
+
dockerfile: (0, import_path5.resolve)(moduleDir, "../docker/sandbox/Dockerfile"),
|
|
55652
|
+
contextDir: (0, import_path5.resolve)(moduleDir, "..")
|
|
54763
55653
|
},
|
|
54764
55654
|
{
|
|
54765
|
-
dockerfile: (0,
|
|
54766
|
-
contextDir: (0,
|
|
55655
|
+
dockerfile: (0, import_path5.resolve)(moduleDir, "../../docker/sandbox/Dockerfile"),
|
|
55656
|
+
contextDir: (0, import_path5.resolve)(moduleDir, "../..")
|
|
54767
55657
|
}
|
|
54768
55658
|
];
|
|
54769
|
-
return candidates.find((candidate) => (0,
|
|
55659
|
+
return candidates.find((candidate) => (0, import_fs5.existsSync)(candidate.dockerfile));
|
|
54770
55660
|
}
|
|
54771
55661
|
function getSandboxRuntimeDependencyPaths(target) {
|
|
54772
55662
|
return [
|
|
54773
55663
|
target.dockerfile,
|
|
54774
|
-
(0,
|
|
54775
|
-
(0,
|
|
54776
|
-
(0,
|
|
54777
|
-
(0,
|
|
54778
|
-
(0,
|
|
54779
|
-
].filter((path) => (0,
|
|
55664
|
+
(0, import_path5.resolve)(target.contextDir, "docker/sandbox/entrypoint.sh"),
|
|
55665
|
+
(0, import_path5.resolve)(target.contextDir, "src/sandbox/proxy-entry.ts"),
|
|
55666
|
+
(0, import_path5.resolve)(target.contextDir, "src/sandbox/proxy.ts"),
|
|
55667
|
+
(0, import_path5.resolve)(target.contextDir, "src/sandbox/twins.ts"),
|
|
55668
|
+
(0, import_path5.resolve)(target.contextDir, "src/sandbox/certs.ts")
|
|
55669
|
+
].filter((path) => (0, import_fs5.existsSync)(path));
|
|
54780
55670
|
}
|
|
54781
55671
|
function getNewestSandboxRuntimeMtimeMs(target) {
|
|
54782
|
-
return getSandboxRuntimeDependencyPaths(target).map((path) => (0,
|
|
55672
|
+
return getSandboxRuntimeDependencyPaths(target).map((path) => (0, import_fs5.statSync)(path).mtimeMs).reduce((max, mtimeMs) => Math.max(max, mtimeMs), 0);
|
|
54783
55673
|
}
|
|
54784
55674
|
function getLocalImageCreatedAtMs(image) {
|
|
54785
55675
|
try {
|
|
54786
|
-
const created = (0,
|
|
55676
|
+
const created = (0, import_child_process2.execFileSync)(
|
|
54787
55677
|
"docker",
|
|
54788
55678
|
["image", "inspect", image, "--format", "{{.Created}}"],
|
|
54789
55679
|
{ stdio: "pipe", timeout: 1e4 }
|
|
@@ -54826,7 +55716,7 @@ function buildSandboxImage(image, target, openclawVersion) {
|
|
|
54826
55716
|
try {
|
|
54827
55717
|
const effectiveVersion = openclawVersion?.trim() || inferOpenclawVersionFromImage(image);
|
|
54828
55718
|
const buildArgs = effectiveVersion ? ["--build-arg", `OPENCLAW_VERSION=${effectiveVersion}`] : [];
|
|
54829
|
-
(0,
|
|
55719
|
+
(0, import_child_process2.execFileSync)(
|
|
54830
55720
|
"docker",
|
|
54831
55721
|
["build", ...buildArgs, "-f", target.dockerfile, "-t", image, target.contextDir],
|
|
54832
55722
|
{ stdio: "pipe", timeout: 6e5 }
|
|
@@ -54842,7 +55732,7 @@ async function ensureSandboxImage(image, openclawVersion) {
|
|
|
54842
55732
|
const requiresVersionedBuild = resolvedImage !== image;
|
|
54843
55733
|
const isManagedImage = isManagedSandboxImage(resolvedImage);
|
|
54844
55734
|
try {
|
|
54845
|
-
(0,
|
|
55735
|
+
(0, import_child_process2.execFileSync)("docker", ["image", "inspect", resolvedImage], { stdio: "pipe", timeout: 1e4 });
|
|
54846
55736
|
if (target && shouldRebuildManagedSandboxImage(resolvedImage, target)) {
|
|
54847
55737
|
return buildSandboxImage(resolvedImage, target, openclawVersion);
|
|
54848
55738
|
}
|
|
@@ -54859,7 +55749,7 @@ async function ensureSandboxImage(image, openclawVersion) {
|
|
|
54859
55749
|
return buildSandboxImage(resolvedImage, target, openclawVersion);
|
|
54860
55750
|
}
|
|
54861
55751
|
try {
|
|
54862
|
-
(0,
|
|
55752
|
+
(0, import_child_process2.execFileSync)("docker", ["pull", resolvedImage], { stdio: "pipe", timeout: 3e5 });
|
|
54863
55753
|
return { ok: true, source: "pull" };
|
|
54864
55754
|
} catch (pullErr) {
|
|
54865
55755
|
if (!isManagedImage) {
|
|
@@ -54876,8 +55766,8 @@ async function ensureSandboxImage(image, openclawVersion) {
|
|
|
54876
55766
|
}
|
|
54877
55767
|
function launchSandbox(config2) {
|
|
54878
55768
|
const image = config2.image ?? DEFAULT_SANDBOX_IMAGE;
|
|
54879
|
-
const artifactsDir = (0,
|
|
54880
|
-
const proxyEventsHostPath = (0,
|
|
55769
|
+
const artifactsDir = (0, import_fs5.mkdtempSync)((0, import_path5.join)((0, import_os4.tmpdir)(), "archal-sandbox-"));
|
|
55770
|
+
const proxyEventsHostPath = (0, import_path5.join)(artifactsDir, "proxy-events.ndjson");
|
|
54881
55771
|
const proxyEventsContainerPath = "/archal-artifacts/proxy-events.ndjson";
|
|
54882
55772
|
const mounts = [];
|
|
54883
55773
|
mounts.push("-v", `${artifactsDir}:/archal-artifacts`);
|
|
@@ -54927,7 +55817,7 @@ function spawnWithTimeout2(command, args, timeoutMs, artifacts) {
|
|
|
54927
55817
|
const proxyEvents = artifacts ? readProxyEvents(artifacts.proxyEventsHostPath) : [];
|
|
54928
55818
|
if (artifacts) {
|
|
54929
55819
|
try {
|
|
54930
|
-
(0,
|
|
55820
|
+
(0, import_fs5.rmSync)(artifacts.cleanupPath, { recursive: true, force: true });
|
|
54931
55821
|
} catch {
|
|
54932
55822
|
}
|
|
54933
55823
|
}
|
|
@@ -54936,7 +55826,7 @@ function spawnWithTimeout2(command, args, timeoutMs, artifacts) {
|
|
|
54936
55826
|
proxyEvents
|
|
54937
55827
|
});
|
|
54938
55828
|
};
|
|
54939
|
-
const child = (0,
|
|
55829
|
+
const child = (0, import_child_process2.spawn)(command, args, {
|
|
54940
55830
|
stdio: ["ignore", "pipe", "pipe"]
|
|
54941
55831
|
});
|
|
54942
55832
|
child.stdout?.on("data", (chunk) => {
|
|
@@ -54980,7 +55870,7 @@ function spawnWithTimeout2(command, args, timeoutMs, artifacts) {
|
|
|
54980
55870
|
}
|
|
54981
55871
|
function readProxyEvents(path) {
|
|
54982
55872
|
try {
|
|
54983
|
-
const raw = (0,
|
|
55873
|
+
const raw = (0, import_fs5.readFileSync)(path, "utf8").trim();
|
|
54984
55874
|
if (!raw) return [];
|
|
54985
55875
|
return raw.split("\n").map((line) => {
|
|
54986
55876
|
try {
|
|
@@ -54995,7 +55885,7 @@ function readProxyEvents(path) {
|
|
|
54995
55885
|
}
|
|
54996
55886
|
function runDockerCommand(args, timeoutMs) {
|
|
54997
55887
|
return new Promise((resolveCommand) => {
|
|
54998
|
-
const child = (0,
|
|
55888
|
+
const child = (0, import_child_process3.spawn)("docker", args, {
|
|
54999
55889
|
stdio: ["ignore", "pipe", "pipe"]
|
|
55000
55890
|
});
|
|
55001
55891
|
let stdout = "";
|
|
@@ -55051,7 +55941,7 @@ function runDockerCommand(args, timeoutMs) {
|
|
|
55051
55941
|
}
|
|
55052
55942
|
function getDockerBridgeGateway() {
|
|
55053
55943
|
try {
|
|
55054
|
-
const result = (0,
|
|
55944
|
+
const result = (0, import_child_process3.execSync)(
|
|
55055
55945
|
"docker network inspect bridge --format '{{(index .IPAM.Config 0).Gateway}}'",
|
|
55056
55946
|
{ encoding: "utf-8", timeout: 5e3 }
|
|
55057
55947
|
).trim();
|
|
@@ -55085,9 +55975,9 @@ function registerDockerCleanupHandlers(containerName, imageName, ownImage) {
|
|
|
55085
55975
|
}
|
|
55086
55976
|
cleaningUp = true;
|
|
55087
55977
|
try {
|
|
55088
|
-
(0,
|
|
55978
|
+
(0, import_child_process3.spawnSync)("docker", ["rm", "-f", containerName], { stdio: "ignore", timeout: 5e3 });
|
|
55089
55979
|
if (ownImage) {
|
|
55090
|
-
(0,
|
|
55980
|
+
(0, import_child_process3.spawnSync)("docker", ["image", "rm", "-f", imageName], { stdio: "ignore", timeout: 5e3 });
|
|
55091
55981
|
}
|
|
55092
55982
|
} catch {
|
|
55093
55983
|
}
|
|
@@ -55157,7 +56047,7 @@ function buildContainerEnv(config2, proxyPort) {
|
|
|
55157
56047
|
return env;
|
|
55158
56048
|
}
|
|
55159
56049
|
function writeMountedConfigFiles(dir, cloudTwinUrls, authToken, caPath) {
|
|
55160
|
-
(0,
|
|
56050
|
+
(0, import_fs3.mkdirSync)(dir, { recursive: true });
|
|
55161
56051
|
const restConfig = {
|
|
55162
56052
|
restEndpoints: cloudTwinUrls,
|
|
55163
56053
|
auth: {
|
|
@@ -55182,7 +56072,7 @@ function writeMountedConfigFiles(dir, cloudTwinUrls, authToken, caPath) {
|
|
|
55182
56072
|
example: 'mcp__github__list_issues -> POST github-url/tools/call with { "name": "list_issues", "arguments": {} }'
|
|
55183
56073
|
}
|
|
55184
56074
|
};
|
|
55185
|
-
(0,
|
|
56075
|
+
(0, import_fs3.writeFileSync)((0, import_path3.join)(dir, "rest-config.json"), JSON.stringify(restConfig, null, 2) + "\n", "utf-8");
|
|
55186
56076
|
const mcpServers = {};
|
|
55187
56077
|
for (const [twinName, baseUrl] of Object.entries(cloudTwinUrls)) {
|
|
55188
56078
|
const trimmed = baseUrl.trim().replace(/\/+$/, "");
|
|
@@ -55192,9 +56082,9 @@ function writeMountedConfigFiles(dir, cloudTwinUrls, authToken, caPath) {
|
|
|
55192
56082
|
headers: { Authorization: `Bearer ${authToken}` }
|
|
55193
56083
|
};
|
|
55194
56084
|
}
|
|
55195
|
-
(0,
|
|
55196
|
-
(0,
|
|
55197
|
-
(0,
|
|
56085
|
+
(0, import_fs3.writeFileSync)((0, import_path3.join)(dir, "mcp-config.json"), JSON.stringify({ mcpServers }, null, 2) + "\n", "utf-8");
|
|
56086
|
+
(0, import_fs3.writeFileSync)((0, import_path3.join)(dir, "mcp-servers.json"), JSON.stringify(mcpServers), "utf-8");
|
|
56087
|
+
(0, import_fs3.writeFileSync)((0, import_path3.join)(dir, "ca.crt"), (0, import_fs3.readFileSync)(caPath, "utf-8"), "utf-8");
|
|
55198
56088
|
}
|
|
55199
56089
|
async function ensurePreparedImage(repoPath, dockerfilePath, image, timeoutMs) {
|
|
55200
56090
|
const buildArgs = ["build", "-f", dockerfilePath, "-t", image, repoPath];
|
|
@@ -55217,12 +56107,12 @@ async function cleanupDockerImage(imageName) {
|
|
|
55217
56107
|
await runDockerCommand(["image", "rm", "-f", imageName], 1e4);
|
|
55218
56108
|
}
|
|
55219
56109
|
async function buildDockerHarnessImage(repoPath, dockerfilePath, timeoutMs) {
|
|
55220
|
-
const resolvedRepoPath = (0,
|
|
56110
|
+
const resolvedRepoPath = (0, import_path3.resolve)(repoPath);
|
|
55221
56111
|
const dockerIdSuffix = `${Date.now().toString(36)}-${process.pid}`;
|
|
55222
56112
|
const imageName = `archal/harness-${dockerIdSuffix}`;
|
|
55223
|
-
const buildDir = (0,
|
|
56113
|
+
const buildDir = (0, import_fs3.mkdtempSync)((0, import_path3.join)((0, import_os2.tmpdir)(), "archal-harness-build-"));
|
|
55224
56114
|
try {
|
|
55225
|
-
const generatedDockerfilePath = (0,
|
|
56115
|
+
const generatedDockerfilePath = (0, import_path3.join)(buildDir, "Dockerfile.generated");
|
|
55226
56116
|
let dockerfile;
|
|
55227
56117
|
try {
|
|
55228
56118
|
dockerfile = resolveDockerfile(resolvedRepoPath, {
|
|
@@ -55248,7 +56138,7 @@ async function buildDockerHarnessImage(repoPath, dockerfilePath, timeoutMs) {
|
|
|
55248
56138
|
}
|
|
55249
56139
|
return { ok: true, imageName };
|
|
55250
56140
|
} finally {
|
|
55251
|
-
(0,
|
|
56141
|
+
(0, import_fs3.rmSync)(buildDir, { recursive: true, force: true });
|
|
55252
56142
|
}
|
|
55253
56143
|
}
|
|
55254
56144
|
async function runDockerHarness(config2) {
|
|
@@ -55267,9 +56157,9 @@ async function runDockerHarness(config2) {
|
|
|
55267
56157
|
"Install Docker Desktop or Docker Engine before using the Docker harness."
|
|
55268
56158
|
));
|
|
55269
56159
|
}
|
|
55270
|
-
const repoPath = (0,
|
|
55271
|
-
const runDir = (0,
|
|
55272
|
-
const generatedDockerfilePath = (0,
|
|
56160
|
+
const repoPath = (0, import_path3.resolve)(config2.repoPath);
|
|
56161
|
+
const runDir = (0, import_fs3.mkdtempSync)((0, import_path3.join)((0, import_os2.tmpdir)(), "archal-harness-"));
|
|
56162
|
+
const generatedDockerfilePath = (0, import_path3.join)(runDir, "Dockerfile.generated");
|
|
55273
56163
|
const dockerIdSuffix = `${Date.now().toString(36)}-${process.pid}`;
|
|
55274
56164
|
const imageName = config2.prebuiltImage ?? `archal/harness-${dockerIdSuffix}`;
|
|
55275
56165
|
const containerName = `archal-harness-${dockerIdSuffix}`;
|
|
@@ -55318,24 +56208,24 @@ async function runDockerHarness(config2) {
|
|
|
55318
56208
|
return fail(stageError("Docker harness attach failed", reason));
|
|
55319
56209
|
}
|
|
55320
56210
|
try {
|
|
55321
|
-
const mountedConfigDir = (0,
|
|
56211
|
+
const mountedConfigDir = (0, import_path3.join)(runDir, "out");
|
|
55322
56212
|
writeMountedConfigFiles(mountedConfigDir, config2.cloudTwinUrls, config2.authToken, ca.certPath);
|
|
55323
56213
|
const env = buildContainerEnv(config2, proxy.port);
|
|
55324
|
-
env["ARCHAL_MCP_SERVERS"] = (0,
|
|
56214
|
+
env["ARCHAL_MCP_SERVERS"] = (0, import_fs3.readFileSync)((0, import_path3.join)(mountedConfigDir, "mcp-servers.json"), "utf-8");
|
|
55325
56215
|
const envFileLines = [];
|
|
55326
56216
|
let multiLineIdx = 0;
|
|
55327
56217
|
for (const [key, value] of Object.entries(env)) {
|
|
55328
56218
|
if (value.includes("\n")) {
|
|
55329
56219
|
const filename = `_env_${multiLineIdx++}_${key.toLowerCase()}`;
|
|
55330
|
-
(0,
|
|
56220
|
+
(0, import_fs3.writeFileSync)((0, import_path3.join)(mountedConfigDir, filename), value, { encoding: "utf-8", mode: 384 });
|
|
55331
56221
|
envFileLines.push(`${key}_FILE=${OUTPUT_DIR_IN_CONTAINER}/${filename}`);
|
|
55332
56222
|
envFileLines.push(`${key}=${OUTPUT_DIR_IN_CONTAINER}/${filename}`);
|
|
55333
56223
|
} else {
|
|
55334
56224
|
envFileLines.push(`${key}=${value}`);
|
|
55335
56225
|
}
|
|
55336
56226
|
}
|
|
55337
|
-
const envFilePath = (0,
|
|
55338
|
-
(0,
|
|
56227
|
+
const envFilePath = (0, import_path3.join)(runDir, ".env");
|
|
56228
|
+
(0, import_fs3.writeFileSync)(envFilePath, envFileLines.join("\n") + "\n", { encoding: "utf-8", mode: 384 });
|
|
55339
56229
|
const args = [
|
|
55340
56230
|
"run",
|
|
55341
56231
|
"--rm",
|
|
@@ -55406,19 +56296,19 @@ async function runDockerHarness(config2) {
|
|
|
55406
56296
|
}
|
|
55407
56297
|
if (caDir) {
|
|
55408
56298
|
try {
|
|
55409
|
-
(0,
|
|
56299
|
+
(0, import_fs3.rmSync)(caDir, { recursive: true, force: true });
|
|
55410
56300
|
} catch {
|
|
55411
56301
|
}
|
|
55412
56302
|
}
|
|
55413
|
-
const envPath = (0,
|
|
56303
|
+
const envPath = (0, import_path3.join)(runDir, ".env");
|
|
55414
56304
|
try {
|
|
55415
|
-
if ((0,
|
|
55416
|
-
const size = (0,
|
|
55417
|
-
(0,
|
|
56305
|
+
if ((0, import_fs3.existsSync)(envPath)) {
|
|
56306
|
+
const size = (0, import_fs3.statSync)(envPath).size;
|
|
56307
|
+
(0, import_fs3.writeFileSync)(envPath, Buffer.alloc(size, 0), { mode: 384 });
|
|
55418
56308
|
}
|
|
55419
56309
|
} catch {
|
|
55420
56310
|
}
|
|
55421
|
-
(0,
|
|
56311
|
+
(0, import_fs3.rmSync)(runDir, { recursive: true, force: true });
|
|
55422
56312
|
}
|
|
55423
56313
|
}
|
|
55424
56314
|
async function runLocalProxy(config2, task, canaryFiles) {
|
|
@@ -55462,7 +56352,7 @@ async function runLocalProxy(config2, task, canaryFiles) {
|
|
|
55462
56352
|
if (hostsEntries) {
|
|
55463
56353
|
status("NOTE: For full interception in local mode, add these to /etc/hosts:\n" + hostsEntries);
|
|
55464
56354
|
}
|
|
55465
|
-
const workspace = config2.workspacePath ?? (0,
|
|
56355
|
+
const workspace = config2.workspacePath ?? (0, import_path6.join)(process.env["HOME"] ?? "/root", ".openclaw");
|
|
55466
56356
|
const noProxyHosts = "127.0.0.1,localhost,.archal.ai";
|
|
55467
56357
|
const env = {
|
|
55468
56358
|
...process.env,
|
|
@@ -55482,7 +56372,7 @@ async function runLocalProxy(config2, task, canaryFiles) {
|
|
|
55482
56372
|
...config2.openclawEvalMode === "isolated" ? { ARCHAL_SANDBOX_DISABLE_PLUGINS: "1" } : {},
|
|
55483
56373
|
...config2.openclawEvalMode ? { ARCHAL_OPENCLAW_EVAL_MODE: config2.openclawEvalMode } : {}
|
|
55484
56374
|
};
|
|
55485
|
-
if (canaryFiles && (0,
|
|
56375
|
+
if (canaryFiles && (0, import_fs6.existsSync)(workspace)) {
|
|
55486
56376
|
writeCanaryFiles(workspace, canaryFiles);
|
|
55487
56377
|
}
|
|
55488
56378
|
const result = await spawnAgent(workspace, task, env, config2.timeoutMs);
|
|
@@ -55497,24 +56387,24 @@ async function runLocalProxy(config2, task, canaryFiles) {
|
|
|
55497
56387
|
}
|
|
55498
56388
|
}
|
|
55499
56389
|
function writeCanaryFiles(workspace, canaryFiles) {
|
|
55500
|
-
const resolvedWorkspace = (0,
|
|
56390
|
+
const resolvedWorkspace = (0, import_path6.resolve)(workspace);
|
|
55501
56391
|
for (const [relativePath, content] of Object.entries(canaryFiles)) {
|
|
55502
|
-
const filePath = (0,
|
|
55503
|
-
if (filePath !== resolvedWorkspace && !filePath.startsWith(resolvedWorkspace +
|
|
56392
|
+
const filePath = (0, import_path6.resolve)(workspace, relativePath);
|
|
56393
|
+
if (filePath !== resolvedWorkspace && !filePath.startsWith(resolvedWorkspace + import_path6.sep)) {
|
|
55504
56394
|
throw new Error(`Canary path escapes sandbox root: ${relativePath}`);
|
|
55505
56395
|
}
|
|
55506
|
-
(0,
|
|
55507
|
-
(0,
|
|
56396
|
+
(0, import_fs6.mkdirSync)((0, import_path6.dirname)(filePath), { recursive: true });
|
|
56397
|
+
(0, import_fs6.writeFileSync)(filePath, content);
|
|
55508
56398
|
}
|
|
55509
56399
|
}
|
|
55510
56400
|
function spawnAgent(workspace, task, env, timeoutMs) {
|
|
55511
56401
|
return new Promise((resolve62) => {
|
|
55512
56402
|
const agentName = env["ARCHAL_OPENCLAW_AGENT"] ?? "main";
|
|
55513
|
-
const child = (0,
|
|
56403
|
+
const child = (0, import_child_process4.spawn)(
|
|
55514
56404
|
"openclaw",
|
|
55515
56405
|
["agent", "--agent", agentName, "--local", "--message", task, "--json"],
|
|
55516
56406
|
{
|
|
55517
|
-
cwd: (0,
|
|
56407
|
+
cwd: (0, import_fs6.existsSync)(workspace) ? workspace : void 0,
|
|
55518
56408
|
env,
|
|
55519
56409
|
stdio: ["ignore", "pipe", "pipe"]
|
|
55520
56410
|
}
|
|
@@ -55572,9 +56462,9 @@ function spawnAgent(workspace, task, env, timeoutMs) {
|
|
|
55572
56462
|
});
|
|
55573
56463
|
}
|
|
55574
56464
|
function confinePath(root, relativePath) {
|
|
55575
|
-
const resolvedRoot = (0,
|
|
55576
|
-
const resolved = (0,
|
|
55577
|
-
if (resolved !== resolvedRoot && !resolved.startsWith(resolvedRoot +
|
|
56465
|
+
const resolvedRoot = (0, import_path7.resolve)(root);
|
|
56466
|
+
const resolved = (0, import_path7.resolve)(root, relativePath);
|
|
56467
|
+
if (resolved !== resolvedRoot && !resolved.startsWith(resolvedRoot + import_path7.sep)) {
|
|
55578
56468
|
throw new Error(`Canary path escapes sandbox root: ${relativePath}`);
|
|
55579
56469
|
}
|
|
55580
56470
|
return resolved;
|
|
@@ -55837,35 +56727,35 @@ async function runDockerSandbox(config2) {
|
|
|
55837
56727
|
error: result.timedOut ? `Sandbox timed out after ${Math.round(config2.timeoutMs / 1e3)}s` : result.exitCode !== 0 ? `Sandbox exited with code ${result.exitCode}` : void 0
|
|
55838
56728
|
};
|
|
55839
56729
|
}
|
|
55840
|
-
var
|
|
55841
|
-
var
|
|
56730
|
+
var import_fs2, import_path2, import_fs3, import_os2, import_path3, import_crypto3, import_fs4, import_path4, import_os3, import_http, import_https, import_tls, import_net, import_child_process2, import_fs5, import_os4, import_path5, import_url, import_child_process3, import_child_process4, import_fs6, import_path6, import_path7, import_meta3, DockerfileError, NODE_SCRIPT_PRIORITY, CA_COMMON_NAME, CERT_VALIDITY_DAYS, domainCertCache, REQUEST_BODY_PREVIEW_HEAD_LIMIT, REQUEST_BODY_PREVIEW_TAIL_LIMIT, GITHUB_RESPONSE_HEADERS, PASSTHROUGH_CONNECT_TIMEOUT_MS, TWIN_DOMAINS, DEFAULT_SANDBOX_IMAGE, VERSIONED_SANDBOX_TAG_PREFIX, MAX_OUTPUT_BYTES, KILL_GRACE_MS, MAX_OUTPUT_BYTES2, OUTPUT_DIR_IN_CONTAINER, HOST_GATEWAY_NAME, BUILD_TIMEOUT_CAP_MS, SANDBOX_CANARY_TAG, CANARY_LEAK_ERROR_CODE, CANARY_VALUE_PATTERN, SANDBOX_FILES_BLOCK_PATTERN, SNIPPET_RADIUS, DOCKER_IMAGE_NAME;
|
|
56731
|
+
var init_dist6 = __esm({
|
|
55842
56732
|
"../packages/sandbox-runtime/dist/index.js"() {
|
|
55843
56733
|
"use strict";
|
|
55844
|
-
import_fs = require("fs");
|
|
55845
|
-
import_path = require("path");
|
|
55846
56734
|
import_fs2 = require("fs");
|
|
55847
|
-
import_os = require("os");
|
|
55848
56735
|
import_path2 = require("path");
|
|
55849
|
-
init_dist2();
|
|
55850
|
-
import_crypto2 = require("crypto");
|
|
55851
56736
|
import_fs3 = require("fs");
|
|
55852
|
-
import_path3 = require("path");
|
|
55853
56737
|
import_os2 = require("os");
|
|
56738
|
+
import_path3 = require("path");
|
|
56739
|
+
init_dist2();
|
|
56740
|
+
import_crypto3 = require("crypto");
|
|
56741
|
+
import_fs4 = require("fs");
|
|
56742
|
+
import_path4 = require("path");
|
|
56743
|
+
import_os3 = require("os");
|
|
55854
56744
|
import_http = require("http");
|
|
55855
56745
|
import_https = require("https");
|
|
55856
56746
|
import_tls = require("tls");
|
|
55857
56747
|
import_net = require("net");
|
|
55858
|
-
import_child_process = require("child_process");
|
|
55859
|
-
import_fs4 = require("fs");
|
|
55860
|
-
import_os3 = require("os");
|
|
55861
|
-
import_path4 = require("path");
|
|
55862
|
-
import_url = require("url");
|
|
55863
56748
|
import_child_process2 = require("child_process");
|
|
55864
|
-
import_child_process3 = require("child_process");
|
|
55865
56749
|
import_fs5 = require("fs");
|
|
56750
|
+
import_os4 = require("os");
|
|
55866
56751
|
import_path5 = require("path");
|
|
56752
|
+
import_url = require("url");
|
|
56753
|
+
import_child_process3 = require("child_process");
|
|
56754
|
+
import_child_process4 = require("child_process");
|
|
56755
|
+
import_fs6 = require("fs");
|
|
55867
56756
|
import_path6 = require("path");
|
|
55868
|
-
|
|
56757
|
+
import_path7 = require("path");
|
|
56758
|
+
init_dist4();
|
|
55869
56759
|
import_meta3 = {};
|
|
55870
56760
|
DockerfileError = class extends Error {
|
|
55871
56761
|
kind;
|
|
@@ -56110,13 +57000,13 @@ function twinStatusForCredentials(creds, twinName) {
|
|
|
56110
57000
|
if (!creds) {
|
|
56111
57001
|
return "\x1B[32m\u2713 unlocked\x1B[0m";
|
|
56112
57002
|
}
|
|
56113
|
-
return
|
|
57003
|
+
return isEntitled(creds, twinName) ? "\x1B[32m\u2713 unlocked\x1B[0m" : "\x1B[90m\u2022 locked\x1B[0m";
|
|
56114
57004
|
}
|
|
56115
57005
|
function twinCatalogSummary(creds) {
|
|
56116
57006
|
return `All twins unlocked (${creds.plan} plan)`;
|
|
56117
57007
|
}
|
|
56118
57008
|
async function listTwinCatalog(json2) {
|
|
56119
|
-
const creds =
|
|
57009
|
+
const creds = getCredentials2();
|
|
56120
57010
|
if (!creds) {
|
|
56121
57011
|
if (json2) {
|
|
56122
57012
|
writeLocalTwinCatalogJson();
|
|
@@ -56282,7 +57172,7 @@ function resolveManagedTraceUploadEndpoint() {
|
|
|
56282
57172
|
if (explicit) {
|
|
56283
57173
|
return explicit.replace(/\/+$/, "");
|
|
56284
57174
|
}
|
|
56285
|
-
const baseUrl =
|
|
57175
|
+
const baseUrl = getConfiguredApiBaseUrl2();
|
|
56286
57176
|
if (!baseUrl) {
|
|
56287
57177
|
return null;
|
|
56288
57178
|
}
|
|
@@ -56293,7 +57183,7 @@ async function resolveManagedTraceUploadToken() {
|
|
|
56293
57183
|
if (envToken) {
|
|
56294
57184
|
return envToken;
|
|
56295
57185
|
}
|
|
56296
|
-
const creds =
|
|
57186
|
+
const creds = getCredentials2();
|
|
56297
57187
|
if (!creds) return null;
|
|
56298
57188
|
try {
|
|
56299
57189
|
const { refreshAuthFromServer: refreshAuthFromServer2, REQUEST_METADATA: REQUEST_METADATA3 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
|
|
@@ -56491,7 +57381,7 @@ async function uploadManagedTraceIfEnabled(report, options, config2, fetchImpl =
|
|
|
56491
57381
|
const telemetryToken = resolveTelemetryIngestToken(options);
|
|
56492
57382
|
let response;
|
|
56493
57383
|
try {
|
|
56494
|
-
response = await
|
|
57384
|
+
response = await fetchWithRetry2(endpoint, {
|
|
56495
57385
|
method: "POST",
|
|
56496
57386
|
headers: {
|
|
56497
57387
|
authorization: `Bearer ${token}`,
|
|
@@ -56517,14 +57407,14 @@ async function uploadManagedTraceIfEnabled(report, options, config2, fetchImpl =
|
|
|
56517
57407
|
const body = await response.text().catch(() => "");
|
|
56518
57408
|
const telemetryAuthRequired = response.status === 403 && /invalid telemetry ingest token/i.test(body) && !telemetryToken;
|
|
56519
57409
|
if (telemetryAuthRequired) {
|
|
56520
|
-
|
|
57410
|
+
debug3("Managed trace upload skipped (telemetry ingest token required by endpoint)", {
|
|
56521
57411
|
status: response.status,
|
|
56522
57412
|
endpoint
|
|
56523
57413
|
});
|
|
56524
57414
|
return { uploaded: false, reason: "telemetry_auth_required" };
|
|
56525
57415
|
}
|
|
56526
57416
|
if (response.status === 404) {
|
|
56527
|
-
|
|
57417
|
+
debug3("Managed trace upload skipped (endpoint not found \u2014 expected on self-hosted instances)", {
|
|
56528
57418
|
status: response.status,
|
|
56529
57419
|
endpoint
|
|
56530
57420
|
});
|
|
@@ -56537,7 +57427,7 @@ async function uploadManagedTraceIfEnabled(report, options, config2, fetchImpl =
|
|
|
56537
57427
|
});
|
|
56538
57428
|
return { uploaded: false, reason: `http_${response.status}` };
|
|
56539
57429
|
}
|
|
56540
|
-
|
|
57430
|
+
debug3("Managed trace upload succeeded", {
|
|
56541
57431
|
endpoint,
|
|
56542
57432
|
traceId: payload.traceId,
|
|
56543
57433
|
entries: payload.entries.length
|
|
@@ -56749,7 +57639,7 @@ function resolveProviderApiKey(explicitKey, provider) {
|
|
|
56749
57639
|
if (!normalizedExplicit) return providerEnvKey;
|
|
56750
57640
|
const mismatch = validateKeyForProvider(normalizedExplicit, provider);
|
|
56751
57641
|
if (mismatch && providerEnvKey) {
|
|
56752
|
-
|
|
57642
|
+
debug3("Configured API key appears mismatched for provider; falling back to provider env key", {
|
|
56753
57643
|
provider,
|
|
56754
57644
|
providerEnvVar: PROVIDER_ENV_VARS[provider]
|
|
56755
57645
|
});
|
|
@@ -56810,12 +57700,12 @@ function normalizeTokenUsage(inputTokens, outputTokens, totalTokens) {
|
|
|
56810
57700
|
};
|
|
56811
57701
|
}
|
|
56812
57702
|
async function callLlmViaArchal(options) {
|
|
56813
|
-
const creds =
|
|
57703
|
+
const creds = getCredentials2();
|
|
56814
57704
|
if (!creds?.token) {
|
|
56815
57705
|
throw new Error("Archal auth required. Run `archal login` or set ARCHAL_TOKEN.");
|
|
56816
57706
|
}
|
|
56817
57707
|
const hostedSessionId = getRunSessionContext()?.hostedSessionId;
|
|
56818
|
-
|
|
57708
|
+
debug3("Calling LLM via Archal backend", { intent: options.intent ?? "evaluate" });
|
|
56819
57709
|
const result = await requestLlmCompletion(creds.token, {
|
|
56820
57710
|
intent: options.intent ?? "evaluate",
|
|
56821
57711
|
systemPrompt: options.systemPrompt,
|
|
@@ -56838,10 +57728,10 @@ async function callLlmViaArchal(options) {
|
|
|
56838
57728
|
}
|
|
56839
57729
|
llmState.lastKnownRemaining = result.data.remaining ?? null;
|
|
56840
57730
|
const actualModel = result.data.model;
|
|
56841
|
-
|
|
57731
|
+
debug3("Archal backend response", { model: actualModel, remaining: String(result.data.remaining ?? "unknown") });
|
|
56842
57732
|
const isSeedGen = options.intent === "seed-generate";
|
|
56843
57733
|
if (!llmState.modelMismatchWarned && !isSeedGen && options.model && actualModel && actualModel !== "unknown" && !actualModel.includes(options.model) && !options.model.includes(actualModel)) {
|
|
56844
|
-
|
|
57734
|
+
debug3(`Archal backend used "${actualModel}" (requested "${options.model}"). To use a specific model, pass --api-key with your own API key.`);
|
|
56845
57735
|
llmState.modelMismatchWarned = true;
|
|
56846
57736
|
}
|
|
56847
57737
|
return {
|
|
@@ -56881,10 +57771,10 @@ async function callLlmWithUsage(options) {
|
|
|
56881
57771
|
return callLlmViaArchal(options);
|
|
56882
57772
|
}
|
|
56883
57773
|
if (routing === "direct-only" || directKey) {
|
|
56884
|
-
|
|
57774
|
+
debug3("Calling LLM provider directly", { provider: options.provider, model: options.model });
|
|
56885
57775
|
return callLlmDirect({ ...options, apiKey: directKey });
|
|
56886
57776
|
}
|
|
56887
|
-
const creds =
|
|
57777
|
+
const creds = getCredentials2();
|
|
56888
57778
|
if (options.provider !== "openai-compatible" && creds?.token) {
|
|
56889
57779
|
try {
|
|
56890
57780
|
return await callLlmViaArchal(options);
|
|
@@ -57052,7 +57942,7 @@ async function callOpenAiCompatible(options) {
|
|
|
57052
57942
|
);
|
|
57053
57943
|
}
|
|
57054
57944
|
const url2 = `${options.baseUrl.replace(/\/+$/, "")}/v1/chat/completions`;
|
|
57055
|
-
|
|
57945
|
+
debug3("Calling OpenAI-compatible endpoint", { url: url2, model: options.model });
|
|
57056
57946
|
const response = await fetch(url2, {
|
|
57057
57947
|
method: "POST",
|
|
57058
57948
|
headers: {
|
|
@@ -57981,7 +58871,7 @@ function parseScenarioMarkdown(markdown, sourcePath) {
|
|
|
57981
58871
|
tags: parsedConfig.tags ?? [],
|
|
57982
58872
|
difficulty: parsedConfig.difficulty
|
|
57983
58873
|
};
|
|
57984
|
-
|
|
58874
|
+
debug3("Parsed scenario", {
|
|
57985
58875
|
title: sections.title,
|
|
57986
58876
|
criteriaCount: successCriteria.length,
|
|
57987
58877
|
deterministicCount: successCriteria.filter((c) => c.type === "deterministic").length,
|
|
@@ -58611,7 +59501,7 @@ function writeLastRunLog(report) {
|
|
|
58611
59501
|
}
|
|
58612
59502
|
|
|
58613
59503
|
// src/runner/openclaw/openclaw-adapter.ts
|
|
58614
|
-
|
|
59504
|
+
init_dist4();
|
|
58615
59505
|
|
|
58616
59506
|
// src/runner/preflight.ts
|
|
58617
59507
|
init_auth();
|
|
@@ -58621,7 +59511,7 @@ function preflightCheck(scenario, apiKey, model, baseUrl, options) {
|
|
|
58621
59511
|
if (hasProbabilistic && !options?.skipEvaluatorAuth) {
|
|
58622
59512
|
const provider = detectProvider(model);
|
|
58623
59513
|
const resolvedKey = resolveProviderApiKey(apiKey, provider);
|
|
58624
|
-
const creds =
|
|
59514
|
+
const creds = getCredentials2();
|
|
58625
59515
|
if (provider === "openai-compatible" && !baseUrl) {
|
|
58626
59516
|
errors.push({
|
|
58627
59517
|
check: "evaluator.baseUrl",
|
|
@@ -58652,7 +59542,7 @@ function preflightCheck(scenario, apiKey, model, baseUrl, options) {
|
|
|
58652
59542
|
}
|
|
58653
59543
|
}
|
|
58654
59544
|
if (!options?.skipSeedAuth) {
|
|
58655
|
-
const creds =
|
|
59545
|
+
const creds = getCredentials2();
|
|
58656
59546
|
if (!creds?.token) {
|
|
58657
59547
|
errors.push({
|
|
58658
59548
|
check: "archal-auth-seed",
|
|
@@ -59260,7 +60150,7 @@ function selectSeedForTwin(twinName, setupDescription) {
|
|
|
59260
60150
|
0
|
|
59261
60151
|
);
|
|
59262
60152
|
const confidence = maxPossibleScore > 0 ? Math.min(bestScore / maxPossibleScore, 1) : 0;
|
|
59263
|
-
|
|
60153
|
+
debug3("Seed selection", {
|
|
59264
60154
|
twin: twinName,
|
|
59265
60155
|
seed: bestSeed,
|
|
59266
60156
|
confidence: confidence.toFixed(2),
|
|
@@ -59280,7 +60170,7 @@ function overrideSeedSelection(selections, overrides) {
|
|
|
59280
60170
|
return selections.map((sel) => {
|
|
59281
60171
|
const override = overrides[sel.twinName];
|
|
59282
60172
|
if (override) {
|
|
59283
|
-
|
|
60173
|
+
debug3(`Seed override for ${sel.twinName}: ${override}`);
|
|
59284
60174
|
return {
|
|
59285
60175
|
...sel,
|
|
59286
60176
|
seedName: override,
|
|
@@ -59720,7 +60610,7 @@ async function executeAgent(params) {
|
|
|
59720
60610
|
generateCertAuthority: generateCertAuthority2,
|
|
59721
60611
|
startProxy: startProxy2,
|
|
59722
60612
|
buildCloudTwinMappings: buildCloudTwinMappings2
|
|
59723
|
-
} = await Promise.resolve().then(() => (
|
|
60613
|
+
} = await Promise.resolve().then(() => (init_dist6(), dist_exports));
|
|
59724
60614
|
info("Starting TLS proxy for transparent HTTP routing...");
|
|
59725
60615
|
ca = generateCertAuthority2();
|
|
59726
60616
|
const mappings = buildCloudTwinMappings2(twinUrls);
|
|
@@ -59731,10 +60621,10 @@ async function executeAgent(params) {
|
|
|
59731
60621
|
ca,
|
|
59732
60622
|
twinAuthHeaders: bearerToken ? { Authorization: `Bearer ${bearerToken}` } : {},
|
|
59733
60623
|
onIntercept: (event) => {
|
|
59734
|
-
|
|
60624
|
+
debug3(`[proxy] ${event.method ?? "?"} ${event.domain}${event.path ?? "/"} \u2192 twin`);
|
|
59735
60625
|
},
|
|
59736
60626
|
onPassthrough: (event) => {
|
|
59737
|
-
|
|
60627
|
+
debug3(`[proxy] ${event.method ?? "?"} ${event.domain}${event.path ?? "/"} \u2192 passthrough`);
|
|
59738
60628
|
}
|
|
59739
60629
|
});
|
|
59740
60630
|
const noProxyHosts = "127.0.0.1,localhost,.archal.ai";
|
|
@@ -59783,10 +60673,10 @@ async function executeAgent(params) {
|
|
|
59783
60673
|
cwd: agentConfig.cwd,
|
|
59784
60674
|
env: agentEnv,
|
|
59785
60675
|
onStdout: (chunk) => {
|
|
59786
|
-
|
|
60676
|
+
debug3(`[agent stdout] ${chunk.trimEnd()}`);
|
|
59787
60677
|
},
|
|
59788
60678
|
onStderr: (chunk) => {
|
|
59789
|
-
|
|
60679
|
+
debug3(`[agent stderr] ${chunk.trimEnd()}`);
|
|
59790
60680
|
}
|
|
59791
60681
|
});
|
|
59792
60682
|
} finally {
|
|
@@ -59796,7 +60686,7 @@ async function executeAgent(params) {
|
|
|
59796
60686
|
}
|
|
59797
60687
|
if (ca) {
|
|
59798
60688
|
try {
|
|
59799
|
-
const { destroyCertAuthority: destroyCertAuthority2 } = await Promise.resolve().then(() => (
|
|
60689
|
+
const { destroyCertAuthority: destroyCertAuthority2 } = await Promise.resolve().then(() => (init_dist6(), dist_exports));
|
|
59800
60690
|
destroyCertAuthority2(ca);
|
|
59801
60691
|
} catch {
|
|
59802
60692
|
}
|
|
@@ -59847,7 +60737,7 @@ ${stderrPreview}`);
|
|
|
59847
60737
|
} catch (cleanupErr) {
|
|
59848
60738
|
const code = getErrnoCode(cleanupErr);
|
|
59849
60739
|
if (code !== "ENOENT") {
|
|
59850
|
-
|
|
60740
|
+
debug3(`Failed to clean up metrics file ${metricsFilePath}: ${errorMessage(cleanupErr)}`);
|
|
59851
60741
|
}
|
|
59852
60742
|
}
|
|
59853
60743
|
}
|
|
@@ -59873,7 +60763,7 @@ ${stderrPreview}`);
|
|
|
59873
60763
|
} catch (cleanupErr) {
|
|
59874
60764
|
const code = getErrnoCode(cleanupErr);
|
|
59875
60765
|
if (code !== "ENOENT") {
|
|
59876
|
-
|
|
60766
|
+
debug3(`Failed to clean up agent trace file ${agentTraceFilePath}: ${errorMessage(cleanupErr)}`);
|
|
59877
60767
|
}
|
|
59878
60768
|
}
|
|
59879
60769
|
}
|
|
@@ -60172,7 +61062,7 @@ ${scenario.seedState}` : scenario.setup;
|
|
|
60172
61062
|
sel.seedName = entry.seedName;
|
|
60173
61063
|
sel.seedData = entry.seedData;
|
|
60174
61064
|
}
|
|
60175
|
-
|
|
61065
|
+
debug3("Using managed seed snapshot replay", {
|
|
60176
61066
|
snapshotPath: options.seedSnapshotIn,
|
|
60177
61067
|
twins: scenario.config.twins.join(", ")
|
|
60178
61068
|
});
|
|
@@ -60995,7 +61885,7 @@ function resolveEngineConfiguration(scenario, options, timeoutSeconds, projectCo
|
|
|
60995
61885
|
const openclawAgent = options.agent?.trim() || process.env["ARCHAL_OPENCLAW_AGENT"] || "main";
|
|
60996
61886
|
const fallbackLocalAgentConfig = resolvedFallbackLocalAgentConfig ?? { command: "openclaw", args: ["--agent", openclawAgent] };
|
|
60997
61887
|
if (!resolvedHarness.manifest && !resolvedHarness.localCommand) {
|
|
60998
|
-
|
|
61888
|
+
debug3(
|
|
60999
61889
|
"Harness manifest not found for local mode; using agent command defaults.",
|
|
61000
61890
|
{ manifestPath: resolvedHarness.manifestPath }
|
|
61001
61891
|
);
|
|
@@ -61119,7 +62009,7 @@ async function cleanupDockerImage2(..._args) {
|
|
|
61119
62009
|
|
|
61120
62010
|
// src/runner/execution/run-executor.ts
|
|
61121
62011
|
var import_node_fs17 = require("fs");
|
|
61122
|
-
|
|
62012
|
+
init_dist6();
|
|
61123
62013
|
init_logger();
|
|
61124
62014
|
|
|
61125
62015
|
// src/runner/lifecycle/timeout-budget.ts
|
|
@@ -61299,7 +62189,7 @@ async function executeAgentPhase(params) {
|
|
|
61299
62189
|
effectiveRemoteTwinUrls,
|
|
61300
62190
|
apiRouting,
|
|
61301
62191
|
openclawEvalMode,
|
|
61302
|
-
{ debug, info }
|
|
62192
|
+
{ debug: debug3, info }
|
|
61303
62193
|
) : await executeAgent({
|
|
61304
62194
|
agentConfig,
|
|
61305
62195
|
mcpConfigPath: configFiles.mcpConfigPath,
|
|
@@ -62212,7 +63102,7 @@ function buildUserPrompt(context) {
|
|
|
62212
63102
|
expectedBehavior: context.expectedBehavior
|
|
62213
63103
|
});
|
|
62214
63104
|
const traceEvidence = renderTraceEvidenceForPrompt(traceEvidencePacket);
|
|
62215
|
-
|
|
63105
|
+
debug3("LLM judge trace evidence selected", {
|
|
62216
63106
|
criterion: context.criterion.id,
|
|
62217
63107
|
totalSpans: String(traceEvidencePacket.summary.totalSpans),
|
|
62218
63108
|
selectedSpans: String(traceEvidencePacket.summary.selectedSpans),
|
|
@@ -62266,7 +63156,7 @@ function buildBatchUserPrompt(criteria, expectedBehavior, stateBefore, stateAfte
|
|
|
62266
63156
|
expectedBehavior
|
|
62267
63157
|
});
|
|
62268
63158
|
const traceEvidence = renderTraceEvidenceForPrompt(traceEvidencePacket);
|
|
62269
|
-
|
|
63159
|
+
debug3("LLM judge batch trace evidence selected", {
|
|
62270
63160
|
criteriaCount: String(criteria.length),
|
|
62271
63161
|
totalSpans: String(traceEvidencePacket.summary.totalSpans),
|
|
62272
63162
|
selectedSpans: String(traceEvidencePacket.summary.selectedSpans),
|
|
@@ -62352,7 +63242,7 @@ var BATCH_RESPONSE_SCHEMA = {
|
|
|
62352
63242
|
async function evaluateBatchWithLlm(criteria, context, config2) {
|
|
62353
63243
|
const provider = detectProvider(config2.model);
|
|
62354
63244
|
const apiKey = resolveProviderApiKey(config2.apiKey, provider);
|
|
62355
|
-
const credentials =
|
|
63245
|
+
const credentials = getCredentials2();
|
|
62356
63246
|
const canUseManagedRouting = provider !== "openai-compatible" && Boolean(credentials?.token);
|
|
62357
63247
|
if (apiKey) {
|
|
62358
63248
|
const mismatch = validateKeyForProvider(apiKey, provider);
|
|
@@ -62374,7 +63264,7 @@ async function evaluateBatchWithLlm(criteria, context, config2) {
|
|
|
62374
63264
|
tokenUsage: null
|
|
62375
63265
|
};
|
|
62376
63266
|
}
|
|
62377
|
-
|
|
63267
|
+
debug3("Calling LLM judge (batch)", {
|
|
62378
63268
|
criteriaCount: String(criteria.length),
|
|
62379
63269
|
criteriaIds: criteria.map((c) => c.id).join(", "),
|
|
62380
63270
|
model: config2.model,
|
|
@@ -62412,7 +63302,7 @@ async function evaluateBatchWithLlm(criteria, context, config2) {
|
|
|
62412
63302
|
evaluations: criteria.map((c) => {
|
|
62413
63303
|
const result = parsed.get(c.id);
|
|
62414
63304
|
if (result) {
|
|
62415
|
-
|
|
63305
|
+
debug3("LLM judge batch result", {
|
|
62416
63306
|
criterion: c.id,
|
|
62417
63307
|
status: result.status,
|
|
62418
63308
|
confidence: result.confidence.toFixed(2)
|
|
@@ -62482,7 +63372,7 @@ async function evaluateWithLlm(criterion, context, config2) {
|
|
|
62482
63372
|
};
|
|
62483
63373
|
const provider = detectProvider(config2.model);
|
|
62484
63374
|
const apiKey = resolveProviderApiKey(config2.apiKey, provider);
|
|
62485
|
-
const credentials =
|
|
63375
|
+
const credentials = getCredentials2();
|
|
62486
63376
|
const canUseManagedRouting = provider !== "openai-compatible" && Boolean(credentials?.token);
|
|
62487
63377
|
if (apiKey) {
|
|
62488
63378
|
const mismatch = validateKeyForProvider(apiKey, provider);
|
|
@@ -62504,7 +63394,7 @@ async function evaluateWithLlm(criterion, context, config2) {
|
|
|
62504
63394
|
tokenUsage: null
|
|
62505
63395
|
};
|
|
62506
63396
|
}
|
|
62507
|
-
|
|
63397
|
+
debug3("Calling LLM judge", {
|
|
62508
63398
|
criterion: criterion.id,
|
|
62509
63399
|
model: config2.model,
|
|
62510
63400
|
provider,
|
|
@@ -62526,7 +63416,7 @@ async function evaluateWithLlm(criterion, context, config2) {
|
|
|
62526
63416
|
});
|
|
62527
63417
|
const text = response.text;
|
|
62528
63418
|
const judgeResult = parseJudgeResponse(text);
|
|
62529
|
-
|
|
63419
|
+
debug3("LLM judge result", {
|
|
62530
63420
|
criterion: criterion.id,
|
|
62531
63421
|
status: judgeResult.status,
|
|
62532
63422
|
confidence: judgeResult.confidence.toFixed(2)
|
|
@@ -63729,7 +64619,7 @@ function stripMarkdownCodeFence(text) {
|
|
|
63729
64619
|
}
|
|
63730
64620
|
function isLlmParsingAvailable(config2) {
|
|
63731
64621
|
if (config2.apiKey) return true;
|
|
63732
|
-
const creds =
|
|
64622
|
+
const creds = getCredentials2();
|
|
63733
64623
|
if (creds?.token) return true;
|
|
63734
64624
|
const model = config2.model ?? "claude-haiku-4-5-20251001";
|
|
63735
64625
|
const provider = detectProvider(model);
|
|
@@ -63739,15 +64629,15 @@ function isLlmParsingAvailable(config2) {
|
|
|
63739
64629
|
async function parseAssertionWithLlm(description, config2) {
|
|
63740
64630
|
const cached2 = parseCache.get(description);
|
|
63741
64631
|
if (cached2 !== void 0) {
|
|
63742
|
-
|
|
64632
|
+
debug3("LLM assertion parser: cache hit", { description: description.slice(0, 60) });
|
|
63743
64633
|
return cached2;
|
|
63744
64634
|
}
|
|
63745
64635
|
const model = config2.model ?? "claude-haiku-4-5-20251001";
|
|
63746
64636
|
const provider = detectProvider(model);
|
|
63747
64637
|
const apiKey = resolveProviderApiKey(config2.apiKey ?? "", provider);
|
|
63748
|
-
const canUseManagedRouting = provider !== "openai-compatible" && Boolean(
|
|
64638
|
+
const canUseManagedRouting = provider !== "openai-compatible" && Boolean(getCredentials2()?.token);
|
|
63749
64639
|
if (!apiKey && !canUseManagedRouting) {
|
|
63750
|
-
|
|
64640
|
+
debug3("LLM assertion parser unavailable: no provider key or managed auth", {
|
|
63751
64641
|
model,
|
|
63752
64642
|
provider
|
|
63753
64643
|
});
|
|
@@ -63773,18 +64663,18 @@ Output:`,
|
|
|
63773
64663
|
const result = await callLlmWithUsage(llmOptions);
|
|
63774
64664
|
const text = stripMarkdownCodeFence(result.text);
|
|
63775
64665
|
if (text === "null" || text === "{}") {
|
|
63776
|
-
|
|
64666
|
+
debug3("LLM assertion parser: returned null for", { description: description.slice(0, 60) });
|
|
63777
64667
|
parseCache.set(description, null);
|
|
63778
64668
|
return null;
|
|
63779
64669
|
}
|
|
63780
64670
|
const parsed = JSON.parse(text);
|
|
63781
64671
|
const assertion = validateParsedAssertion(parsed);
|
|
63782
64672
|
if (!assertion) {
|
|
63783
|
-
|
|
64673
|
+
debug3("LLM assertion parser: invalid structure returned", { description: description.slice(0, 60), raw: text.slice(0, 200) });
|
|
63784
64674
|
parseCache.set(description, null);
|
|
63785
64675
|
return null;
|
|
63786
64676
|
}
|
|
63787
|
-
|
|
64677
|
+
debug3("LLM assertion parser: success", {
|
|
63788
64678
|
description: description.slice(0, 60),
|
|
63789
64679
|
type: assertion.type,
|
|
63790
64680
|
subject: assertion.subject
|
|
@@ -63915,7 +64805,7 @@ function buildFallbackResult(criterion) {
|
|
|
63915
64805
|
async function evaluateDeterministicWithLlmParsing(criterion, stateView, parserConfig) {
|
|
63916
64806
|
const regexAssertion = parseAssertion(criterion.description);
|
|
63917
64807
|
if (regexAssertion) {
|
|
63918
|
-
|
|
64808
|
+
debug3("Parsed assertion (regex)", {
|
|
63919
64809
|
type: regexAssertion.type,
|
|
63920
64810
|
subject: regexAssertion.subject,
|
|
63921
64811
|
value: String(regexAssertion.value ?? ""),
|
|
@@ -63929,7 +64819,7 @@ async function evaluateDeterministicWithLlmParsing(criterion, stateView, parserC
|
|
|
63929
64819
|
info(`[D] regex failed for "${criterion.description}" \u2014 trying LLM structured parser`);
|
|
63930
64820
|
const llmAssertion = await parseAssertionWithLlm(criterion.description, llmConfig);
|
|
63931
64821
|
if (llmAssertion) {
|
|
63932
|
-
|
|
64822
|
+
debug3("Parsed assertion (LLM)", {
|
|
63933
64823
|
type: llmAssertion.type,
|
|
63934
64824
|
subject: llmAssertion.subject,
|
|
63935
64825
|
value: String(llmAssertion.value ?? ""),
|
|
@@ -63940,7 +64830,7 @@ async function evaluateDeterministicWithLlmParsing(criterion, stateView, parserC
|
|
|
63940
64830
|
info(`[D] LLM structured parser also failed for "${criterion.description}" \u2014 falling back to full LLM judge`);
|
|
63941
64831
|
} else {
|
|
63942
64832
|
info(`[D] criterion "${criterion.description}" could not be parsed deterministically \u2014 falling back to LLM judge`);
|
|
63943
|
-
|
|
64833
|
+
debug3(`Unparseable assertion text: "${criterion.description}"`);
|
|
63944
64834
|
}
|
|
63945
64835
|
return buildFallbackResult(criterion);
|
|
63946
64836
|
}
|
|
@@ -64064,7 +64954,7 @@ async function evaluateRun(criteria, context, config2) {
|
|
|
64064
64954
|
} else {
|
|
64065
64955
|
evaluations.push(result);
|
|
64066
64956
|
}
|
|
64067
|
-
|
|
64957
|
+
debug3("Deterministic evaluation", {
|
|
64068
64958
|
criterion: criterion.id,
|
|
64069
64959
|
status: evaluations.at(-1)?.status ?? "fail"
|
|
64070
64960
|
});
|
|
@@ -64101,7 +64991,7 @@ async function evaluateRun(criteria, context, config2) {
|
|
|
64101
64991
|
judgeTokenUsage = accumulateTokenUsage(judgeTokenUsage, tokenUsage);
|
|
64102
64992
|
for (const result of batchResults) {
|
|
64103
64993
|
evaluations.push(result);
|
|
64104
|
-
|
|
64994
|
+
debug3("Probabilistic evaluation (batch)", {
|
|
64105
64995
|
criterion: result.criterionId,
|
|
64106
64996
|
status: result.status,
|
|
64107
64997
|
confidence: result.confidence.toFixed(2)
|
|
@@ -64113,7 +65003,7 @@ async function evaluateRun(criteria, context, config2) {
|
|
|
64113
65003
|
const { evaluation: result, tokenUsage } = await evaluateWithLlm(criterion, context, config2);
|
|
64114
65004
|
judgeTokenUsage = accumulateTokenUsage(judgeTokenUsage, tokenUsage);
|
|
64115
65005
|
evaluations.push(result);
|
|
64116
|
-
|
|
65006
|
+
debug3("Probabilistic evaluation", {
|
|
64117
65007
|
criterion: criterion.id,
|
|
64118
65008
|
status: result.status,
|
|
64119
65009
|
confidence: result.confidence.toFixed(2)
|
|
@@ -64279,7 +65169,7 @@ ${sanitizeForPrompt(logTail, 800)}`);
|
|
|
64279
65169
|
async function generateFailureAnalysisWithUsage(input, config2) {
|
|
64280
65170
|
const provider = detectProvider(config2.model);
|
|
64281
65171
|
const apiKey = resolveProviderApiKey(config2.apiKey, provider);
|
|
64282
|
-
const credentials =
|
|
65172
|
+
const credentials = getCredentials2();
|
|
64283
65173
|
const canUseManagedRouting = provider !== "openai-compatible" && Boolean(credentials?.token);
|
|
64284
65174
|
if (apiKey) {
|
|
64285
65175
|
const mismatch = validateKeyForProvider(apiKey, provider);
|
|
@@ -64288,7 +65178,7 @@ async function generateFailureAnalysisWithUsage(input, config2) {
|
|
|
64288
65178
|
}
|
|
64289
65179
|
}
|
|
64290
65180
|
if (!apiKey && !canUseManagedRouting) {
|
|
64291
|
-
|
|
65181
|
+
debug3("Skipping failure analysis \u2014 no API key or Archal auth for evaluator model");
|
|
64292
65182
|
return { text: void 0, tokenUsage: null };
|
|
64293
65183
|
}
|
|
64294
65184
|
try {
|
|
@@ -64311,7 +65201,7 @@ async function generateFailureAnalysisWithUsage(input, config2) {
|
|
|
64311
65201
|
if (error49 instanceof LlmApiError) {
|
|
64312
65202
|
warn(`Failure analysis skipped: ${error49.message}`);
|
|
64313
65203
|
} else {
|
|
64314
|
-
|
|
65204
|
+
debug3("Failure analysis error", { error: String(error49) });
|
|
64315
65205
|
}
|
|
64316
65206
|
return { text: void 0, tokenUsage: null };
|
|
64317
65207
|
}
|
|
@@ -64529,7 +65419,7 @@ async function syncCapabilityMissesToSessionEvents(token, sessionId, misses) {
|
|
|
64529
65419
|
warn(`Failed to persist capability miss for session ${sessionId}: ${result.error}`);
|
|
64530
65420
|
return;
|
|
64531
65421
|
}
|
|
64532
|
-
|
|
65422
|
+
debug3("Persisted capability miss session event", {
|
|
64533
65423
|
sessionId,
|
|
64534
65424
|
eventIndex: String(result.data.eventIndex),
|
|
64535
65425
|
fingerprint: miss.miss.fingerprint
|
|
@@ -64546,7 +65436,7 @@ async function collectAndExtractPostRunData(stdout, cloudTwinUrls, beforeState,
|
|
|
64546
65436
|
const diff = computeStateDiff(beforeState, stateAfter);
|
|
64547
65437
|
const agentResponseText = extractAgentResponseText(stdout);
|
|
64548
65438
|
if (agentResponseText) {
|
|
64549
|
-
|
|
65439
|
+
debug3("Extracted agent response text", { length: String(agentResponseText.length) });
|
|
64550
65440
|
}
|
|
64551
65441
|
return { stateAfter, trace, events, diff, agentResponseText };
|
|
64552
65442
|
}
|
|
@@ -64737,7 +65627,7 @@ async function executeSandboxPath(ctx, startTime, beforeState, cloudTwinUrls) {
|
|
|
64737
65627
|
});
|
|
64738
65628
|
const abortCapabilityMiss = findAbortCapabilityMiss(capabilityMisses);
|
|
64739
65629
|
const hasTrace = postRun.trace.length > 0;
|
|
64740
|
-
const logSandbox = hasTrace ?
|
|
65630
|
+
const logSandbox = hasTrace ? debug3 : warn;
|
|
64741
65631
|
logSandbox(`Sandbox stdout (agent output, run ${runIndex + 1}):
|
|
64742
65632
|
${sandboxResult.stdout.slice(0, 3e3) || "(empty)"}`);
|
|
64743
65633
|
logSandbox(`Sandbox stderr (setup log, run ${runIndex + 1}, tail):
|
|
@@ -64852,7 +65742,7 @@ async function executeDockerHarnessPath(ctx, startTime, beforeState, cloudTwinUr
|
|
|
64852
65742
|
});
|
|
64853
65743
|
const abortCapabilityMiss = findAbortCapabilityMiss(capabilityMisses);
|
|
64854
65744
|
const hasTrace = postRun.trace.length > 0;
|
|
64855
|
-
const logResult = hasTrace ?
|
|
65745
|
+
const logResult = hasTrace ? debug3 : warn;
|
|
64856
65746
|
logResult(`Docker harness stdout (run ${runIndex + 1}):
|
|
64857
65747
|
${result.stdout.slice(0, 3e3) || "(empty)"}`);
|
|
64858
65748
|
logResult(`Docker harness stderr (run ${runIndex + 1}, tail):
|
|
@@ -66730,7 +67620,7 @@ async function cleanupHostedSession(ctx) {
|
|
|
66730
67620
|
return;
|
|
66731
67621
|
}
|
|
66732
67622
|
const sessionId = ctx.backendSessionId;
|
|
66733
|
-
const freshCreds =
|
|
67623
|
+
const freshCreds = getCredentials2();
|
|
66734
67624
|
const credentials = freshCreds ?? ctx.credentials;
|
|
66735
67625
|
if (!credentials) {
|
|
66736
67626
|
process.stderr.write("Warning: unable to finalize hosted session evidence (missing auth token).\n");
|
|
@@ -66880,7 +67770,7 @@ async function waitForSessionReady(opts) {
|
|
|
66880
67770
|
if (!opts.quiet) process.stderr.write(` Still waiting for session to be ready (${elapsedSec}s)...
|
|
66881
67771
|
`);
|
|
66882
67772
|
}
|
|
66883
|
-
const freshCreds =
|
|
67773
|
+
const freshCreds = getCredentials2();
|
|
66884
67774
|
if (freshCreds) credentials = freshCreds;
|
|
66885
67775
|
let statusResult;
|
|
66886
67776
|
let healthResult;
|
|
@@ -67293,7 +68183,7 @@ function validateHarnessConflicts(opts) {
|
|
|
67293
68183
|
}
|
|
67294
68184
|
}
|
|
67295
68185
|
async function resolveCredentialsAndEntitlements(scenarioArg, scenario, opts) {
|
|
67296
|
-
let credentials =
|
|
68186
|
+
let credentials = getCredentials2();
|
|
67297
68187
|
if (opts.preflightOnly && !credentials) {
|
|
67298
68188
|
const userConfig = loadConfig();
|
|
67299
68189
|
const hasProviderKey = Boolean(
|
|
@@ -67314,7 +68204,7 @@ async function resolveCredentialsAndEntitlements(scenarioArg, scenario, opts) {
|
|
|
67314
68204
|
action: "run a scenario",
|
|
67315
68205
|
nextCommand: `archal run ${scenarioArg}`
|
|
67316
68206
|
});
|
|
67317
|
-
credentials = required2 ??
|
|
68207
|
+
credentials = required2 ?? getCredentials2();
|
|
67318
68208
|
if (!credentials) {
|
|
67319
68209
|
validationError(
|
|
67320
68210
|
"Not logged in.",
|
|
@@ -67323,9 +68213,9 @@ async function resolveCredentialsAndEntitlements(scenarioArg, scenario, opts) {
|
|
|
67323
68213
|
}
|
|
67324
68214
|
}
|
|
67325
68215
|
if (credentials) {
|
|
67326
|
-
credentials = await
|
|
68216
|
+
credentials = await refreshAuthFromServer(credentials, REQUEST_METADATA2);
|
|
67327
68217
|
for (const twinName of scenario.config.twins) {
|
|
67328
|
-
if (!
|
|
68218
|
+
if (!isEntitled(credentials, twinName)) {
|
|
67329
68219
|
validationError(
|
|
67330
68220
|
`Your current plan does not have access to the "${twinName}" twin.`,
|
|
67331
68221
|
"Run `archal list --twins` to see available twins."
|
|
@@ -67875,7 +68765,7 @@ async function executeRunForScenario(scenarioArg, opts, command, configDefaults)
|
|
|
67875
68765
|
ctx.inFlightSessionStart = null;
|
|
67876
68766
|
}
|
|
67877
68767
|
if (sessionResult.ok) {
|
|
67878
|
-
credentials =
|
|
68768
|
+
credentials = getCredentials2() ?? credentials;
|
|
67879
68769
|
ctx.backendSessionId = sessionResult.data.sessionId;
|
|
67880
68770
|
ctx.credentials = credentials;
|
|
67881
68771
|
writeManagedRunStatus({
|
|
@@ -68279,7 +69169,7 @@ var import_node_http = require("http");
|
|
|
68279
69169
|
init_dist2();
|
|
68280
69170
|
|
|
68281
69171
|
// src/auth/constants.ts
|
|
68282
|
-
|
|
69172
|
+
init_dist3();
|
|
68283
69173
|
|
|
68284
69174
|
// src/commands/login.ts
|
|
68285
69175
|
init_auth();
|
|
@@ -68341,7 +69231,7 @@ function credentialsFromApiToken(token) {
|
|
|
68341
69231
|
refreshToken: "",
|
|
68342
69232
|
email: "(from token)",
|
|
68343
69233
|
plan: "free",
|
|
68344
|
-
expiresAt:
|
|
69234
|
+
expiresAt: getJwtExpiry(token) ?? nowSeconds + TOKEN_FALLBACK_TTL_SECONDS
|
|
68345
69235
|
};
|
|
68346
69236
|
}
|
|
68347
69237
|
function buildDashboardLoginSuccessUrl(authBaseUrl) {
|
|
@@ -68350,7 +69240,7 @@ function buildDashboardLoginSuccessUrl(authBaseUrl) {
|
|
|
68350
69240
|
return dashboardUrl.toString();
|
|
68351
69241
|
}
|
|
68352
69242
|
function persistLogin(credentials) {
|
|
68353
|
-
|
|
69243
|
+
saveCredentials(credentials);
|
|
68354
69244
|
bindConfigToLogin(credentials);
|
|
68355
69245
|
success2(`Logged in as ${credentials.email} (${credentials.plan} plan)`);
|
|
68356
69246
|
}
|
|
@@ -68479,7 +69369,7 @@ function createLoginCommand() {
|
|
|
68479
69369
|
const directToken = opts.token?.trim();
|
|
68480
69370
|
if (directToken) {
|
|
68481
69371
|
let credentials = credentialsFromApiToken(directToken);
|
|
68482
|
-
credentials = await
|
|
69372
|
+
credentials = await refreshAuthFromServer(credentials, REQUEST_METADATA2);
|
|
68483
69373
|
if (credentials.email === "(from token)") {
|
|
68484
69374
|
throw new CliRuntimeError(
|
|
68485
69375
|
"Token could not be verified. Check that the token is valid and try again."
|
|
@@ -68489,10 +69379,10 @@ function createLoginCommand() {
|
|
|
68489
69379
|
await maybePromptForModelKey();
|
|
68490
69380
|
return;
|
|
68491
69381
|
}
|
|
68492
|
-
const authBaseUrl =
|
|
69382
|
+
const authBaseUrl = getConfiguredAuthBaseUrl2();
|
|
68493
69383
|
const dashboardTokenUrl = new URL(
|
|
68494
69384
|
"/dashboard",
|
|
68495
|
-
`${authBaseUrl ??
|
|
69385
|
+
`${authBaseUrl ?? HOSTED_DEFAULT_AUTH_BASE_URL}/`
|
|
68496
69386
|
).toString();
|
|
68497
69387
|
if (isHeadlessEnvironment() && opts.browser !== false) {
|
|
68498
69388
|
const lines = [
|
|
@@ -68583,7 +69473,7 @@ function createLoginCommand() {
|
|
|
68583
69473
|
closeAndReject(new Error("Missing code in callback"));
|
|
68584
69474
|
return;
|
|
68585
69475
|
}
|
|
68586
|
-
const credentials = await
|
|
69476
|
+
const credentials = await exchangeCliAuthCode2({
|
|
68587
69477
|
code,
|
|
68588
69478
|
codeVerifier,
|
|
68589
69479
|
redirectUri: redirectUrl
|
|
@@ -68627,7 +69517,7 @@ function createLoginCommand() {
|
|
|
68627
69517
|
init_credential_store();
|
|
68628
69518
|
function createLogoutCommand() {
|
|
68629
69519
|
return new Command("logout").description("Log out of Archal and remove stored credentials").action(() => {
|
|
68630
|
-
const deleted =
|
|
69520
|
+
const deleted = deleteCredentials();
|
|
68631
69521
|
if (deleted) {
|
|
68632
69522
|
console.log("Logged out of Archal.");
|
|
68633
69523
|
} else {
|
|
@@ -68858,7 +69748,7 @@ function parseSeeds(raw) {
|
|
|
68858
69748
|
return seeds;
|
|
68859
69749
|
}
|
|
68860
69750
|
function requireToken() {
|
|
68861
|
-
const token =
|
|
69751
|
+
const token = getCredentials2()?.token?.trim();
|
|
68862
69752
|
if (!token) {
|
|
68863
69753
|
throw new CliRuntimeError("Not authenticated. Run 'archal login' first.");
|
|
68864
69754
|
}
|
|
@@ -69521,10 +70411,10 @@ function suggestNextCommand(commandName, message) {
|
|
|
69521
70411
|
init_errors4();
|
|
69522
70412
|
|
|
69523
70413
|
// src/error-handling.ts
|
|
69524
|
-
|
|
70414
|
+
init_dist3();
|
|
69525
70415
|
init_errors4();
|
|
69526
70416
|
function isExpiredEnvTokenError(error49) {
|
|
69527
|
-
return error49 instanceof
|
|
70417
|
+
return error49 instanceof ExpiredEnvTokenError || error49 instanceof Error && error49.name === "ExpiredEnvTokenError";
|
|
69528
70418
|
}
|
|
69529
70419
|
|
|
69530
70420
|
// src/index.ts
|
|
@@ -69584,7 +70474,7 @@ Did you mean: ${close.map((c) => `archal ${c}`).join(", ")}?` : "";
|
|
|
69584
70474
|
throw new CliUsageError(`unknown command '${guess}'${hint}
|
|
69585
70475
|
Run: archal --help`);
|
|
69586
70476
|
}
|
|
69587
|
-
const creds =
|
|
70477
|
+
const creds = getCredentials2();
|
|
69588
70478
|
if (!creds) {
|
|
69589
70479
|
process.stderr.write(
|
|
69590
70480
|
"\x1B[36marchal\x1B[0m \x1B[2m\u2014 Pre-deployment testing for AI agents\x1B[0m\n\nGet started:\n \x1B[36marchal login\x1B[0m \x1B[2mAuthenticate with Archal\x1B[0m\n \x1B[36marchal --help\x1B[0m \x1B[2mSee all commands\x1B[0m\n\n"
|