@omnicross/daemon 0.4.4 → 0.4.6

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/dist/cli.js CHANGED
@@ -1155,7 +1155,7 @@ import {
1155
1155
  } from "@omnicross/core/search";
1156
1156
 
1157
1157
  // src/bootstrap.ts
1158
- import { accessSync, constants as fsConstants, existsSync as existsSync30, mkdirSync as mkdirSync9 } from "fs";
1158
+ import { accessSync, constants as fsConstants, existsSync as existsSync31, mkdirSync as mkdirSync9 } from "fs";
1159
1159
  import { dirname as dirname17 } from "path";
1160
1160
  import { DEFAULT_AUDIT_CONFIG } from "@omnicross/contracts/audit-types";
1161
1161
  import { DEFAULT_BILLING_CONFIG } from "@omnicross/contracts/billing-types";
@@ -1352,14 +1352,14 @@ async function runKimiDevicePoll(sessionId, deviceCode, deviceId, fingerprint, s
1352
1352
  {
1353
1353
  fingerprint,
1354
1354
  deadlineMs: DEFAULT_KIMI_OAUTH_TTL_MS,
1355
- sleep: (ms) => new Promise((resolve11, reject) => {
1355
+ sleep: (ms) => new Promise((resolve12, reject) => {
1356
1356
  const onAbort = () => {
1357
1357
  clearTimeout(timer);
1358
1358
  reject(new Error("login: cancelled"));
1359
1359
  };
1360
1360
  const timer = setTimeout(() => {
1361
1361
  signal.removeEventListener("abort", onAbort);
1362
- resolve11();
1362
+ resolve12();
1363
1363
  }, ms);
1364
1364
  signal.addEventListener("abort", onAbort, { once: true });
1365
1365
  })
@@ -1435,14 +1435,14 @@ async function runGrokDevicePoll(sessionId, tokenEndpoint, deviceCode, signal, d
1435
1435
  fetchImpl,
1436
1436
  {
1437
1437
  deadlineMs: DEFAULT_GROK_OAUTH_TTL_MS,
1438
- sleep: (ms) => new Promise((resolve11, reject) => {
1438
+ sleep: (ms) => new Promise((resolve12, reject) => {
1439
1439
  const onAbort = () => {
1440
1440
  clearTimeout(timer);
1441
1441
  reject(new Error("login: cancelled"));
1442
1442
  };
1443
1443
  const timer = setTimeout(() => {
1444
1444
  signal.removeEventListener("abort", onAbort);
1445
- resolve11();
1445
+ resolve12();
1446
1446
  }, ms);
1447
1447
  signal.addEventListener("abort", onAbort, { once: true });
1448
1448
  })
@@ -1520,14 +1520,14 @@ async function runCopilotDevicePoll(sessionId, deviceCode, signal, deps, enterpr
1520
1520
  {
1521
1521
  deadlineMs: DEFAULT_COPILOT_OAUTH_TTL_MS,
1522
1522
  ...enterpriseUrl ? { enterpriseUrl } : {},
1523
- sleep: (ms) => new Promise((resolve11, reject) => {
1523
+ sleep: (ms) => new Promise((resolve12, reject) => {
1524
1524
  const onAbort = () => {
1525
1525
  clearTimeout(timer);
1526
1526
  reject(new Error("login: cancelled"));
1527
1527
  };
1528
1528
  const timer = setTimeout(() => {
1529
1529
  signal.removeEventListener("abort", onAbort);
1530
- resolve11();
1530
+ resolve12();
1531
1531
  }, ms);
1532
1532
  signal.addEventListener("abort", onAbort, { once: true });
1533
1533
  })
@@ -3913,19 +3913,19 @@ function teardown() {
3913
3913
 
3914
3914
  // src/admin/webhookTestApi.ts
3915
3915
  function readJsonBody(req) {
3916
- return new Promise((resolve11) => {
3916
+ return new Promise((resolve12) => {
3917
3917
  const chunks = [];
3918
3918
  req.on("data", (c) => chunks.push(c));
3919
3919
  req.on("end", () => {
3920
3920
  try {
3921
3921
  const raw = Buffer.concat(chunks).toString("utf8");
3922
3922
  const parsed = raw ? JSON.parse(raw) : {};
3923
- resolve11(parsed && typeof parsed === "object" ? parsed : {});
3923
+ resolve12(parsed && typeof parsed === "object" ? parsed : {});
3924
3924
  } catch {
3925
- resolve11({});
3925
+ resolve12({});
3926
3926
  }
3927
3927
  });
3928
- req.on("error", () => resolve11({}));
3928
+ req.on("error", () => resolve12({}));
3929
3929
  });
3930
3930
  }
3931
3931
  async function handleWebhookTest(req, res) {
@@ -4028,13 +4028,771 @@ async function handleRouteLeaseApi(req, res, path2, deps) {
4028
4028
  }
4029
4029
  }
4030
4030
 
4031
+ // src/admin/codexSessionManager.ts
4032
+ import { homedir as homedir2 } from "os";
4033
+ import { basename, join as join6, resolve, win32 } from "path";
4034
+ import {
4035
+ copyFile,
4036
+ open,
4037
+ readdir,
4038
+ readFile,
4039
+ rename,
4040
+ stat,
4041
+ unlink,
4042
+ writeFile
4043
+ } from "fs/promises";
4044
+ import { existsSync as existsSync5 } from "fs";
4045
+ import { randomUUID as randomUUID2 } from "crypto";
4046
+ import { TextDecoder as TextDecoder2 } from "util";
4047
+ var PROVIDER_PROPERTY_NAMES = /* @__PURE__ */ new Set(["model_provider", "model_provider_id"]);
4048
+ var FIRST_LINE_LIMIT = 4 * 1024 * 1024;
4049
+ var PROVIDER_ID_LIMIT = 256;
4050
+ var CodexSessionManagerError = class extends Error {
4051
+ constructor(message) {
4052
+ super(message);
4053
+ this.name = "CodexSessionManagerError";
4054
+ }
4055
+ };
4056
+ var CodexSessionManager = class {
4057
+ codexHome;
4058
+ stateDatabasePath;
4059
+ mutationTail = Promise.resolve();
4060
+ constructor(options = {}) {
4061
+ const configuredHome = options.codexHome?.trim() || process.env["CODEX_HOME"]?.trim();
4062
+ this.codexHome = configuredHome || join6(homedir2(), ".codex");
4063
+ this.stateDatabasePath = options.stateDatabasePath?.trim() || join6(this.codexHome, "state_5.sqlite");
4064
+ }
4065
+ async list(projectPath) {
4066
+ const project = await validateProjectPath(projectPath);
4067
+ const [files, state] = await Promise.all([
4068
+ scanSessionFiles(join6(this.codexHome, "sessions")),
4069
+ readStateThreads(this.stateDatabasePath)
4070
+ ]);
4071
+ return mergeSessionMetadata(project.displayPath, this.codexHome, files, state);
4072
+ }
4073
+ async preview(input) {
4074
+ const normalized2 = normalizeApplyInput(input);
4075
+ const project = await validateProjectPath(normalized2.projectPath);
4076
+ const [files, state] = await Promise.all([
4077
+ scanSessionFiles(join6(this.codexHome, "sessions")),
4078
+ readStateThreads(this.stateDatabasePath)
4079
+ ]);
4080
+ const snapshot = mergeSessionMetadata(project.displayPath, this.codexHome, files, state);
4081
+ const plans = await buildProviderPlans(normalized2, snapshot, state.rows);
4082
+ return {
4083
+ projectPath: project.displayPath,
4084
+ fromProvider: normalized2.fromProvider ?? null,
4085
+ toProvider: normalized2.toProvider,
4086
+ stateDatabase: state.status,
4087
+ sessions: plans,
4088
+ warnings: snapshot.warnings
4089
+ };
4090
+ }
4091
+ async apply(input) {
4092
+ return this.withMutationLock(() => this.applyLocked(input));
4093
+ }
4094
+ async applyLocked(input) {
4095
+ const normalized2 = normalizeApplyInput(input);
4096
+ const project = await validateProjectPath(normalized2.projectPath);
4097
+ const [files, state] = await Promise.all([
4098
+ scanSessionFiles(join6(this.codexHome, "sessions")),
4099
+ readStateThreads(this.stateDatabasePath)
4100
+ ]);
4101
+ if (!state.status.available) {
4102
+ throw new CodexSessionManagerError(
4103
+ state.status.reason || `Codex state database is unavailable: ${state.status.path}`
4104
+ );
4105
+ }
4106
+ const snapshot = mergeSessionMetadata(project.displayPath, this.codexHome, files, state);
4107
+ const plans = await buildProviderPlans(normalized2, snapshot, state.rows);
4108
+ const selected = plans.filter((plan) => plan.action !== "no_change");
4109
+ const blocked = selected.filter((plan) => plan.action === "blocked");
4110
+ if (blocked.length > 0) {
4111
+ const details = blocked.map((plan) => `${plan.id}: ${plan.reason || "blocked"}`).join("; ");
4112
+ throw new CodexSessionManagerError(`cannot update selected Codex sessions: ${details}`);
4113
+ }
4114
+ if (selected.length === 0) {
4115
+ return {
4116
+ ok: true,
4117
+ projectPath: project.displayPath,
4118
+ fromProvider: normalized2.fromProvider ?? null,
4119
+ toProvider: normalized2.toProvider,
4120
+ updatedSessions: 0,
4121
+ jsonlFiles: 0,
4122
+ jsonlFields: 0,
4123
+ sqliteRows: 0,
4124
+ backups: []
4125
+ };
4126
+ }
4127
+ const fileChanges = [];
4128
+ for (const plan of selected) {
4129
+ const file = files.get(plan.id);
4130
+ if (!file || file.status !== "ready") {
4131
+ throw new CodexSessionManagerError(
4132
+ `rollout for session '${plan.id}' is unavailable; no files were changed`
4133
+ );
4134
+ }
4135
+ const before = await snapshotFile(file.filePath);
4136
+ const inspection = await inspectAndTransformFile(file.filePath, normalized2.fromProvider, normalized2.toProvider);
4137
+ const after = await snapshotFile(file.filePath);
4138
+ if (!sameFileSnapshot(before, after)) {
4139
+ throw new CodexSessionManagerError(
4140
+ `rollout '${file.filePath}' changed while it was being read; no files were changed`
4141
+ );
4142
+ }
4143
+ if (inspection.changedFields > 0) {
4144
+ fileChanges.push({
4145
+ id: plan.id,
4146
+ filePath: file.filePath,
4147
+ before,
4148
+ transformedText: inspection.transformedText,
4149
+ changedFields: inspection.changedFields
4150
+ });
4151
+ }
4152
+ }
4153
+ const stateRowsById = new Map(state.rows.map((row) => [row.id, row]));
4154
+ const dbChanges = plans.filter((plan) => plan.action === "update").map((plan) => stateRowsById.get(plan.id)).filter((row) => {
4155
+ if (!row) return false;
4156
+ if (normalized2.fromProvider && row.modelProvider !== normalized2.fromProvider) return false;
4157
+ return row.modelProvider !== normalized2.toProvider;
4158
+ });
4159
+ const temporaryFiles = [];
4160
+ const backups = [];
4161
+ let database;
4162
+ let committed = false;
4163
+ try {
4164
+ for (const change of fileChanges) {
4165
+ const tempPath = `${change.filePath}.provider-switch-${randomUUID2()}.tmp`;
4166
+ await writeFile(tempPath, change.transformedText, "utf8");
4167
+ temporaryFiles.push(tempPath);
4168
+ }
4169
+ if (dbChanges.length > 0) {
4170
+ const sqlite = await loadSqlite();
4171
+ database = openDatabase(sqlite, this.stateDatabasePath, false);
4172
+ const databaseBackup = await createDatabaseBackup(sqlite, database, this.stateDatabasePath);
4173
+ backups.push(databaseBackup);
4174
+ database.exec("BEGIN IMMEDIATE");
4175
+ assertDatabaseRowsUnchanged(database, dbChanges);
4176
+ }
4177
+ for (let index = 0; index < fileChanges.length; index += 1) {
4178
+ const change = fileChanges[index];
4179
+ const tempPath = temporaryFiles[index];
4180
+ const current = await snapshotFile(change.filePath);
4181
+ if (!sameFileSnapshot(change.before, current)) {
4182
+ throw new CodexSessionManagerError(
4183
+ `rollout '${change.filePath}' changed before replacement; no files were changed`
4184
+ );
4185
+ }
4186
+ const backupPath = await createUniqueBackupPath(change.filePath);
4187
+ await copyFile(change.filePath, backupPath);
4188
+ backups.push(backupPath);
4189
+ await replaceFileAtomically(tempPath, change.filePath);
4190
+ temporaryFiles[index] = "";
4191
+ }
4192
+ if (database && dbChanges.length > 0) {
4193
+ const update = database.prepare("UPDATE threads SET model_provider = ? WHERE id = ?");
4194
+ for (const row of dbChanges) update.run(normalized2.toProvider, row.id);
4195
+ database.exec("COMMIT");
4196
+ committed = true;
4197
+ } else {
4198
+ committed = true;
4199
+ }
4200
+ return {
4201
+ ok: true,
4202
+ projectPath: project.displayPath,
4203
+ fromProvider: normalized2.fromProvider ?? null,
4204
+ toProvider: normalized2.toProvider,
4205
+ updatedSessions: (/* @__PURE__ */ new Set([...fileChanges.map((change) => change.id), ...dbChanges.map((row) => row.id)])).size,
4206
+ jsonlFiles: fileChanges.length,
4207
+ jsonlFields: fileChanges.reduce((total, change) => total + change.changedFields, 0),
4208
+ sqliteRows: dbChanges.length,
4209
+ backups
4210
+ };
4211
+ } catch (error) {
4212
+ if (database?.isTransaction) {
4213
+ try {
4214
+ database.exec("ROLLBACK");
4215
+ } catch {
4216
+ }
4217
+ }
4218
+ if (!committed) {
4219
+ try {
4220
+ await restoreBackups(backups.filter((path2) => /\.jsonl\.provider-switch-[^/\\]+\.bak$/iu.test(path2)));
4221
+ } catch (restoreError) {
4222
+ const original = error instanceof Error ? error.message : String(error);
4223
+ const restoration = restoreError instanceof Error ? restoreError.message : String(restoreError);
4224
+ throw new CodexSessionManagerError(
4225
+ `${original}; JSONL restoration also failed: ${restoration}`
4226
+ );
4227
+ }
4228
+ }
4229
+ throw error;
4230
+ } finally {
4231
+ if (database?.isOpen) database.close();
4232
+ for (const tempPath of temporaryFiles) {
4233
+ if (!tempPath) continue;
4234
+ await unlinkIfPresent(tempPath);
4235
+ }
4236
+ }
4237
+ }
4238
+ async withMutationLock(operation) {
4239
+ const previous = this.mutationTail;
4240
+ let release;
4241
+ this.mutationTail = new Promise((resolve12) => {
4242
+ release = resolve12;
4243
+ });
4244
+ await previous;
4245
+ try {
4246
+ return await operation();
4247
+ } finally {
4248
+ release();
4249
+ }
4250
+ }
4251
+ };
4252
+ function normalizeApplyInput(input) {
4253
+ const projectPath = typeof input.projectPath === "string" ? input.projectPath.trim() : "";
4254
+ const toProvider = typeof input.toProvider === "string" ? input.toProvider.trim() : "";
4255
+ const fromProvider = typeof input.fromProvider === "string" ? input.fromProvider.trim() : void 0;
4256
+ if (!projectPath) throw new CodexSessionManagerError("projectPath must be a non-empty string");
4257
+ validateProviderId(toProvider, "toProvider");
4258
+ if (fromProvider) validateProviderId(fromProvider, "fromProvider");
4259
+ if (!Array.isArray(input.sessionIds) || input.sessionIds.length === 0) {
4260
+ throw new CodexSessionManagerError("sessionIds must contain at least one session id");
4261
+ }
4262
+ const sessionIds = [
4263
+ ...new Set(
4264
+ input.sessionIds.filter((id) => typeof id === "string" && id.trim().length > 0).map((id) => id.trim())
4265
+ )
4266
+ ];
4267
+ if (sessionIds.length === 0) throw new CodexSessionManagerError("sessionIds must contain at least one session id");
4268
+ if (sessionIds.length > 1e4) throw new CodexSessionManagerError("too many sessionIds");
4269
+ return { projectPath, sessionIds, toProvider, ...fromProvider ? { fromProvider } : {} };
4270
+ }
4271
+ function validateProviderId(value, name) {
4272
+ if (!value) throw new CodexSessionManagerError(`${name} must be a non-empty string`);
4273
+ if (value.length > PROVIDER_ID_LIMIT || /[\u0000-\u001f\u007f]/u.test(value)) {
4274
+ throw new CodexSessionManagerError(`${name} is invalid`);
4275
+ }
4276
+ }
4277
+ async function validateProjectPath(projectPath) {
4278
+ if (typeof projectPath !== "string" || !projectPath.trim()) {
4279
+ throw new CodexSessionManagerError("projectPath must be a non-empty string");
4280
+ }
4281
+ const displayPath = resolve(projectPath.trim());
4282
+ let info;
4283
+ try {
4284
+ info = await stat(displayPath);
4285
+ } catch {
4286
+ throw new CodexSessionManagerError(`project path does not exist: ${displayPath}`);
4287
+ }
4288
+ if (!info.isDirectory()) throw new CodexSessionManagerError(`project path is not a directory: ${displayPath}`);
4289
+ return { displayPath };
4290
+ }
4291
+ async function scanSessionFiles(sessionsRoot) {
4292
+ const files = await collectJsonlFiles(sessionsRoot);
4293
+ const records = /* @__PURE__ */ new Map();
4294
+ for (const filePath of files) {
4295
+ let fileStat;
4296
+ try {
4297
+ fileStat = await stat(filePath);
4298
+ const firstLine = await readFirstLine(filePath);
4299
+ const parsed = parseSessionMetadata(firstLine, filePath);
4300
+ if (!parsed.id) continue;
4301
+ const record = {
4302
+ id: parsed.id,
4303
+ filePath,
4304
+ cwd: parsed.cwd,
4305
+ jsonlProvider: parsed.provider,
4306
+ timestamp: parsed.timestamp,
4307
+ size: fileStat.size,
4308
+ mtimeMs: fileStat.mtimeMs,
4309
+ status: "ready"
4310
+ };
4311
+ const existing = records.get(record.id);
4312
+ if (!existing || record.mtimeMs > existing.mtimeMs) records.set(record.id, record);
4313
+ } catch {
4314
+ const id = sessionIdFromRolloutPath(filePath);
4315
+ if (!id) continue;
4316
+ let fallbackStat;
4317
+ try {
4318
+ fallbackStat = await stat(filePath);
4319
+ } catch {
4320
+ continue;
4321
+ }
4322
+ const existing = records.get(id);
4323
+ if (!existing || fallbackStat.mtimeMs > existing.mtimeMs) {
4324
+ records.set(id, {
4325
+ id,
4326
+ filePath,
4327
+ cwd: null,
4328
+ jsonlProvider: null,
4329
+ timestamp: null,
4330
+ size: fallbackStat.size,
4331
+ mtimeMs: fallbackStat.mtimeMs,
4332
+ status: "unreadable_rollout"
4333
+ });
4334
+ }
4335
+ }
4336
+ }
4337
+ return records;
4338
+ }
4339
+ async function collectJsonlFiles(root) {
4340
+ if (!existsSync5(root)) return [];
4341
+ const result = [];
4342
+ const pending = [root];
4343
+ while (pending.length > 0) {
4344
+ const current = pending.pop();
4345
+ let entries;
4346
+ try {
4347
+ entries = await readdir(current, { withFileTypes: true });
4348
+ } catch {
4349
+ continue;
4350
+ }
4351
+ for (const entry of entries) {
4352
+ const fullPath = join6(current, entry.name);
4353
+ if (entry.isDirectory()) pending.push(fullPath);
4354
+ else if (entry.isFile() && entry.name.toLowerCase().endsWith(".jsonl")) result.push(fullPath);
4355
+ }
4356
+ }
4357
+ return result.sort((a, b) => a.localeCompare(b));
4358
+ }
4359
+ async function readFirstLine(filePath) {
4360
+ const handle = await open(filePath, "r");
4361
+ const chunks = [];
4362
+ let total = 0;
4363
+ try {
4364
+ while (total < FIRST_LINE_LIMIT) {
4365
+ const chunk = Buffer.allocUnsafe(Math.min(128 * 1024, FIRST_LINE_LIMIT - total));
4366
+ const result = await handle.read(chunk, 0, chunk.length, null);
4367
+ if (result.bytesRead === 0) break;
4368
+ const used = chunk.subarray(0, result.bytesRead);
4369
+ const lineEnd = findLineEnd(used);
4370
+ if (lineEnd >= 0) {
4371
+ chunks.push(used.subarray(0, lineEnd));
4372
+ return decodeUtf8(Buffer.concat(chunks));
4373
+ }
4374
+ chunks.push(used);
4375
+ total += result.bytesRead;
4376
+ }
4377
+ } finally {
4378
+ await handle.close();
4379
+ }
4380
+ if (total > 0 && total < FIRST_LINE_LIMIT) return decodeUtf8(Buffer.concat(chunks));
4381
+ throw new CodexSessionManagerError(`session metadata line is too large or incomplete: ${filePath}`);
4382
+ }
4383
+ function findLineEnd(buffer) {
4384
+ for (let index = 0; index < buffer.length; index += 1) {
4385
+ if (buffer[index] === 10 || buffer[index] === 13) return index;
4386
+ }
4387
+ return -1;
4388
+ }
4389
+ function parseSessionMetadata(line, filePath) {
4390
+ const value = JSON.parse(line.replace(/^\uFEFF/u, ""));
4391
+ if (!isRecord6(value)) throw new Error("metadata is not an object");
4392
+ const payload = isRecord6(value["payload"]) ? value["payload"] : {};
4393
+ const id = sessionIdFromRolloutPath(filePath) || firstString(payload["session_id"], payload["id"]);
4394
+ return {
4395
+ id,
4396
+ cwd: firstString(payload["cwd"]),
4397
+ provider: firstString(payload["model_provider"]),
4398
+ timestamp: firstString(payload["timestamp"]) || firstString(value["timestamp"])
4399
+ };
4400
+ }
4401
+ function sessionIdFromRolloutPath(filePath) {
4402
+ const match = basename(filePath).match(/([0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12})\.jsonl$/iu);
4403
+ return match?.[1] ?? null;
4404
+ }
4405
+ async function readStateThreads(databasePath) {
4406
+ const unavailable = (reason) => ({
4407
+ status: { path: databasePath, available: false, reason },
4408
+ rows: []
4409
+ });
4410
+ if (!existsSync5(databasePath)) return unavailable(`Codex state database not found: ${databasePath}`);
4411
+ let sqlite;
4412
+ try {
4413
+ sqlite = await loadSqlite();
4414
+ } catch (error) {
4415
+ return unavailable(error instanceof Error ? error.message : String(error));
4416
+ }
4417
+ let database;
4418
+ try {
4419
+ database = openDatabase(sqlite, databasePath, true);
4420
+ const columns = new Set(
4421
+ database.prepare("PRAGMA table_info('threads')").all().map((row) => String(row["name"] ?? ""))
4422
+ );
4423
+ for (const required of ["id", "rollout_path", "cwd", "model_provider"]) {
4424
+ if (!columns.has(required)) return unavailable(`state_5.sqlite is missing threads.${required}`);
4425
+ }
4426
+ const selected = ["id", "rollout_path", "cwd", "model_provider", "model", "created_at", "updated_at", "created_at_ms", "updated_at_ms"].filter((column) => columns.has(column));
4427
+ const rows = database.prepare(`SELECT ${selected.join(", ")} FROM threads`).all();
4428
+ return {
4429
+ status: { path: databasePath, available: true },
4430
+ rows: rows.map(toStateThreadRow)
4431
+ };
4432
+ } catch (error) {
4433
+ return unavailable(`could not read Codex state database: ${error instanceof Error ? error.message : String(error)}`);
4434
+ } finally {
4435
+ if (database?.isOpen) database.close();
4436
+ }
4437
+ }
4438
+ async function loadSqlite() {
4439
+ const specifier = "node:sqlite";
4440
+ try {
4441
+ return await import(specifier);
4442
+ } catch (error) {
4443
+ const cause = error instanceof Error ? error.message : String(error);
4444
+ throw new CodexSessionManagerError(
4445
+ `Codex session SQLite support requires Node.js 22.16 or newer (node:sqlite); this daemon runs ${process.version} (import failed: ${cause})`
4446
+ );
4447
+ }
4448
+ }
4449
+ function openDatabase(sqlite, databasePath, readOnly) {
4450
+ const database = new sqlite.DatabaseSync(databasePath, { readOnly, timeout: 5e3 });
4451
+ database.exec("PRAGMA busy_timeout = 5000");
4452
+ return database;
4453
+ }
4454
+ function toStateThreadRow(row) {
4455
+ return {
4456
+ id: String(row["id"] ?? ""),
4457
+ rolloutPath: String(row["rollout_path"] ?? ""),
4458
+ cwd: String(row["cwd"] ?? ""),
4459
+ modelProvider: String(row["model_provider"] ?? ""),
4460
+ model: row["model"] == null ? null : String(row["model"]),
4461
+ createdAt: timestampFromSqlite(row["created_at_ms"] ?? row["created_at"]),
4462
+ updatedAt: timestampFromSqlite(row["updated_at_ms"] ?? row["updated_at"])
4463
+ };
4464
+ }
4465
+ function timestampFromSqlite(value) {
4466
+ const numeric = typeof value === "bigint" ? Number(value) : typeof value === "number" ? value : Number(value);
4467
+ if (!Number.isFinite(numeric) || numeric <= 0) return null;
4468
+ const milliseconds = numeric < 1e11 ? numeric * 1e3 : numeric;
4469
+ const date = new Date(milliseconds);
4470
+ return Number.isNaN(date.getTime()) ? null : date.toISOString();
4471
+ }
4472
+ function mergeSessionMetadata(projectPath, codexHome, files, state) {
4473
+ const stateRows = new Map(state.rows.map((row) => [row.id, row]));
4474
+ const ids = /* @__PURE__ */ new Set();
4475
+ for (const [id, file] of files) {
4476
+ if (file.cwd && isPathInside(projectPath, file.cwd)) ids.add(id);
4477
+ }
4478
+ for (const row of state.rows) {
4479
+ if (isPathInside(projectPath, row.cwd)) ids.add(row.id);
4480
+ }
4481
+ const sessions2 = [];
4482
+ for (const id of ids) {
4483
+ const file = files.get(id);
4484
+ const row = stateRows.get(id);
4485
+ const cwd = row?.cwd || file?.cwd || projectPath;
4486
+ if (!isPathInside(projectPath, cwd)) continue;
4487
+ const rolloutPath = file?.filePath || row?.rolloutPath || "";
4488
+ const provider = row?.modelProvider || file?.jsonlProvider || null;
4489
+ sessions2.push({
4490
+ id,
4491
+ cwd,
4492
+ rolloutPath,
4493
+ provider,
4494
+ jsonlProvider: file?.jsonlProvider ?? null,
4495
+ model: row?.model ?? null,
4496
+ createdAt: row?.createdAt ?? file?.timestamp ?? null,
4497
+ updatedAt: row?.updatedAt ?? (file ? new Date(file.mtimeMs).toISOString() : null),
4498
+ fileSize: file?.size ?? null,
4499
+ fileModifiedAt: file ? new Date(file.mtimeMs).toISOString() : null,
4500
+ status: file?.status ?? "missing_rollout",
4501
+ inStateDatabase: Boolean(row)
4502
+ });
4503
+ }
4504
+ sessions2.sort((a, b) => (b.updatedAt ?? "").localeCompare(a.updatedAt ?? "") || a.id.localeCompare(b.id));
4505
+ const warnings = [];
4506
+ if (!state.status.available) warnings.push(state.status.reason || "state database unavailable");
4507
+ return { projectPath, codexHome, stateDatabase: state.status, sessions: sessions2, warnings };
4508
+ }
4509
+ async function buildProviderPlans(input, snapshot, stateRows) {
4510
+ const byId = new Map(snapshot.sessions.map((session) => [session.id, session]));
4511
+ const stateById = new Map(stateRows.map((row) => [row.id, row]));
4512
+ const plans = [];
4513
+ for (const id of input.sessionIds) {
4514
+ const session = byId.get(id);
4515
+ const row = stateById.get(id);
4516
+ if (!session) {
4517
+ plans.push({
4518
+ id,
4519
+ provider: null,
4520
+ model: null,
4521
+ rolloutPath: "",
4522
+ status: "blocked",
4523
+ providers: [],
4524
+ matchingFields: 0,
4525
+ changedFields: 0,
4526
+ sqliteWillUpdate: false,
4527
+ action: "blocked",
4528
+ reason: "session is not associated with the requested project"
4529
+ });
4530
+ continue;
4531
+ }
4532
+ if (session.status !== "ready") {
4533
+ plans.push({
4534
+ id,
4535
+ provider: session.provider,
4536
+ model: session.model,
4537
+ rolloutPath: session.rolloutPath,
4538
+ status: session.status,
4539
+ providers: [],
4540
+ matchingFields: 0,
4541
+ changedFields: 0,
4542
+ sqliteWillUpdate: false,
4543
+ action: "blocked",
4544
+ reason: "rollout file is missing or unreadable"
4545
+ });
4546
+ continue;
4547
+ }
4548
+ const inspection = await inspectAndTransformFile(session.rolloutPath, input.fromProvider, input.toProvider);
4549
+ const sqliteWillUpdate = Boolean(
4550
+ row && (!input.fromProvider || row.modelProvider === input.fromProvider) && row.modelProvider !== input.toProvider
4551
+ );
4552
+ const changed = inspection.changedFields > 0 || sqliteWillUpdate;
4553
+ plans.push({
4554
+ id,
4555
+ provider: session.provider,
4556
+ model: session.model,
4557
+ rolloutPath: session.rolloutPath,
4558
+ status: "ready",
4559
+ providers: inspection.providers,
4560
+ matchingFields: inspection.matchingFields,
4561
+ changedFields: inspection.changedFields,
4562
+ sqliteWillUpdate,
4563
+ action: changed ? "update" : "no_change"
4564
+ });
4565
+ }
4566
+ return plans;
4567
+ }
4568
+ async function inspectAndTransformFile(filePath, fromProvider, toProvider) {
4569
+ const bytes = await readFile(filePath);
4570
+ const originalText = decodeUtf8(bytes);
4571
+ const parts = originalText.split(/(\r\n|\n|\r)/u);
4572
+ const providers = /* @__PURE__ */ new Set();
4573
+ let matchingFields = 0;
4574
+ let changedFields = 0;
4575
+ const hasBom = parts[0].startsWith("\uFEFF");
4576
+ for (let index = 0; index < parts.length; index += 2) {
4577
+ const line = parts[index];
4578
+ if (!line.trim()) continue;
4579
+ let value;
4580
+ try {
4581
+ value = JSON.parse(line.replace(index === 0 ? /^\uFEFF/u : /^/u, ""));
4582
+ } catch (error) {
4583
+ throw new CodexSessionManagerError(
4584
+ `invalid JSONL at ${filePath}:${Math.floor(index / 2) + 1}: ${error instanceof Error ? error.message : String(error)}`
4585
+ );
4586
+ }
4587
+ const result = replaceStructuredProviderFields(value, fromProvider, toProvider, providers);
4588
+ matchingFields += result.matchingFields;
4589
+ changedFields += result.changedFields;
4590
+ if (result.changedFields > 0) {
4591
+ parts[index] = `${index === 0 && hasBom ? "\uFEFF" : ""}${JSON.stringify(value)}`;
4592
+ }
4593
+ }
4594
+ return {
4595
+ transformedText: parts.join(""),
4596
+ providers: [...providers].sort(),
4597
+ matchingFields,
4598
+ changedFields
4599
+ };
4600
+ }
4601
+ function replaceStructuredProviderFields(value, fromProvider, toProvider, providers = /* @__PURE__ */ new Set()) {
4602
+ let matchingFields = 0;
4603
+ let changedFields = 0;
4604
+ const visit = (node) => {
4605
+ if (Array.isArray(node)) {
4606
+ for (const child of node) visit(child);
4607
+ return;
4608
+ }
4609
+ if (!isRecord6(node)) return;
4610
+ for (const [key, child] of Object.entries(node)) {
4611
+ if (PROVIDER_PROPERTY_NAMES.has(key) && typeof child === "string") {
4612
+ providers.add(child);
4613
+ if (!fromProvider || child === fromProvider) {
4614
+ matchingFields += 1;
4615
+ if (child !== toProvider) {
4616
+ node[key] = toProvider;
4617
+ changedFields += 1;
4618
+ }
4619
+ }
4620
+ }
4621
+ visit(node[key]);
4622
+ }
4623
+ };
4624
+ visit(value);
4625
+ return { matchingFields, changedFields };
4626
+ }
4627
+ async function snapshotFile(filePath) {
4628
+ const info = await stat(filePath);
4629
+ return { size: info.size, mtimeMs: info.mtimeMs };
4630
+ }
4631
+ function sameFileSnapshot(a, b) {
4632
+ return a.size === b.size && a.mtimeMs === b.mtimeMs;
4633
+ }
4634
+ async function createUniqueBackupPath(filePath) {
4635
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[.:]/gu, "-");
4636
+ let candidate = `${filePath}.provider-switch-${stamp}.bak`;
4637
+ let suffix = 1;
4638
+ while (existsSync5(candidate)) {
4639
+ candidate = `${filePath}.provider-switch-${stamp}-${suffix}.bak`;
4640
+ suffix += 1;
4641
+ }
4642
+ return candidate;
4643
+ }
4644
+ async function createDatabaseBackup(sqlite, database, databasePath) {
4645
+ const backupPath = await createUniqueBackupPath(databasePath);
4646
+ if (typeof sqlite.backup !== "function") {
4647
+ throw new CodexSessionManagerError(
4648
+ "Codex session updates require the node:sqlite backup API (Node.js 22.16 or newer)"
4649
+ );
4650
+ }
4651
+ await sqlite.backup(database, backupPath);
4652
+ return backupPath;
4653
+ }
4654
+ function assertDatabaseRowsUnchanged(database, rows) {
4655
+ const read = database.prepare("SELECT model_provider FROM threads WHERE id = ?");
4656
+ for (const row of rows) {
4657
+ const current = read.get(row.id);
4658
+ if (!current || String(current["model_provider"] ?? "") !== row.modelProvider) {
4659
+ throw new CodexSessionManagerError(
4660
+ `SQLite session '${row.id}' changed while the update was prepared; no files were changed`
4661
+ );
4662
+ }
4663
+ }
4664
+ }
4665
+ async function replaceFileAtomically(tempPath, targetPath) {
4666
+ try {
4667
+ await rename(tempPath, targetPath);
4668
+ } catch (error) {
4669
+ if (process.platform !== "win32") throw error;
4670
+ await copyFile(tempPath, targetPath);
4671
+ await unlinkIfPresent(tempPath);
4672
+ }
4673
+ }
4674
+ async function restoreBackups(backupPaths) {
4675
+ for (const backupPath of backupPaths.reverse()) {
4676
+ if (!existsSync5(backupPath)) continue;
4677
+ const targetPath = backupPath.replace(/\.provider-switch-[^.]+(?:-[0-9]+)?\.bak$/u, "");
4678
+ if (targetPath === backupPath) continue;
4679
+ const tempPath = `${targetPath}.provider-restore-${randomUUID2()}.tmp`;
4680
+ try {
4681
+ await copyFile(backupPath, tempPath);
4682
+ await replaceFileAtomically(tempPath, targetPath);
4683
+ } finally {
4684
+ await unlinkIfPresent(tempPath);
4685
+ }
4686
+ }
4687
+ }
4688
+ async function unlinkIfPresent(filePath) {
4689
+ try {
4690
+ await unlink(filePath);
4691
+ } catch {
4692
+ }
4693
+ }
4694
+ function decodeUtf8(bytes) {
4695
+ try {
4696
+ return new TextDecoder2("utf-8", { fatal: true }).decode(bytes);
4697
+ } catch {
4698
+ throw new CodexSessionManagerError("Codex session contains invalid UTF-8");
4699
+ }
4700
+ }
4701
+ function isRecord6(value) {
4702
+ return value !== null && typeof value === "object" && !Array.isArray(value);
4703
+ }
4704
+ function firstString(...values) {
4705
+ for (const value of values) if (typeof value === "string" && value.trim()) return value;
4706
+ return null;
4707
+ }
4708
+ function normalizeComparablePath(value) {
4709
+ const stripped = value.trim().replace(/^\\\\\?\\/u, "");
4710
+ if (process.platform === "win32") {
4711
+ const normalized2 = win32.normalize(stripped).replace(/[\\/]+$/u, "");
4712
+ return normalized2.toLowerCase();
4713
+ }
4714
+ return stripped.replace(/\/+$/u, "") || "/";
4715
+ }
4716
+ function isPathInside(projectPath, candidatePath) {
4717
+ const project = normalizeComparablePath(projectPath);
4718
+ const candidate = normalizeComparablePath(candidatePath);
4719
+ if (project === candidate) return true;
4720
+ const separator = process.platform === "win32" ? "\\" : "/";
4721
+ return candidate.startsWith(`${project}${separator}`);
4722
+ }
4723
+
4724
+ // src/admin/codexSessionApi.ts
4725
+ async function handleCodexSessionApi(req, res, path2, manager) {
4726
+ if (!manager) return writeJsonError(res, 501, "Codex session management is not available");
4727
+ try {
4728
+ const method = (req.method ?? "GET").toUpperCase();
4729
+ if (path2 === "/admin/api/codex-sessions" && (method === "GET" || method === "HEAD")) {
4730
+ const projectPath = new URL(req.url ?? "/", "http://localhost").searchParams.get("projectPath") ?? "";
4731
+ return writeJson(res, 200, await manager.list(projectPath));
4732
+ }
4733
+ if (path2 === "/admin/api/codex-sessions/preview" && method === "POST") {
4734
+ const body = await readJsonBody2(req);
4735
+ return writeJson(res, 200, await manager.preview(parseApplyInput(body)));
4736
+ }
4737
+ if (path2 === "/admin/api/codex-sessions/apply" && method === "POST") {
4738
+ const body = await readJsonBody2(req);
4739
+ return writeJson(res, 200, await manager.apply(parseApplyInput(body)));
4740
+ }
4741
+ return writeJsonError(res, 404, "unknown Codex session admin route");
4742
+ } catch (error) {
4743
+ const message = error instanceof Error ? error.message : String(error);
4744
+ return writeJsonError(res, error instanceof CodexSessionManagerError ? 400 : 500, message);
4745
+ }
4746
+ }
4747
+ async function readJsonBody2(req) {
4748
+ const chunks = [];
4749
+ for await (const chunk of req) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
4750
+ if (chunks.length === 0) return {};
4751
+ try {
4752
+ const value = JSON.parse(Buffer.concat(chunks).toString("utf8"));
4753
+ return isRecord7(value) ? value : {};
4754
+ } catch {
4755
+ throw new CodexSessionManagerError("request body must be a JSON object");
4756
+ }
4757
+ }
4758
+ function parseApplyInput(body) {
4759
+ const projectPath = body["projectPath"];
4760
+ const sessionIds = body["sessionIds"];
4761
+ const toProvider = body["toProvider"];
4762
+ const fromProvider = body["fromProvider"];
4763
+ if (typeof projectPath !== "string") throw new CodexSessionManagerError("projectPath must be a string");
4764
+ if (!Array.isArray(sessionIds) || !sessionIds.every((value) => typeof value === "string")) {
4765
+ throw new CodexSessionManagerError("sessionIds must be an array of strings");
4766
+ }
4767
+ if (typeof toProvider !== "string") throw new CodexSessionManagerError("toProvider must be a string");
4768
+ if (fromProvider !== void 0 && typeof fromProvider !== "string") {
4769
+ throw new CodexSessionManagerError("fromProvider must be a string when provided");
4770
+ }
4771
+ return {
4772
+ projectPath,
4773
+ sessionIds,
4774
+ toProvider,
4775
+ ...fromProvider === void 0 ? {} : { fromProvider }
4776
+ };
4777
+ }
4778
+ function writeJson(res, status, body) {
4779
+ res.writeHead(status, { "Content-Type": "application/json" });
4780
+ res.end(JSON.stringify(body));
4781
+ }
4782
+ function writeJsonError(res, status, message) {
4783
+ writeJson(res, status, { error: { type: "admin_api_error", message } });
4784
+ }
4785
+ function isRecord7(value) {
4786
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
4787
+ }
4788
+
4031
4789
  // src/admin/adminApi.ts
4032
4790
  import http from "http";
4033
4791
  import {
4034
4792
  createNamedKey,
4035
4793
  DEFAULT_IMAGES_SERVER_CONFIG,
4036
4794
  DEFAULT_SEARCH_SERVER_CONFIG as DEFAULT_SEARCH_SERVER_CONFIG2,
4037
- effectiveOutboundPermissions as effectiveOutboundPermissions2,
4795
+ effectiveOutboundPermissions as effectiveOutboundPermissions3,
4038
4796
  gatewayBindingToEndpointConfig,
4039
4797
  isKindMappedEndpoint,
4040
4798
  loadServerConfig as loadServerConfig3,
@@ -4052,6 +4810,34 @@ import { getSharedAccountHealth } from "@omnicross/core/pipeline/SubscriptionAcc
4052
4810
  import { fetchUpstream as fetchUpstream10 } from "@omnicross/core/pipeline/upstreamFetch";
4053
4811
  import { mergeExtraHeaders } from "@omnicross/core";
4054
4812
 
4813
+ // src/admin/testEgressIdentity.ts
4814
+ import {
4815
+ getOpenCodeGoUserAgent as getOpenCodeGoUserAgent2,
4816
+ OPENCODE_SESSION_HEADER
4817
+ } from "@omnicross/core/provider-proxy/identity/openCodeGoHeaders";
4818
+ var ADMIN_PROBE_OPENCODE_SESSION = "omnicross-admin-probe";
4819
+ function isOpenCodeUpstream(baseUrl) {
4820
+ if (!baseUrl) return false;
4821
+ try {
4822
+ const host = new URL(baseUrl).hostname.toLowerCase();
4823
+ return host === "opencode.ai" || host.endsWith(".opencode.ai");
4824
+ } catch {
4825
+ return false;
4826
+ }
4827
+ }
4828
+ function hasHeader2(headers, name) {
4829
+ const lower = name.toLowerCase();
4830
+ return Object.keys(headers).some((key) => key.toLowerCase() === lower);
4831
+ }
4832
+ function applyAdminProbeIdentity(headers, row) {
4833
+ if (!hasHeader2(headers, "user-agent")) {
4834
+ headers["user-agent"] = getOpenCodeGoUserAgent2();
4835
+ }
4836
+ if (isOpenCodeUpstream(row.baseUrl) && !hasHeader2(headers, OPENCODE_SESSION_HEADER)) {
4837
+ headers[OPENCODE_SESSION_HEADER] = ADMIN_PROBE_OPENCODE_SESSION;
4838
+ }
4839
+ }
4840
+
4055
4841
  // src/image-generation/imagesConfigValidation.ts
4056
4842
  import { validateImagesServerConfig } from "@omnicross/core/outbound-api";
4057
4843
 
@@ -4059,7 +4845,7 @@ import { validateImagesServerConfig } from "@omnicross/core/outbound-api";
4059
4845
  import { randomBytes as randomBytes3 } from "crypto";
4060
4846
  import {
4061
4847
  chmodSync as chmodSync2,
4062
- existsSync as existsSync5,
4848
+ existsSync as existsSync6,
4063
4849
  lstatSync,
4064
4850
  mkdirSync as mkdirSync3,
4065
4851
  realpathSync,
@@ -4067,20 +4853,20 @@ import {
4067
4853
  statSync as statSync4,
4068
4854
  unlinkSync as unlinkSync2
4069
4855
  } from "fs";
4070
- import { homedir as homedir2, tmpdir } from "os";
4856
+ import { homedir as homedir3, tmpdir } from "os";
4071
4857
  import {
4072
- basename,
4858
+ basename as basename2,
4073
4859
  dirname as dirname4,
4074
4860
  isAbsolute,
4075
- join as join6,
4861
+ join as join7,
4076
4862
  parse,
4077
4863
  relative,
4078
- resolve
4864
+ resolve as resolve2
4079
4865
  } from "path";
4080
4866
  var OPAQUE_NAME = /^(?:file|directory)-[a-f0-9]{32}(?:\.(?:bin|json|tmp))?$/u;
4081
4867
  var MOUNT_MANIFEST_NAME = "catalog.v1.json";
4082
4868
  function normalized(path2) {
4083
- const canonical = resolve(path2);
4869
+ const canonical = resolve2(path2);
4084
4870
  return process.platform === "win32" ? canonical.toLowerCase() : canonical;
4085
4871
  }
4086
4872
  function samePath(left, right) {
@@ -4091,26 +4877,26 @@ function isSameOrDescendant(candidate, parent) {
4091
4877
  return rel === "" || !rel.startsWith("..") && !isAbsolute(rel);
4092
4878
  }
4093
4879
  function assertNoSymlinkComponents(target) {
4094
- const absolute = resolve(target);
4880
+ const absolute = resolve2(target);
4095
4881
  const filesystemRoot = parse(absolute).root;
4096
4882
  let cursor = filesystemRoot;
4097
4883
  for (const segment of relative(filesystemRoot, absolute).split(/[\\/]+/u).filter(Boolean)) {
4098
- cursor = join6(cursor, segment);
4099
- if (!existsSync5(cursor)) break;
4884
+ cursor = join7(cursor, segment);
4885
+ if (!existsSync6(cursor)) break;
4100
4886
  if (lstatSync(cursor).isSymbolicLink()) {
4101
4887
  throw new TypeError("image storage paths must not traverse a symbolic link");
4102
4888
  }
4103
4889
  }
4104
4890
  }
4105
4891
  function isInsideDetectedWorktree(target) {
4106
- let cursor = resolve(target);
4107
- while (!existsSync5(cursor)) {
4892
+ let cursor = resolve2(target);
4893
+ while (!existsSync6(cursor)) {
4108
4894
  const parent = dirname4(cursor);
4109
4895
  if (parent === cursor) break;
4110
4896
  cursor = parent;
4111
4897
  }
4112
4898
  while (true) {
4113
- if (existsSync5(join6(cursor, ".git"))) return true;
4899
+ if (existsSync6(join7(cursor, ".git"))) return true;
4114
4900
  const parent = dirname4(cursor);
4115
4901
  if (parent === cursor) return false;
4116
4902
  cursor = parent;
@@ -4118,15 +4904,15 @@ function isInsideDetectedWorktree(target) {
4118
4904
  }
4119
4905
  function isBroadRoot(target, options) {
4120
4906
  const filesystemRoot = parse(target).root;
4121
- const processDirectory = resolve(options.processDirectory ?? process.cwd());
4122
- const userHome = resolve(options.userHome ?? homedir2());
4123
- const temporaryDirectory = resolve(options.temporaryDirectory ?? tmpdir());
4907
+ const processDirectory = resolve2(options.processDirectory ?? process.cwd());
4908
+ const userHome = resolve2(options.userHome ?? homedir3());
4909
+ const temporaryDirectory = resolve2(options.temporaryDirectory ?? tmpdir());
4124
4910
  return samePath(target, filesystemRoot) || samePath(target, userHome) || samePath(target, temporaryDirectory) || isSameOrDescendant(processDirectory, target) || isSameOrDescendant(userHome, target) || isSameOrDescendant(temporaryDirectory, target);
4125
4911
  }
4126
4912
  function validateImageRootCandidate(candidate, options = {}) {
4127
4913
  const label = options.label ?? "image storage root";
4128
4914
  if (!candidate.trim() || !isAbsolute(candidate)) return [`${label} must be an absolute path`];
4129
- const target = resolve(candidate);
4915
+ const target = resolve2(candidate);
4130
4916
  const errors = [];
4131
4917
  if (isBroadRoot(target, options)) errors.push(`${label} is too broad`);
4132
4918
  try {
@@ -4164,22 +4950,22 @@ var DaemonImagePathResolver = class {
4164
4950
  #issued = /* @__PURE__ */ new WeakSet();
4165
4951
  constructor(options) {
4166
4952
  if (!isAbsolute(options.configPath)) throw new TypeError("daemon configPath must be absolute");
4167
- const applicationDataRoot = resolve(dirname4(options.configPath));
4953
+ const applicationDataRoot = resolve2(dirname4(options.configPath));
4168
4954
  const applicationErrors = validateImageRootCandidate(applicationDataRoot, {
4169
4955
  ...options,
4170
4956
  label: "daemon application data root"
4171
4957
  });
4172
4958
  if (applicationErrors.length > 0) throw new TypeError(applicationErrors.join("; "));
4173
- const imagesRoot = join6(applicationDataRoot, "images");
4174
- const durableRoot = resolve(options.storageRoot ?? join6(imagesRoot, "storage"));
4959
+ const imagesRoot = join7(applicationDataRoot, "images");
4960
+ const durableRoot = resolve2(options.storageRoot ?? join7(imagesRoot, "storage"));
4175
4961
  const durableErrors = validateImageRootCandidate(durableRoot, {
4176
4962
  ...options,
4177
4963
  label: "image durable storage root"
4178
4964
  });
4179
4965
  const reservedRoots = [
4180
- join6(imagesRoot, "temporary"),
4181
- join6(imagesRoot, "evidence"),
4182
- join6(imagesRoot, "mount-catalog")
4966
+ join7(imagesRoot, "temporary"),
4967
+ join7(imagesRoot, "evidence"),
4968
+ join7(imagesRoot, "mount-catalog")
4183
4969
  ];
4184
4970
  if (reservedRoots.some((reserved) => isSameOrDescendant(durableRoot, reserved) || isSameOrDescendant(reserved, durableRoot))) {
4185
4971
  durableErrors.push("image durable storage root must not overlap daemon image control roots");
@@ -4188,13 +4974,13 @@ var DaemonImagePathResolver = class {
4188
4974
  const paths = Object.freeze({
4189
4975
  applicationDataRoot,
4190
4976
  imagesRoot,
4191
- temporaryRoot: join6(imagesRoot, "temporary"),
4977
+ temporaryRoot: join7(imagesRoot, "temporary"),
4192
4978
  durableRoot,
4193
- artifactsRoot: join6(durableRoot, "artifacts"),
4194
- stateRoot: join6(durableRoot, "state"),
4195
- evidenceRoot: join6(imagesRoot, "evidence"),
4196
- mountManifestRoot: join6(imagesRoot, "mount-catalog"),
4197
- mountManifestPath: join6(imagesRoot, "mount-catalog", MOUNT_MANIFEST_NAME)
4979
+ artifactsRoot: join7(durableRoot, "artifacts"),
4980
+ stateRoot: join7(durableRoot, "state"),
4981
+ evidenceRoot: join7(imagesRoot, "evidence"),
4982
+ mountManifestRoot: join7(imagesRoot, "mount-catalog"),
4983
+ mountManifestPath: join7(imagesRoot, "mount-catalog", MOUNT_MANIFEST_NAME)
4198
4984
  });
4199
4985
  const rootEntries = [
4200
4986
  ["temporary", paths.temporaryRoot],
@@ -4226,7 +5012,7 @@ var DaemonImagePathResolver = class {
4226
5012
  /** Revalidate immediately before unlinking a resolver-issued file capability. */
4227
5013
  removeFile(target) {
4228
5014
  const path2 = this.verifyDestructiveTarget(target, ["opaque-file", "mount-manifest"]);
4229
- if (!existsSync5(path2)) return;
5015
+ if (!existsSync6(path2)) return;
4230
5016
  const info = lstatSync(path2);
4231
5017
  if (info.isSymbolicLink() || !info.isFile()) {
4232
5018
  throw new TypeError("refusing to unlink an unverified image file");
@@ -4236,7 +5022,7 @@ var DaemonImagePathResolver = class {
4236
5022
  /** Only empty opaque directories may be removed until the owned-marker layer is composed. */
4237
5023
  removeEmptyDirectory(target) {
4238
5024
  const path2 = this.verifyDestructiveTarget(target, ["opaque-directory"]);
4239
- if (!existsSync5(path2)) return;
5025
+ if (!existsSync6(path2)) return;
4240
5026
  const info = lstatSync(path2);
4241
5027
  if (info.isSymbolicLink() || !info.isDirectory()) {
4242
5028
  throw new TypeError("refusing to remove an unverified image directory");
@@ -4246,7 +5032,7 @@ var DaemonImagePathResolver = class {
4246
5032
  issue(area, name, kind) {
4247
5033
  const handle = Object.freeze({
4248
5034
  area,
4249
- absolutePath: join6(this.#roots[area].path, name),
5035
+ absolutePath: join7(this.#roots[area].path, name),
4250
5036
  kind
4251
5037
  });
4252
5038
  this.#issued.add(handle);
@@ -4261,11 +5047,11 @@ var DaemonImagePathResolver = class {
4261
5047
  }
4262
5048
  const root = this.#roots[target.area];
4263
5049
  assertRootIdentity(root);
4264
- const candidate = resolve(target.absolutePath);
5050
+ const candidate = resolve2(target.absolutePath);
4265
5051
  if (!samePath(dirname4(candidate), root.path) || !isSameOrDescendant(candidate, root.path)) {
4266
5052
  throw new TypeError("refusing a destructive operation outside the verified image root");
4267
5053
  }
4268
- const name = basename(candidate);
5054
+ const name = basename2(candidate);
4269
5055
  const validName = target.kind === "mount-manifest" ? name === MOUNT_MANIFEST_NAME : OPAQUE_NAME.test(name);
4270
5056
  if (!validName) throw new TypeError("refusing a caller-derived image filename");
4271
5057
  assertNoSymlinkComponents(candidate);
@@ -4729,29 +5515,29 @@ function resolveEnvKey(rawKey) {
4729
5515
 
4730
5516
  // src/integrations/IntegrationManager.ts
4731
5517
  import { createHash } from "crypto";
4732
- import { existsSync as existsSync7, readFileSync as readFileSync7, unlinkSync as unlinkSync4 } from "fs";
4733
- import { homedir as homedir3 } from "os";
4734
- import { join as join7, resolve as resolve3 } from "path";
5518
+ import { existsSync as existsSync8, readFileSync as readFileSync7, unlinkSync as unlinkSync4 } from "fs";
5519
+ import { homedir as homedir4 } from "os";
5520
+ import { join as join8, resolve as resolve4 } from "path";
4735
5521
  import {
4736
5522
  createIntegrationKey,
4737
5523
  effectiveOutboundPermissions
4738
5524
  } from "@omnicross/core";
4739
5525
 
4740
5526
  // src/integrations/codexAuthHelper.ts
4741
- import { resolve as resolve2 } from "path";
5527
+ import { resolve as resolve3 } from "path";
4742
5528
  function currentProcessCodexAuthHelper(configPath, masterKeyFilePath) {
4743
5529
  const entrypoint = process.argv[1];
4744
5530
  if (!entrypoint) throw new Error("cannot configure Codex auth helper without a daemon CLI entrypoint");
4745
5531
  return {
4746
5532
  command: process.execPath,
4747
5533
  args: [
4748
- resolve2(entrypoint),
5534
+ resolve3(entrypoint),
4749
5535
  "integrations",
4750
5536
  "token",
4751
5537
  "codex",
4752
5538
  "--config",
4753
- resolve2(configPath),
4754
- ...masterKeyFilePath ? ["--master-key-file", resolve2(masterKeyFilePath)] : []
5539
+ resolve3(configPath),
5540
+ ...masterKeyFilePath ? ["--master-key-file", resolve3(masterKeyFilePath)] : []
4755
5541
  ]
4756
5542
  };
4757
5543
  }
@@ -4759,7 +5545,7 @@ function currentProcessCodexAuthHelper(configPath, masterKeyFilePath) {
4759
5545
  // src/integrations/IntegrationStateStore.ts
4760
5546
  import {
4761
5547
  chmodSync as chmodSync3,
4762
- existsSync as existsSync6,
5548
+ existsSync as existsSync7,
4763
5549
  mkdirSync as mkdirSync4,
4764
5550
  readFileSync as readFileSync6,
4765
5551
  renameSync as renameSync3,
@@ -4776,7 +5562,7 @@ var IntegrationStateStore = class {
4776
5562
  path;
4777
5563
  box;
4778
5564
  load() {
4779
- if (!existsSync6(this.path)) return { ...EMPTY_STATE, clients: {} };
5565
+ if (!existsSync7(this.path)) return { ...EMPTY_STATE, clients: {} };
4780
5566
  let raw;
4781
5567
  try {
4782
5568
  raw = JSON.parse(readFileSync6(this.path, "utf8"));
@@ -4882,7 +5668,7 @@ function atomicWrite(path2, content) {
4882
5668
  }
4883
5669
  throw error;
4884
5670
  } finally {
4885
- if (existsSync6(path2)) {
5671
+ if (existsSync7(path2)) {
4886
5672
  try {
4887
5673
  chmodSync3(path2, 384);
4888
5674
  } catch {
@@ -5067,7 +5853,7 @@ var IntegrationManager = class {
5067
5853
  constructor(options) {
5068
5854
  this.options = options;
5069
5855
  assertLoopbackGatewayUrl(options.gatewayBaseUrl);
5070
- this.homeDir = options.homeDir ?? homedir3();
5856
+ this.homeDir = options.homeDir ?? homedir4();
5071
5857
  this.codexAuthHelper = options.codexAuthHelper ?? currentProcessCodexAuthHelper(options.configPath);
5072
5858
  }
5073
5859
  options;
@@ -5081,7 +5867,7 @@ var IntegrationManager = class {
5081
5867
  async plan(client, configPath = this.defaultConfigPath(client)) {
5082
5868
  const state = this.options.stateStore.load();
5083
5869
  const record = state.clients[client];
5084
- const target = record?.configPath ?? resolve3(configPath);
5870
+ const target = record?.configPath ?? resolve4(configPath);
5085
5871
  const status = await this.statusFor(client, state, await this.options.keyDb.outboundApiKeysList());
5086
5872
  const changes = client === "codex" ? ["model_provider", "model_providers.omnicross", "model_providers.omnicross.auth"] : ["env.ANTHROPIC_BASE_URL", "env.ANTHROPIC_AUTH_TOKEN", "env.ANTHROPIC_API_KEY"];
5087
5873
  if (!record) {
@@ -5097,7 +5883,7 @@ var IntegrationManager = class {
5097
5883
  return { client, configPath: target, action: "repair", canApply: true, changes, warnings };
5098
5884
  }
5099
5885
  async install(client, configPath = this.defaultConfigPath(client)) {
5100
- const target = resolve3(configPath);
5886
+ const target = resolve4(configPath);
5101
5887
  const state = this.options.stateStore.load();
5102
5888
  const previousState = cloneState(state);
5103
5889
  const existingRecord = state.clients[client];
@@ -5304,6 +6090,33 @@ var IntegrationManager = class {
5304
6090
  }
5305
6091
  return details.secret;
5306
6092
  }
6093
+ /**
6094
+ * Resolve ONE access key's plaintext by id — the `--key-id` variant the
6095
+ * command-auth helper serves for key-scoped Codex launches (each terminal
6096
+ * picks its own gateway key, so concurrent sessions can route to different
6097
+ * upstreams through their keys' bindings). Enforces the SAME usability
6098
+ * contract as the client-bound path: existing, enabled, not revoked,
6099
+ * revealable, and holding the codex-required endpoint permissions.
6100
+ */
6101
+ async getKeyToken(keyId) {
6102
+ const rows = await this.options.keyDb.outboundApiKeysList();
6103
+ const row = rows.find((candidate) => candidate.id === keyId);
6104
+ if (!row) {
6105
+ throw new IntegrationConflictError(`access key '${keyId}' does not exist`);
6106
+ }
6107
+ const secret = await this.options.keyDb.outboundApiKeysReveal(keyId);
6108
+ if (!row.enabled || row.revokedAt !== null || !secret) {
6109
+ throw new IntegrationConflictError(
6110
+ `access key '${keyId}' is disabled, revoked, or not revealable`
6111
+ );
6112
+ }
6113
+ if (!hasRequiredPermissions(row, "codex")) {
6114
+ throw new IntegrationConflictError(
6115
+ `access key '${keyId}' lacks the responses+images endpoint permissions Codex requires`
6116
+ );
6117
+ }
6118
+ return secret;
6119
+ }
5307
6120
  /** Compatibility alias for callers predating per-client bindings. */
5308
6121
  async getGatewayToken(client = "codex") {
5309
6122
  return this.getIntegrationToken(client);
@@ -5444,7 +6257,7 @@ var IntegrationManager = class {
5444
6257
  }
5445
6258
  }
5446
6259
  defaultConfigPath(client) {
5447
- return client === "codex" ? join7(this.homeDir, ".codex", "config.toml") : join7(this.homeDir, ".claude", "settings.json");
6260
+ return client === "codex" ? join8(this.homeDir, ".codex", "config.toml") : join8(this.homeDir, ".claude", "settings.json");
5448
6261
  }
5449
6262
  renderInstalled(client, base, secret) {
5450
6263
  if (client === "claude") {
@@ -5487,7 +6300,7 @@ function cloneState(state) {
5487
6300
  };
5488
6301
  }
5489
6302
  function readOptional(path2) {
5490
- return existsSync7(path2) ? readFileSync7(path2, "utf8") : null;
6303
+ return existsSync8(path2) ? readFileSync7(path2, "utf8") : null;
5491
6304
  }
5492
6305
  function sha256(value) {
5493
6306
  return createHash("sha256").update(value, "utf8").digest("hex");
@@ -5547,7 +6360,7 @@ function writeOptional(path2, content) {
5547
6360
  atomicWrite(path2, content);
5548
6361
  return;
5549
6362
  }
5550
- if (existsSync7(path2)) unlinkSync4(path2);
6363
+ if (existsSync8(path2)) unlinkSync4(path2);
5551
6364
  }
5552
6365
  async function bestEffortRevoke(db, keyId) {
5553
6366
  try {
@@ -5887,7 +6700,7 @@ import { SUBSCRIPTION_MODEL_CATALOG } from "@omnicross/contracts/subscription-mo
5887
6700
  import { ANTIGRAVITY_CODE_ASSIST_ENDPOINT as ANTIGRAVITY_CODE_ASSIST_ENDPOINT2 } from "@omnicross/core/auth/GeminiCodeAssistProjectResolver";
5888
6701
  import { fetchUpstream as fetchUpstream9 } from "@omnicross/core/pipeline/upstreamFetch";
5889
6702
  import { getAntigravityUserAgent as getAntigravityUserAgent2 } from "@omnicross/core/transformer/transformers/antigravityIdentity";
5890
- function isRecord6(value) {
6703
+ function isRecord8(value) {
5891
6704
  return !!value && typeof value === "object" && !Array.isArray(value);
5892
6705
  }
5893
6706
  function optionalString(value) {
@@ -5900,13 +6713,13 @@ function optionalBoolean(value) {
5900
6713
  return typeof value === "boolean" ? value : void 0;
5901
6714
  }
5902
6715
  function parseAntigravityAvailableModels(payload) {
5903
- if (!isRecord6(payload)) return [];
6716
+ if (!isRecord8(payload)) return [];
5904
6717
  const models = payload["models"];
5905
- if (!isRecord6(models)) return [];
6718
+ if (!isRecord8(models)) return [];
5906
6719
  const out = [];
5907
6720
  for (const [id, raw] of Object.entries(models)) {
5908
6721
  if (ANTIGRAVITY_DISCOVERY_DENYLIST.has(id)) continue;
5909
- if (!isRecord6(raw)) continue;
6722
+ if (!isRecord8(raw)) continue;
5910
6723
  if (raw["isInternal"] === true) continue;
5911
6724
  out.push({
5912
6725
  id,
@@ -5967,7 +6780,7 @@ async function fetchAntigravityAvailableModels(accessToken, fetchImpl = (url, in
5967
6780
  }
5968
6781
  if (!response.ok) return null;
5969
6782
  const payload = await response.json().catch(() => null);
5970
- if (!isRecord6(payload) || !isRecord6(payload["models"])) return null;
6783
+ if (!isRecord8(payload) || !isRecord8(payload["models"])) return null;
5971
6784
  return parseAntigravityAvailableModels(payload);
5972
6785
  }
5973
6786
  async function handleAntigravityModelsRoute(deps) {
@@ -6323,21 +7136,26 @@ async function exchangeGemini(code, codeVerifier, exchangeFetch) {
6323
7136
 
6324
7137
  // src/admin/cliLaunch.ts
6325
7138
  import { exec, spawn } from "child_process";
6326
- import { randomUUID as randomUUID2 } from "crypto";
6327
- import { chmodSync as chmodSync4, existsSync as existsSync8, mkdtempSync, rmSync as rmSync2, writeFileSync as writeFileSync6 } from "fs";
7139
+ import { randomUUID as randomUUID3 } from "crypto";
7140
+ import { chmodSync as chmodSync4, existsSync as existsSync9, mkdtempSync, rmSync as rmSync2, writeFileSync as writeFileSync6 } from "fs";
6328
7141
  import { createServer } from "net";
6329
7142
  import { tmpdir as tmpdir2 } from "os";
6330
- import { delimiter, join as join8 } from "path";
7143
+ import { delimiter, join as join9 } from "path";
6331
7144
  import {
6332
7145
  buildChatCliLaunchConfig,
6333
7146
  buildClaudeCliLaunchConfig,
6334
7147
  buildCodexLaunchConfig,
6335
- buildGeminiCliLaunchConfig
7148
+ buildGeminiCliLaunchConfig,
7149
+ CODEX_PROXY_PROVIDER_NAME
6336
7150
  } from "@omnicross/cli-launcher";
6337
7151
  import {
6338
7152
  ROUTE_LEASE_REQUEST_SCHEMA,
6339
7153
  RouteLeaseError as RouteLeaseError2
6340
7154
  } from "@omnicross/core/provider-proxy";
7155
+ import {
7156
+ candidateGatewayBindings,
7157
+ effectiveOutboundPermissions as effectiveOutboundPermissions2
7158
+ } from "@omnicross/core/outbound-api";
6341
7159
 
6342
7160
  // src/routeLeaseRenewal.ts
6343
7161
  var TERMINAL_LEASE_TTL_SECONDS = 600;
@@ -6384,8 +7202,8 @@ function isLaunchCliId(id) {
6384
7202
  function probeDefault(candidate) {
6385
7203
  const segments = (process.env["PATH"] ?? "").split(delimiter).filter(Boolean);
6386
7204
  for (const seg of segments) {
6387
- const full = join8(seg, candidate);
6388
- if (existsSync8(full)) return full;
7205
+ const full = join9(seg, candidate);
7206
+ if (existsSync9(full)) return full;
6389
7207
  }
6390
7208
  return null;
6391
7209
  }
@@ -6418,6 +7236,75 @@ function resolveLaunchTarget(providers, requested) {
6418
7236
  function firstModel(p) {
6419
7237
  return p.models?.[0] ?? p.modelConfigs?.[0]?.id;
6420
7238
  }
7239
+ var CMD_METACHAR_RE = /[&|<>^%]/;
7240
+ var KEY_SCOPED_CODEX_PERMISSIONS = ["responses", "images"];
7241
+ function buildKeyScopedCodexArgs(input) {
7242
+ let root = input.gatewayBaseUrl;
7243
+ while (root.endsWith("/")) root = root.slice(0, -1);
7244
+ const name = CODEX_PROXY_PROVIDER_NAME;
7245
+ const helperArgs = [...input.authHelper.args, "--key-id", input.keyId];
7246
+ return [
7247
+ "-c",
7248
+ `model_provider="${name}"`,
7249
+ "-c",
7250
+ `model_providers.${name}.name="OmniCross Local Gateway"`,
7251
+ "-c",
7252
+ `model_providers.${name}.base_url="${root}/v1"`,
7253
+ "-c",
7254
+ `model_providers.${name}.wire_api="responses"`,
7255
+ "-c",
7256
+ `model_providers.${name}.supports_websockets=false`,
7257
+ "-c",
7258
+ `model_providers.${name}.http_headers={"X-OpenAI-Actor-Authorization"="omnicross"}`,
7259
+ "-c",
7260
+ `model_providers.${name}.auth.command=${JSON.stringify(input.authHelper.command)}`,
7261
+ "-c",
7262
+ `model_providers.${name}.auth.args=${JSON.stringify(helperArgs)}`,
7263
+ "-c",
7264
+ `model_providers.${name}.auth.refresh_interval_ms=0`,
7265
+ "-c",
7266
+ `model_providers.${name}.auth.timeout_ms=5000`,
7267
+ "-c",
7268
+ "disable_response_storage=true"
7269
+ ];
7270
+ }
7271
+ async function preflightKeyScopedLaunch(deps, keyId) {
7272
+ if (!deps.gatewayRunning) {
7273
+ return {
7274
+ ok: false,
7275
+ status: 409,
7276
+ message: "the outbound gateway is not running \u2014 key-scoped launches route through it"
7277
+ };
7278
+ }
7279
+ const rows = await deps.keyDb.outboundApiKeysList();
7280
+ const row = rows.find((candidate) => candidate.id === keyId);
7281
+ if (!row) return { ok: false, status: 404, message: `access key '${keyId}' does not exist` };
7282
+ if (!row.enabled || row.revokedAt !== null) {
7283
+ return { ok: false, status: 400, message: `access key '${row.name}' is disabled or revoked` };
7284
+ }
7285
+ const secret = await deps.keyDb.outboundApiKeysReveal(keyId);
7286
+ if (!secret) {
7287
+ return { ok: false, status: 400, message: `access key '${row.name}' is not revealable` };
7288
+ }
7289
+ const allowed = effectiveOutboundPermissions2(row.allowedEndpoints);
7290
+ for (const permission of KEY_SCOPED_CODEX_PERMISSIONS) {
7291
+ if (!allowed.includes(permission)) {
7292
+ return {
7293
+ ok: false,
7294
+ status: 400,
7295
+ message: `access key '${row.name}' lacks the '${permission}' endpoint permission Codex requires`
7296
+ };
7297
+ }
7298
+ }
7299
+ if (candidateGatewayBindings(deps.bindings, keyId, "responses").length === 0) {
7300
+ return {
7301
+ ok: false,
7302
+ status: 400,
7303
+ message: `access key '${row.name}' has no enabled responses route \u2014 bind it to a downstream route on the API Service page first`
7304
+ };
7305
+ }
7306
+ return { ok: true, keyName: row.name };
7307
+ }
6421
7308
  async function buildLaunchEnv(cli, llmConfig, target) {
6422
7309
  const common = {
6423
7310
  llmConfig,
@@ -6489,10 +7376,10 @@ function openTerminal({ cli, command, extraArgs, env, cwd, platform, onFailure }
6489
7376
  const runLine = [command, ...extraArgs].map(shq).join(" ");
6490
7377
  const script = `${cwd ? `cd ${shq(cwd)}; ` : ""}${runLine}`;
6491
7378
  if (platform === "darwin") {
6492
- const launchDir = mkdtempSync(join8(tmpdir2(), "omnicross-terminal-"));
6493
- const commandFile = join8(launchDir, "launch.command");
6494
- const bootstrapFile = join8(launchDir, "bootstrap.cjs");
6495
- const socketPath = macIpc.socketPath ?? join8(launchDir, "descriptor.sock");
7379
+ const launchDir = mkdtempSync(join9(tmpdir2(), "omnicross-terminal-"));
7380
+ const commandFile = join9(launchDir, "launch.command");
7381
+ const bootstrapFile = join9(launchDir, "bootstrap.cjs");
7382
+ const socketPath = macIpc.socketPath ?? join9(launchDir, "descriptor.sock");
6496
7383
  const openerEnv = { ...process.env };
6497
7384
  for (const key of Object.keys(env)) delete openerEnv[key];
6498
7385
  let claimed = false;
@@ -6621,10 +7508,10 @@ function resetCliSessions() {
6621
7508
  function errBody(message) {
6622
7509
  return { error: { type: "admin_api_error", message } };
6623
7510
  }
6624
- var defaultCommandRunner = (command) => new Promise((resolve11) => {
7511
+ var defaultCommandRunner = (command) => new Promise((resolve12) => {
6625
7512
  exec(command, { timeout: 18e4 }, (err9, _stdout, stderr) => {
6626
- if (err9) resolve11({ ok: false, error: stderr.trim() || err9.message });
6627
- else resolve11({ ok: true });
7513
+ if (err9) resolve12({ ok: false, error: stderr.trim() || err9.message });
7514
+ else resolve12({ ok: true });
6628
7515
  });
6629
7516
  });
6630
7517
  async function handleCliInstall(cli, runner = defaultCommandRunner) {
@@ -6663,44 +7550,84 @@ async function handleCliLaunch(cli, body, ctx) {
6663
7550
  if (!isCliInstalled(meta.command, platform, probe)) {
6664
7551
  return { status: 400, body: errBody(`"${meta.command}" is not installed (not found on PATH)`) };
6665
7552
  }
7553
+ const keyId = typeof body["keyId"] === "string" && body["keyId"].trim() ? body["keyId"].trim() : void 0;
6666
7554
  let target;
6667
- try {
6668
- target = resolveLaunchTarget(ctx.providers, {
6669
- providerId: typeof body["providerId"] === "string" ? body["providerId"] : void 0,
6670
- model: typeof body["model"] === "string" ? body["model"] : void 0
6671
- });
6672
- } catch (err9) {
6673
- return { status: 400, body: errBody(err9 instanceof Error ? err9.message : "no launch target") };
6674
- }
6675
- const id = randomUUID2();
7555
+ let keyLaunch;
7556
+ const id = randomUUID3();
6676
7557
  let leaseId2;
6677
7558
  let launch;
6678
- try {
6679
- if ((cli === "claude" || cli === "codex") && ctx.routeLeaseManager) {
6680
- const outcome = await ctx.routeLeaseManager.createFromRequest({
6681
- schemaVersion: ROUTE_LEASE_REQUEST_SCHEMA,
6682
- consumer: "omnicross-terminal",
6683
- runtime: cli,
6684
- upstream: { kind: "provider", providerId: target.providerId },
6685
- model: target.model,
6686
- execution: { sessionId: id }
6687
- }, `omnicross-terminal:${id}`);
6688
- leaseId2 = outcome.result.leaseId;
6689
- const stopRenewal = startTerminalLeaseRenewal(ctx.routeLeaseManager, leaseId2);
6690
- launch = {
6691
- env: outcome.result.launch.env,
6692
- extraArgs: outcome.result.launch.extraArgs,
6693
- onSessionEnd: () => {
6694
- stopRenewal();
6695
- ctx.routeLeaseManager?.release(outcome.result.leaseId);
6696
- }
6697
- };
6698
- } else {
6699
- launch = await buildLaunchEnv(cli, ctx.llmConfig, target);
7559
+ if (keyId) {
7560
+ if (cli !== "codex") {
7561
+ return { status: 400, body: errBody("key-scoped launch is only supported for codex") };
7562
+ }
7563
+ const deps = ctx.keyScoped;
7564
+ if (!deps) {
7565
+ return { status: 501, body: errBody("key-scoped launch is not available in this build") };
7566
+ }
7567
+ const preflight = await preflightKeyScopedLaunch(deps, keyId);
7568
+ if (!preflight.ok) return { status: preflight.status, body: errBody(preflight.message) };
7569
+ if (platform === "win32") {
7570
+ const unsafe = [deps.codexAuthHelper.command, ...deps.codexAuthHelper.args].filter((value) => CMD_METACHAR_RE.test(value));
7571
+ if (unsafe.length > 0) {
7572
+ return {
7573
+ status: 400,
7574
+ body: errBody(
7575
+ "the Codex auth-helper path contains cmd.exe metacharacters and cannot be passed through a Windows terminal launch"
7576
+ )
7577
+ };
7578
+ }
7579
+ }
7580
+ keyLaunch = { keyId, keyName: preflight.keyName };
7581
+ launch = {
7582
+ env: {},
7583
+ extraArgs: buildKeyScopedCodexArgs({
7584
+ gatewayBaseUrl: deps.gatewayBaseUrl,
7585
+ authHelper: deps.codexAuthHelper,
7586
+ keyId
7587
+ }),
7588
+ // No route or lease exists to release — the gateway key outlives the
7589
+ // terminal and its bindings route every request.
7590
+ onSessionEnd: () => {
7591
+ }
7592
+ };
7593
+ } else {
7594
+ let resolved;
7595
+ try {
7596
+ resolved = resolveLaunchTarget(ctx.providers, {
7597
+ providerId: typeof body["providerId"] === "string" ? body["providerId"] : void 0,
7598
+ model: typeof body["model"] === "string" ? body["model"] : void 0
7599
+ });
7600
+ } catch (err9) {
7601
+ return { status: 400, body: errBody(err9 instanceof Error ? err9.message : "no launch target") };
7602
+ }
7603
+ target = resolved;
7604
+ try {
7605
+ if ((cli === "claude" || cli === "codex") && ctx.routeLeaseManager) {
7606
+ const outcome = await ctx.routeLeaseManager.createFromRequest({
7607
+ schemaVersion: ROUTE_LEASE_REQUEST_SCHEMA,
7608
+ consumer: "omnicross-terminal",
7609
+ runtime: cli,
7610
+ upstream: { kind: "provider", providerId: resolved.providerId },
7611
+ model: resolved.model,
7612
+ execution: { sessionId: id }
7613
+ }, `omnicross-terminal:${id}`);
7614
+ leaseId2 = outcome.result.leaseId;
7615
+ const stopRenewal = startTerminalLeaseRenewal(ctx.routeLeaseManager, leaseId2);
7616
+ launch = {
7617
+ env: outcome.result.launch.env,
7618
+ extraArgs: outcome.result.launch.extraArgs,
7619
+ onSessionEnd: () => {
7620
+ stopRenewal();
7621
+ ctx.routeLeaseManager?.release(outcome.result.leaseId);
7622
+ }
7623
+ };
7624
+ } else {
7625
+ launch = await buildLaunchEnv(cli, ctx.llmConfig, resolved);
7626
+ }
7627
+ } catch (err9) {
7628
+ const status = err9 instanceof RouteLeaseError2 ? err9.status : 400;
7629
+ return { status, body: errBody(err9 instanceof Error ? err9.message : "failed to build launch env") };
6700
7630
  }
6701
- } catch (err9) {
6702
- const status = err9 instanceof RouteLeaseError2 ? err9.status : 400;
6703
- return { status, body: errBody(err9 instanceof Error ? err9.message : "failed to build launch env") };
6704
7631
  }
6705
7632
  const cwd = typeof body["cwd"] === "string" && body["cwd"].trim() ? body["cwd"].trim() : void 0;
6706
7633
  const opener = ctx.opener ?? defaultTerminalOpener;
@@ -6739,15 +7666,19 @@ async function handleCliLaunch(cli, body, ctx) {
6739
7666
  sessions.set(id, {
6740
7667
  id,
6741
7668
  cli,
6742
- providerId: target.providerId,
6743
- model: target.model,
7669
+ providerId: target?.providerId ?? "",
7670
+ model: target?.model ?? "",
7671
+ ...keyLaunch ? { keyId: keyLaunch.keyId, keyName: keyLaunch.keyName } : {},
6744
7672
  ...leaseId2 ? { leaseId: leaseId2 } : {},
6745
7673
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
6746
7674
  onSessionEnd
6747
7675
  });
6748
7676
  published = true;
6749
7677
  if (ended) sessions.delete(id);
6750
- return { status: 200, body: { sessionId: id, providerId: target.providerId, model: target.model } };
7678
+ return {
7679
+ status: 200,
7680
+ body: keyLaunch ? { sessionId: id, keyId: keyLaunch.keyId, keyName: keyLaunch.keyName } : { sessionId: id, providerId: target?.providerId, model: target?.model }
7681
+ };
6751
7682
  }
6752
7683
 
6753
7684
  // src/admin/auditConfigBody.ts
@@ -7081,17 +8012,17 @@ function sanitizeResultField(value, cap) {
7081
8012
  const text = typeof value === "string" ? value : value === null || value === void 0 ? "" : String(value);
7082
8013
  return text.replace(/[\u0000-\u001f\u007f]/gu, "").slice(0, cap);
7083
8014
  }
7084
- function writeJson(res, status, body) {
8015
+ function writeJson2(res, status, body) {
7085
8016
  res.writeHead(status, { "Content-Type": "application/json" });
7086
8017
  res.end(JSON.stringify(body));
7087
8018
  }
7088
8019
  function writeErr(res, status, message) {
7089
- writeJson(res, status, { error: { type: "admin_api_error", message } });
8020
+ writeJson2(res, status, { error: { type: "admin_api_error", message } });
7090
8021
  }
7091
8022
  var SEARCH_MAX_BODY_BYTES = 64 * 1024;
7092
8023
  var SearchBodyTooLargeError = class extends Error {
7093
8024
  };
7094
- async function readJsonBody2(req) {
8025
+ async function readJsonBody3(req) {
7095
8026
  const chunks = [];
7096
8027
  let bytes = 0;
7097
8028
  for await (const chunk of req) {
@@ -7111,7 +8042,7 @@ async function readJsonBody2(req) {
7111
8042
  }
7112
8043
  async function readBodyOrReject(req, res) {
7113
8044
  try {
7114
- return await readJsonBody2(req);
8045
+ return await readJsonBody3(req);
7115
8046
  } catch (error) {
7116
8047
  if (error instanceof SearchBodyTooLargeError) {
7117
8048
  writeErr(res, 400, error.message);
@@ -7169,7 +8100,7 @@ async function handleSearchDiagnostics(res, deps) {
7169
8100
  },
7170
8101
  applySemantics: { codex: "immediate", rest: "restart" }
7171
8102
  };
7172
- return writeJson(res, 200, { diagnostics: snapshot });
8103
+ return writeJson2(res, 200, { diagnostics: snapshot });
7173
8104
  }
7174
8105
  function persistedSearchContributions(search, fetchImpl) {
7175
8106
  if (fetchImpl) {
@@ -7215,11 +8146,11 @@ async function handleSearchTest(req, res, deps) {
7215
8146
  checkedAt
7216
8147
  );
7217
8148
  const response = { diagnostic, resultCount: results.length };
7218
- return writeJson(res, 200, { result: response });
8149
+ return writeJson2(res, 200, { result: response });
7219
8150
  } catch (error) {
7220
8151
  const diagnostic = classifyLiveSearchOutcome(contribution.id, { kind: "failure", error }, checkedAt);
7221
8152
  const response = { diagnostic };
7222
- return writeJson(res, 200, { result: response });
8153
+ return writeJson2(res, 200, { result: response });
7223
8154
  }
7224
8155
  }
7225
8156
  async function handleSearchQuery(req, res, deps) {
@@ -7282,18 +8213,18 @@ async function handleSearchQuery(req, res, deps) {
7282
8213
  resultCount: sanitized.length,
7283
8214
  results: sanitized
7284
8215
  };
7285
- return writeJson(res, 200, { result: response });
8216
+ return writeJson2(res, 200, { result: response });
7286
8217
  } catch (error) {
7287
8218
  const diagnostic = classifyLiveSearchOutcome(providerId, { kind: "failure", error }, checkedAt);
7288
8219
  const response = { diagnostic };
7289
- return writeJson(res, 200, { result: response });
8220
+ return writeJson2(res, 200, { result: response });
7290
8221
  }
7291
8222
  }
7292
8223
 
7293
8224
  // src/admin/searchAdminView.ts
7294
8225
  var API_KEY_PROVIDERS = /* @__PURE__ */ new Set(["tavily", "jina", "zhipu", "z.ai"]);
7295
8226
  var BASIC_AUTH_PROVIDERS = /* @__PURE__ */ new Set(["searxng"]);
7296
- function isRecord7(value) {
8227
+ function isRecord9(value) {
7297
8228
  return value !== null && typeof value === "object" && !Array.isArray(value);
7298
8229
  }
7299
8230
  function redactSearchServerConfig(search) {
@@ -7343,13 +8274,13 @@ function resolveSecretField(entry, field, stored) {
7343
8274
  else delete entry[field];
7344
8275
  }
7345
8276
  function preserveSearchSecrets(incoming, current) {
7346
- if (!isRecord7(incoming)) return incoming;
8277
+ if (!isRecord9(incoming)) return incoming;
7347
8278
  const section = { ...incoming };
7348
8279
  const providersValue = section["providers"];
7349
- if (!isRecord7(providersValue)) return section;
8280
+ if (!isRecord9(providersValue)) return section;
7350
8281
  const providers = {};
7351
8282
  for (const [id, entryValue] of Object.entries(providersValue)) {
7352
- if (!isRecord7(entryValue)) {
8283
+ if (!isRecord9(entryValue)) {
7353
8284
  providers[id] = entryValue;
7354
8285
  continue;
7355
8286
  }
@@ -7427,7 +8358,8 @@ function parseKeyPolicyBody(body) {
7427
8358
  var ENDPOINTS = /* @__PURE__ */ new Set(["chat", "responses", "messages", "gemini"]);
7428
8359
  var TARGET_KINDS = /* @__PURE__ */ new Set(["account", "account-group", "account-pool", "provider"]);
7429
8360
  var FALLBACKS = /* @__PURE__ */ new Set(["next", "fail", "global"]);
7430
- function isRecord8(value) {
8361
+ var EFFORT_MAX_LENGTH = 32;
8362
+ function isRecord10(value) {
7431
8363
  return !!value && typeof value === "object" && !Array.isArray(value);
7432
8364
  }
7433
8365
  function nonBlank(value) {
@@ -7447,7 +8379,7 @@ function validateGatewayBindingsSegment(patch) {
7447
8379
  const ids = /* @__PURE__ */ new Set();
7448
8380
  raw.forEach((entry, index) => {
7449
8381
  const path2 = `bindings[${index}]`;
7450
- if (!isRecord8(entry)) {
8382
+ if (!isRecord10(entry)) {
7451
8383
  errors.push(`${path2} must be an object`);
7452
8384
  return;
7453
8385
  }
@@ -7476,12 +8408,18 @@ function validateGatewayBindingsSegment(patch) {
7476
8408
  } else if (entry.modelMappings.length > 100) {
7477
8409
  errors.push(`${path2}.modelMappings cannot contain more than 100 entries`);
7478
8410
  } else if (entry.modelMappings.some(
7479
- (mapping) => !isRecord8(mapping) || !nonBlank(mapping.source) || !nonBlank(mapping.target)
8411
+ (mapping) => !isRecord10(mapping) || !nonBlank(mapping.source) || !nonBlank(mapping.target)
7480
8412
  )) {
7481
8413
  errors.push(`${path2}.modelMappings must contain non-empty source and target strings`);
8414
+ } else if (entry.modelMappings.some(
8415
+ (mapping) => mapping.effort !== void 0 && (typeof mapping.effort !== "string" || mapping.effort.trim() === "" || mapping.effort.trim().length > EFFORT_MAX_LENGTH)
8416
+ )) {
8417
+ errors.push(
8418
+ `${path2}.modelMappings effort must be a non-empty string of at most ${EFFORT_MAX_LENGTH} characters`
8419
+ );
7482
8420
  }
7483
8421
  }
7484
- if (!isRecord8(entry.target) || !TARGET_KINDS.has(String(entry.target.kind))) {
8422
+ if (!isRecord10(entry.target) || !TARGET_KINDS.has(String(entry.target.kind))) {
7485
8423
  errors.push(`${path2}.target is invalid`);
7486
8424
  } else {
7487
8425
  if (!nonBlank(entry.target.providerId)) errors.push(`${path2}.target.providerId is required`);
@@ -7496,7 +8434,7 @@ function validateGatewayBindingsSegment(patch) {
7496
8434
  }
7497
8435
  }
7498
8436
  if (entry.modelMap !== void 0) {
7499
- if (!isRecord8(entry.modelMap) || Object.values(entry.modelMap).some((value) => typeof value !== "string")) {
8437
+ if (!isRecord10(entry.modelMap) || Object.values(entry.modelMap).some((value) => typeof value !== "string")) {
7500
8438
  errors.push(`${path2}.modelMap must contain string values`);
7501
8439
  }
7502
8440
  }
@@ -7522,23 +8460,23 @@ import {
7522
8460
  toVoucherInfo,
7523
8461
  voucherCodePrefix
7524
8462
  } from "@omnicross/core/outbound-api";
7525
- function writeJson2(res, status, body) {
8463
+ function writeJson3(res, status, body) {
7526
8464
  res.writeHead(status, { "Content-Type": "application/json" });
7527
8465
  res.end(JSON.stringify(body));
7528
8466
  }
7529
8467
  function writeErr2(res, status, message) {
7530
- writeJson2(res, status, { error: { type: "voucher_error", message } });
8468
+ writeJson3(res, status, { error: { type: "voucher_error", message } });
7531
8469
  }
7532
- function readJsonBody3(req) {
7533
- return new Promise((resolve11, reject) => {
8470
+ function readJsonBody4(req) {
8471
+ return new Promise((resolve12, reject) => {
7534
8472
  const chunks = [];
7535
8473
  req.on("data", (c) => chunks.push(c));
7536
8474
  req.on("end", () => {
7537
8475
  const raw = Buffer.concat(chunks).toString("utf8");
7538
- if (!raw.trim()) return resolve11({});
8476
+ if (!raw.trim()) return resolve12({});
7539
8477
  try {
7540
8478
  const parsed = JSON.parse(raw);
7541
- resolve11(parsed && typeof parsed === "object" ? parsed : {});
8479
+ resolve12(parsed && typeof parsed === "object" ? parsed : {});
7542
8480
  } catch {
7543
8481
  reject(new Error("invalid-json"));
7544
8482
  }
@@ -7588,13 +8526,13 @@ async function handleVoucher(req, res, method, rest, deps) {
7588
8526
  if (!voucherDb) return writeErr2(res, 501, "Voucher feature is not available");
7589
8527
  if (method === "GET" && rest.length === 0) {
7590
8528
  const rows = await voucherDb.voucherList();
7591
- return writeJson2(res, 200, { vouchers: rows.map(toVoucherInfo) });
8529
+ return writeJson3(res, 200, { vouchers: rows.map(toVoucherInfo) });
7592
8530
  }
7593
8531
  if (method === "POST" && rest.length === 0) {
7594
8532
  if (!await voucherEnabled(deps)) return writeErr2(res, 403, "Voucher feature is disabled");
7595
8533
  let body;
7596
8534
  try {
7597
- body = await readJsonBody3(req);
8535
+ body = await readJsonBody4(req);
7598
8536
  } catch {
7599
8537
  return writeErr2(res, 400, "Invalid JSON in request body");
7600
8538
  }
@@ -7607,7 +8545,7 @@ async function handleVoucher(req, res, method, rest, deps) {
7607
8545
  codePrefix: voucherCodePrefix(code),
7608
8546
  ...parsed.input
7609
8547
  });
7610
- return writeJson2(res, 201, {
8548
+ return writeJson3(res, 201, {
7611
8549
  id: created.id,
7612
8550
  codePrefix: created.codePrefix,
7613
8551
  type: created.type,
@@ -7620,7 +8558,7 @@ async function handleVoucher(req, res, method, rest, deps) {
7620
8558
  if (method === "POST" && id && rest[1] === "revoke") {
7621
8559
  if (!await voucherEnabled(deps)) return writeErr2(res, 403, "Voucher feature is disabled");
7622
8560
  const ok = await voucherDb.voucherRevokeCas(id, Date.now());
7623
- return writeJson2(res, ok ? 200 : 409, { ok });
8561
+ return writeJson3(res, ok ? 200 : 409, { ok });
7624
8562
  }
7625
8563
  return writeErr2(res, 405, `method ${method} not allowed on voucher`);
7626
8564
  }
@@ -7781,7 +8719,7 @@ import {
7781
8719
  } from "@omnicross/core/outbound-api";
7782
8720
 
7783
8721
  // src/ports/account-multi.ts
7784
- import { randomUUID as randomUUID3 } from "crypto";
8722
+ import { randomUUID as randomUUID4 } from "crypto";
7785
8723
  var PROVIDER_KEYS = {
7786
8724
  claude: { block: "claude", accounts: "claudeAccounts", active: "activeClaudeAccountId" },
7787
8725
  codex: { block: "codex", accounts: "codexAccounts", active: "activeCodexAccountId" },
@@ -7855,7 +8793,7 @@ function migrateLazily(config) {
7855
8793
  }
7856
8794
  function addAccount(config, p, tokens, label) {
7857
8795
  const accounts = [...getAccounts(config, p)];
7858
- const id = randomUUID3();
8796
+ const id = randomUUID4();
7859
8797
  accounts.push({
7860
8798
  id,
7861
8799
  label: label ?? `Account ${accounts.length + 1}`,
@@ -8544,22 +9482,22 @@ async function handlePricingResolveConflicts(body, deps) {
8544
9482
  }
8545
9483
 
8546
9484
  // src/admin/accountAllowanceApi.ts
8547
- function writeJson3(res, status, body) {
9485
+ function writeJson4(res, status, body) {
8548
9486
  res.writeHead(status, { "Content-Type": "application/json" });
8549
9487
  res.end(JSON.stringify(body));
8550
9488
  }
8551
9489
  function writeError2(res, status, message) {
8552
- writeJson3(res, status, { error: { type: "account_allowance_error", message } });
9490
+ writeJson4(res, status, { error: { type: "account_allowance_error", message } });
8553
9491
  }
8554
9492
  function readJson2(req) {
8555
- return new Promise((resolve11, reject) => {
9493
+ return new Promise((resolve12, reject) => {
8556
9494
  const chunks = [];
8557
9495
  req.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
8558
9496
  req.on("end", () => {
8559
9497
  try {
8560
9498
  const text = Buffer.concat(chunks).toString("utf8");
8561
9499
  const parsed = text ? JSON.parse(text) : {};
8562
- resolve11(parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {});
9500
+ resolve12(parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {});
8563
9501
  } catch (error) {
8564
9502
  reject(error);
8565
9503
  }
@@ -8582,7 +9520,7 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
8582
9520
  if (!service.getSchedulingStatus) {
8583
9521
  return writeError2(res, 501, "allowance scheduling diagnostics are not available");
8584
9522
  }
8585
- return writeJson3(res, 200, { scheduling: service.getSchedulingStatus() });
9523
+ return writeJson4(res, 200, { scheduling: service.getSchedulingStatus() });
8586
9524
  }
8587
9525
  if (method === "GET") {
8588
9526
  const params = query(req);
@@ -8593,7 +9531,7 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
8593
9531
  }
8594
9532
  const accountId = rest.length >= 2 ? rest[1] : params.get("accountId") ?? void 0;
8595
9533
  const allowances = await service.list({ providerId, accountId });
8596
- return writeJson3(res, 200, { allowances });
9534
+ return writeJson4(res, 200, { allowances });
8597
9535
  }
8598
9536
  if (method === "POST" && rest[0] === "refresh") {
8599
9537
  const body = await readJson2(req);
@@ -8609,7 +9547,7 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
8609
9547
  if (accountId && allowances2.length === 0) {
8610
9548
  return writeError2(res, 404, `Codex account '${accountId}' not found`);
8611
9549
  }
8612
- return writeJson3(res, 200, { allowances: allowances2 });
9550
+ return writeJson4(res, 200, { allowances: allowances2 });
8613
9551
  }
8614
9552
  if (requestedProvider === "kimi") {
8615
9553
  if (!service.refreshKimi) {
@@ -8619,7 +9557,7 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
8619
9557
  if (accountId && allowances2.length === 0) {
8620
9558
  return writeError2(res, 404, `Kimi account '${accountId}' not found`);
8621
9559
  }
8622
- return writeJson3(res, 200, { allowances: allowances2 });
9560
+ return writeJson4(res, 200, { allowances: allowances2 });
8623
9561
  }
8624
9562
  if (requestedProvider === "opencodego") {
8625
9563
  if (!service.refreshOpenCodeGo) {
@@ -8629,7 +9567,7 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
8629
9567
  if (accountId && allowances2.length === 0) {
8630
9568
  return writeError2(res, 404, `OpenCodeGo account '${accountId}' not found`);
8631
9569
  }
8632
- return writeJson3(res, 200, { allowances: allowances2 });
9570
+ return writeJson4(res, 200, { allowances: allowances2 });
8633
9571
  }
8634
9572
  if (requestedProvider === "copilot") {
8635
9573
  if (!service.refreshCopilot) {
@@ -8639,7 +9577,7 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
8639
9577
  if (accountId && allowances2.length === 0) {
8640
9578
  return writeError2(res, 404, `Copilot account '${accountId}' not found`);
8641
9579
  }
8642
- return writeJson3(res, 200, { allowances: allowances2 });
9580
+ return writeJson4(res, 200, { allowances: allowances2 });
8643
9581
  }
8644
9582
  if (requestedProvider === "grok") {
8645
9583
  if (!service.refreshGrok) {
@@ -8649,7 +9587,7 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
8649
9587
  if (accountId && allowances2.length === 0) {
8650
9588
  return writeError2(res, 404, `Grok account '${accountId}' not found`);
8651
9589
  }
8652
- return writeJson3(res, 200, { allowances: allowances2 });
9590
+ return writeJson4(res, 200, { allowances: allowances2 });
8653
9591
  }
8654
9592
  if (requestedProvider === "antigravity") {
8655
9593
  if (!service.refreshAntigravity) {
@@ -8659,7 +9597,7 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
8659
9597
  if (accountId && allowances2.length === 0) {
8660
9598
  return writeError2(res, 404, `Antigravity account '${accountId}' not found`);
8661
9599
  }
8662
- return writeJson3(res, 200, { allowances: allowances2 });
9600
+ return writeJson4(res, 200, { allowances: allowances2 });
8663
9601
  }
8664
9602
  if (requestedProvider === "gemini") {
8665
9603
  if (!service.refreshGemini) {
@@ -8669,13 +9607,13 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
8669
9607
  if (accountId && allowances2.length === 0) {
8670
9608
  return writeError2(res, 404, `Gemini account '${accountId}' not found`);
8671
9609
  }
8672
- return writeJson3(res, 200, { allowances: allowances2 });
9610
+ return writeJson4(res, 200, { allowances: allowances2 });
8673
9611
  }
8674
9612
  const allowances = await service.refreshClaude(accountId);
8675
9613
  if (accountId && allowances.length === 0) {
8676
9614
  return writeError2(res, 404, `Claude account '${accountId}' not found`);
8677
9615
  }
8678
- return writeJson3(res, 200, { allowances });
9616
+ return writeJson4(res, 200, { allowances });
8679
9617
  }
8680
9618
  return writeError2(res, 405, `method ${method} not allowed on account allowances`);
8681
9619
  }
@@ -8687,14 +9625,14 @@ import {
8687
9625
  } from "@omnicross/core/pipeline/AccountRouteActivity";
8688
9626
  import { getSharedOverloadCounter } from "@omnicross/core/pipeline/ServerOverloadCounter";
8689
9627
  function readBody(req) {
8690
- return new Promise((resolve11, reject) => {
9628
+ return new Promise((resolve12, reject) => {
8691
9629
  const chunks = [];
8692
9630
  req.on("data", (chunk) => chunks.push(chunk));
8693
- req.on("end", () => resolve11(Buffer.concat(chunks).toString("utf8")));
9631
+ req.on("end", () => resolve12(Buffer.concat(chunks).toString("utf8")));
8694
9632
  req.on("error", reject);
8695
9633
  });
8696
9634
  }
8697
- async function readJsonBody4(req) {
9635
+ async function readJsonBody5(req) {
8698
9636
  const raw = await readBody(req);
8699
9637
  if (!raw.trim()) return {};
8700
9638
  try {
@@ -8704,12 +9642,12 @@ async function readJsonBody4(req) {
8704
9642
  return {};
8705
9643
  }
8706
9644
  }
8707
- function writeJson4(res, status, body) {
9645
+ function writeJson5(res, status, body) {
8708
9646
  res.writeHead(status, { "Content-Type": "application/json" });
8709
9647
  res.end(JSON.stringify(body));
8710
9648
  }
8711
- function writeJsonError(res, status, message) {
8712
- writeJson4(res, status, { error: { type: "admin_api_error", message } });
9649
+ function writeJsonError2(res, status, message) {
9650
+ writeJson5(res, status, { error: { type: "admin_api_error", message } });
8713
9651
  }
8714
9652
  function maskProviderApiKey(apiKey) {
8715
9653
  if (!apiKey) return "";
@@ -8730,7 +9668,7 @@ function toKeyInfo(row) {
8730
9668
  lastUsedAt: row.lastUsedAt,
8731
9669
  revoked: row.revokedAt !== null,
8732
9670
  kind: row.kind,
8733
- allowedEndpoints: [...effectiveOutboundPermissions2(row.allowedEndpoints)],
9671
+ allowedEndpoints: [...effectiveOutboundPermissions3(row.allowedEndpoints)],
8734
9672
  legacyPermissions: row.allowedEndpoints === void 0,
8735
9673
  loopbackOnly: row.loopbackOnly,
8736
9674
  maxConcurrency: row.maxConcurrency,
@@ -8748,7 +9686,12 @@ function toKeyInfo(row) {
8748
9686
  // Per-key model restriction (#6) — secret-free scalars the UI pre-fills.
8749
9687
  enableModelRestriction: row.enableModelRestriction,
8750
9688
  restrictionMode: row.restrictionMode,
8751
- restrictedModels: row.restrictedModels
9689
+ restrictedModels: row.restrictedModels,
9690
+ // Direct upstream passthrough target (key→upstream binding) — references
9691
+ // only, never a credential. Absent = the key is served by the downstream
9692
+ // routes. `boundUpstreamProviderId` is the legacy first-cut shape.
9693
+ boundUpstream: row.boundUpstream,
9694
+ boundUpstreamProviderId: row.boundUpstreamProviderId
8752
9695
  };
8753
9696
  }
8754
9697
  function toProviderView(row) {
@@ -8842,10 +9785,10 @@ async function handleAdminApi(req, res, path2, deps) {
8842
9785
  case "pricing":
8843
9786
  return await handlePricing(req, res, method, rest, deps);
8844
9787
  default:
8845
- return writeJsonError(res, 404, `unknown admin resource '${resource}'`);
9788
+ return writeJsonError2(res, 404, `unknown admin resource '${resource}'`);
8846
9789
  }
8847
9790
  } catch (err9) {
8848
- writeJsonError(res, 500, err9 instanceof Error ? err9.message : String(err9));
9791
+ writeJsonError2(res, 500, err9 instanceof Error ? err9.message : String(err9));
8849
9792
  }
8850
9793
  }
8851
9794
  function requestQuery(req) {
@@ -8854,35 +9797,35 @@ function requestQuery(req) {
8854
9797
  return new URLSearchParams(qIdx >= 0 ? raw.slice(qIdx + 1) : "");
8855
9798
  }
8856
9799
  function writeResult(res, result) {
8857
- writeJson4(res, result.status, result.body);
9800
+ writeJson5(res, result.status, result.body);
8858
9801
  }
8859
9802
  async function handleUsage(req, res, method, rest, deps) {
8860
- if (method !== "GET") return writeJsonError(res, 405, `method ${method} not allowed on usage`);
9803
+ if (method !== "GET") return writeJsonError2(res, 405, `method ${method} not allowed on usage`);
8861
9804
  return writeResult(res, await handleUsageGet(rest[0], requestQuery(req), deps));
8862
9805
  }
8863
9806
  async function handleDashboardRoute(res, method, deps) {
8864
- if (method !== "GET") return writeJsonError(res, 405, `method ${method} not allowed on dashboard`);
9807
+ if (method !== "GET") return writeJsonError2(res, 405, `method ${method} not allowed on dashboard`);
8865
9808
  const result = await handleDashboard(deps);
8866
- return writeJson4(res, result.status, result.body);
9809
+ return writeJson5(res, result.status, result.body);
8867
9810
  }
8868
9811
  async function handlePricing(req, res, method, rest, deps) {
8869
9812
  if (rest.length === 0) {
8870
9813
  if (method === "GET") return writeResult(res, await handlePricingList(deps));
8871
9814
  if (method === "PUT") {
8872
- return writeResult(res, await handlePricingUpsert(await readJsonBody4(req), deps));
9815
+ return writeResult(res, await handlePricingUpsert(await readJsonBody5(req), deps));
8873
9816
  }
8874
9817
  if (method === "DELETE") {
8875
9818
  return writeResult(res, await handlePricingDelete(requestQuery(req), deps));
8876
9819
  }
8877
- return writeJsonError(res, 405, `method ${method} not allowed on pricing`);
9820
+ return writeJsonError2(res, 405, `method ${method} not allowed on pricing`);
8878
9821
  }
8879
9822
  if (method === "POST" && rest.length === 1 && rest[0] === "fetch-latest") {
8880
9823
  return writeResult(res, await handlePricingFetchLatest(deps));
8881
9824
  }
8882
9825
  if (method === "POST" && rest.length === 1 && rest[0] === "resolve-conflicts") {
8883
- return writeResult(res, await handlePricingResolveConflicts(await readJsonBody4(req), deps));
9826
+ return writeResult(res, await handlePricingResolveConflicts(await readJsonBody5(req), deps));
8884
9827
  }
8885
- return writeJsonError(res, 404, `unknown pricing route '${rest.join("/")}'`);
9828
+ return writeJsonError2(res, 404, `unknown pricing route '${rest.join("/")}'`);
8886
9829
  }
8887
9830
  function migrationDeps(deps) {
8888
9831
  return {
@@ -8893,16 +9836,16 @@ function migrationDeps(deps) {
8893
9836
  };
8894
9837
  }
8895
9838
  async function handleMigrationExport(req, res, method, deps) {
8896
- if (method !== "POST") return writeJsonError(res, 405, `method ${method} not allowed on export`);
8897
- const body = await readJsonBody4(req);
9839
+ if (method !== "POST") return writeJsonError2(res, 405, `method ${method} not allowed on export`);
9840
+ const body = await readJsonBody5(req);
8898
9841
  const result = await handleExport(body, migrationDeps(deps));
8899
- return writeJson4(res, result.status, result.body);
9842
+ return writeJson5(res, result.status, result.body);
8900
9843
  }
8901
9844
  async function handleMigrationImport(req, res, method, deps) {
8902
- if (method !== "POST") return writeJsonError(res, 405, `method ${method} not allowed on import`);
8903
- const body = await readJsonBody4(req);
9845
+ if (method !== "POST") return writeJsonError2(res, 405, `method ${method} not allowed on import`);
9846
+ const body = await readJsonBody5(req);
8904
9847
  const result = await handleImport(body, migrationDeps(deps));
8905
- return writeJson4(res, result.status, result.body);
9848
+ return writeJson5(res, result.status, result.body);
8906
9849
  }
8907
9850
  async function handleProviders(req, res, method, rest, deps) {
8908
9851
  const cfg = loadConfig(deps.configPath);
@@ -8935,52 +9878,52 @@ async function handleProviders(req, res, method, rest, deps) {
8935
9878
  }
8936
9879
  if (method === "GET" && rest.length === 2 && rest[1] === "reveal-key") {
8937
9880
  const row = cfg.providers.find((p) => p.id === rest[0]);
8938
- if (!row) return writeJsonError(res, 404, `provider '${rest[0]}' not found`);
8939
- return writeJson4(res, 200, { apiKey: row.apiKey ?? "" });
9881
+ if (!row) return writeJsonError2(res, 404, `provider '${rest[0]}' not found`);
9882
+ return writeJson5(res, 200, { apiKey: row.apiKey ?? "" });
8940
9883
  }
8941
9884
  if (method === "GET") {
8942
- return writeJson4(res, 200, { providers: cfg.providers.map(toProviderView) });
9885
+ return writeJson5(res, 200, { providers: cfg.providers.map(toProviderView) });
8943
9886
  }
8944
9887
  if (method === "POST") {
8945
- const body = await readJsonBody4(req);
9888
+ const body = await readJsonBody5(req);
8946
9889
  const provider = parseProviderInput(body, void 0);
8947
- if (!provider) return writeJsonError(res, 400, "invalid provider (id, apiFormat, baseUrl required)");
9890
+ if (!provider) return writeJsonError2(res, 400, "invalid provider (id, apiFormat, baseUrl required)");
8948
9891
  if (cfg.providers.some((p) => p.id === provider.id)) {
8949
- return writeJsonError(res, 409, `provider '${provider.id}' already exists`);
9892
+ return writeJsonError2(res, 409, `provider '${provider.id}' already exists`);
8950
9893
  }
8951
9894
  cfg.providers.push(provider);
8952
9895
  persistProviders(cfg, deps);
8953
- return writeJson4(res, 201, { provider: toProviderView(provider) });
9896
+ return writeJson5(res, 201, { provider: toProviderView(provider) });
8954
9897
  }
8955
9898
  const id = rest[0];
8956
- if (!id) return writeJsonError(res, 400, "provider id required in path");
9899
+ if (!id) return writeJsonError2(res, 400, "provider id required in path");
8957
9900
  const idx = cfg.providers.findIndex((p) => p.id === id);
8958
- if (idx < 0) return writeJsonError(res, 404, `provider '${id}' not found`);
9901
+ if (idx < 0) return writeJsonError2(res, 404, `provider '${id}' not found`);
8959
9902
  if (method === "PUT") {
8960
- const body = await readJsonBody4(req);
9903
+ const body = await readJsonBody5(req);
8961
9904
  const existing = cfg.providers[idx];
8962
9905
  const updated = parseProviderInput(body, existing);
8963
- if (!updated) return writeJsonError(res, 400, "invalid provider (apiFormat, baseUrl required)");
9906
+ if (!updated) return writeJsonError2(res, 400, "invalid provider (apiFormat, baseUrl required)");
8964
9907
  cfg.providers[idx] = updated;
8965
9908
  persistProviders(cfg, deps);
8966
- return writeJson4(res, 200, { provider: toProviderView(updated) });
9909
+ return writeJson5(res, 200, { provider: toProviderView(updated) });
8967
9910
  }
8968
9911
  if (method === "DELETE") {
8969
9912
  cfg.providers.splice(idx, 1);
8970
9913
  persistProviders(cfg, deps);
8971
- return writeJson4(res, 200, { ok: true });
9914
+ return writeJson5(res, 200, { ok: true });
8972
9915
  }
8973
- return writeJsonError(res, 405, `method ${method} not allowed on providers`);
9916
+ return writeJsonError2(res, 405, `method ${method} not allowed on providers`);
8974
9917
  }
8975
9918
  function persistProviders(cfg, deps) {
8976
9919
  saveConfig(deps.configPath, cfg);
8977
9920
  deps.llmConfig.reload(cfg);
8978
9921
  }
8979
9922
  async function handleProviderReorder(req, res, cfg, deps) {
8980
- const body = await readJsonBody4(req);
9923
+ const body = await readJsonBody5(req);
8981
9924
  const rawOrder = body["order"];
8982
9925
  if (!Array.isArray(rawOrder)) {
8983
- return writeJsonError(res, 400, "reorder requires { order: string[] }");
9926
+ return writeJsonError2(res, 400, "reorder requires { order: string[] }");
8984
9927
  }
8985
9928
  const order = rawOrder.filter((x) => typeof x === "string");
8986
9929
  const byId = new Map(cfg.providers.map((p) => [p.id, p]));
@@ -9001,17 +9944,17 @@ async function handleProviderReorder(req, res, cfg, deps) {
9001
9944
  }
9002
9945
  cfg.providers = reordered;
9003
9946
  persistProviders(cfg, deps);
9004
- return writeJson4(res, 200, { ok: true, providers: cfg.providers.map(toProviderView) });
9947
+ return writeJson5(res, 200, { ok: true, providers: cfg.providers.map(toProviderView) });
9005
9948
  }
9006
9949
  function expandRowExtraHeaders(row) {
9007
9950
  return mergeExtraHeaders({}, row.extraHeaders);
9008
9951
  }
9009
9952
  async function handleDiscoverModels(res, id, cfg) {
9010
- if (!id) return writeJsonError(res, 400, "provider id required in path");
9953
+ if (!id) return writeJsonError2(res, 400, "provider id required in path");
9011
9954
  const row = cfg.providers.find((p) => p.id === id);
9012
- if (!row) return writeJsonError(res, 404, `provider '${id}' not found`);
9955
+ if (!row) return writeJsonError2(res, 404, `provider '${id}' not found`);
9013
9956
  if (row.apiFormat !== "openai" && row.apiFormat !== "openai-response") {
9014
- return writeJson4(res, 200, { models: [], unsupportedFormat: true });
9957
+ return writeJson5(res, 200, { models: [], unsupportedFormat: true });
9015
9958
  }
9016
9959
  const resolvedKey = resolveEnvKey(row.apiKey);
9017
9960
  const base = row.baseUrl.replace(/\/+$/, "");
@@ -9020,6 +9963,7 @@ async function handleDiscoverModels(res, id, cfg) {
9020
9963
  const headers = { Accept: "application/json" };
9021
9964
  if (resolvedKey) headers["Authorization"] = `Bearer ${resolvedKey}`;
9022
9965
  Object.assign(headers, expandRowExtraHeaders(row));
9966
+ applyAdminProbeIdentity(headers, row);
9023
9967
  const response = await fetchUpstream10(url, { method: "GET", headers }, { providerId: "byo" });
9024
9968
  if (!response.ok) {
9025
9969
  const text = await response.text().catch(() => "");
@@ -9029,32 +9973,32 @@ async function handleDiscoverModels(res, id, cfg) {
9029
9973
  message = parsed?.error?.message || parsed?.message || message;
9030
9974
  } catch {
9031
9975
  }
9032
- return writeJson4(res, 200, {
9976
+ return writeJson5(res, 200, {
9033
9977
  models: [],
9034
9978
  error: `discovery failed (${response.status})${message ? `: ${message}` : ""}`
9035
9979
  });
9036
9980
  }
9037
9981
  const data = await response.json();
9038
9982
  const models = Array.isArray(data?.data) ? data.data.map((m) => typeof m?.id === "string" ? m.id : "").filter((m) => m.length > 0) : [];
9039
- return writeJson4(res, 200, { models });
9983
+ return writeJson5(res, 200, { models });
9040
9984
  } catch (err9) {
9041
9985
  const message = err9 instanceof Error ? err9.message : String(err9);
9042
- return writeJson4(res, 200, { models: [], error: `discovery failed: ${message}` });
9986
+ return writeJson5(res, 200, { models: [], error: `discovery failed: ${message}` });
9043
9987
  }
9044
9988
  }
9045
9989
  async function handleTestModel(req, res, id, cfg) {
9046
- if (!id) return writeJsonError(res, 400, "provider id required in path");
9990
+ if (!id) return writeJsonError2(res, 400, "provider id required in path");
9047
9991
  const row = cfg.providers.find((p) => p.id === id);
9048
- if (!row) return writeJsonError(res, 404, `provider '${id}' not found`);
9049
- const body = await readJsonBody4(req);
9992
+ if (!row) return writeJsonError2(res, 404, `provider '${id}' not found`);
9993
+ const body = await readJsonBody5(req);
9050
9994
  const model = typeof body["model"] === "string" ? body["model"].trim() : "";
9051
- if (!model) return writeJsonError(res, 400, "test requires a { model } string");
9995
+ if (!model) return writeJsonError2(res, 400, "test requires a { model } string");
9052
9996
  if (row.apiFormat === "gemini") {
9053
- return writeJson4(res, 200, { ok: false, unsupportedFormat: true });
9997
+ return writeJson5(res, 200, { ok: false, unsupportedFormat: true });
9054
9998
  }
9055
9999
  const resolvedKey = resolveEnvKey(row.apiKey);
9056
10000
  if (!resolvedKey) {
9057
- return writeJson4(res, 200, { ok: false, message: "no API key configured for this provider" });
10001
+ return writeJson5(res, 200, { ok: false, message: "no API key configured for this provider" });
9058
10002
  }
9059
10003
  let url = row.baseUrl.replace(/\/+$/, "");
9060
10004
  const prompt = "Reply with the single word: OK.";
@@ -9078,6 +10022,7 @@ async function handleTestModel(req, res, id, cfg) {
9078
10022
  };
9079
10023
  }
9080
10024
  Object.assign(headers, expandRowExtraHeaders(row));
10025
+ applyAdminProbeIdentity(headers, row);
9081
10026
  const startedAt = Date.now();
9082
10027
  try {
9083
10028
  const response = await fetchUpstream10(
@@ -9094,9 +10039,9 @@ async function handleTestModel(req, res, id, cfg) {
9094
10039
  message = parsed?.error?.message || parsed?.message || message;
9095
10040
  } catch {
9096
10041
  }
9097
- return writeJson4(res, 200, { ok: false, status: response.status, latencyMs, message });
10042
+ return writeJson5(res, 200, { ok: false, status: response.status, latencyMs, message });
9098
10043
  }
9099
- return writeJson4(res, 200, {
10044
+ return writeJson5(res, 200, {
9100
10045
  ok: true,
9101
10046
  status: response.status,
9102
10047
  latencyMs,
@@ -9104,7 +10049,7 @@ async function handleTestModel(req, res, id, cfg) {
9104
10049
  });
9105
10050
  } catch (err9) {
9106
10051
  const message = err9 instanceof Error ? err9.message : String(err9);
9107
- return writeJson4(res, 200, { ok: false, latencyMs: Date.now() - startedAt, message });
10052
+ return writeJson5(res, 200, { ok: false, latencyMs: Date.now() - startedAt, message });
9108
10053
  }
9109
10054
  }
9110
10055
  function extractSampleText(text, apiFormat) {
@@ -9141,9 +10086,9 @@ function toPoolKeyView(row, cooldown, deps) {
9141
10086
  });
9142
10087
  }
9143
10088
  async function handleProviderKeys(res, id, cfg, deps) {
9144
- if (!id) return writeJsonError(res, 400, "provider id required in path");
10089
+ if (!id) return writeJsonError2(res, 400, "provider id required in path");
9145
10090
  const row = cfg.providers.find((p) => p.id === id);
9146
- if (!row) return writeJsonError(res, 404, `provider '${id}' not found`);
10091
+ if (!row) return writeJsonError2(res, 404, `provider '${id}' not found`);
9147
10092
  const cooldown = await deps.apiKeyPool.getKeyHealth(id);
9148
10093
  const views = toPoolKeyView(row, cooldown, deps);
9149
10094
  if (deps.providerKeyQuota) {
@@ -9155,19 +10100,19 @@ async function handleProviderKeys(res, id, cfg, deps) {
9155
10100
  if (settled.status === "fulfilled" && settled.value) view.quota = settled.value;
9156
10101
  });
9157
10102
  }
9158
- return writeJson4(res, 200, { keys: views });
10103
+ return writeJson5(res, 200, { keys: views });
9159
10104
  }
9160
10105
  async function handleProviderKeyQuotaRefresh(res, id, keyId, cfg, deps) {
9161
- if (!deps.providerKeyQuota) return writeJsonError(res, 501, "provider key quota is not available");
9162
- if (!id || !keyId) return writeJsonError(res, 400, "provider id and key id required in path");
10106
+ if (!deps.providerKeyQuota) return writeJsonError2(res, 501, "provider key quota is not available");
10107
+ if (!id || !keyId) return writeJsonError2(res, 400, "provider id and key id required in path");
9163
10108
  const row = cfg.providers.find((p) => p.id === id);
9164
- if (!row) return writeJsonError(res, 404, `provider '${id}' not found`);
10109
+ if (!row) return writeJsonError2(res, 404, `provider '${id}' not found`);
9165
10110
  try {
9166
10111
  const quota = await deps.providerKeyQuota.quotaFor(row, keyId, { force: true });
9167
- if (!quota) return writeJsonError(res, 404, `no quota endpoint for key '${keyId}'`);
9168
- return writeJson4(res, 200, { quota });
10112
+ if (!quota) return writeJsonError2(res, 404, `no quota endpoint for key '${keyId}'`);
10113
+ return writeJson5(res, 200, { quota });
9169
10114
  } catch {
9170
- return writeJsonError(res, 502, "quota refresh failed");
10115
+ return writeJsonError2(res, 502, "quota refresh failed");
9171
10116
  }
9172
10117
  }
9173
10118
  function parsePoolKeyInput(body, existing) {
@@ -9184,12 +10129,12 @@ function parsePoolKeyInput(body, existing) {
9184
10129
  return out;
9185
10130
  }
9186
10131
  async function handleAddProviderKey(req, res, id, cfg, deps) {
9187
- if (!id) return writeJsonError(res, 400, "provider id required in path");
10132
+ if (!id) return writeJsonError2(res, 400, "provider id required in path");
9188
10133
  const idx = cfg.providers.findIndex((p) => p.id === id);
9189
- if (idx < 0) return writeJsonError(res, 404, `provider '${id}' not found`);
9190
- const body = await readJsonBody4(req);
10134
+ if (idx < 0) return writeJsonError2(res, 404, `provider '${id}' not found`);
10135
+ const body = await readJsonBody5(req);
9191
10136
  const parsed = parsePoolKeyInput(body);
9192
- if (!parsed.apiKey) return writeJsonError(res, 400, "add requires a non-empty apiKey");
10137
+ if (!parsed.apiKey) return writeJsonError2(res, 400, "add requires a non-empty apiKey");
9193
10138
  const keyId = `key-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
9194
10139
  const entry = { id: keyId, apiKey: parsed.apiKey };
9195
10140
  if (parsed.label !== void 0) entry.label = parsed.label;
@@ -9199,17 +10144,17 @@ async function handleAddProviderKey(req, res, id, cfg, deps) {
9199
10144
  row.apiKeys = [...row.apiKeys ?? [], entry];
9200
10145
  persistProviders(cfg, deps);
9201
10146
  const cooldown = await deps.apiKeyPool.getKeyHealth(id);
9202
- return writeJson4(res, 201, { keys: toPoolKeyView(row, cooldown, deps) });
10147
+ return writeJson5(res, 201, { keys: toPoolKeyView(row, cooldown, deps) });
9203
10148
  }
9204
10149
  async function handleUpdateProviderKey(req, res, id, keyId, cfg, deps) {
9205
- if (!id) return writeJsonError(res, 400, "provider id required in path");
9206
- if (!keyId) return writeJsonError(res, 400, "key id required in path");
10150
+ if (!id) return writeJsonError2(res, 400, "provider id required in path");
10151
+ if (!keyId) return writeJsonError2(res, 400, "key id required in path");
9207
10152
  const idx = cfg.providers.findIndex((p) => p.id === id);
9208
- if (idx < 0) return writeJsonError(res, 404, `provider '${id}' not found`);
10153
+ if (idx < 0) return writeJsonError2(res, 404, `provider '${id}' not found`);
9209
10154
  const row = cfg.providers[idx];
9210
10155
  const keyIdx = (row.apiKeys ?? []).findIndex((k) => k.id === keyId);
9211
- if (keyIdx < 0) return writeJsonError(res, 404, `pool key '${keyId}' not found`);
9212
- const body = await readJsonBody4(req);
10156
+ if (keyIdx < 0) return writeJsonError2(res, 404, `pool key '${keyId}' not found`);
10157
+ const body = await readJsonBody5(req);
9213
10158
  const existing = row.apiKeys[keyIdx];
9214
10159
  const parsed = parsePoolKeyInput(body, existing);
9215
10160
  const entry = { id: keyId, apiKey: parsed.apiKey || existing.apiKey };
@@ -9219,35 +10164,35 @@ async function handleUpdateProviderKey(req, res, id, keyId, cfg, deps) {
9219
10164
  row.apiKeys[keyIdx] = entry;
9220
10165
  persistProviders(cfg, deps);
9221
10166
  const cooldown = await deps.apiKeyPool.getKeyHealth(id);
9222
- return writeJson4(res, 200, { keys: toPoolKeyView(row, cooldown, deps) });
10167
+ return writeJson5(res, 200, { keys: toPoolKeyView(row, cooldown, deps) });
9223
10168
  }
9224
10169
  async function handleDeleteProviderKey(res, id, keyId, cfg, deps) {
9225
- if (!id) return writeJsonError(res, 400, "provider id required in path");
9226
- if (!keyId) return writeJsonError(res, 400, "key id required in path");
10170
+ if (!id) return writeJsonError2(res, 400, "provider id required in path");
10171
+ if (!keyId) return writeJsonError2(res, 400, "key id required in path");
9227
10172
  const idx = cfg.providers.findIndex((p) => p.id === id);
9228
- if (idx < 0) return writeJsonError(res, 404, `provider '${id}' not found`);
10173
+ if (idx < 0) return writeJsonError2(res, 404, `provider '${id}' not found`);
9229
10174
  const row = cfg.providers[idx];
9230
10175
  const keyIdx = (row.apiKeys ?? []).findIndex((k) => k.id === keyId);
9231
- if (keyIdx < 0) return writeJsonError(res, 404, `pool key '${keyId}' not found`);
10176
+ if (keyIdx < 0) return writeJsonError2(res, 404, `pool key '${keyId}' not found`);
9232
10177
  row.apiKeys.splice(keyIdx, 1);
9233
10178
  if (row.apiKeys.length === 0) row.apiKeys = void 0;
9234
10179
  persistProviders(cfg, deps);
9235
10180
  const cooldown = await deps.apiKeyPool.getKeyHealth(id);
9236
- return writeJson4(res, 200, { keys: toPoolKeyView(row, cooldown, deps) });
10181
+ return writeJson5(res, 200, { keys: toPoolKeyView(row, cooldown, deps) });
9237
10182
  }
9238
10183
  async function handleToggleProviderKey(req, res, id, keyId, cfg, deps) {
9239
- if (!id) return writeJsonError(res, 400, "provider id required in path");
9240
- if (!keyId) return writeJsonError(res, 400, "key id required in path");
10184
+ if (!id) return writeJsonError2(res, 400, "provider id required in path");
10185
+ if (!keyId) return writeJsonError2(res, 400, "key id required in path");
9241
10186
  const idx = cfg.providers.findIndex((p) => p.id === id);
9242
- if (idx < 0) return writeJsonError(res, 404, `provider '${id}' not found`);
10187
+ if (idx < 0) return writeJsonError2(res, 404, `provider '${id}' not found`);
9243
10188
  const row = cfg.providers[idx];
9244
10189
  const keyIdx = (row.apiKeys ?? []).findIndex((k) => k.id === keyId);
9245
- if (keyIdx < 0) return writeJsonError(res, 404, `pool key '${keyId}' not found`);
9246
- const body = await readJsonBody4(req);
10190
+ if (keyIdx < 0) return writeJsonError2(res, 404, `pool key '${keyId}' not found`);
10191
+ const body = await readJsonBody5(req);
9247
10192
  row.apiKeys[keyIdx].enabled = Boolean(body["enabled"]);
9248
10193
  persistProviders(cfg, deps);
9249
10194
  const cooldown = await deps.apiKeyPool.getKeyHealth(id);
9250
- return writeJson4(res, 200, { keys: toPoolKeyView(row, cooldown, deps) });
10195
+ return writeJson5(res, 200, { keys: toPoolKeyView(row, cooldown, deps) });
9251
10196
  }
9252
10197
  function parseApiKeysInput(raw, existing) {
9253
10198
  if (!Array.isArray(raw)) return existing;
@@ -9419,7 +10364,7 @@ function parseProviderInput(body, existing) {
9419
10364
  };
9420
10365
  }
9421
10366
  function handlePresets(res, method) {
9422
- if (method !== "GET") return writeJsonError(res, 405, `method ${method} not allowed on presets`);
10367
+ if (method !== "GET") return writeJsonError2(res, 405, `method ${method} not allowed on presets`);
9423
10368
  const { mappable, excluded } = listMappablePresets();
9424
10369
  const presets = mappable.map((p) => ({
9425
10370
  id: p.id,
@@ -9438,13 +10383,13 @@ function handlePresets(res, method) {
9438
10383
  // row (the write gateway re-validates via the shared allowlist).
9439
10384
  extraHeaders: p.extraHeaders
9440
10385
  }));
9441
- return writeJson4(res, 200, { presets, excluded });
10386
+ return writeJson5(res, 200, { presets, excluded });
9442
10387
  }
9443
10388
  async function handleKeys(req, res, method, rest, deps) {
9444
10389
  if (method === "GET" && rest.length === 0) {
9445
10390
  const rows = await deps.keyDb.outboundApiKeysList();
9446
10391
  const reader = deps.keySpendReader;
9447
- if (!reader) return writeJson4(res, 200, { keys: rows.map(toKeyInfo) });
10392
+ if (!reader) return writeJson5(res, 200, { keys: rows.map(toKeyInfo) });
9448
10393
  const now = Date.now();
9449
10394
  const keys = await Promise.all(
9450
10395
  rows.map(async (row) => {
@@ -9456,13 +10401,13 @@ async function handleKeys(req, res, method, rest, deps) {
9456
10401
  return info;
9457
10402
  })
9458
10403
  );
9459
- return writeJson4(res, 200, { keys });
10404
+ return writeJson5(res, 200, { keys });
9460
10405
  }
9461
10406
  if (method === "POST" && rest.length === 0) {
9462
- const body = await readJsonBody4(req);
10407
+ const body = await readJsonBody5(req);
9463
10408
  const name = typeof body["name"] === "string" && body["name"].trim() ? body["name"].trim() : "key";
9464
10409
  const created = await createNamedKey(deps.keyDb, name);
9465
- return writeJson4(res, 201, {
10410
+ return writeJson5(res, 201, {
9466
10411
  id: created.id,
9467
10412
  name: created.name,
9468
10413
  keyPrefix: created.keyPrefix,
@@ -9473,10 +10418,10 @@ async function handleKeys(req, res, method, rest, deps) {
9473
10418
  }
9474
10419
  if (method === "GET" && rest.length === 2 && rest[1] === "reveal") {
9475
10420
  const revealed = await deps.keyDb.outboundApiKeysReveal(rest[0]);
9476
- if (revealed !== null) return writeJson4(res, 200, { key: revealed });
10421
+ if (revealed !== null) return writeJson5(res, 200, { key: revealed });
9477
10422
  const exists = (await deps.keyDb.outboundApiKeysList()).some((r) => r.id === rest[0]);
9478
- if (!exists) return writeJsonError(res, 404, `key '${rest[0]}' not found`);
9479
- return writeJsonError(
10423
+ if (!exists) return writeJsonError2(res, 404, `key '${rest[0]}' not found`);
10424
+ return writeJsonError2(
9480
10425
  res,
9481
10426
  409,
9482
10427
  `key '${rest[0]}' is not revealable (created before revealable key storage)`
@@ -9486,55 +10431,55 @@ async function handleKeys(req, res, method, rest, deps) {
9486
10431
  const action = rest[1];
9487
10432
  if (method === "POST" && id && action === "revoke") {
9488
10433
  const bound = await integrationKeyRequirement(deps, id);
9489
- if (bound) return writeJsonError(res, 409, bound);
10434
+ if (bound) return writeJsonError2(res, 409, bound);
9490
10435
  const ok = await deps.keyDb.outboundApiKeysRevoke(id);
9491
- return writeJson4(res, ok ? 200 : 404, { ok });
10436
+ return writeJson5(res, ok ? 200 : 404, { ok });
9492
10437
  }
9493
10438
  if (method === "DELETE" && id && !action) {
9494
10439
  const bound = await integrationKeyRequirement(deps, id);
9495
- if (bound) return writeJsonError(res, 409, bound);
10440
+ if (bound) return writeJsonError2(res, 409, bound);
9496
10441
  const ok = await deps.keyDb.outboundApiKeysDelete(id);
9497
- return writeJson4(res, ok ? 200 : 404, { ok });
10442
+ return writeJson5(res, ok ? 200 : 404, { ok });
9498
10443
  }
9499
10444
  if (method === "POST" && id && action === "enabled") {
9500
- const body = await readJsonBody4(req);
10445
+ const body = await readJsonBody5(req);
9501
10446
  const enabled = body["enabled"] === true;
9502
10447
  if (!enabled) {
9503
10448
  const bound = await integrationKeyRequirement(deps, id);
9504
- if (bound) return writeJsonError(res, 409, bound);
10449
+ if (bound) return writeJsonError2(res, 409, bound);
9505
10450
  }
9506
10451
  const ok = await deps.keyDb.outboundApiKeysSetEnabled(id, enabled);
9507
- return writeJson4(res, ok ? 200 : 404, { ok, enabled });
10452
+ return writeJson5(res, ok ? 200 : 404, { ok, enabled });
9508
10453
  }
9509
10454
  if (method === "POST" && id && action === "permissions") {
9510
- const body = await readJsonBody4(req);
10455
+ const body = await readJsonBody5(req);
9511
10456
  if (Object.keys(body).length !== 1 || !Object.prototype.hasOwnProperty.call(body, "permissions")) {
9512
- return writeJsonError(res, 400, "body must contain only permissions");
10457
+ return writeJsonError2(res, 400, "body must contain only permissions");
9513
10458
  }
9514
10459
  let permissions;
9515
10460
  try {
9516
10461
  permissions = validateOutboundPermissions(body["permissions"]);
9517
10462
  } catch {
9518
- return writeJsonError(
10463
+ return writeJsonError2(
9519
10464
  res,
9520
10465
  400,
9521
10466
  "permissions must be an array of unique chat, responses, messages, gemini, or images values"
9522
10467
  );
9523
10468
  }
9524
10469
  const before = (await deps.keyDb.outboundApiKeysList()).find((row) => row.id === id);
9525
- if (!before) return writeJson4(res, 404, { ok: false });
9526
- if (before.revokedAt !== null) return writeJson4(res, 409, { ok: false });
10470
+ if (!before) return writeJson5(res, 404, { ok: false });
10471
+ if (before.revokedAt !== null) return writeJson5(res, 409, { ok: false });
9527
10472
  const required = await integrationKeyRequirement(deps, id, permissions);
9528
- if (required) return writeJsonError(res, 409, required);
10473
+ if (required) return writeJsonError2(res, 409, required);
9529
10474
  const ok = await deps.keyDb.outboundApiKeysSetPermissions(id, permissions);
9530
10475
  if (!ok) {
9531
10476
  const current = (await deps.keyDb.outboundApiKeysList()).find((row) => row.id === id);
9532
- return writeJson4(res, current?.revokedAt !== null ? 409 : 404, { ok: false });
10477
+ return writeJson5(res, current?.revokedAt !== null ? 409 : 404, { ok: false });
9533
10478
  }
9534
- return writeJson4(res, 200, { ok: true, allowedEndpoints: permissions });
10479
+ return writeJson5(res, 200, { ok: true, allowedEndpoints: permissions });
9535
10480
  }
9536
10481
  if (method === "POST" && id && action === "max-concurrency") {
9537
- const body = await readJsonBody4(req);
10482
+ const body = await readJsonBody5(req);
9538
10483
  const raw = body["maxConcurrency"];
9539
10484
  let value;
9540
10485
  if (raw === null) {
@@ -9542,23 +10487,73 @@ async function handleKeys(req, res, method, rest, deps) {
9542
10487
  } else if (typeof raw === "number" && Number.isInteger(raw) && raw >= 1 && raw <= 1e3) {
9543
10488
  value = raw;
9544
10489
  } else {
9545
- return writeJsonError(
10490
+ return writeJsonError2(
9546
10491
  res,
9547
10492
  400,
9548
10493
  "maxConcurrency must be an integer 1..1000 or null"
9549
10494
  );
9550
10495
  }
9551
10496
  const ok = await deps.keyDb.outboundApiKeysSetMaxConcurrency(id, value);
9552
- return writeJson4(res, ok ? 200 : 404, { ok, maxConcurrency: value });
10497
+ return writeJson5(res, ok ? 200 : 404, { ok, maxConcurrency: value });
10498
+ }
10499
+ if (method === "POST" && id && action === "upstream") {
10500
+ const body = await readJsonBody5(req);
10501
+ let raw;
10502
+ if (Object.prototype.hasOwnProperty.call(body, "target")) {
10503
+ raw = body["target"];
10504
+ } else if (Object.prototype.hasOwnProperty.call(body, "providerId")) {
10505
+ const legacy = body["providerId"];
10506
+ raw = legacy === null || legacy === void 0 ? null : { kind: "provider", providerId: legacy };
10507
+ } else {
10508
+ return writeJsonError2(res, 400, "body must contain target (or the legacy providerId)");
10509
+ }
10510
+ if (raw === null || raw === void 0) {
10511
+ const ok2 = await deps.keyDb.outboundApiKeysSetUpstream(id, null);
10512
+ return writeJson5(res, ok2 ? 200 : 404, { ok: ok2, target: null });
10513
+ }
10514
+ if (typeof raw !== "object" || Array.isArray(raw)) {
10515
+ return writeJsonError2(res, 400, "target must be an object or null");
10516
+ }
10517
+ const t = raw;
10518
+ const kind = t["kind"];
10519
+ const providerId = typeof t["providerId"] === "string" ? t["providerId"].trim() : "";
10520
+ if (!providerId) {
10521
+ return writeJsonError2(res, 400, "target.providerId is required");
10522
+ }
10523
+ if (kind === "provider") {
10524
+ const cfg = loadConfig(deps.configPath);
10525
+ if (!cfg.providers.some((p) => p.id === providerId)) {
10526
+ return writeJsonError2(res, 404, `provider '${providerId}' not found`);
10527
+ }
10528
+ } else if (kind === "account" || kind === "account-group" || kind === "account-pool") {
10529
+ if (providerId !== "claude" && providerId !== "kimi") {
10530
+ return writeJsonError2(
10531
+ res,
10532
+ 400,
10533
+ `subscription provider '${providerId}' cannot be direct-bound: its upstream wire differs from the client wire (translation required \u2014 use a downstream route); only claude and kimi subscriptions speak the same Anthropic Messages wire as the client`
10534
+ );
10535
+ }
10536
+ if (kind === "account" && typeof t["accountId"] !== "string") {
10537
+ return writeJsonError2(res, 400, "target.accountId is required for kind account");
10538
+ }
10539
+ if (kind === "account-group" && typeof t["group"] !== "string") {
10540
+ return writeJsonError2(res, 400, "target.group is required for kind account-group");
10541
+ }
10542
+ } else {
10543
+ return writeJsonError2(res, 400, "target.kind must be provider, account, account-group, or account-pool");
10544
+ }
10545
+ const target = raw;
10546
+ const ok = await deps.keyDb.outboundApiKeysSetUpstream(id, target);
10547
+ return writeJson5(res, ok ? 200 : 404, { ok, target });
9553
10548
  }
9554
10549
  if (method === "POST" && id && action === "policy") {
9555
- const body = await readJsonBody4(req);
10550
+ const body = await readJsonBody5(req);
9556
10551
  const parsed = parseKeyPolicyBody(body);
9557
- if (!parsed.ok) return writeJsonError(res, 400, parsed.message);
10552
+ if (!parsed.ok) return writeJsonError2(res, 400, parsed.message);
9558
10553
  const ok = await deps.keyDb.outboundApiKeysSetPolicy(id, parsed.policy);
9559
- return writeJson4(res, ok ? 200 : 404, { ok });
10554
+ return writeJson5(res, ok ? 200 : 404, { ok });
9560
10555
  }
9561
- return writeJsonError(res, 405, `method ${method} not allowed on keys`);
10556
+ return writeJsonError2(res, 405, `method ${method} not allowed on keys`);
9562
10557
  }
9563
10558
  function validateQueueSegments(patch) {
9564
10559
  const errors = [];
@@ -9722,17 +10717,17 @@ async function handleServer(req, res, method, deps) {
9722
10717
  search: redactSearchServerConfig(config.search)
9723
10718
  };
9724
10719
  }
9725
- return writeJson4(res, 200, { server: projectImagesConfigForAdmin(server) });
10720
+ return writeJson5(res, 200, { server: projectImagesConfigForAdmin(server) });
9726
10721
  }
9727
10722
  if (method === "PUT") {
9728
- const patch = await readJsonBody4(req);
10723
+ const patch = await readJsonBody5(req);
9729
10724
  const queueErrors = validateQueueSegments(patch);
9730
10725
  if (queueErrors.length > 0) {
9731
- return writeJsonError(res, 400, `invalid queue config: ${queueErrors.join("; ")}`);
10726
+ return writeJsonError2(res, 400, `invalid queue config: ${queueErrors.join("; ")}`);
9732
10727
  }
9733
10728
  const allowanceErrors = validateAllowanceSchedulingSegment(patch);
9734
10729
  if (allowanceErrors.length > 0) {
9735
- return writeJsonError(
10730
+ return writeJsonError2(
9736
10731
  res,
9737
10732
  400,
9738
10733
  `invalid allowance scheduling config: ${allowanceErrors.join("; ")}`
@@ -9740,19 +10735,19 @@ async function handleServer(req, res, method, deps) {
9740
10735
  }
9741
10736
  const bindingErrors = validateGatewayBindingsSegment(patch);
9742
10737
  if (bindingErrors.length > 0) {
9743
- return writeJsonError(res, 400, `invalid gateway bindings: ${bindingErrors.join("; ")}`);
10738
+ return writeJsonError2(res, 400, `invalid gateway bindings: ${bindingErrors.join("; ")}`);
9744
10739
  }
9745
10740
  const webhookErrors = validateWebhookSegment(patch);
9746
10741
  if (webhookErrors.length > 0) {
9747
- return writeJsonError(res, 400, `invalid webhook config: ${webhookErrors.join("; ")}`);
10742
+ return writeJsonError2(res, 400, `invalid webhook config: ${webhookErrors.join("; ")}`);
9748
10743
  }
9749
10744
  const auditErrors = validateAuditSegment(patch);
9750
10745
  if (auditErrors.length > 0) {
9751
- return writeJsonError(res, 400, `invalid audit config: ${auditErrors.join("; ")}`);
10746
+ return writeJsonError2(res, 400, `invalid audit config: ${auditErrors.join("; ")}`);
9752
10747
  }
9753
10748
  const billingErrors = validateBillingSegment(patch);
9754
10749
  if (billingErrors.length > 0) {
9755
- return writeJsonError(res, 400, `invalid billing config: ${billingErrors.join("; ")}`);
10750
+ return writeJsonError2(res, 400, `invalid billing config: ${billingErrors.join("; ")}`);
9756
10751
  }
9757
10752
  const current = await loadServerConfig3(deps.settingsStore);
9758
10753
  let effectivePatch = patch;
@@ -9771,7 +10766,7 @@ async function handleServer(req, res, method, deps) {
9771
10766
  remoteResolverAvailable: deps.imageRemoteResolverAvailable
9772
10767
  });
9773
10768
  if (imageErrors.length > 0) {
9774
- return writeJsonError(res, 400, `invalid Images config: ${imageErrors.join("; ")}`);
10769
+ return writeJsonError2(res, 400, `invalid Images config: ${imageErrors.join("; ")}`);
9775
10770
  }
9776
10771
  effectivePatch = { ...effectivePatch, images };
9777
10772
  }
@@ -9782,7 +10777,7 @@ async function handleServer(req, res, method, deps) {
9782
10777
  );
9783
10778
  const searchErrors = validateSearchServerConfig(searchPatch);
9784
10779
  if (searchErrors.length > 0) {
9785
- return writeJsonError(res, 400, `invalid search config: ${searchErrors.join("; ")}`);
10780
+ return writeJsonError2(res, 400, `invalid search config: ${searchErrors.join("; ")}`);
9786
10781
  }
9787
10782
  effectivePatch = {
9788
10783
  ...effectivePatch,
@@ -9824,7 +10819,7 @@ async function handleServer(req, res, method, deps) {
9824
10819
  });
9825
10820
  } catch (error) {
9826
10821
  if (error instanceof ServerConfigTransactionError) {
9827
- return writeJsonError(res, 500, error.message);
10822
+ return writeJsonError2(res, 500, error.message);
9828
10823
  }
9829
10824
  throw error;
9830
10825
  }
@@ -9845,24 +10840,27 @@ async function handleServer(req, res, method, deps) {
9845
10840
  ...merged,
9846
10841
  search: redactSearchServerConfig(merged.search)
9847
10842
  } : merged;
9848
- return writeJson4(res, 200, { server: projectImagesConfigForAdmin(mergedForAdmin) });
10843
+ return writeJson5(res, 200, { server: projectImagesConfigForAdmin(mergedForAdmin) });
9849
10844
  }
9850
- return writeJsonError(res, 405, `method ${method} not allowed on server`);
10845
+ return writeJsonError2(res, 405, `method ${method} not allowed on server`);
9851
10846
  }
9852
10847
  async function handleAccounts(req, res, method, rest, deps) {
9853
10848
  if (rest[0] === "route-activity" && rest.length === 1) {
9854
10849
  if (method !== "GET") {
9855
- return writeJsonError(res, 405, `method ${method} not allowed on account route activity`);
10850
+ return writeJsonError2(res, 405, `method ${method} not allowed on account route activity`);
9856
10851
  }
9857
10852
  const query2 = requestQuery(req);
9858
10853
  const parsedLimit = Number(query2.get("limit") ?? "100");
10854
+ const kindParam = query2.get("credentialKind");
10855
+ const credentialKind = kindParam === "subscription-account" || kindParam === "provider-key" ? kindParam : void 0;
9859
10856
  const records = getSharedAccountRouteActivity().list({
9860
10857
  providerId: query2.get("providerId") ?? void 0,
9861
10858
  accountId: query2.get("accountId") ?? void 0,
9862
10859
  sessionKey: query2.get("sessionKey") ?? void 0,
10860
+ credentialKind,
9863
10861
  limit: Number.isFinite(parsedLimit) ? parsedLimit : 100
9864
10862
  });
9865
- return writeJson4(res, 200, {
10863
+ return writeJson5(res, 200, {
9866
10864
  available: true,
9867
10865
  records,
9868
10866
  capacity: ACCOUNT_ROUTE_ACTIVITY_LIMIT,
@@ -9871,14 +10869,14 @@ async function handleAccounts(req, res, method, rest, deps) {
9871
10869
  }
9872
10870
  if (rest[0] === "overload-counters" && rest.length === 1) {
9873
10871
  if (method !== "GET") {
9874
- return writeJsonError(res, 405, `method ${method} not allowed on overload counters`);
10872
+ return writeJsonError2(res, 405, `method ${method} not allowed on overload counters`);
9875
10873
  }
9876
10874
  const query2 = requestQuery(req);
9877
10875
  const entries = getSharedOverloadCounter().list({
9878
10876
  providerId: query2.get("providerId") ?? void 0,
9879
10877
  accountId: query2.get("accountId") ?? void 0
9880
10878
  });
9881
- return writeJson4(res, 200, {
10879
+ return writeJson5(res, 200, {
9882
10880
  available: true,
9883
10881
  entries,
9884
10882
  collectedAt: Date.now()
@@ -9897,21 +10895,21 @@ async function handleAccounts(req, res, method, rest, deps) {
9897
10895
  const result = await handleAntigravityModelsRoute({
9898
10896
  resolveAntigravityAccessToken: deps.resolveAntigravityAccessToken ?? (async () => null)
9899
10897
  });
9900
- return writeJson4(res, result.status, result.body);
10898
+ return writeJson5(res, result.status, result.body);
9901
10899
  }
9902
10900
  if (method === "GET" && rest.length === 0) {
9903
10901
  const accounts = await deps.subscriptionAccounts.listAll();
9904
10902
  const providerAccounts = await deps.subscriptionTokenWriter.listSanitizedAccounts();
9905
10903
  const externalCli = await deps.subscriptionTokenWriter.listExternalCliAvailability();
9906
- return writeJson4(res, 200, { accounts, providerAccounts, externalCli });
10904
+ return writeJson5(res, 200, { accounts, providerAccounts, externalCli });
9907
10905
  }
9908
10906
  if (method === "POST" && rest[0] === "batch" && rest.length === 1) {
9909
- const body = await readJsonBody4(req);
10907
+ const body = await readJsonBody5(req);
9910
10908
  const parsed = validateAccountBatchBody(body);
9911
- if (!parsed) return writeJsonError(res, 400, "invalid account batch request");
10909
+ if (!parsed) return writeJsonError2(res, 400, "invalid account batch request");
9912
10910
  const result = await deps.subscriptionTokenWriter.batchManageAccounts(parsed.refs, parsed.mutation);
9913
10911
  if (!result.ok) {
9914
- return writeJsonError(
10912
+ return writeJsonError2(
9915
10913
  res,
9916
10914
  404,
9917
10915
  `account '${result.missing.accountId}' not found for provider '${result.missing.providerId}'`
@@ -9922,23 +10920,23 @@ async function handleAccounts(req, res, method, rest, deps) {
9922
10920
  deps.accountAllowanceService?.removeAccountSnapshot?.(ref.providerId, ref.accountId);
9923
10921
  }
9924
10922
  }
9925
- return writeJson4(res, 200, { ok: true, affected: result.affected });
10923
+ return writeJson5(res, 200, { ok: true, affected: result.affected });
9926
10924
  }
9927
10925
  if (method === "GET" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot" || rest[0] === "antigravity") && rest[1] === "oauth" && rest[3] === "status") {
9928
10926
  const result = rest[0] === "codex" ? handleCodexOAuthStatus(rest[2], deps) : rest[0] === "kimi" ? handleKimiOAuthStatus(rest[2], deps) : rest[0] === "grok" ? handleGrokOAuthStatus(rest[2], deps) : rest[0] === "copilot" ? handleCopilotOAuthStatus(rest[2], deps) : handleAntigravityOAuthStatus(rest[2], deps);
9929
- return writeJson4(res, result.status, result.body);
10927
+ return writeJson5(res, result.status, result.body);
9930
10928
  }
9931
10929
  if (method === "DELETE" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot" || rest[0] === "antigravity") && rest[1] === "oauth" && rest[2]) {
9932
10930
  const result = rest[0] === "codex" ? handleCodexOAuthCancel(rest[2], deps) : rest[0] === "kimi" ? handleKimiOAuthCancel(rest[2], deps) : rest[0] === "grok" ? handleGrokOAuthCancel(rest[2], deps) : rest[0] === "copilot" ? handleCopilotOAuthCancel(rest[2], deps) : handleAntigravityOAuthCancel(rest[2], deps);
9933
- return writeJson4(res, result.status, result.body);
10931
+ return writeJson5(res, result.status, result.body);
9934
10932
  }
9935
10933
  if (method === "GET" && rest.length === 3 && rest[2] === "diagnostics") {
9936
10934
  const providerId = asSubscriptionProviderId(rest[0]);
9937
- if (!providerId) return writeJsonError(res, 400, `unknown subscription provider '${rest[0] ?? ""}'`);
10935
+ if (!providerId) return writeJsonError2(res, 400, `unknown subscription provider '${rest[0] ?? ""}'`);
9938
10936
  const accountId = rest[1];
9939
10937
  const listed = await deps.subscriptionTokenWriter.listSanitizedAccounts();
9940
10938
  if (!(listed[providerId] ?? []).some((account) => account.id === accountId)) {
9941
- return writeJsonError(res, 404, `account '${accountId}' not found`);
10939
+ return writeJsonError2(res, 404, `account '${accountId}' not found`);
9942
10940
  }
9943
10941
  const health2 = getSharedAccountHealth().getDiagnostics({ providerId, accountId });
9944
10942
  const allowance = deps.accountAllowanceService?.getSchedulingStatus?.()?.history.filter((entry) => entry.providerId === providerId && entry.accountId === accountId).map((entry) => ({
@@ -9952,88 +10950,88 @@ async function handleAccounts(req, res, method, rest, deps) {
9952
10950
  resumeAt: entry.resumeAt
9953
10951
  })) ?? [];
9954
10952
  const diagnostics = [...health2, ...allowance].sort((left, right) => right.at - left.at).slice(0, 200);
9955
- return writeJson4(res, 200, { diagnostics });
10953
+ return writeJson5(res, 200, { diagnostics });
9956
10954
  }
9957
10955
  if (method === "GET" && rest.length === 3 && rest[2] === "events") {
9958
10956
  const providerId = asSubscriptionProviderId(rest[0]);
9959
- if (!providerId) return writeJsonError(res, 400, `unknown subscription provider '${rest[0] ?? ""}'`);
10957
+ if (!providerId) return writeJsonError2(res, 400, `unknown subscription provider '${rest[0] ?? ""}'`);
9960
10958
  const accountId = rest[1];
9961
10959
  const listed = await deps.subscriptionTokenWriter.listSanitizedAccounts();
9962
10960
  if (!(listed[providerId] ?? []).some((account) => account.id === accountId)) {
9963
- return writeJsonError(res, 404, `account '${accountId}' not found`);
10961
+ return writeJsonError2(res, 404, `account '${accountId}' not found`);
9964
10962
  }
9965
10963
  const snapshot = deps.accountProbeService?.getAllHistory().find((entry) => entry.providerId === providerId && entry.accountId === accountId);
9966
10964
  const diagnostics = getSharedAccountHealth().getDiagnostics({ providerId, accountId });
9967
- return writeJson4(res, 200, { events: snapshot?.records ?? [], diagnostics });
10965
+ return writeJson5(res, 200, { events: snapshot?.records ?? [], diagnostics });
9968
10966
  }
9969
10967
  if (method === "PATCH" && rest.length === 2) {
9970
10968
  const providerId = asSubscriptionProviderId(rest[0]);
9971
- if (!providerId) return writeJsonError(res, 400, `unknown subscription provider '${rest[0] ?? ""}'`);
9972
- const body = await readJsonBody4(req);
10969
+ if (!providerId) return writeJsonError2(res, 400, `unknown subscription provider '${rest[0] ?? ""}'`);
10970
+ const body = await readJsonBody5(req);
9973
10971
  const patch = validateAccountMetadataPatch(body);
9974
- if (!patch) return writeJsonError(res, 400, "invalid account metadata patch");
10972
+ if (!patch) return writeJsonError2(res, 400, "invalid account metadata patch");
9975
10973
  const result = await deps.subscriptionTokenWriter.patchAccountMetadata(providerId, rest[1], patch);
9976
- if (!result.ok) return writeJsonError(res, 404, `account '${rest[1]}' not found`);
9977
- return writeJson4(res, 200, { ok: true });
10974
+ if (!result.ok) return writeJsonError2(res, 404, `account '${rest[1]}' not found`);
10975
+ return writeJson5(res, 200, { ok: true });
9978
10976
  }
9979
10977
  if (method === "PUT" || method === "POST" || method === "DELETE") {
9980
10978
  const providerId = asSubscriptionProviderId(rest[0]);
9981
10979
  if (!providerId) {
9982
- return writeJsonError(res, 400, `unknown subscription provider '${rest[0] ?? ""}'`);
10980
+ return writeJsonError2(res, 400, `unknown subscription provider '${rest[0] ?? ""}'`);
9983
10981
  }
9984
10982
  if (method === "POST" && rest[1] === "oauth" && rest[2] === "start") {
9985
10983
  if (providerId === "codex") {
9986
10984
  const result2 = handleCodexOAuthStart(deps);
9987
- return writeJson4(res, result2.status, result2.body);
10985
+ return writeJson5(res, result2.status, result2.body);
9988
10986
  }
9989
10987
  if (providerId === "kimi") {
9990
10988
  const result2 = await handleKimiOAuthStart(deps);
9991
- return writeJson4(res, result2.status, result2.body);
10989
+ return writeJson5(res, result2.status, result2.body);
9992
10990
  }
9993
10991
  if (providerId === "grok") {
9994
10992
  const result2 = await handleGrokOAuthStart(deps);
9995
- return writeJson4(res, result2.status, result2.body);
10993
+ return writeJson5(res, result2.status, result2.body);
9996
10994
  }
9997
10995
  if (providerId === "copilot") {
9998
- const body2 = await readJsonBody4(req);
10996
+ const body2 = await readJsonBody5(req);
9999
10997
  const result2 = await handleCopilotOAuthStart(deps, body2["enterpriseUrl"]);
10000
- return writeJson4(res, result2.status, result2.body);
10998
+ return writeJson5(res, result2.status, result2.body);
10001
10999
  }
10002
11000
  if (providerId === "antigravity") {
10003
11001
  const result2 = handleAntigravityOAuthStart(deps);
10004
- return writeJson4(res, result2.status, result2.body);
11002
+ return writeJson5(res, result2.status, result2.body);
10005
11003
  }
10006
11004
  const result = handleOAuthStart(providerId, deps);
10007
- return writeJson4(res, result.status, result.body);
11005
+ return writeJson5(res, result.status, result.body);
10008
11006
  }
10009
11007
  if (method === "POST" && rest[1] === "oauth" && rest[2] === "complete") {
10010
- const body2 = await readJsonBody4(req);
11008
+ const body2 = await readJsonBody5(req);
10011
11009
  const result = await handleOAuthComplete(providerId, body2, deps);
10012
- return writeJson4(res, result.status, result.body);
11010
+ return writeJson5(res, result.status, result.body);
10013
11011
  }
10014
11012
  if (method === "POST" && rest[1] === "accounts") {
10015
- const body2 = await readJsonBody4(req);
11013
+ const body2 = await readJsonBody5(req);
10016
11014
  const block = validateTokenBody(providerId, body2);
10017
11015
  if (!block) {
10018
- return writeJsonError(res, 400, `malformed token body for provider '${providerId}'`);
11016
+ return writeJsonError2(res, 400, `malformed token body for provider '${providerId}'`);
10019
11017
  }
10020
11018
  const label = typeof body2["label"] === "string" && body2["label"].trim() ? body2["label"].trim() : void 0;
10021
11019
  await deps.subscriptionAccountAppender.appendProviderAccount(providerId, block, label);
10022
11020
  const status2 = await statusEntryFor(deps.subscriptionAccounts, providerId);
10023
- return writeJson4(res, 200, status2 ? { account: status2 } : { ok: true });
11021
+ return writeJson5(res, 200, status2 ? { account: status2 } : { ok: true });
10024
11022
  }
10025
11023
  if (method === "POST" && rest[1] === "import-external") {
10026
11024
  if (providerId !== "claude" && providerId !== "codex") {
10027
- return writeJsonError(res, 400, `provider '${providerId}' has no external CLI store`);
11025
+ return writeJsonError2(res, 400, `provider '${providerId}' has no external CLI store`);
10028
11026
  }
10029
- const body2 = await readJsonBody4(req);
11027
+ const body2 = await readJsonBody5(req);
10030
11028
  const label = typeof body2["label"] === "string" && body2["label"].trim() ? body2["label"].trim() : void 0;
10031
11029
  const result = await deps.subscriptionTokenWriter.importExternalCliAccount(providerId, label);
10032
11030
  if (!result.ok) {
10033
- return writeJsonError(res, 409, `no usable external ${providerId} CLI credential found`);
11031
+ return writeJsonError2(res, 409, `no usable external ${providerId} CLI credential found`);
10034
11032
  }
10035
11033
  const status2 = await statusEntryFor(deps.subscriptionAccounts, providerId);
10036
- return writeJson4(res, 200, {
11034
+ return writeJson5(res, 200, {
10037
11035
  ok: true,
10038
11036
  account: status2 ?? void 0,
10039
11037
  nativeCredentialMode: result.nativeCredentialMode,
@@ -10043,22 +11041,22 @@ async function handleAccounts(req, res, method, rest, deps) {
10043
11041
  }
10044
11042
  if (method === "POST" && rest[1] === "refresh") {
10045
11043
  if (providerId === "opencodego") {
10046
- return writeJsonError(res, 400, "opencodego credentials are not refreshable");
11044
+ return writeJsonError2(res, 400, "opencodego credentials are not refreshable");
10047
11045
  }
10048
11046
  const writer2 = deps.subscriptionTokenWriter;
10049
11047
  const ok = providerId === "claude" ? await writer2.refreshClaudeToken() : providerId === "codex" ? await writer2.refreshCodexToken() : await writer2.refreshGeminiToken();
10050
11048
  const status2 = await statusEntryFor(deps.subscriptionAccounts, providerId);
10051
- return writeJson4(res, 200, { ok, account: status2 ?? void 0 });
11049
+ return writeJson5(res, 200, { ok, account: status2 ?? void 0 });
10052
11050
  }
10053
11051
  if (method === "POST" && rest.length === 3 && rest[2] === "test") {
10054
11052
  const accountId = rest[1];
10055
- if (!deps.accountProbeService) return writeJsonError(res, 501, "account probe service unavailable");
11053
+ if (!deps.accountProbeService) return writeJsonError2(res, 501, "account probe service unavailable");
10056
11054
  const listed = await deps.subscriptionTokenWriter.listSanitizedAccounts();
10057
11055
  if (!(listed[providerId] ?? []).some((account) => account.id === accountId)) {
10058
- return writeJsonError(res, 404, `account '${accountId}' not found`);
11056
+ return writeJsonError2(res, 404, `account '${accountId}' not found`);
10059
11057
  }
10060
11058
  const result = await deps.accountProbeService.testAccountConnection(providerId, accountId);
10061
- return writeJson4(res, 200, {
11059
+ return writeJson5(res, 200, {
10062
11060
  ok: result.ok,
10063
11061
  marked: result.marked,
10064
11062
  tier: result.tier,
@@ -10067,176 +11065,189 @@ async function handleAccounts(req, res, method, rest, deps) {
10067
11065
  }
10068
11066
  if (method === "POST" && rest[2] === "label") {
10069
11067
  const accountId = rest[1];
10070
- const body2 = await readJsonBody4(req);
11068
+ const body2 = await readJsonBody5(req);
10071
11069
  const label = typeof body2["label"] === "string" ? body2["label"].trim() : "";
10072
11070
  const result = await deps.subscriptionTokenWriter.renameAccount(providerId, accountId, label);
10073
- if (!result.ok) return writeJsonError(res, 404, `account '${accountId}' not found`);
10074
- return writeJson4(res, 200, { ok: true });
11071
+ if (!result.ok) return writeJsonError2(res, 404, `account '${accountId}' not found`);
11072
+ return writeJson5(res, 200, { ok: true });
10075
11073
  }
10076
11074
  if (method === "POST" && rest[2] === "priority") {
10077
11075
  const accountId = rest[1];
10078
- const body2 = await readJsonBody4(req);
11076
+ const body2 = await readJsonBody5(req);
10079
11077
  const raw = body2["priority"];
10080
11078
  const priority = typeof raw === "number" ? raw : Number(raw);
10081
11079
  if (!Number.isFinite(priority)) {
10082
- return writeJsonError(res, 400, "priority must be a finite number");
11080
+ return writeJsonError2(res, 400, "priority must be a finite number");
10083
11081
  }
10084
11082
  const result = await deps.subscriptionTokenWriter.setAccountPriority(providerId, accountId, priority);
10085
- if (!result.ok) return writeJsonError(res, 404, `account '${accountId}' not found`);
10086
- return writeJson4(res, 200, { ok: true });
11083
+ if (!result.ok) return writeJsonError2(res, 404, `account '${accountId}' not found`);
11084
+ return writeJson5(res, 200, { ok: true });
10087
11085
  }
10088
11086
  if (method === "POST" && rest[2] === "proxy") {
10089
11087
  const accountId = rest[1];
10090
- const body2 = await readJsonBody4(req);
11088
+ const body2 = await readJsonBody5(req);
10091
11089
  const rawProxy = body2["proxy"];
10092
11090
  let proxy;
10093
11091
  if (rawProxy !== null && rawProxy !== void 0) {
10094
11092
  proxy = normalizeProxyConfig(rawProxy);
10095
- if (!proxy) return writeJsonError(res, 400, "invalid proxy config");
11093
+ if (!proxy) return writeJsonError2(res, 400, "invalid proxy config");
10096
11094
  }
10097
11095
  const result = await deps.subscriptionTokenWriter.setAccountProxy(providerId, accountId, proxy);
10098
- if (!result.ok) return writeJsonError(res, 404, `account '${accountId}' not found`);
10099
- return writeJson4(res, 200, { ok: true });
11096
+ if (!result.ok) return writeJsonError2(res, 404, `account '${accountId}' not found`);
11097
+ return writeJson5(res, 200, { ok: true });
10100
11098
  }
10101
11099
  if (method === "POST" && rest[2] === "supported-models") {
10102
11100
  const accountId = rest[1];
10103
- const body2 = await readJsonBody4(req);
11101
+ const body2 = await readJsonBody5(req);
10104
11102
  const parsed = validateSupportedModelsBody(body2["supportedModels"]);
10105
- if (!parsed.ok) return writeJsonError(res, 400, "invalid supportedModels");
11103
+ if (!parsed.ok) return writeJsonError2(res, 400, "invalid supportedModels");
10106
11104
  const result = await deps.subscriptionTokenWriter.setAccountSupportedModels(providerId, accountId, parsed.value);
10107
- if (!result.ok) return writeJsonError(res, 404, `account '${accountId}' not found`);
10108
- return writeJson4(res, 200, { ok: true });
11105
+ if (!result.ok) return writeJsonError2(res, 404, `account '${accountId}' not found`);
11106
+ return writeJson5(res, 200, { ok: true });
10109
11107
  }
10110
11108
  if (method === "PUT" && rest[1] === "active") {
10111
- const body2 = await readJsonBody4(req);
11109
+ const body2 = await readJsonBody5(req);
10112
11110
  const id = typeof body2["id"] === "string" ? body2["id"] : "";
10113
- if (!id) return writeJsonError(res, 400, "active switch requires { id }");
11111
+ if (!id) return writeJsonError2(res, 400, "active switch requires { id }");
10114
11112
  const result = await deps.subscriptionTokenWriter.setActiveAccount(providerId, id);
10115
- if (!result.ok) return writeJsonError(res, 404, `account '${id}' not found`);
10116
- return writeJson4(res, 200, { ok: true });
11113
+ if (!result.ok) return writeJsonError2(res, 404, `account '${id}' not found`);
11114
+ return writeJson5(res, 200, { ok: true });
10117
11115
  }
10118
11116
  if (method === "DELETE" && rest.length === 2) {
10119
11117
  const accountId = rest[1];
10120
11118
  const result = await deps.subscriptionTokenWriter.removeAccount(providerId, accountId);
10121
- if (!result.removed) return writeJsonError(res, 404, `account '${accountId}' not found`);
11119
+ if (!result.removed) return writeJsonError2(res, 404, `account '${accountId}' not found`);
10122
11120
  deps.accountAllowanceService?.removeAccountSnapshot?.(providerId, accountId);
10123
- return writeJson4(res, 200, { ok: true });
11121
+ return writeJson5(res, 200, { ok: true });
10124
11122
  }
10125
11123
  if (method === "DELETE" && rest.length === 1) {
10126
11124
  await deps.subscriptionTokenWriter.clearProvider(providerId);
10127
11125
  deps.accountAllowanceService?.removeProviderSnapshots?.(providerId);
10128
- return writeJson4(res, 200, { ok: true });
11126
+ return writeJson5(res, 200, { ok: true });
10129
11127
  }
10130
11128
  if (method === "DELETE") {
10131
- return writeJsonError(res, 405, "method DELETE not allowed on this accounts path");
11129
+ return writeJsonError2(res, 405, "method DELETE not allowed on this accounts path");
10132
11130
  }
10133
- const body = await readJsonBody4(req);
11131
+ const body = await readJsonBody5(req);
10134
11132
  const config = validateTokenBody(providerId, body);
10135
11133
  if (!config) {
10136
- return writeJsonError(res, 400, `malformed token body for provider '${providerId}'`);
11134
+ return writeJsonError2(res, 400, `malformed token body for provider '${providerId}'`);
10137
11135
  }
10138
11136
  await deps.subscriptionTokenWriter.writeProviderTokens(providerId, config);
10139
11137
  const status = await statusEntryFor(deps.subscriptionAccounts, providerId);
10140
- return writeJson4(res, 200, status ? { account: status } : { ok: true });
11138
+ return writeJson5(res, 200, status ? { account: status } : { ok: true });
10141
11139
  }
10142
- return writeJsonError(res, 405, `method ${method} not allowed on accounts`);
11140
+ return writeJsonError2(res, 405, `method ${method} not allowed on accounts`);
10143
11141
  }
10144
11142
  async function handleCli(req, res, method, rest, deps) {
10145
11143
  if (method === "GET" && rest.length === 0) {
10146
11144
  const result = handleCliList(process.platform, deps.cliPathProbe);
10147
- return writeJson4(res, result.status, result.body);
11145
+ return writeJson5(res, result.status, result.body);
10148
11146
  }
10149
11147
  if (method === "GET" && rest[0] === "sessions") {
10150
11148
  const result = handleCliSessions();
10151
- return writeJson4(res, result.status, result.body);
11149
+ return writeJson5(res, result.status, result.body);
10152
11150
  }
10153
11151
  if (method === "DELETE" && rest[0] === "sessions" && rest[1]) {
10154
11152
  const result = handleCliStop(rest[1]);
10155
- return writeJson4(res, result.status, result.body);
11153
+ return writeJson5(res, result.status, result.body);
10156
11154
  }
10157
11155
  if (method === "POST" && rest[1] === "install") {
10158
11156
  const cli = rest[0];
10159
11157
  if (!isLaunchCliId(cli)) {
10160
- return writeJsonError(res, 400, `unknown cli '${cli ?? ""}'`);
11158
+ return writeJsonError2(res, 400, `unknown cli '${cli ?? ""}'`);
10161
11159
  }
10162
11160
  const result = await handleCliInstall(cli, deps.cliCommandRunner);
10163
- return writeJson4(res, result.status, result.body);
11161
+ return writeJson5(res, result.status, result.body);
10164
11162
  }
10165
11163
  if (method === "POST" && rest[1] === "launch") {
10166
11164
  const cli = rest[0];
10167
11165
  if (!isLaunchCliId(cli)) {
10168
- return writeJsonError(res, 400, `unknown cli '${cli ?? ""}'`);
11166
+ return writeJsonError2(res, 400, `unknown cli '${cli ?? ""}'`);
10169
11167
  }
10170
- const body = await readJsonBody4(req);
11168
+ const body = await readJsonBody5(req);
10171
11169
  const providers = loadConfig(deps.configPath).providers ?? [];
11170
+ const codexAuthHelper = deps.codexAuthHelper;
11171
+ const keyScoped = codexAuthHelper ? await (async () => {
11172
+ const gateway = deps.outboundApiServer.getStatus();
11173
+ const serverConfig = await loadServerConfig3(deps.settingsStore);
11174
+ return {
11175
+ keyDb: deps.keyDb,
11176
+ bindings: serverConfig.bindings ?? [],
11177
+ gatewayRunning: gateway.running,
11178
+ gatewayBaseUrl: gateway.loopbackUrl ?? `http://127.0.0.1:${gateway.port}`,
11179
+ codexAuthHelper
11180
+ };
11181
+ })() : void 0;
10172
11182
  const result = await handleCliLaunch(cli, body, {
10173
11183
  llmConfig: deps.llmConfig,
10174
11184
  providers,
10175
11185
  routeLeaseManager: deps.routeLeaseManager,
11186
+ keyScoped,
10176
11187
  opener: deps.cliTerminalOpener,
10177
11188
  probe: deps.cliPathProbe
10178
11189
  });
10179
- return writeJson4(res, result.status, result.body);
11190
+ return writeJson5(res, result.status, result.body);
10180
11191
  }
10181
- return writeJsonError(res, 405, `method ${method} not allowed on cli`);
11192
+ return writeJsonError2(res, 405, `method ${method} not allowed on cli`);
10182
11193
  }
10183
11194
  async function handleIntegrations(req, res, method, rest, deps) {
10184
11195
  const factory = deps.integrationManagerFactory;
10185
- if (!factory) return writeJsonError(res, 501, "native CLI integration is not available");
11196
+ if (!factory) return writeJsonError2(res, 501, "native CLI integration is not available");
10186
11197
  const manager = factory();
10187
11198
  try {
10188
11199
  if (method === "GET" && rest.length === 0) {
10189
- return writeJson4(res, 200, {
11200
+ return writeJson5(res, 200, {
10190
11201
  integrations: await manager.listStatus(),
10191
11202
  gateway: deps.outboundApiServer.getStatus()
10192
11203
  });
10193
11204
  }
10194
11205
  if (method === "POST" && rest.length === 1 && rest[0] === "rotate") {
10195
11206
  await manager.rotateGatewayKey();
10196
- return writeJson4(res, 200, { ok: true, integrations: await manager.listStatus() });
11207
+ return writeJson5(res, 200, { ok: true, integrations: await manager.listStatus() });
10197
11208
  }
10198
11209
  const client = rest[0];
10199
11210
  if (!isIntegrationClient(client)) {
10200
- return writeJsonError(res, 400, `unknown integration client '${client ?? ""}'`);
11211
+ return writeJsonError2(res, 400, `unknown integration client '${client ?? ""}'`);
10201
11212
  }
10202
11213
  if (method === "POST" && rest[1] === "key") {
10203
- const body = await readJsonBody4(req);
11214
+ const body = await readJsonBody5(req);
10204
11215
  if (Object.keys(body).length !== 1 || typeof body.keyId !== "string" || !body.keyId.trim()) {
10205
- return writeJsonError(res, 400, "body must contain a non-empty keyId string");
11216
+ return writeJsonError2(res, 400, "body must contain a non-empty keyId string");
10206
11217
  }
10207
11218
  const status = await manager.bindIntegrationKey(client, body.keyId.trim());
10208
- return writeJson4(res, 200, { integration: status });
11219
+ return writeJson5(res, 200, { integration: status });
10209
11220
  }
10210
11221
  if (method === "POST" && rest[1] === "plan") {
10211
- const body = await readJsonBody4(req);
11222
+ const body = await readJsonBody5(req);
10212
11223
  const configPath = body.configPath;
10213
11224
  if (configPath !== void 0 && typeof configPath !== "string") {
10214
- return writeJsonError(res, 400, "configPath must be a string");
11225
+ return writeJsonError2(res, 400, "configPath must be a string");
10215
11226
  }
10216
11227
  const plan = await manager.plan(client, configPath);
10217
- return writeJson4(res, 200, { plan });
11228
+ return writeJson5(res, 200, { plan });
10218
11229
  }
10219
11230
  if (method === "POST" && (rest[1] === "install" || rest[1] === "apply")) {
10220
- const body = await readJsonBody4(req);
11231
+ const body = await readJsonBody5(req);
10221
11232
  const configPath = body.configPath;
10222
11233
  if (configPath !== void 0 && typeof configPath !== "string") {
10223
- return writeJsonError(res, 400, "configPath must be a string");
11234
+ return writeJsonError2(res, 400, "configPath must be a string");
10224
11235
  }
10225
11236
  const status = await manager.install(client, configPath);
10226
- return writeJson4(res, 200, { integration: status });
11237
+ return writeJson5(res, 200, { integration: status });
10227
11238
  }
10228
11239
  if (method === "POST" && rest[1] === "repair") {
10229
11240
  const status = await manager.repair(client);
10230
- return writeJson4(res, 200, { integration: status });
11241
+ return writeJson5(res, 200, { integration: status });
10231
11242
  }
10232
11243
  if (method === "DELETE" && rest.length === 1 || method === "POST" && rest[1] === "remove") {
10233
11244
  const status = await manager.remove(client);
10234
- return writeJson4(res, 200, { integration: status });
11245
+ return writeJson5(res, 200, { integration: status });
10235
11246
  }
10236
- return writeJsonError(res, 405, `method ${method} not allowed on integrations`);
11247
+ return writeJsonError2(res, 405, `method ${method} not allowed on integrations`);
10237
11248
  } catch (error) {
10238
11249
  if (error instanceof IntegrationConflictError) {
10239
- return writeJsonError(res, 409, error.message);
11250
+ return writeJsonError2(res, 409, error.message);
10240
11251
  }
10241
11252
  throw error;
10242
11253
  }
@@ -10379,7 +11390,7 @@ function imageProviderEvidence(images, capabilities) {
10379
11390
  async function handleImagesVerifyLive(req, res, deps) {
10380
11391
  const verifier = deps.imageLiveVerifier;
10381
11392
  if (!verifier) {
10382
- return writeJsonError(res, 501, "Images live verification is not available");
11393
+ return writeJsonError2(res, 501, "Images live verification is not available");
10383
11394
  }
10384
11395
  const serverConfig = await loadServerConfig3(deps.settingsStore);
10385
11396
  const images = serverConfig.images ?? DEFAULT_IMAGES_SERVER_CONFIG;
@@ -10388,7 +11399,7 @@ async function handleImagesVerifyLive(req, res, deps) {
10388
11399
  req.on("close", () => controller.abort());
10389
11400
  const result = await verifier.verifyLive(images, controller.signal);
10390
11401
  const antigravityRouted = Object.values(images.models).includes("antigravity-subscription");
10391
- return writeJson4(res, 200, {
11402
+ return writeJson5(res, 200, {
10392
11403
  ...result,
10393
11404
  ...antigravityRouted ? { antigravityDeferred: true } : {}
10394
11405
  });
@@ -10396,18 +11407,18 @@ async function handleImagesVerifyLive(req, res, deps) {
10396
11407
  async function handleImages(req, res, method, rest, deps) {
10397
11408
  if (rest.length === 1 && rest[0] === "verify-live") {
10398
11409
  if (method !== "POST") {
10399
- return writeJsonError(res, 405, `method ${method} not allowed on Images verify-live`);
11410
+ return writeJsonError2(res, 405, `method ${method} not allowed on Images verify-live`);
10400
11411
  }
10401
11412
  return handleImagesVerifyLive(req, res, deps);
10402
11413
  }
10403
11414
  if (rest.length !== 1 || rest[0] !== "capabilities") {
10404
- return writeJsonError(res, 404, "unknown Images admin resource");
11415
+ return writeJsonError2(res, 404, "unknown Images admin resource");
10405
11416
  }
10406
11417
  if (method !== "GET") {
10407
- return writeJsonError(res, 405, `method ${method} not allowed on Images capabilities`);
11418
+ return writeJsonError2(res, 405, `method ${method} not allowed on Images capabilities`);
10408
11419
  }
10409
11420
  const reader = deps.imageRuntimeStatus;
10410
- if (!reader) return writeJsonError(res, 501, "Images runtime status is not available");
11421
+ if (!reader) return writeJsonError2(res, 501, "Images runtime status is not available");
10411
11422
  const serverConfig = await loadServerConfig3(deps.settingsStore);
10412
11423
  const images = serverConfig.images ?? DEFAULT_IMAGES_SERVER_CONFIG;
10413
11424
  const lifecycle = reader.status();
@@ -10428,7 +11439,7 @@ async function handleImages(req, res, method, rest, deps) {
10428
11439
  httpLeases: safeStatusCount(generation.httpLeases),
10429
11440
  hostedLeases: safeStatusCount(generation.hostedLeases)
10430
11441
  }));
10431
- return writeJson4(res, 200, {
11442
+ return writeJson5(res, 200, {
10432
11443
  configured: {
10433
11444
  enabled: images.enabled,
10434
11445
  provider: images.models[images.defaultModel] ?? "codex-subscription",
@@ -10455,7 +11466,7 @@ async function handleImages(req, res, method, rest, deps) {
10455
11466
  });
10456
11467
  }
10457
11468
  async function handleStatus(res, method, deps) {
10458
- if (method !== "GET") return writeJsonError(res, 405, `method ${method} not allowed on status`);
11469
+ if (method !== "GET") return writeJsonError2(res, 405, `method ${method} not allowed on status`);
10459
11470
  const status = deps.outboundApiServer.getStatus();
10460
11471
  const serverConfig = await loadServerConfig3(deps.settingsStore);
10461
11472
  const endpoints = ["chat", "responses", "messages", "gemini"].map((endpoint) => {
@@ -10495,14 +11506,14 @@ async function handleStatus(res, method, deps) {
10495
11506
  })() : void 0;
10496
11507
  if (status.running) {
10497
11508
  const queueStatus = deps.outboundApiServer.getQueueStatus();
10498
- return writeJson4(res, 200, {
11509
+ return writeJson5(res, 200, {
10499
11510
  ...status,
10500
11511
  endpoints,
10501
11512
  queueStatus,
10502
11513
  ...imageRuntime ? { imageRuntime } : {}
10503
11514
  });
10504
11515
  }
10505
- return writeJson4(res, 200, {
11516
+ return writeJson5(res, 200, {
10506
11517
  ...status,
10507
11518
  endpoints,
10508
11519
  ...imageRuntime ? { imageRuntime } : {}
@@ -10525,23 +11536,23 @@ function resolvePlaygroundPath(endpoint, body) {
10525
11536
  }
10526
11537
  }
10527
11538
  async function handlePlayground(req, res, method, deps) {
10528
- if (method !== "POST") return writeJsonError(res, 405, `method ${method} not allowed on playground`);
10529
- const body = await readJsonBody4(req);
11539
+ if (method !== "POST") return writeJsonError2(res, 405, `method ${method} not allowed on playground`);
11540
+ const body = await readJsonBody5(req);
10530
11541
  const endpoint = typeof body["endpoint"] === "string" ? body["endpoint"] : "";
10531
11542
  const key = typeof body["key"] === "string" ? body["key"] : "";
10532
11543
  const payload = body["body"];
10533
11544
  const status = deps.outboundApiServer.getStatus();
10534
- if (!status.running || !status.port) return writeJsonError(res, 503, "outbound server not running");
10535
- const path2 = resolvePlaygroundPath(endpoint, isRecord9(payload) ? payload : {});
10536
- if (!path2) return writeJsonError(res, 400, `unknown endpoint '${endpoint}'`);
11545
+ if (!status.running || !status.port) return writeJsonError2(res, 503, "outbound server not running");
11546
+ const path2 = resolvePlaygroundPath(endpoint, isRecord11(payload) ? payload : {});
11547
+ if (!path2) return writeJsonError2(res, 400, `unknown endpoint '${endpoint}'`);
10537
11548
  const upstreamBody = typeof payload === "string" ? payload : JSON.stringify(payload ?? {});
10538
11549
  await proxyToOutbound(res, status.port, path2, key, upstreamBody);
10539
11550
  }
10540
- function isRecord9(v) {
11551
+ function isRecord11(v) {
10541
11552
  return !!v && typeof v === "object" && !Array.isArray(v);
10542
11553
  }
10543
11554
  function proxyToOutbound(res, outboundPort, path2, key, body) {
10544
- return new Promise((resolve11) => {
11555
+ return new Promise((resolve12) => {
10545
11556
  const upstream = http.request(
10546
11557
  {
10547
11558
  host: "127.0.0.1",
@@ -10562,14 +11573,14 @@ function proxyToOutbound(res, outboundPort, path2, key, body) {
10562
11573
  proxRes.on("data", (chunk) => res.write(chunk));
10563
11574
  proxRes.on("end", () => {
10564
11575
  res.end();
10565
- resolve11();
11576
+ resolve12();
10566
11577
  });
10567
11578
  }
10568
11579
  );
10569
11580
  upstream.on("error", (err9) => {
10570
- if (!res.headersSent) writeJsonError(res, 502, `playground proxy failed: ${err9.message}`);
11581
+ if (!res.headersSent) writeJsonError2(res, 502, `playground proxy failed: ${err9.message}`);
10571
11582
  else res.end();
10572
- resolve11();
11583
+ resolve12();
10573
11584
  });
10574
11585
  upstream.write(body);
10575
11586
  upstream.end();
@@ -10577,8 +11588,8 @@ function proxyToOutbound(res, outboundPort, path2, key, body) {
10577
11588
  }
10578
11589
 
10579
11590
  // src/admin/uiStatic.ts
10580
- import { existsSync as existsSync9, statSync as statSync5 } from "fs";
10581
- import { readFile } from "fs/promises";
11591
+ import { existsSync as existsSync10, statSync as statSync5 } from "fs";
11592
+ import { readFile as readFile2 } from "fs/promises";
10582
11593
  import { createRequire } from "module";
10583
11594
  import path from "path";
10584
11595
  var CONTENT_TYPES = {
@@ -10600,13 +11611,13 @@ var CONTENT_TYPES = {
10600
11611
  function resolveUiDist() {
10601
11612
  const fromEnv = process.env["OMNICROSS_UI_DIST"];
10602
11613
  if (fromEnv) {
10603
- return existsSync9(path.join(fromEnv, "index.html")) ? path.resolve(fromEnv) : null;
11614
+ return existsSync10(path.join(fromEnv, "index.html")) ? path.resolve(fromEnv) : null;
10604
11615
  }
10605
11616
  try {
10606
11617
  const req = createRequire(typeof __filename !== "undefined" ? __filename : import.meta.url);
10607
11618
  const pkgJson = req.resolve("@omnicross/ui/package.json");
10608
11619
  const dist = path.join(path.dirname(pkgJson), "dist");
10609
- return existsSync9(path.join(dist, "index.html")) ? dist : null;
11620
+ return existsSync10(path.join(dist, "index.html")) ? dist : null;
10610
11621
  } catch {
10611
11622
  return null;
10612
11623
  }
@@ -10655,7 +11666,7 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
10655
11666
  return true;
10656
11667
  }
10657
11668
  let target = filePath;
10658
- if (!existsSync9(target) || statSync5(target).isDirectory()) {
11669
+ if (!existsSync10(target) || statSync5(target).isDirectory()) {
10659
11670
  if (path.extname(rel) === "") {
10660
11671
  target = path.join(uiDist, "index.html");
10661
11672
  } else {
@@ -10664,7 +11675,7 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
10664
11675
  return true;
10665
11676
  }
10666
11677
  }
10667
- const body = await readFile(target);
11678
+ const body = await readFile2(target);
10668
11679
  const type = CONTENT_TYPES[path.extname(target).toLowerCase()] ?? "application/octet-stream";
10669
11680
  res.writeHead(200, { "Content-Type": type, "Content-Length": body.length });
10670
11681
  res.end(req.method === "HEAD" ? void 0 : body);
@@ -10672,7 +11683,7 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
10672
11683
  }
10673
11684
 
10674
11685
  // src/admin/version.ts
10675
- var DAEMON_VERSION = true ? "0.4.4" : "0.0.0-dev";
11686
+ var DAEMON_VERSION = true ? "0.4.6" : "0.0.0-dev";
10676
11687
 
10677
11688
  // src/admin/AdminServer.ts
10678
11689
  var LOOPBACK_ADDR = "127.0.0.1";
@@ -10711,14 +11722,14 @@ var AdminServer = class {
10711
11722
  }
10712
11723
  /** Bind once; on EADDRINUSE retry with an ephemeral port (port 0). */
10713
11724
  listen(bindAddr, port) {
10714
- return new Promise((resolve11, reject) => {
11725
+ return new Promise((resolve12, reject) => {
10715
11726
  const server = http2.createServer((req, res) => {
10716
11727
  this.onRequest(req, res);
10717
11728
  });
10718
11729
  const onError = (err9) => {
10719
11730
  if (err9.code === "EADDRINUSE" && port !== 0) {
10720
11731
  server.removeListener("error", onError);
10721
- this.listen(bindAddr, 0).then(resolve11, reject);
11732
+ this.listen(bindAddr, 0).then(resolve12, reject);
10722
11733
  return;
10723
11734
  }
10724
11735
  reject(err9);
@@ -10730,7 +11741,7 @@ var AdminServer = class {
10730
11741
  server.removeListener("error", onError);
10731
11742
  server.on("error", (e) => this.deps.logger.error("[AdminServer] server error", e));
10732
11743
  this.server = server;
10733
- resolve11(addr.port);
11744
+ resolve12(addr.port);
10734
11745
  } else {
10735
11746
  reject(new Error("Failed to get admin server address"));
10736
11747
  }
@@ -10804,6 +11815,10 @@ var AdminServer = class {
10804
11815
  await handleRouteLeaseApi(req, res, path2, this.deps);
10805
11816
  return;
10806
11817
  }
11818
+ if (path2 === "/admin/api/codex-sessions" || path2 === "/admin/api/codex-sessions/preview" || path2 === "/admin/api/codex-sessions/apply") {
11819
+ await handleCodexSessionApi(req, res, path2, this.deps.codexSessionManager);
11820
+ return;
11821
+ }
10807
11822
  if (path2.startsWith("/admin/api/")) {
10808
11823
  await handleAdminApi(req, res, path2, this.deps);
10809
11824
  return;
@@ -10827,8 +11842,8 @@ var AdminServer = class {
10827
11842
  if (!server) return;
10828
11843
  this.server = null;
10829
11844
  this.boundPort = 0;
10830
- return new Promise((resolve11) => {
10831
- server.close(() => resolve11());
11845
+ return new Promise((resolve12) => {
11846
+ server.close(() => resolve12());
10832
11847
  });
10833
11848
  }
10834
11849
  /** A live status snapshot. */
@@ -10967,7 +11982,7 @@ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal
10967
11982
  const port = binding.port ?? LOOPBACK_PORT;
10968
11983
  const callbackPath = binding.path ?? CALLBACK_PATH;
10969
11984
  const label = binding.label ?? "codex";
10970
- return new Promise((resolve11, reject) => {
11985
+ return new Promise((resolve12, reject) => {
10971
11986
  let settled = false;
10972
11987
  const finish = (server2, fn) => {
10973
11988
  if (settled) return;
@@ -10999,7 +12014,7 @@ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal
10999
12014
  }
11000
12015
  res.writeHead(200, HTML_HEADERS);
11001
12016
  res.end(pageHtml("Login complete."));
11002
- finish(server, () => resolve11(code));
12017
+ finish(server, () => resolve12(code));
11003
12018
  });
11004
12019
  const abort = () => finish(server, () => reject(new Error("login: cancelled")));
11005
12020
  if (signal?.aborted) {
@@ -11128,7 +12143,7 @@ function secondsUntil9(instant, now) {
11128
12143
  if (!instant) return void 0;
11129
12144
  return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
11130
12145
  }
11131
- function isRecord10(value) {
12146
+ function isRecord12(value) {
11132
12147
  return !!value && typeof value === "object" && !Array.isArray(value);
11133
12148
  }
11134
12149
  function detectProviderKeyQuotaAdapter(baseUrl) {
@@ -11195,17 +12210,17 @@ function zaiWindowIdLabel(durationMs) {
11195
12210
  return { id: "quota", label: "Quota" };
11196
12211
  }
11197
12212
  function parseZaiQuotaPayload(payload, now) {
11198
- if (!isRecord10(payload)) return null;
11199
- const data = isRecord10(payload["data"]) ? payload["data"] : payload;
12213
+ if (!isRecord12(payload)) return null;
12214
+ const data = isRecord12(payload["data"]) ? payload["data"] : payload;
11200
12215
  if (payload["success"] === false) return null;
11201
12216
  const limits = Array.isArray(data["limits"]) ? data["limits"] : [];
11202
12217
  const byWindow = /* @__PURE__ */ new Map();
11203
12218
  for (const raw of limits) {
11204
- if (!isRecord10(raw)) continue;
12219
+ if (!isRecord12(raw)) continue;
11205
12220
  const item = raw;
11206
12221
  if (item.type === void 0) continue;
11207
12222
  const details = raw["usageDetails"];
11208
- if (Array.isArray(details) && details.some((d) => isRecord10(d) && d["modelCode"] === "zread")) {
12223
+ if (Array.isArray(details) && details.some((d) => isRecord12(d) && d["modelCode"] === "zread")) {
11209
12224
  continue;
11210
12225
  }
11211
12226
  const durationMs = zaiWindowDurationMs(item);
@@ -11238,7 +12253,7 @@ function parseZaiQuotaPayload(payload, now) {
11238
12253
  var MINIMAX_STATUS_EXHAUSTED = 2;
11239
12254
  var MINIMAX_SHARED_BUCKET = "general";
11240
12255
  function parseMiniMaxBucket(value) {
11241
- if (!isRecord10(value)) return null;
12256
+ if (!isRecord12(value)) return null;
11242
12257
  const modelName = typeof value["model_name"] === "string" ? value["model_name"].trim() : "";
11243
12258
  if (!modelName) return null;
11244
12259
  const instant = (v) => {
@@ -11270,9 +12285,9 @@ function minimaxWindow(id, label, windowMinutes, resetsAtMs, remainingPercent, s
11270
12285
  };
11271
12286
  }
11272
12287
  function parseMiniMaxTokenPlanPayload(payload, now) {
11273
- if (!isRecord10(payload)) return null;
12288
+ if (!isRecord12(payload)) return null;
11274
12289
  const baseResp = payload["base_resp"];
11275
- if (!isRecord10(baseResp) || baseResp["status_code"] !== 0) return null;
12290
+ if (!isRecord12(baseResp) || baseResp["status_code"] !== 0) return null;
11276
12291
  const buckets = Array.isArray(payload["model_remains"]) ? payload["model_remains"] : [];
11277
12292
  let general = null;
11278
12293
  for (const raw of buckets) {
@@ -11305,11 +12320,11 @@ function parseMiniMaxTokenPlanPayload(payload, now) {
11305
12320
  ];
11306
12321
  }
11307
12322
  function parseUmansUsagePayload(payload, now) {
11308
- if (!isRecord10(payload)) return null;
11309
- const limits = isRecord10(payload["limits"]) ? payload["limits"] : void 0;
11310
- const requests = limits && isRecord10(limits["requests"]) ? limits["requests"] : void 0;
11311
- const usage = isRecord10(payload["usage"]) ? payload["usage"] : void 0;
11312
- const window = isRecord10(payload["window"]) ? payload["window"] : void 0;
12323
+ if (!isRecord12(payload)) return null;
12324
+ const limits = isRecord12(payload["limits"]) ? payload["limits"] : void 0;
12325
+ const requests = limits && isRecord12(limits["requests"]) ? limits["requests"] : void 0;
12326
+ const usage = isRecord12(payload["usage"]) ? payload["usage"] : void 0;
12327
+ const window = isRecord12(payload["window"]) ? payload["window"] : void 0;
11313
12328
  const hardCap = finiteNumber5(requests?.["hard_cap"]);
11314
12329
  const softLimit = finiteNumber5(requests?.["limit"]);
11315
12330
  const requestsInWindow = finiteNumber5(usage?.["requests_in_window"]);
@@ -11336,9 +12351,9 @@ function parseUmansUsagePayload(payload, now) {
11336
12351
  ];
11337
12352
  }
11338
12353
  function parseSyntheticQuotasPayload(payload, now) {
11339
- if (!isRecord10(payload)) return null;
11340
- const fiveHour = isRecord10(payload["rollingFiveHourLimit"]) ? payload["rollingFiveHourLimit"] : void 0;
11341
- const weekly = isRecord10(payload["weeklyTokenLimit"]) ? payload["weeklyTokenLimit"] : void 0;
12354
+ if (!isRecord12(payload)) return null;
12355
+ const fiveHour = isRecord12(payload["rollingFiveHourLimit"]) ? payload["rollingFiveHourLimit"] : void 0;
12356
+ const weekly = isRecord12(payload["weeklyTokenLimit"]) ? payload["weeklyTokenLimit"] : void 0;
11342
12357
  const windows = [];
11343
12358
  if (fiveHour) {
11344
12359
  const max = finiteNumber5(fiveHour["max"]);
@@ -11379,12 +12394,12 @@ var CLINE_WINDOW_CONFIG = {
11379
12394
  monthly: { id: "thirty-day", label: "30 days", minutes: 30 * 24 * 60 }
11380
12395
  };
11381
12396
  function parseClinePassUsageLimitsPayload(payload, now) {
11382
- if (!isRecord10(payload)) return null;
11383
- const data = isRecord10(payload["data"]) ? payload["data"] : payload;
12397
+ if (!isRecord12(payload)) return null;
12398
+ const data = isRecord12(payload["data"]) ? payload["data"] : payload;
11384
12399
  const limits = Array.isArray(data["limits"]) ? data["limits"] : [];
11385
12400
  const windows = [];
11386
12401
  for (const raw of limits) {
11387
- if (!isRecord10(raw)) continue;
12402
+ if (!isRecord12(raw)) continue;
11388
12403
  const config = CLINE_WINDOW_CONFIG[typeof raw["type"] === "string" ? raw["type"] : ""];
11389
12404
  if (!config) continue;
11390
12405
  const usedPercent = finitePercent4(raw["percentUsed"]);
@@ -11553,7 +12568,7 @@ import { createHmac as createHmac2, randomBytes as randomBytes5 } from "crypto";
11553
12568
  import {
11554
12569
  chmodSync as chmodSync6,
11555
12570
  closeSync as closeSync3,
11556
- existsSync as existsSync11,
12571
+ existsSync as existsSync12,
11557
12572
  fsyncSync as fsyncSync2,
11558
12573
  lstatSync as lstatSync3,
11559
12574
  openSync as openSync3,
@@ -11562,7 +12577,7 @@ import {
11562
12577
  unlinkSync as unlinkSync5,
11563
12578
  writeFileSync as writeFileSync8
11564
12579
  } from "fs";
11565
- import { basename as basename2, dirname as dirname6, join as join10, resolve as resolve4 } from "path";
12580
+ import { basename as basename3, dirname as dirname6, join as join11, resolve as resolve5 } from "path";
11566
12581
  import { IMAGE_SERVER_HARD_CEILINGS } from "@omnicross/core/outbound-api";
11567
12582
 
11568
12583
  // src/image-generation/imageTenantHmac.ts
@@ -11571,7 +12586,7 @@ import {
11571
12586
  chmodSync as chmodSync5,
11572
12587
  closeSync as closeSync2,
11573
12588
  constants,
11574
- existsSync as existsSync10,
12589
+ existsSync as existsSync11,
11575
12590
  fstatSync,
11576
12591
  fsyncSync,
11577
12592
  lstatSync as lstatSync2,
@@ -11579,7 +12594,7 @@ import {
11579
12594
  readFileSync as readFileSync8,
11580
12595
  writeFileSync as writeFileSync7
11581
12596
  } from "fs";
11582
- import { join as join9 } from "path";
12597
+ import { join as join10 } from "path";
11583
12598
  var TENANT_SALT_NAME = "tenant-hmac-salt.v1.bin";
11584
12599
  var TENANT_KEY_PATTERN = /^[a-f0-9]{64}$/u;
11585
12600
  var REFERENCE_DOMAIN = Buffer.from("omnicross:image-reference:tenant:v1\0", "utf8");
@@ -11597,8 +12612,8 @@ function deriveImageTenantHmac(salt, purpose, tenantId) {
11597
12612
  }
11598
12613
  function loadOrCreateImageTenantHmacSalt(paths, random) {
11599
12614
  const root = paths.verifiedRoot("mountManifest");
11600
- const path2 = join9(root, TENANT_SALT_NAME);
11601
- if (!existsSync10(path2)) {
12615
+ const path2 = join10(root, TENANT_SALT_NAME);
12616
+ if (!existsSync11(path2)) {
11602
12617
  const salt = random(32);
11603
12618
  if (salt.byteLength !== 32) throw new TypeError("image tenant HMAC salt generator returned invalid bytes");
11604
12619
  let fd2;
@@ -11703,8 +12718,8 @@ function validateObservation(value) {
11703
12718
  }
11704
12719
  }
11705
12720
  function samePath2(left, right) {
11706
- const a = resolve4(left);
11707
- const b = resolve4(right);
12721
+ const a = resolve5(left);
12722
+ const b = resolve5(right);
11708
12723
  return process.platform === "win32" ? a.toLowerCase() === b.toLowerCase() : a === b;
11709
12724
  }
11710
12725
  function capabilityValues(entry) {
@@ -11766,7 +12781,7 @@ var FileCodexImageCapabilityEvidenceManifestOwner = class {
11766
12781
  this.#replaceManifest = options.replaceManifest ?? ((target, contents) => {
11767
12782
  this.#atomicReplace(target, contents);
11768
12783
  });
11769
- if (existsSync11(this.#manifestPath())) this.#load();
12784
+ if (existsSync12(this.#manifestPath())) this.#load();
11770
12785
  }
11771
12786
  createSource(ttlMs) {
11772
12787
  return new FileCodexImageCapabilityEvidenceSource({ owner: this, ttlMs });
@@ -11878,7 +12893,7 @@ var FileCodexImageCapabilityEvidenceManifestOwner = class {
11878
12893
  return Math.min(entry.expiresAt, entry.verifiedAt + ttlMs);
11879
12894
  }
11880
12895
  #manifestPath() {
11881
- return join10(this.#paths.verifiedRoot("evidence"), MANIFEST_NAME);
12896
+ return join11(this.#paths.verifiedRoot("evidence"), MANIFEST_NAME);
11882
12897
  }
11883
12898
  #serialized(entries, revision) {
11884
12899
  const manifest = {
@@ -11923,15 +12938,15 @@ var FileCodexImageCapabilityEvidenceManifestOwner = class {
11923
12938
  this.#entries = entries;
11924
12939
  }
11925
12940
  #refresh() {
11926
- if (!existsSync11(this.#manifestPath())) return;
12941
+ if (!existsSync12(this.#manifestPath())) return;
11927
12942
  this.#load();
11928
12943
  }
11929
12944
  #atomicReplace(targetPath, contents) {
11930
12945
  const root = this.#paths.verifiedRoot("evidence");
11931
- if (!samePath2(dirname6(resolve4(targetPath)), root) || basename2(targetPath) !== MANIFEST_NAME) {
12946
+ if (!samePath2(dirname6(resolve5(targetPath)), root) || basename3(targetPath) !== MANIFEST_NAME) {
11932
12947
  throw new TypeError("Codex image evidence manifest target is invalid");
11933
12948
  }
11934
- const temporaryPath = join10(
12949
+ const temporaryPath = join11(
11935
12950
  root,
11936
12951
  `.codex-image-evidence.${process.pid}.${this.#random(8).toString("hex")}.tmp`
11937
12952
  );
@@ -11951,7 +12966,7 @@ var FileCodexImageCapabilityEvidenceManifestOwner = class {
11951
12966
  } catch {
11952
12967
  }
11953
12968
  }
11954
- if (existsSync11(temporaryPath)) {
12969
+ if (existsSync12(temporaryPath)) {
11955
12970
  try {
11956
12971
  unlinkSync5(temporaryPath);
11957
12972
  } catch {
@@ -12543,11 +13558,11 @@ var DaemonImageExecutionScheduler = class {
12543
13558
  retrySafety: "before_acceptance"
12544
13559
  });
12545
13560
  }
12546
- return new Promise((resolve11, reject) => {
13561
+ return new Promise((resolve12, reject) => {
12547
13562
  const waiter = {
12548
13563
  tenantKey,
12549
13564
  signal: request.signal,
12550
- resolve: resolve11,
13565
+ resolve: resolve12,
12551
13566
  reject,
12552
13567
  onAbort: () => void 0,
12553
13568
  settled: false
@@ -12710,7 +13725,7 @@ import {
12710
13725
  ImageGenerationError as ImageGenerationError3,
12711
13726
  ImageRequestResourceScope
12712
13727
  } from "@omnicross/core/image-generation";
12713
- import { dirname as dirname7, resolve as resolve5 } from "path";
13728
+ import { dirname as dirname7, resolve as resolve6 } from "path";
12714
13729
  function capacityExceeded() {
12715
13730
  throw new ImageGenerationError3("image_too_large");
12716
13731
  }
@@ -12795,10 +13810,10 @@ var DaemonImageActiveScopeRegistry = class {
12795
13810
  #temporaryRoot;
12796
13811
  #active = /* @__PURE__ */ new Set();
12797
13812
  constructor(paths) {
12798
- this.#temporaryRoot = resolve5(paths.paths.temporaryRoot);
13813
+ this.#temporaryRoot = resolve6(paths.paths.temporaryRoot);
12799
13814
  }
12800
13815
  register(privateDirectory) {
12801
- const normalized2 = resolve5(privateDirectory);
13816
+ const normalized2 = resolve6(privateDirectory);
12802
13817
  if (dirname7(normalized2) !== this.#temporaryRoot || this.#active.has(normalized2)) {
12803
13818
  throw new TypeError("image temporary scope directory is invalid or already active");
12804
13819
  }
@@ -12811,7 +13826,7 @@ var DaemonImageActiveScopeRegistry = class {
12811
13826
  };
12812
13827
  }
12813
13828
  isActive(privateDirectory) {
12814
- return this.#active.has(resolve5(privateDirectory));
13829
+ return this.#active.has(resolve6(privateDirectory));
12815
13830
  }
12816
13831
  status() {
12817
13832
  return Object.freeze({ activeDirectories: this.#active.size });
@@ -13105,14 +14120,14 @@ function createImageRuntimeGeneration(options) {
13105
14120
 
13106
14121
  // src/image-generation/ImageStartupReconciler.ts
13107
14122
  import {
13108
- existsSync as existsSync15,
14123
+ existsSync as existsSync16,
13109
14124
  lstatSync as lstatSync7,
13110
14125
  readFileSync as readFileSync13,
13111
14126
  readdirSync as readdirSync6,
13112
14127
  rmdirSync as rmdirSync2,
13113
14128
  unlinkSync as unlinkSync9
13114
14129
  } from "fs";
13115
- import { basename as basename6, dirname as dirname11, isAbsolute as isAbsolute3, relative as relative2, resolve as resolve9 } from "path";
14130
+ import { basename as basename7, dirname as dirname11, isAbsolute as isAbsolute3, relative as relative2, resolve as resolve10 } from "path";
13116
14131
  import {
13117
14132
  IMAGE_REQUEST_DIRECTORY_MARKER_CONTENT,
13118
14133
  IMAGE_REQUEST_DIRECTORY_MARKER_NAME
@@ -13122,7 +14137,7 @@ import {
13122
14137
  import { randomBytes as randomBytes9 } from "crypto";
13123
14138
  import {
13124
14139
  closeSync as closeSync6,
13125
- existsSync as existsSync14,
14140
+ existsSync as existsSync15,
13126
14141
  fsyncSync as fsyncSync5,
13127
14142
  lstatSync as lstatSync6,
13128
14143
  openSync as openSync6,
@@ -13132,7 +14147,7 @@ import {
13132
14147
  unlinkSync as unlinkSync8,
13133
14148
  writeFileSync as writeFileSync11
13134
14149
  } from "fs";
13135
- import { basename as basename5, dirname as dirname10, isAbsolute as isAbsolute2, join as join13, resolve as resolve8 } from "path";
14150
+ import { basename as basename6, dirname as dirname10, isAbsolute as isAbsolute2, join as join14, resolve as resolve9 } from "path";
13136
14151
  import { ImageGenerationError as ImageGenerationError7 } from "@omnicross/core/image-generation";
13137
14152
 
13138
14153
  // src/image-generation/FileImageReferenceStore.ts
@@ -13141,7 +14156,7 @@ import {
13141
14156
  closeSync as closeSync4,
13142
14157
  constants as constants2,
13143
14158
  createReadStream,
13144
- existsSync as existsSync12,
14159
+ existsSync as existsSync13,
13145
14160
  fstatSync as fstatSync2,
13146
14161
  fsyncSync as fsyncSync3,
13147
14162
  lstatSync as lstatSync4,
@@ -13153,8 +14168,8 @@ import {
13153
14168
  unlinkSync as unlinkSync6,
13154
14169
  writeFileSync as writeFileSync9
13155
14170
  } from "fs";
13156
- import { open } from "fs/promises";
13157
- import { basename as basename3, dirname as dirname8, join as join11, resolve as resolve6 } from "path";
14171
+ import { open as open2 } from "fs/promises";
14172
+ import { basename as basename4, dirname as dirname8, join as join12, resolve as resolve7 } from "path";
13158
14173
  import { Readable } from "stream";
13159
14174
  import {
13160
14175
  ImageGenerationError as ImageGenerationError5
@@ -13180,8 +14195,8 @@ function safeInteger(value) {
13180
14195
  return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
13181
14196
  }
13182
14197
  function samePath3(left, right) {
13183
- const normalizedLeft = resolve6(left);
13184
- const normalizedRight = resolve6(right);
14198
+ const normalizedLeft = resolve7(left);
14199
+ const normalizedRight = resolve7(right);
13185
14200
  return process.platform === "win32" ? normalizedLeft.toLowerCase() === normalizedRight.toLowerCase() : normalizedLeft === normalizedRight;
13186
14201
  }
13187
14202
  function validEntry2(value) {
@@ -13483,7 +14498,7 @@ var FileImageReferenceStore = class {
13483
14498
  const ownedArtifact = ARTIFACT_FILE.test(name);
13484
14499
  const incomplete = /^artifact-[a-f0-9]{32}\.tmp$/u.test(name);
13485
14500
  if ((!ownedArtifact || referenced.has(name)) && !incomplete) continue;
13486
- const path2 = resolve6(root, name);
14501
+ const path2 = resolve7(root, name);
13487
14502
  let info;
13488
14503
  try {
13489
14504
  info = lstatSync4(path2);
@@ -13634,10 +14649,10 @@ var FileImageReferenceStore = class {
13634
14649
  async writeArtifact(asset, limits) {
13635
14650
  const root = this.#paths.verifiedRoot("artifacts");
13636
14651
  const suffix = this.#random(16).toString("hex");
13637
- const tempPath = join11(root, `artifact-${suffix}.tmp`);
14652
+ const tempPath = join12(root, `artifact-${suffix}.tmp`);
13638
14653
  const fileName = `artifact-${suffix}.bin`;
13639
- const finalPath = join11(root, fileName);
13640
- const handle = await open(tempPath, "wx", 384);
14654
+ const finalPath = join12(root, fileName);
14655
+ const handle = await open2(tempPath, "wx", 384);
13641
14656
  let reader;
13642
14657
  let observed = 0;
13643
14658
  let writeFailure;
@@ -13686,8 +14701,8 @@ var FileImageReferenceStore = class {
13686
14701
  artifactPath(fileName) {
13687
14702
  if (!ARTIFACT_FILE.test(fileName)) throw new TypeError("invalid image artifact filename");
13688
14703
  const root = this.#paths.verifiedRoot("artifacts");
13689
- const path2 = resolve6(root, fileName);
13690
- if (!samePath3(dirname8(path2), root) || basename3(path2) !== fileName) {
14704
+ const path2 = resolve7(root, fileName);
14705
+ if (!samePath3(dirname8(path2), root) || basename4(path2) !== fileName) {
13691
14706
  throw new TypeError("image artifact escaped its root");
13692
14707
  }
13693
14708
  return path2;
@@ -13710,12 +14725,12 @@ var FileImageReferenceStore = class {
13710
14725
  }
13711
14726
  safeUnlinkArtifactPath(path2) {
13712
14727
  const root = this.#paths.verifiedRoot("artifacts");
13713
- const target = resolve6(path2);
13714
- const name = basename3(target);
14728
+ const target = resolve7(path2);
14729
+ const name = basename4(target);
13715
14730
  if (!samePath3(dirname8(target), root) || !/^artifact-[a-f0-9]{32}\.(?:bin|tmp)$/u.test(name)) {
13716
14731
  throw new TypeError("refusing to unlink an unverified image artifact");
13717
14732
  }
13718
- if (!existsSync12(target)) return;
14733
+ if (!existsSync13(target)) return;
13719
14734
  const info = lstatSync4(target);
13720
14735
  if (info.isSymbolicLink() || !info.isFile()) throw new TypeError("refusing to unlink an unverified image artifact");
13721
14736
  unlinkSync6(target);
@@ -13737,7 +14752,7 @@ var FileImageReferenceStore = class {
13737
14752
  });
13738
14753
  }
13739
14754
  manifestPath() {
13740
- return join11(this.#paths.verifiedRoot("state"), MANIFEST_NAME2);
14755
+ return join12(this.#paths.verifiedRoot("state"), MANIFEST_NAME2);
13741
14756
  }
13742
14757
  persist(entries, tombstones) {
13743
14758
  const manifest = {
@@ -13753,10 +14768,10 @@ var FileImageReferenceStore = class {
13753
14768
  }
13754
14769
  atomicReplace(targetPath, contents) {
13755
14770
  const root = this.#paths.verifiedRoot("state");
13756
- if (!samePath3(dirname8(resolve6(targetPath)), root) || basename3(targetPath) !== MANIFEST_NAME2) {
14771
+ if (!samePath3(dirname8(resolve7(targetPath)), root) || basename4(targetPath) !== MANIFEST_NAME2) {
13757
14772
  throw new TypeError("invalid image reference manifest target");
13758
14773
  }
13759
- const temporaryPath = join11(root, `.references.${process.pid}.${this.#random(8).toString("hex")}.tmp`);
14774
+ const temporaryPath = join12(root, `.references.${process.pid}.${this.#random(8).toString("hex")}.tmp`);
13760
14775
  let fd;
13761
14776
  try {
13762
14777
  fd = openSync4(temporaryPath, "wx", 384);
@@ -13772,7 +14787,7 @@ var FileImageReferenceStore = class {
13772
14787
  } catch {
13773
14788
  }
13774
14789
  }
13775
- if (existsSync12(temporaryPath)) {
14790
+ if (existsSync13(temporaryPath)) {
13776
14791
  try {
13777
14792
  unlinkSync6(temporaryPath);
13778
14793
  } catch {
@@ -13782,7 +14797,7 @@ var FileImageReferenceStore = class {
13782
14797
  }
13783
14798
  loadManifest() {
13784
14799
  const path2 = this.manifestPath();
13785
- if (!existsSync12(path2)) return;
14800
+ if (!existsSync13(path2)) return;
13786
14801
  const info = lstatSync4(path2);
13787
14802
  if (info.isSymbolicLink() || !info.isFile() || info.size > MAX_MANIFEST_BYTES2) {
13788
14803
  throw new TypeError("image reference manifest is invalid");
@@ -13831,7 +14846,7 @@ var FileImageReferenceStore = class {
13831
14846
  import { randomBytes as randomBytes8 } from "crypto";
13832
14847
  import {
13833
14848
  closeSync as closeSync5,
13834
- existsSync as existsSync13,
14849
+ existsSync as existsSync14,
13835
14850
  fsyncSync as fsyncSync4,
13836
14851
  lstatSync as lstatSync5,
13837
14852
  openSync as openSync5,
@@ -13840,7 +14855,7 @@ import {
13840
14855
  unlinkSync as unlinkSync7,
13841
14856
  writeFileSync as writeFileSync10
13842
14857
  } from "fs";
13843
- import { basename as basename4, dirname as dirname9, join as join12, resolve as resolve7 } from "path";
14858
+ import { basename as basename5, dirname as dirname9, join as join13, resolve as resolve8 } from "path";
13844
14859
  import { ImageGenerationError as ImageGenerationError6 } from "@omnicross/core/image-generation";
13845
14860
  var MANIFEST_VERSION3 = 1;
13846
14861
  var MANIFEST_NAME3 = "responses-image-state.v1.json";
@@ -13893,8 +14908,8 @@ function validPendingReferenceDelete(value) {
13893
14908
  return exactKeys2(row, ["callId", "referenceTenantKey", "referenceId", "expiresAt"]) && typeof row.callId === "string" && CALL_ID_PATTERN.test(row.callId) && isImageTenantHmac(row.referenceTenantKey) && typeof row.referenceId === "string" && REFERENCE_ID_PATTERN.test(row.referenceId) && safeTimestamp2(row.expiresAt);
13894
14909
  }
13895
14910
  function samePath4(left, right) {
13896
- const normalizedLeft = resolve7(left);
13897
- const normalizedRight = resolve7(right);
14911
+ const normalizedLeft = resolve8(left);
14912
+ const normalizedRight = resolve8(right);
13898
14913
  return process.platform === "win32" ? normalizedLeft.toLowerCase() === normalizedRight.toLowerCase() : normalizedLeft === normalizedRight;
13899
14914
  }
13900
14915
  function sameBinding(left, right) {
@@ -14377,7 +15392,7 @@ var FileResponsesImageStateStore = class {
14377
15392
  });
14378
15393
  }
14379
15394
  manifestPath() {
14380
- return join12(this.#paths.verifiedRoot("state"), MANIFEST_NAME3);
15395
+ return join13(this.#paths.verifiedRoot("state"), MANIFEST_NAME3);
14381
15396
  }
14382
15397
  persist(calls, responses, tombstones, pendingReferenceDeletes) {
14383
15398
  const manifest = {
@@ -14397,10 +15412,10 @@ var FileResponsesImageStateStore = class {
14397
15412
  }
14398
15413
  atomicReplace(targetPath, contents) {
14399
15414
  const root = this.#paths.verifiedRoot("state");
14400
- if (!samePath4(dirname9(resolve7(targetPath)), root) || basename4(targetPath) !== MANIFEST_NAME3) {
15415
+ if (!samePath4(dirname9(resolve8(targetPath)), root) || basename5(targetPath) !== MANIFEST_NAME3) {
14401
15416
  throw new TypeError("invalid responses image state manifest target");
14402
15417
  }
14403
- const temporaryPath = join12(
15418
+ const temporaryPath = join13(
14404
15419
  root,
14405
15420
  `.responses-image-state.${process.pid}.${this.#random(8).toString("hex")}.tmp`
14406
15421
  );
@@ -14419,7 +15434,7 @@ var FileResponsesImageStateStore = class {
14419
15434
  } catch {
14420
15435
  }
14421
15436
  }
14422
- if (existsSync13(temporaryPath)) {
15437
+ if (existsSync14(temporaryPath)) {
14423
15438
  try {
14424
15439
  unlinkSync7(temporaryPath);
14425
15440
  } catch {
@@ -14429,7 +15444,7 @@ var FileResponsesImageStateStore = class {
14429
15444
  }
14430
15445
  loadManifest() {
14431
15446
  const path2 = this.manifestPath();
14432
- if (!existsSync13(path2)) return;
15447
+ if (!existsSync14(path2)) return;
14433
15448
  const info = lstatSync5(path2);
14434
15449
  if (info.isSymbolicLink() || !info.isFile() || info.size > MAX_MANIFEST_BYTES3) {
14435
15450
  throw new TypeError("responses image state manifest is invalid");
@@ -14523,8 +15538,8 @@ function validMount(value) {
14523
15538
  return exactKeys3(row, ["id", "durableRoot", "createdAt"]) && typeof row.id === "string" && MOUNT_ID_PATTERN.test(row.id) && typeof row.durableRoot === "string" && isAbsolute2(row.durableRoot) && safeInteger2(row.createdAt);
14524
15539
  }
14525
15540
  function samePath5(left, right) {
14526
- const normalizedLeft = resolve8(left);
14527
- const normalizedRight = resolve8(right);
15541
+ const normalizedLeft = resolve9(left);
15542
+ const normalizedRight = resolve9(right);
14528
15543
  return process.platform === "win32" ? normalizedLeft.toLowerCase() === normalizedRight.toLowerCase() : normalizedLeft === normalizedRight;
14529
15544
  }
14530
15545
  var ImageStorageMountCatalog = class {
@@ -14552,7 +15567,7 @@ var ImageStorageMountCatalog = class {
14552
15567
  this.#catalogResolver = this.createResolver(options.activeStorageRoot);
14553
15568
  this.#reconcileCorruptManifests = options.reconcileCorruptManifests ?? false;
14554
15569
  this.#replaceCatalog = options.replaceCatalog ?? ((target, contents) => this.atomicReplace(target, contents));
14555
- if (existsSync14(this.catalogPath())) {
15570
+ if (existsSync15(this.catalogPath())) {
14556
15571
  try {
14557
15572
  this.loadCatalog();
14558
15573
  } catch (error) {
@@ -14804,15 +15819,15 @@ var ImageStorageMountCatalog = class {
14804
15819
  }
14805
15820
  quarantineManifest(resolver, area, name, label) {
14806
15821
  const root = resolver.verifiedRoot(area);
14807
- const source = join13(root, name);
14808
- if (!existsSync14(source)) throw new TypeError("corrupt image manifest is missing");
15822
+ const source = join14(root, name);
15823
+ if (!existsSync15(source)) throw new TypeError("corrupt image manifest is missing");
14809
15824
  const info = lstatSync6(source);
14810
15825
  if (info.isSymbolicLink() || !info.isFile()) {
14811
15826
  throw new TypeError("refusing to quarantine an unverified image manifest");
14812
15827
  }
14813
15828
  for (let attempt = 0; attempt < 8; attempt += 1) {
14814
- const target = join13(root, `.corrupt-${label}-${this.#random(8).toString("hex")}.json`);
14815
- if (existsSync14(target)) continue;
15829
+ const target = join14(root, `.corrupt-${label}-${this.#random(8).toString("hex")}.json`);
15830
+ if (existsSync15(target)) continue;
14816
15831
  resolver.verifiedRoot(area);
14817
15832
  renameSync7(source, target);
14818
15833
  this.#corruptManifestsQuarantined += 1;
@@ -14857,10 +15872,10 @@ var ImageStorageMountCatalog = class {
14857
15872
  }
14858
15873
  atomicReplace(targetPath, contents) {
14859
15874
  const root = this.#catalogResolver.verifiedRoot("mountManifest");
14860
- if (!samePath5(dirname10(resolve8(targetPath)), root) || basename5(targetPath) !== CATALOG_NAME) {
15875
+ if (!samePath5(dirname10(resolve9(targetPath)), root) || basename6(targetPath) !== CATALOG_NAME) {
14861
15876
  throw new TypeError("invalid image storage mount catalog target");
14862
15877
  }
14863
- const temporaryPath = join13(
15878
+ const temporaryPath = join14(
14864
15879
  root,
14865
15880
  `.catalog.${process.pid}.${this.#random(8).toString("hex")}.tmp`
14866
15881
  );
@@ -14879,7 +15894,7 @@ var ImageStorageMountCatalog = class {
14879
15894
  } catch {
14880
15895
  }
14881
15896
  }
14882
- if (existsSync14(temporaryPath)) {
15897
+ if (existsSync15(temporaryPath)) {
14883
15898
  try {
14884
15899
  unlinkSync8(temporaryPath);
14885
15900
  } catch {
@@ -15101,12 +16116,12 @@ function positiveInteger4(value, name) {
15101
16116
  return value;
15102
16117
  }
15103
16118
  function samePath6(left, right) {
15104
- const normalizedLeft = resolve9(left);
15105
- const normalizedRight = resolve9(right);
16119
+ const normalizedLeft = resolve10(left);
16120
+ const normalizedRight = resolve10(right);
15106
16121
  return process.platform === "win32" ? normalizedLeft.toLowerCase() === normalizedRight.toLowerCase() : normalizedLeft === normalizedRight;
15107
16122
  }
15108
16123
  function isDirectChild(path2, root) {
15109
- const target = resolve9(path2);
16124
+ const target = resolve10(path2);
15110
16125
  const rel = relative2(root, target);
15111
16126
  return !samePath6(target, root) && !isAbsolute3(rel) && !rel.startsWith("..") && samePath6(dirname11(target), root);
15112
16127
  }
@@ -15228,8 +16243,8 @@ var ImageStartupReconciler = class {
15228
16243
  let removed = 0;
15229
16244
  let invalid = 0;
15230
16245
  for (const name of readdirSync6(root).filter((value) => pattern.test(value)).slice(0, limit)) {
15231
- const path2 = resolve9(root, name);
15232
- if (!isDirectChild(path2, root) || basename6(path2) !== name) {
16246
+ const path2 = resolve10(root, name);
16247
+ if (!isDirectChild(path2, root) || basename7(path2) !== name) {
15233
16248
  invalid += 1;
15234
16249
  continue;
15235
16250
  }
@@ -15251,7 +16266,7 @@ var ImageStartupReconciler = class {
15251
16266
  let invalid = 0;
15252
16267
  let active = 0;
15253
16268
  for (const name of readdirSync6(root).slice(0, this.#maxTemporaryDirectoriesPerPass)) {
15254
- const path2 = resolve9(root, name);
16269
+ const path2 = resolve10(root, name);
15255
16270
  if (!OWNED_TEMPORARY_DIRECTORY.test(name) || !isDirectChild(path2, root)) {
15256
16271
  foreign += 1;
15257
16272
  continue;
@@ -15266,8 +16281,8 @@ var ImageStartupReconciler = class {
15266
16281
  active += 1;
15267
16282
  continue;
15268
16283
  }
15269
- const markerPath = resolve9(path2, IMAGE_REQUEST_DIRECTORY_MARKER_NAME);
15270
- if (!isDirectChild(markerPath, path2) || !existsSync15(markerPath)) {
16284
+ const markerPath = resolve10(path2, IMAGE_REQUEST_DIRECTORY_MARKER_NAME);
16285
+ if (!isDirectChild(markerPath, path2) || !existsSync16(markerPath)) {
15271
16286
  foreign += 1;
15272
16287
  continue;
15273
16288
  }
@@ -15299,7 +16314,7 @@ var ImageStartupReconciler = class {
15299
16314
  throw new TypeError("refusing to remove an unsupported temporary descendant");
15300
16315
  }
15301
16316
  for (const name of readdirSync6(path2)) {
15302
- this.removeTreeWithoutFollowingSymlinks(resolve9(path2, name), path2);
16317
+ this.removeTreeWithoutFollowingSymlinks(resolve10(path2, name), path2);
15303
16318
  }
15304
16319
  rmdirSync2(path2);
15305
16320
  }
@@ -15768,8 +16783,8 @@ function createHostedImageContributionFactory(manager) {
15768
16783
  function deferredRecord(generation, phase) {
15769
16784
  let resolveDisposed;
15770
16785
  let rejectDisposed;
15771
- const disposed = new Promise((resolve11, reject) => {
15772
- resolveDisposed = resolve11;
16786
+ const disposed = new Promise((resolve12, reject) => {
16787
+ resolveDisposed = resolve12;
15773
16788
  rejectDisposed = reject;
15774
16789
  });
15775
16790
  void disposed.catch(() => void 0);
@@ -16348,7 +17363,7 @@ function toLLMProvider(row) {
16348
17363
  // src/ports/ConfigurableLogger.ts
16349
17364
  import {
16350
17365
  createWriteStream,
16351
- existsSync as existsSync16,
17366
+ existsSync as existsSync17,
16352
17367
  renameSync as renameSync8,
16353
17368
  statSync as statSync6,
16354
17369
  unlinkSync as unlinkSync10
@@ -16400,7 +17415,7 @@ var ConfigurableLogger = class {
16400
17415
  this.fileStream = null;
16401
17416
  this.rotateQueue = [];
16402
17417
  if (!stream) return Promise.resolve();
16403
- return new Promise((resolve11) => stream.end(() => resolve11()));
17418
+ return new Promise((resolve12) => stream.end(() => resolve12()));
16404
17419
  }
16405
17420
  emit(level, message, error, meta) {
16406
17421
  if (LEVEL_ORDER[level] > this.threshold) return;
@@ -16482,12 +17497,12 @@ var ConfigurableLogger = class {
16482
17497
  /** `<file>.N` unlinked, `<file>.k` → `<file>.k+1`, `<file>` → `<file>.1`. */
16483
17498
  shiftGenerations(path2) {
16484
17499
  const oldest = `${path2}.${this.maxFiles}`;
16485
- if (existsSync16(oldest)) unlinkSync10(oldest);
17500
+ if (existsSync17(oldest)) unlinkSync10(oldest);
16486
17501
  for (let i = this.maxFiles - 1; i >= 1; i--) {
16487
17502
  const from = `${path2}.${i}`;
16488
- if (existsSync16(from)) renameSync8(from, `${path2}.${i + 1}`);
17503
+ if (existsSync17(from)) renameSync8(from, `${path2}.${i + 1}`);
16489
17504
  }
16490
- if (existsSync16(path2)) renameSync8(path2, `${path2}.1`);
17505
+ if (existsSync17(path2)) renameSync8(path2, `${path2}.1`);
16491
17506
  }
16492
17507
  /**
16493
17508
  * Lazily open the append-only file stream; disable the sink on any error. The
@@ -16498,7 +17513,7 @@ var ConfigurableLogger = class {
16498
17513
  if (this.fileDisabled || !this.filePath) return null;
16499
17514
  if (this.fileStream) return this.fileStream;
16500
17515
  try {
16501
- this.fileBytes = existsSync16(this.filePath) ? statSync6(this.filePath).size : 0;
17516
+ this.fileBytes = existsSync17(this.filePath) ? statSync6(this.filePath).size : 0;
16502
17517
  const stream = createWriteStream(this.filePath, { flags: "a" });
16503
17518
  stream.on("error", () => {
16504
17519
  this.fileDisabled = true;
@@ -16571,7 +17586,7 @@ function safeStringify(value) {
16571
17586
  import { randomBytes as randomBytes10 } from "crypto";
16572
17587
  import {
16573
17588
  closeSync as closeSync7,
16574
- existsSync as existsSync17,
17589
+ existsSync as existsSync18,
16575
17590
  fsyncSync as fsyncSync6,
16576
17591
  openSync as openSync7,
16577
17592
  readFileSync as readFileSync14,
@@ -16579,12 +17594,12 @@ import {
16579
17594
  unlinkSync as unlinkSync11,
16580
17595
  writeFileSync as writeFileSync12
16581
17596
  } from "fs";
16582
- import { basename as basename7, dirname as dirname12, join as join14 } from "path";
17597
+ import { basename as basename8, dirname as dirname12, join as join15 } from "path";
16583
17598
  import { OUTBOUND_API_SERVER_CONFIG_KEY } from "@omnicross/core/outbound-api";
16584
17599
  function atomicReplaceDocument(targetPath, contents) {
16585
- const tempPath = join14(
17600
+ const tempPath = join15(
16586
17601
  dirname12(targetPath),
16587
- `.${basename7(targetPath)}.${process.pid}.${randomBytes10(8).toString("hex")}.tmp`
17602
+ `.${basename8(targetPath)}.${process.pid}.${randomBytes10(8).toString("hex")}.tmp`
16588
17603
  );
16589
17604
  let fd;
16590
17605
  try {
@@ -16601,7 +17616,7 @@ function atomicReplaceDocument(targetPath, contents) {
16601
17616
  } catch {
16602
17617
  }
16603
17618
  }
16604
- if (existsSync17(tempPath)) {
17619
+ if (existsSync18(tempPath)) {
16605
17620
  try {
16606
17621
  unlinkSync11(tempPath);
16607
17622
  } catch {
@@ -16644,13 +17659,13 @@ var JsonApiServerSettingsStore = class {
16644
17659
  }
16645
17660
  /** Capture the exact prior document for an admin transaction rollback. */
16646
17661
  captureDocumentSnapshot() {
16647
- if (!existsSync17(this.configPath)) return { existed: false };
17662
+ if (!existsSync18(this.configPath)) return { existed: false };
16648
17663
  return { existed: true, bytes: readFileSync14(this.configPath) };
16649
17664
  }
16650
17665
  /** Restore exact prior bytes (including unrelated fields and encrypted secrets). */
16651
17666
  restoreDocumentSnapshot(snapshot) {
16652
17667
  if (!snapshot.existed) {
16653
- if (existsSync17(this.configPath)) unlinkSync11(this.configPath);
17668
+ if (existsSync18(this.configPath)) unlinkSync11(this.configPath);
16654
17669
  return;
16655
17670
  }
16656
17671
  if (!snapshot.bytes) throw new TypeError("settings snapshot is missing prior bytes");
@@ -16687,13 +17702,13 @@ var JsonApiServerSettingsStore = class {
16687
17702
  };
16688
17703
 
16689
17704
  // src/ports/JsonlUsageEventStore.ts
16690
- import { randomUUID as randomUUID4 } from "crypto";
17705
+ import { randomUUID as randomUUID5 } from "crypto";
16691
17706
  import { appendFileSync, mkdirSync as mkdirSync5 } from "fs";
16692
- import { join as join18 } from "path";
17707
+ import { join as join19 } from "path";
16693
17708
 
16694
17709
  // src/usage/usageFiles.ts
16695
- import { readdir } from "fs/promises";
16696
- import { dirname as dirname13, join as join15 } from "path";
17710
+ import { readdir as readdir2 } from "fs/promises";
17711
+ import { dirname as dirname13, join as join16 } from "path";
16697
17712
  var USAGE_DIR_NAME = "usage";
16698
17713
  var USAGE_SHARD_RE = /^usage-(\d{4})-(\d{2})-(\d{2})\.jsonl$/;
16699
17714
  var USAGE_ROLLUP_RE = /^usage-(\d{4})-(\d{2})-(\d{2})\.rollup\.json$/;
@@ -16710,7 +17725,7 @@ function usageRollupName(dayKey) {
16710
17725
  return `usage-${dayKey}.rollup.json`;
16711
17726
  }
16712
17727
  function usageDirFor(eventsPath) {
16713
- return join15(dirname13(eventsPath), USAGE_DIR_NAME);
17728
+ return join16(dirname13(eventsPath), USAGE_DIR_NAME);
16714
17729
  }
16715
17730
  function dayKeyStartTs(dayKey) {
16716
17731
  const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(dayKey);
@@ -16731,7 +17746,7 @@ function dayKeyEndTs(dayKey) {
16731
17746
  async function listUsageDays(usageDir) {
16732
17747
  let names;
16733
17748
  try {
16734
- names = await readdir(usageDir);
17749
+ names = await readdir2(usageDir);
16735
17750
  } catch {
16736
17751
  return [];
16737
17752
  }
@@ -16971,12 +17986,12 @@ function isUsageDayRollup(parsed) {
16971
17986
  }
16972
17987
 
16973
17988
  // src/usage/usageRollupStore.ts
16974
- import { mkdir, readFile as readFile2, rename, unlink, writeFile } from "fs/promises";
16975
- import { join as join17 } from "path";
17989
+ import { mkdir, readFile as readFile3, rename as rename2, unlink as unlink2, writeFile as writeFile2 } from "fs/promises";
17990
+ import { join as join18 } from "path";
16976
17991
 
16977
17992
  // src/usage/usageShardCache.ts
16978
- import { open as open2 } from "fs/promises";
16979
- import { join as join16 } from "path";
17993
+ import { open as open3 } from "fs/promises";
17994
+ import { join as join17 } from "path";
16980
17995
 
16981
17996
  // src/usage/usageRow.ts
16982
17997
  var NUMERIC_FIELDS = [
@@ -17036,10 +18051,10 @@ var NEWLINE2 = 10;
17036
18051
  var READ_CHUNK_BYTES = 8 * 1024 * 1024;
17037
18052
  var DEFAULT_MAX_RESIDENT_DAYS = 3;
17038
18053
  async function streamShardRows(usageDir, dayKey, onRow) {
17039
- const path2 = join16(usageDir, usageShardName(dayKey));
18054
+ const path2 = join17(usageDir, usageShardName(dayKey));
17040
18055
  let handle;
17041
18056
  try {
17042
- handle = await open2(path2, "r");
18057
+ handle = await open3(path2, "r");
17043
18058
  } catch {
17044
18059
  return;
17045
18060
  }
@@ -17069,7 +18084,7 @@ async function streamShardRows(usageDir, dayKey, onRow) {
17069
18084
  async function shardSize(usageDir, dayKey) {
17070
18085
  let handle;
17071
18086
  try {
17072
- handle = await open2(join16(usageDir, usageShardName(dayKey)), "r");
18087
+ handle = await open3(join17(usageDir, usageShardName(dayKey)), "r");
17073
18088
  } catch {
17074
18089
  return null;
17075
18090
  }
@@ -17125,10 +18140,10 @@ var UsageShardCache = class {
17125
18140
  } else {
17126
18141
  this.touch(dayKey);
17127
18142
  }
17128
- const path2 = join16(this.usageDir, usageShardName(dayKey));
18143
+ const path2 = join17(this.usageDir, usageShardName(dayKey));
17129
18144
  let handle;
17130
18145
  try {
17131
- handle = await open2(path2, "r");
18146
+ handle = await open3(path2, "r");
17132
18147
  } catch {
17133
18148
  return entry;
17134
18149
  }
@@ -17247,7 +18262,7 @@ var UsageRollupStore = class {
17247
18262
  }
17248
18263
  async readSidecar(dayKey) {
17249
18264
  try {
17250
- const raw = await readFile2(join17(this.usageDir, usageRollupName(dayKey)), "utf8");
18265
+ const raw = await readFile3(join18(this.usageDir, usageRollupName(dayKey)), "utf8");
17251
18266
  const parsed = JSON.parse(raw);
17252
18267
  return isUsageDayRollup(parsed) && parsed.date === dayKey ? parsed : null;
17253
18268
  } catch {
@@ -17255,14 +18270,14 @@ var UsageRollupStore = class {
17255
18270
  }
17256
18271
  }
17257
18272
  async writeSidecar(dayKey, rollup) {
17258
- const target = join17(this.usageDir, usageRollupName(dayKey));
18273
+ const target = join18(this.usageDir, usageRollupName(dayKey));
17259
18274
  const temp = `${target}.tmp`;
17260
18275
  try {
17261
18276
  await mkdir(this.usageDir, { recursive: true });
17262
- await writeFile(temp, JSON.stringify(rollup), "utf8");
17263
- await rename(temp, target);
18277
+ await writeFile2(temp, JSON.stringify(rollup), "utf8");
18278
+ await rename2(temp, target);
17264
18279
  } catch {
17265
- await unlink(temp).catch(() => {
18280
+ await unlink2(temp).catch(() => {
17266
18281
  });
17267
18282
  }
17268
18283
  }
@@ -17337,13 +18352,13 @@ var JsonlUsageEventStore = class {
17337
18352
  async insert(input) {
17338
18353
  const row = {
17339
18354
  ...input,
17340
- id: randomUUID4(),
18355
+ id: randomUUID5(),
17341
18356
  ts: input.ts ?? Date.now()
17342
18357
  };
17343
18358
  const dayKey = usageDayKey(row.ts);
17344
18359
  this.ensureDir();
17345
18360
  const line = JSON.stringify(row) + "\n";
17346
- appendFileSync(join18(this.usageDir, usageShardName(dayKey)), line, "utf8");
18361
+ appendFileSync(join19(this.usageDir, usageShardName(dayKey)), line, "utf8");
17347
18362
  if (dayKey !== this.lastAppendDay) {
17348
18363
  this.rollups.invalidate(dayKey);
17349
18364
  this.lastAppendDay = dayKey;
@@ -17718,7 +18733,7 @@ function bucketLabel(bucketStartTs, bucket) {
17718
18733
  }
17719
18734
 
17720
18735
  // src/ports/JsonOutboundKeyDb.ts
17721
- import { existsSync as existsSync19, readFileSync as readFileSync15 } from "fs";
18736
+ import { existsSync as existsSync20, readFileSync as readFileSync15 } from "fs";
17722
18737
  import {
17723
18738
  validateOutboundPermissions as validateOutboundPermissions3
17724
18739
  } from "@omnicross/core";
@@ -17727,18 +18742,18 @@ import {
17727
18742
  import { randomBytes as randomBytes11 } from "crypto";
17728
18743
  import {
17729
18744
  closeSync as closeSync8,
17730
- existsSync as existsSync18,
18745
+ existsSync as existsSync19,
17731
18746
  fsyncSync as fsyncSync7,
17732
18747
  openSync as openSync8,
17733
18748
  renameSync as renameSync10,
17734
18749
  unlinkSync as unlinkSync12,
17735
18750
  writeFileSync as writeFileSync13
17736
18751
  } from "fs";
17737
- import { basename as basename8, dirname as dirname14, join as join19 } from "path";
18752
+ import { basename as basename9, dirname as dirname14, join as join20 } from "path";
17738
18753
  function atomicReplaceUtf8(targetPath, contents) {
17739
- const tempPath = join19(
18754
+ const tempPath = join20(
17740
18755
  dirname14(targetPath),
17741
- `.${basename8(targetPath)}.${process.pid}.${randomBytes11(8).toString("hex")}.tmp`
18756
+ `.${basename9(targetPath)}.${process.pid}.${randomBytes11(8).toString("hex")}.tmp`
17742
18757
  );
17743
18758
  let fd;
17744
18759
  try {
@@ -17755,7 +18770,7 @@ function atomicReplaceUtf8(targetPath, contents) {
17755
18770
  } catch {
17756
18771
  }
17757
18772
  }
17758
- if (existsSync18(tempPath)) {
18773
+ if (existsSync19(tempPath)) {
17759
18774
  try {
17760
18775
  unlinkSync12(tempPath);
17761
18776
  } catch {
@@ -17866,6 +18881,19 @@ var JsonOutboundKeyDb = class {
17866
18881
  return true;
17867
18882
  });
17868
18883
  }
18884
+ async outboundApiKeysSetUpstream(id, target) {
18885
+ return this.mutateRow(id, (row) => {
18886
+ if (row.revokedAt !== null) return false;
18887
+ if (target === null) {
18888
+ delete row.boundUpstream;
18889
+ delete row.boundUpstreamProviderId;
18890
+ } else {
18891
+ row.boundUpstream = target;
18892
+ delete row.boundUpstreamProviderId;
18893
+ }
18894
+ return true;
18895
+ });
18896
+ }
17869
18897
  async outboundApiKeysSetPolicy(id, policy) {
17870
18898
  return this.mutateRow(id, (row) => {
17871
18899
  if (row.revokedAt !== null) return false;
@@ -17908,7 +18936,7 @@ var JsonOutboundKeyDb = class {
17908
18936
  }
17909
18937
  /** Read the key rows, tolerating a missing/corrupt file (→ empty list). */
17910
18938
  readRows() {
17911
- if (!existsSync19(this.keysPath)) return [];
18939
+ if (!existsSync20(this.keysPath)) return [];
17912
18940
  try {
17913
18941
  const parsed = JSON.parse(readFileSync15(this.keysPath, "utf8"));
17914
18942
  return Array.isArray(parsed) ? parsed : [];
@@ -17927,8 +18955,8 @@ function applyPolicyField(row, field, value) {
17927
18955
  }
17928
18956
 
17929
18957
  // src/ports/JsonPricingStore.ts
17930
- import { existsSync as existsSync20, readFileSync as readFileSync16, renameSync as renameSync11, rmSync as rmSync3, writeFileSync as writeFileSync14 } from "fs";
17931
- import { randomUUID as randomUUID5 } from "crypto";
18958
+ import { existsSync as existsSync21, readFileSync as readFileSync16, renameSync as renameSync11, rmSync as rmSync3, writeFileSync as writeFileSync14 } from "fs";
18959
+ import { randomUUID as randomUUID6 } from "crypto";
17932
18960
  var JsonPricingStore = class {
17933
18961
  constructor(pricingPath) {
17934
18962
  this.pricingPath = pricingPath;
@@ -17942,7 +18970,7 @@ var JsonPricingStore = class {
17942
18970
  * otherwise unusable pricing table after a crash or manual file edit.
17943
18971
  */
17944
18972
  hasUsableSnapshot() {
17945
- if (!existsSync20(this.pricingPath)) return false;
18973
+ if (!existsSync21(this.pricingPath)) return false;
17946
18974
  try {
17947
18975
  const parsed = JSON.parse(readFileSync16(this.pricingPath, "utf8"));
17948
18976
  return Array.isArray(parsed) && parsed.some(isUsablePricingRow);
@@ -18057,7 +19085,7 @@ var JsonPricingStore = class {
18057
19085
  }
18058
19086
  /** Read the pricing rows, tolerating a missing/corrupt file (→ empty list). */
18059
19087
  readRows() {
18060
- if (!existsSync20(this.pricingPath)) return [];
19088
+ if (!existsSync21(this.pricingPath)) return [];
18061
19089
  try {
18062
19090
  const parsed = JSON.parse(readFileSync16(this.pricingPath, "utf8"));
18063
19091
  return Array.isArray(parsed) ? parsed : [];
@@ -18066,7 +19094,7 @@ var JsonPricingStore = class {
18066
19094
  }
18067
19095
  }
18068
19096
  writeRows(rows) {
18069
- const temporaryPath = `${this.pricingPath}.${process.pid}.${randomUUID5()}.tmp`;
19097
+ const temporaryPath = `${this.pricingPath}.${process.pid}.${randomUUID6()}.tmp`;
18070
19098
  try {
18071
19099
  writeFileSync14(temporaryPath, JSON.stringify(rows, null, 2) + "\n", {
18072
19100
  encoding: "utf8",
@@ -18089,7 +19117,7 @@ function isUsablePricingRow(value) {
18089
19117
  }
18090
19118
 
18091
19119
  // src/pricing/PricingRefreshScheduler.ts
18092
- import { existsSync as existsSync21, readFileSync as readFileSync17, renameSync as renameSync12, writeFileSync as writeFileSync15 } from "fs";
19120
+ import { existsSync as existsSync22, readFileSync as readFileSync17, renameSync as renameSync12, writeFileSync as writeFileSync15 } from "fs";
18093
19121
  var EMPTY_STATE2 = {
18094
19122
  lastAttemptAt: null,
18095
19123
  lastSuccessAt: null,
@@ -18127,7 +19155,7 @@ var PricingRefreshScheduler = class {
18127
19155
  this.timer = null;
18128
19156
  }
18129
19157
  getState() {
18130
- if (!existsSync21(this.statePath)) return { ...EMPTY_STATE2, sources: [] };
19158
+ if (!existsSync22(this.statePath)) return { ...EMPTY_STATE2, sources: [] };
18131
19159
  try {
18132
19160
  const value = JSON.parse(readFileSync17(this.statePath, "utf8"));
18133
19161
  return {
@@ -18192,7 +19220,7 @@ function finiteOrNull(value) {
18192
19220
  }
18193
19221
 
18194
19222
  // src/ports/JsonVoucherDb.ts
18195
- import { existsSync as existsSync22, readFileSync as readFileSync18, writeFileSync as writeFileSync16 } from "fs";
19223
+ import { existsSync as existsSync23, readFileSync as readFileSync18, writeFileSync as writeFileSync16 } from "fs";
18196
19224
  var JsonVoucherDb = class {
18197
19225
  constructor(vouchersPath) {
18198
19226
  this.vouchersPath = vouchersPath;
@@ -18270,7 +19298,7 @@ var JsonVoucherDb = class {
18270
19298
  }
18271
19299
  /** Read the voucher rows, tolerating a missing/corrupt file (→ empty list). */
18272
19300
  readRows() {
18273
- if (!existsSync22(this.vouchersPath)) return [];
19301
+ if (!existsSync23(this.vouchersPath)) return [];
18274
19302
  try {
18275
19303
  const parsed = JSON.parse(readFileSync18(this.vouchersPath, "utf8"));
18276
19304
  return Array.isArray(parsed) ? parsed : [];
@@ -18284,7 +19312,7 @@ var JsonVoucherDb = class {
18284
19312
  };
18285
19313
 
18286
19314
  // src/ports/JsonSubscriptionCredentialStore.ts
18287
- import { existsSync as existsSync24, mkdirSync as mkdirSync6, readFileSync as readFileSync20, renameSync as renameSync13 } from "fs";
19315
+ import { existsSync as existsSync25, mkdirSync as mkdirSync6, readFileSync as readFileSync20, renameSync as renameSync13 } from "fs";
18288
19316
  import { dirname as dirname15 } from "path";
18289
19317
  import { getAntigravityProjectResolver as getAntigravityProjectResolver2 } from "@omnicross/core/auth/GeminiCodeAssistProjectResolver";
18290
19318
  import { getSharedAccountHealth as getSharedAccountHealth2 } from "@omnicross/core/pipeline/SubscriptionAccountHealth";
@@ -18342,11 +19370,11 @@ function findDuplicateCredentialIds(accounts) {
18342
19370
  }
18343
19371
 
18344
19372
  // src/ports/external-cli-credentials.ts
18345
- import { existsSync as existsSync23, readFileSync as readFileSync19 } from "fs";
18346
- import { homedir as homedir4 } from "os";
18347
- import { join as join20 } from "path";
18348
- function externalStorePath(provider, home = homedir4()) {
18349
- return provider === "claude" ? join20(home, ".claude", ".credentials.json") : join20(home, ".codex", "auth.json");
19373
+ import { existsSync as existsSync24, readFileSync as readFileSync19 } from "fs";
19374
+ import { homedir as homedir5 } from "os";
19375
+ import { join as join21 } from "path";
19376
+ function externalStorePath(provider, home = homedir5()) {
19377
+ return provider === "claude" ? join21(home, ".claude", ".credentials.json") : join21(home, ".codex", "auth.json");
18350
19378
  }
18351
19379
  function decodeJwtExpiryMs(token) {
18352
19380
  try {
@@ -18393,9 +19421,9 @@ function parseCodexTokensEnvelope(raw) {
18393
19421
  }
18394
19422
  return parsed;
18395
19423
  }
18396
- function readExternalCliCredentials(provider, home = homedir4()) {
19424
+ function readExternalCliCredentials(provider, home = homedir5()) {
18397
19425
  const path2 = externalStorePath(provider, home);
18398
- if (!existsSync23(path2)) return null;
19426
+ if (!existsSync24(path2)) return null;
18399
19427
  let raw;
18400
19428
  try {
18401
19429
  const parsed = JSON.parse(readFileSync19(path2, "utf8"));
@@ -19202,7 +20230,7 @@ var JsonSubscriptionCredentialStore = class {
19202
20230
  * its parse try.
19203
20231
  */
19204
20232
  readConfig() {
19205
- if (!existsSync24(this.tokensPath)) return { updatedAt: "" };
20233
+ if (!existsSync25(this.tokensPath)) return { updatedAt: "" };
19206
20234
  let parsed;
19207
20235
  try {
19208
20236
  const raw = JSON.parse(readFileSync20(this.tokensPath, "utf8"));
@@ -19779,21 +20807,21 @@ var AccountHealthSweeper = class {
19779
20807
  };
19780
20808
 
19781
20809
  // src/audit/AuditPruneSweeper.ts
19782
- import { createReadStream as createReadStream3, createWriteStream as createWriteStream2, existsSync as existsSync26, readdirSync as readdirSync8, rmSync as rmSync4, unlinkSync as unlinkSync13 } from "fs";
19783
- import { join as join22 } from "path";
20810
+ import { createReadStream as createReadStream3, createWriteStream as createWriteStream2, existsSync as existsSync27, readdirSync as readdirSync8, rmSync as rmSync4, unlinkSync as unlinkSync13 } from "fs";
20811
+ import { join as join23 } from "path";
19784
20812
  import { pipeline } from "stream/promises";
19785
20813
  import { createGzip } from "zlib";
19786
20814
 
19787
20815
  // src/audit/auditStats.ts
19788
20816
  import {
19789
20817
  createReadStream as createReadStream2,
19790
- existsSync as existsSync25,
20818
+ existsSync as existsSync26,
19791
20819
  readFileSync as readFileSync21,
19792
20820
  readdirSync as readdirSync7,
19793
20821
  statSync as statSync7,
19794
20822
  writeFileSync as writeFileSync17
19795
20823
  } from "fs";
19796
- import { basename as basename9, dirname as dirname16, join as join21 } from "path";
20824
+ import { basename as basename10, dirname as dirname16, join as join22 } from "path";
19797
20825
  var SIDECAR_VERSION = 1;
19798
20826
  var META_PREFIX_BYTES = 64 * 1024;
19799
20827
  var READ_CHUNK_BYTES2 = 4 * 1024 * 1024;
@@ -19801,7 +20829,7 @@ function auditStatsFileName(auditFile) {
19801
20829
  return auditFile.replace(/\.jsonl$/, ".stats.json");
19802
20830
  }
19803
20831
  function readPersisted(path2) {
19804
- if (!existsSync25(path2)) return null;
20832
+ if (!existsSync26(path2)) return null;
19805
20833
  try {
19806
20834
  const value = JSON.parse(readFileSync21(path2, "utf8"));
19807
20835
  if (value.version !== SIDECAR_VERSION || !Number.isSafeInteger(value.auditBytes) || (value.auditBytes ?? -1) < 0 || !Number.isSafeInteger(value.requestCount) || (value.requestCount ?? -1) < 0 || !Number.isSafeInteger(value.errorCount) || (value.errorCount ?? -1) < 0 || (value.errorCount ?? 0) > (value.requestCount ?? -1) || typeof value.complete !== "boolean" || value.minTs !== null && !Number.isFinite(value.minTs) || value.maxTs !== null && !Number.isFinite(value.maxTs)) {
@@ -19813,7 +20841,7 @@ function readPersisted(path2) {
19813
20841
  }
19814
20842
  }
19815
20843
  function updateAuditStatsAfterAppend(auditPath, auditBytesBefore, auditBytesAfter, record) {
19816
- const statsPath = join21(dirname16(auditPath), auditStatsFileName(basename9(auditPath)));
20844
+ const statsPath = join22(dirname16(auditPath), auditStatsFileName(basename10(auditPath)));
19817
20845
  const previous = auditBytesBefore === 0 ? {
19818
20846
  version: SIDECAR_VERSION,
19819
20847
  auditBytes: 0,
@@ -19944,20 +20972,20 @@ function mergePersistedStats(previous, appended) {
19944
20972
  };
19945
20973
  }
19946
20974
  async function readAuditStats(auditDir, query2 = {}) {
19947
- if (!existsSync25(auditDir)) return { requestCount: 0, errorCount: 0, complete: true };
20975
+ if (!existsSync26(auditDir)) return { requestCount: 0, errorCount: 0, complete: true };
19948
20976
  const from = typeof query2.from === "number" ? query2.from : -Infinity;
19949
20977
  const to = typeof query2.to === "number" ? query2.to : Infinity;
19950
20978
  let sources;
19951
20979
  try {
19952
20980
  sources = readdirSync7(auditDir).filter((name) => fileOverlaps(name, from, to)).sort().map(
19953
20981
  (name) => AUDIT_DAY_DIR_RE.test(name) ? {
19954
- auditPath: join21(auditDir, name, AUDIT_META_FILE),
19955
- statsPath: join21(auditDir, name, auditStatsFileName(AUDIT_META_FILE))
20982
+ auditPath: join22(auditDir, name, AUDIT_META_FILE),
20983
+ statsPath: join22(auditDir, name, auditStatsFileName(AUDIT_META_FILE))
19956
20984
  } : {
19957
- auditPath: join21(auditDir, name),
19958
- statsPath: join21(auditDir, auditStatsFileName(name))
20985
+ auditPath: join22(auditDir, name),
20986
+ statsPath: join22(auditDir, auditStatsFileName(name))
19959
20987
  }
19960
- ).filter((source) => existsSync25(source.auditPath));
20988
+ ).filter((source) => existsSync26(source.auditPath));
19961
20989
  } catch {
19962
20990
  return { requestCount: 0, errorCount: 0, complete: false };
19963
20991
  }
@@ -20055,7 +21083,7 @@ var AuditPruneSweeper = class {
20055
21083
  if (!this.config.enabled || this.sweeping) return 0;
20056
21084
  this.sweeping = true;
20057
21085
  try {
20058
- if (!existsSync26(this.auditDir)) return 0;
21086
+ if (!existsSync27(this.auditDir)) return 0;
20059
21087
  const cutoff = this.todayMidnight() - (this.config.retentionDays - 1) * DAY_MS4;
20060
21088
  let removed = 0;
20061
21089
  for (const name of readdirSync8(this.auditDir)) {
@@ -20063,11 +21091,11 @@ var AuditPruneSweeper = class {
20063
21091
  if (dateMs === null || dateMs >= cutoff) continue;
20064
21092
  try {
20065
21093
  if (isAuditDayDir(name)) {
20066
- rmSync4(join22(this.auditDir, name), { recursive: true, force: true });
21094
+ rmSync4(join23(this.auditDir, name), { recursive: true, force: true });
20067
21095
  } else {
20068
- unlinkSync13(join22(this.auditDir, name));
20069
- const statsPath = join22(this.auditDir, auditStatsFileName(name));
20070
- if (existsSync26(statsPath)) unlinkSync13(statsPath);
21096
+ unlinkSync13(join23(this.auditDir, name));
21097
+ const statsPath = join23(this.auditDir, auditStatsFileName(name));
21098
+ if (existsSync27(statsPath)) unlinkSync13(statsPath);
20071
21099
  }
20072
21100
  removed += 1;
20073
21101
  } catch (error) {
@@ -20097,14 +21125,14 @@ var AuditPruneSweeper = class {
20097
21125
  if (!this.config.enabled || this.archiving) return 0;
20098
21126
  this.archiving = true;
20099
21127
  try {
20100
- if (!existsSync26(this.auditDir)) return 0;
21128
+ if (!existsSync27(this.auditDir)) return 0;
20101
21129
  const today = this.todayMidnight();
20102
21130
  let compressed = 0;
20103
21131
  for (const name of readdirSync8(this.auditDir)) {
20104
21132
  if (compressed >= ARCHIVE_BATCH) break;
20105
21133
  const dateMs = auditFileDateMs(name);
20106
21134
  if (dateMs === null || dateMs >= today || !isAuditDayDir(name)) continue;
20107
- const dayPath = join22(this.auditDir, name);
21135
+ const dayPath = join23(this.auditDir, name);
20108
21136
  try {
20109
21137
  const compaction = compactAuditDay(dayPath);
20110
21138
  if (compaction.shards > 0) {
@@ -20122,7 +21150,7 @@ var AuditPruneSweeper = class {
20122
21150
  });
20123
21151
  }
20124
21152
  compressed += await this.archiveDay(
20125
- join22(dayPath, AUDIT_BODIES_DIR),
21153
+ join23(dayPath, AUDIT_BODIES_DIR),
20126
21154
  ARCHIVE_BATCH - compressed
20127
21155
  );
20128
21156
  }
@@ -20148,10 +21176,10 @@ var AuditPruneSweeper = class {
20148
21176
  let compressed = 0;
20149
21177
  for (const shard of shards) {
20150
21178
  if (compressed >= budget) break;
20151
- const source = join22(bodiesPath, shard);
21179
+ const source = join23(bodiesPath, shard);
20152
21180
  const target = `${source}.gz`;
20153
21181
  try {
20154
- if (existsSync26(target)) {
21182
+ if (existsSync27(target)) {
20155
21183
  unlinkSync13(source);
20156
21184
  continue;
20157
21185
  }
@@ -20160,7 +21188,7 @@ var AuditPruneSweeper = class {
20160
21188
  compressed += 1;
20161
21189
  } catch (error) {
20162
21190
  try {
20163
- if (existsSync26(target)) unlinkSync13(target);
21191
+ if (existsSync27(target)) unlinkSync13(target);
20164
21192
  } catch {
20165
21193
  }
20166
21194
  this.logger.warn("[AuditPruneSweeper] failed to archive audit body shard", {
@@ -20175,8 +21203,8 @@ var AuditPruneSweeper = class {
20175
21203
 
20176
21204
  // src/usage/usageMigrate.ts
20177
21205
  import { createReadStream as createReadStream4 } from "fs";
20178
- import { mkdir as mkdir2, open as open3, readdir as readdir2, rename as rename2, rm, stat, unlink as unlink2, writeFile as writeFile2 } from "fs/promises";
20179
- import { join as join23 } from "path";
21206
+ import { mkdir as mkdir2, open as open4, readdir as readdir3, rename as rename3, rm, stat as stat2, unlink as unlink3, writeFile as writeFile3 } from "fs/promises";
21207
+ import { join as join24 } from "path";
20180
21208
  import { createInterface } from "readline";
20181
21209
  var FLUSH_BYTES = 4 * 1024 * 1024;
20182
21210
  async function writeLine(writer2, line) {
@@ -20200,14 +21228,14 @@ var IDLE = {
20200
21228
  };
20201
21229
  async function migrateLegacyUsageEvents(opts) {
20202
21230
  const { eventsPath, usageDir, logger } = opts;
20203
- const legacy = await stat(eventsPath).catch(() => null);
21231
+ const legacy = await stat2(eventsPath).catch(() => null);
20204
21232
  if (!legacy || !legacy.isFile()) return IDLE;
20205
21233
  if (legacy.size === 0) {
20206
- await unlink2(eventsPath).catch(() => {
21234
+ await unlink3(eventsPath).catch(() => {
20207
21235
  });
20208
21236
  return { ...IDLE, migrated: true };
20209
21237
  }
20210
- const scratch = join23(usageDir, USAGE_MIGRATING_DIR);
21238
+ const scratch = join24(usageDir, USAGE_MIGRATING_DIR);
20211
21239
  logger?.info("[usage] migrating legacy usage-events.jsonl into day shards", {
20212
21240
  bytes: legacy.size
20213
21241
  });
@@ -20236,7 +21264,7 @@ async function migrateLegacyUsageEvents(opts) {
20236
21264
  let writer2 = writers.get(dayKey);
20237
21265
  if (!writer2) {
20238
21266
  writer2 = {
20239
- handle: await open3(join23(scratch, usageShardName(dayKey)), "a"),
21267
+ handle: await open4(join24(scratch, usageShardName(dayKey)), "a"),
20240
21268
  buffer: [],
20241
21269
  bytes: 0
20242
21270
  };
@@ -20266,17 +21294,17 @@ async function migrateLegacyUsageEvents(opts) {
20266
21294
  const today = usageDayKey(opts.now ?? Date.now());
20267
21295
  for (const [dayKey, acc] of rollups) {
20268
21296
  if (dayKey === today) continue;
20269
- const size = await stat(join23(scratch, usageShardName(dayKey))).then((s) => s.size).catch(() => null);
21297
+ const size = await stat2(join24(scratch, usageShardName(dayKey))).then((s) => s.size).catch(() => null);
20270
21298
  if (size === null) continue;
20271
- await writeFile2(
20272
- join23(scratch, usageRollupName(dayKey)),
21299
+ await writeFile3(
21300
+ join24(scratch, usageRollupName(dayKey)),
20273
21301
  JSON.stringify(acc.finish(dayKey, size)),
20274
21302
  "utf8"
20275
21303
  );
20276
21304
  }
20277
21305
  await mkdir2(usageDir, { recursive: true });
20278
- const staged = await readdir2(scratch);
20279
- const existing = new Set(await readdir2(usageDir).catch(() => []));
21306
+ const staged = await readdir3(scratch);
21307
+ const existing = new Set(await readdir3(usageDir).catch(() => []));
20280
21308
  const collisions = staged.filter((name) => existing.has(name));
20281
21309
  if (collisions.length > 0) {
20282
21310
  const reason = `refusing to overwrite existing shards in ${usageDir} (${collisions.slice(0, 3).join(", ")}${collisions.length > 3 ? ", \u2026" : ""}); a previous migration may have partially committed \u2014 move or remove them and restart`;
@@ -20286,11 +21314,11 @@ async function migrateLegacyUsageEvents(opts) {
20286
21314
  return { ...IDLE, linesRead, rowsWritten, skipped, reason };
20287
21315
  }
20288
21316
  for (const name of staged) {
20289
- await rename2(join23(scratch, name), join23(usageDir, name));
21317
+ await rename3(join24(scratch, name), join24(usageDir, name));
20290
21318
  }
20291
21319
  await rm(scratch, { recursive: true, force: true }).catch(() => {
20292
21320
  });
20293
- await unlink2(eventsPath);
21321
+ await unlink3(eventsPath);
20294
21322
  const days = rollups.size;
20295
21323
  logger?.info("[usage] migration complete; legacy usage-events.jsonl removed", {
20296
21324
  linesRead,
@@ -20311,8 +21339,8 @@ async function closeAll(writers) {
20311
21339
  }
20312
21340
 
20313
21341
  // src/usage/UsagePruneSweeper.ts
20314
- import { unlink as unlink3 } from "fs/promises";
20315
- import { join as join24 } from "path";
21342
+ import { unlink as unlink4 } from "fs/promises";
21343
+ import { join as join25 } from "path";
20316
21344
  var DAY_MS5 = 24 * 60 * 6e4;
20317
21345
  var SWEEP_INTERVAL_MS3 = 60 * 6e4;
20318
21346
  var DEFAULT_USAGE_RETENTION_DAYS = 90;
@@ -20393,7 +21421,7 @@ var UsagePruneSweeper = class {
20393
21421
  continue;
20394
21422
  }
20395
21423
  try {
20396
- await unlink3(join24(this.usageDir, usageShardName(entry.dayKey)));
21424
+ await unlink4(join25(this.usageDir, usageShardName(entry.dayKey)));
20397
21425
  removed += 1;
20398
21426
  } catch (error) {
20399
21427
  this.logger.warn("[usage] retention: could not remove expired shard", {
@@ -20428,8 +21456,8 @@ var UsagePruneSweeper = class {
20428
21456
  };
20429
21457
 
20430
21458
  // src/audit/auditReader.ts
20431
- import { existsSync as existsSync27, readdirSync as readdirSync9 } from "fs";
20432
- import { join as join25 } from "path";
21459
+ import { existsSync as existsSync28, readdirSync as readdirSync9 } from "fs";
21460
+ import { join as join26 } from "path";
20433
21461
  var DEFAULT_LIMIT = 200;
20434
21462
  var MAX_LIMIT = 2e3;
20435
21463
  var OVERSCAN = 256;
@@ -20445,10 +21473,10 @@ function daySources(auditDir) {
20445
21473
  const dateMs = auditFileDateMs(name);
20446
21474
  if (dateMs === null) continue;
20447
21475
  if (AUDIT_DAY_DIR_RE.test(name)) {
20448
- const path2 = join25(auditDir, name, AUDIT_META_FILE);
20449
- if (existsSync27(path2)) sources.push({ path: path2, dateMs });
21476
+ const path2 = join26(auditDir, name, AUDIT_META_FILE);
21477
+ if (existsSync28(path2)) sources.push({ path: path2, dateMs });
20450
21478
  } else if (AUDIT_FILE_RE.test(name)) {
20451
- sources.push({ path: join25(auditDir, name), dateMs });
21479
+ sources.push({ path: join26(auditDir, name), dateMs });
20452
21480
  }
20453
21481
  }
20454
21482
  return sources.sort((a, b) => b.dateMs - a.dateMs);
@@ -20464,7 +21492,7 @@ function toMetaRecord(record) {
20464
21492
  return { ...meta, hasBody: true };
20465
21493
  }
20466
21494
  function readAuditRecords(auditDir, query2 = {}) {
20467
- if (!existsSync27(auditDir)) return [];
21495
+ if (!existsSync28(auditDir)) return [];
20468
21496
  const from = typeof query2.from === "number" ? query2.from : -Infinity;
20469
21497
  const to = typeof query2.to === "number" ? query2.to : Infinity;
20470
21498
  const limit = Math.min(MAX_LIMIT, Math.max(1, Math.trunc(query2.limit ?? DEFAULT_LIMIT)));
@@ -20492,8 +21520,8 @@ function readAuditRecords(auditDir, query2 = {}) {
20492
21520
  }
20493
21521
 
20494
21522
  // src/audit/AuditWriter.ts
20495
- import { appendFileSync as appendFileSync2, existsSync as existsSync28, mkdirSync as mkdirSync7, statSync as statSync8 } from "fs";
20496
- import { join as join26 } from "path";
21523
+ import { appendFileSync as appendFileSync2, existsSync as existsSync29, mkdirSync as mkdirSync7, statSync as statSync8 } from "fs";
21524
+ import { join as join27 } from "path";
20497
21525
  var AuditWriter = class {
20498
21526
  constructor(auditDir, logger, defer = (fn) => setTimeout(fn, 0)) {
20499
21527
  this.auditDir = auditDir;
@@ -20533,7 +21561,7 @@ var AuditWriter = class {
20533
21561
  */
20534
21562
  appendNow(record) {
20535
21563
  const dayDir = auditDayDirName(record.ts);
20536
- const dayPath = this.ensureDir(join26(this.auditDir, dayDir));
21564
+ const dayPath = this.ensureDir(join27(this.auditDir, dayDir));
20537
21565
  this.appendMeta(dayPath, record);
20538
21566
  this.appendBody(dayPath, dayDir, record);
20539
21567
  }
@@ -20548,9 +21576,9 @@ var AuditWriter = class {
20548
21576
  /** Write the body-free metadata line + refresh the exact-count sidecar. */
20549
21577
  appendMeta(dayPath, record) {
20550
21578
  const { requestBody: _req, responseBody: _res, ...meta } = record;
20551
- const file = join26(dayPath, AUDIT_META_FILE);
21579
+ const file = join27(dayPath, AUDIT_META_FILE);
20552
21580
  const line = JSON.stringify(meta) + "\n";
20553
- const bytesBefore = existsSync28(file) ? statSync8(file).size : 0;
21581
+ const bytesBefore = existsSync29(file) ? statSync8(file).size : 0;
20554
21582
  appendFileSync2(file, line, "utf8");
20555
21583
  try {
20556
21584
  updateAuditStatsAfterAppend(
@@ -20582,8 +21610,8 @@ var AuditWriter = class {
20582
21610
  try {
20583
21611
  const line = encodeBodyEntry(record, sessionKey, dayDir, this.bases);
20584
21612
  if (line === null) return;
20585
- const bodiesPath = this.ensureDir(join26(dayPath, AUDIT_BODIES_DIR));
20586
- appendFileSync2(join26(bodiesPath, auditBodyFileName(sessionKey)), line + "\n", "utf8");
21613
+ const bodiesPath = this.ensureDir(join27(dayPath, AUDIT_BODIES_DIR));
21614
+ appendFileSync2(join27(bodiesPath, auditBodyFileName(sessionKey)), line + "\n", "utf8");
20587
21615
  } catch (error) {
20588
21616
  this.bases.forget(sessionKey);
20589
21617
  this.logger.warn("[AuditWriter] failed to append audit body shard", {
@@ -20597,7 +21625,7 @@ var AuditWriter = class {
20597
21625
  // src/billing/BillingPublisher.ts
20598
21626
  import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync8 } from "fs";
20599
21627
  import { createHmac as createHmac5 } from "crypto";
20600
- import { join as join27 } from "path";
21628
+ import { join as join28 } from "path";
20601
21629
  import { fetchUpstream as fetchUpstream14 } from "@omnicross/core/pipeline/upstreamFetch";
20602
21630
 
20603
21631
  // src/billing/billingFiles.ts
@@ -20668,7 +21696,7 @@ var BillingPublisher = class {
20668
21696
  */
20669
21697
  appendNow(event) {
20670
21698
  this.ensureDir();
20671
- const file = join27(this.billingDir, billingFileName(event.ts));
21699
+ const file = join28(this.billingDir, billingFileName(event.ts));
20672
21700
  appendFileSync3(file, JSON.stringify(event) + "\n", "utf8");
20673
21701
  }
20674
21702
  /**
@@ -20718,7 +21746,7 @@ var BillingPublisher = class {
20718
21746
  markDelivered(event) {
20719
21747
  try {
20720
21748
  this.ensureDir();
20721
- const file = join27(this.billingDir, deliveredFileName(event.ts));
21749
+ const file = join28(this.billingDir, deliveredFileName(event.ts));
20722
21750
  appendFileSync3(file, JSON.stringify({ id: event.id, deliveredAt: this.now() }) + "\n", "utf8");
20723
21751
  } catch (error) {
20724
21752
  this.logger.warn("[BillingPublisher] failed to append delivery marker", {
@@ -20734,11 +21762,11 @@ var BillingPublisher = class {
20734
21762
  };
20735
21763
 
20736
21764
  // src/billing/billingReader.ts
20737
- import { existsSync as existsSync29, readdirSync as readdirSync10, readFileSync as readFileSync22 } from "fs";
20738
- import { join as join28 } from "path";
21765
+ import { existsSync as existsSync30, readdirSync as readdirSync10, readFileSync as readFileSync22 } from "fs";
21766
+ import { join as join29 } from "path";
20739
21767
  function readBillingLedger(billingDir) {
20740
21768
  const view = { events: [], deliveredIds: /* @__PURE__ */ new Set() };
20741
- if (!existsSync29(billingDir)) return view;
21769
+ if (!existsSync30(billingDir)) return view;
20742
21770
  let files;
20743
21771
  try {
20744
21772
  files = readdirSync10(billingDir);
@@ -20772,7 +21800,7 @@ function readBillingStatus(billingDir) {
20772
21800
  function parseLines(dir, file) {
20773
21801
  let raw;
20774
21802
  try {
20775
- raw = readFileSync22(join28(dir, file), "utf8");
21803
+ raw = readFileSync22(join29(dir, file), "utf8");
20776
21804
  } catch {
20777
21805
  return [];
20778
21806
  }
@@ -21579,6 +22607,7 @@ function buildDaemon(config, paths) {
21579
22607
  });
21580
22608
  const auditDir = defaultAuditDir(paths.configPath);
21581
22609
  const billingDir = defaultBillingDir(paths.configPath);
22610
+ const codexSessionManager = new CodexSessionManager();
21582
22611
  const adminServer = new AdminServer({
21583
22612
  configPath: paths.configPath,
21584
22613
  llmConfig,
@@ -21676,6 +22705,10 @@ function buildDaemon(config, paths) {
21676
22705
  cliTerminalOpener: paths.cliTerminalOpener,
21677
22706
  cliPathProbe: paths.cliPathProbe,
21678
22707
  cliCommandRunner: paths.cliCommandRunner,
22708
+ // One helper invocation shared by the integration install and KEY-SCOPED
22709
+ // launches (the latter append `--key-id` per spawn) — same entrypoint, same
22710
+ // config/master-key resolution, so the two paths can never drift.
22711
+ codexAuthHelper: currentProcessCodexAuthHelper(paths.configPath, paths.masterKeyFilePath),
21679
22712
  integrationManagerFactory: () => {
21680
22713
  const live = outboundApiServer.getStatus();
21681
22714
  const port = live.port || decryptedConfig.server?.port || DEFAULT_OUTBOUND_PORT;
@@ -21720,7 +22753,8 @@ function buildDaemon(config, paths) {
21720
22753
  auditCompactor: () => compactAllClosedAuditDays(auditDir),
21721
22754
  // billing-event-stream: the AUTHED `GET /admin/api/billing-status` returns the
21722
22755
  // secret-free total/delivered/pending counts of the durable ledger.
21723
- billingStatusReader: () => readBillingStatus(billingDir)
22756
+ billingStatusReader: () => readBillingStatus(billingDir),
22757
+ codexSessionManager
21724
22758
  });
21725
22759
  const webhookDispatcher = new WebhookDispatcher({
21726
22760
  logger,
@@ -21786,6 +22820,7 @@ function buildDaemon(config, paths) {
21786
22820
  pricingEngine,
21787
22821
  pricingRefreshScheduler,
21788
22822
  usageRecorder,
22823
+ codexSessionManager,
21789
22824
  adminServer,
21790
22825
  tokenRefreshScheduler,
21791
22826
  accountHealthSweeper,
@@ -21801,7 +22836,7 @@ function buildDaemon(config, paths) {
21801
22836
  }
21802
22837
  function isTokensStoreReadable(tokensPath) {
21803
22838
  try {
21804
- if (!existsSync30(tokensPath)) return true;
22839
+ if (!existsSync31(tokensPath)) return true;
21805
22840
  accessSync(tokensPath, fsConstants.R_OK);
21806
22841
  return true;
21807
22842
  } catch {
@@ -22340,7 +23375,7 @@ async function runImportCcr(argv) {
22340
23375
  }
22341
23376
 
22342
23377
  // src/commands/integrations.ts
22343
- import { resolve as resolve10 } from "path";
23378
+ import { resolve as resolve11 } from "path";
22344
23379
  import { parseArgs as parseArgs4 } from "util";
22345
23380
  async function runIntegrations(argv) {
22346
23381
  const { values, positionals } = parseArgs4({
@@ -22349,7 +23384,8 @@ async function runIntegrations(argv) {
22349
23384
  config: { type: "string", short: "c" },
22350
23385
  "gateway-base-url": { type: "string" },
22351
23386
  target: { type: "string" },
22352
- "master-key-file": { type: "string" }
23387
+ "master-key-file": { type: "string" },
23388
+ "key-id": { type: "string" }
22353
23389
  },
22354
23390
  allowPositionals: true
22355
23391
  });
@@ -22362,7 +23398,7 @@ async function runIntegrations(argv) {
22362
23398
  const savedUrl = saved.clients.codex?.gatewayBaseUrl ?? saved.clients.claude?.gatewayBaseUrl;
22363
23399
  const gatewayBaseUrl = values["gateway-base-url"] ?? savedUrl ?? "http://127.0.0.1:8765";
22364
23400
  const manager = new IntegrationManager({
22365
- configPath: resolve10(values.config),
23401
+ configPath: resolve11(values.config),
22366
23402
  gatewayBaseUrl,
22367
23403
  keyDb: new JsonOutboundKeyDb(defaultKeysPath(values.config), secretBox3),
22368
23404
  stateStore: store,
@@ -22370,7 +23406,9 @@ async function runIntegrations(argv) {
22370
23406
  });
22371
23407
  if (action === "token") {
22372
23408
  if (client !== "codex") throw new Error("integrations token: expected client 'codex'");
22373
- process.stdout.write(`${await manager.getIntegrationToken(client)}
23409
+ const keyId = values["key-id"];
23410
+ const token = keyId ? await manager.getKeyToken(keyId) : await manager.getIntegrationToken(client);
23411
+ process.stdout.write(`${token}
22374
23412
  `);
22375
23413
  return;
22376
23414
  }
@@ -22456,9 +23494,9 @@ async function keysRevoke(db, id) {
22456
23494
 
22457
23495
  // src/commands/launch.ts
22458
23496
  import { spawn as spawn2 } from "child_process";
22459
- import { randomUUID as randomUUID6 } from "crypto";
22460
- import { existsSync as existsSync31 } from "fs";
22461
- import { delimiter as delimiter2, join as join29 } from "path";
23497
+ import { randomUUID as randomUUID7 } from "crypto";
23498
+ import { existsSync as existsSync32 } from "fs";
23499
+ import { delimiter as delimiter2, join as join30 } from "path";
22462
23500
  import { parseArgs as parseArgs6 } from "util";
22463
23501
  import {
22464
23502
  buildChatCliLaunchConfig as buildChatCliLaunchConfig2,
@@ -22504,8 +23542,8 @@ function buildCliSpawnPlan(opts) {
22504
23542
  function resolveInPathDefault(candidate) {
22505
23543
  const segments = (process.env["PATH"] ?? "").split(delimiter2).filter(Boolean);
22506
23544
  for (const seg of segments) {
22507
- const full = join29(seg, candidate);
22508
- if (existsSync31(full)) return full;
23545
+ const full = join30(seg, candidate);
23546
+ if (existsSync32(full)) return full;
22509
23547
  }
22510
23548
  return null;
22511
23549
  }
@@ -22585,7 +23623,7 @@ async function runLaunch(argv, deps) {
22585
23623
  }
22586
23624
  async function buildLaunchConfig(cli, daemon, opts) {
22587
23625
  if (cli === "claude" || cli === "codex") {
22588
- const internalId = randomUUID6();
23626
+ const internalId = randomUUID7();
22589
23627
  const outcome = await daemon.routeLeaseManager.createFromRequest({
22590
23628
  schemaVersion: ROUTE_LEASE_REQUEST_SCHEMA2,
22591
23629
  consumer: "omnicross-terminal",
@@ -22643,7 +23681,7 @@ async function shutdownLaunchDaemon(daemon) {
22643
23681
  daemon.pricingRefreshScheduler.dispose();
22644
23682
  }
22645
23683
  function spawnCliInherit(plan) {
22646
- return new Promise((resolve11, reject) => {
23684
+ return new Promise((resolve12, reject) => {
22647
23685
  const child = spawn2(plan.command, plan.args, {
22648
23686
  stdio: "inherit",
22649
23687
  env: plan.env,
@@ -22677,7 +23715,7 @@ function spawnCliInherit(plan) {
22677
23715
  });
22678
23716
  child.on("exit", (code, signal) => {
22679
23717
  detach();
22680
- resolve11(code ?? (signal ? 1 : 0));
23718
+ resolve12(code ?? (signal ? 1 : 0));
22681
23719
  });
22682
23720
  });
22683
23721
  }
@@ -23045,30 +24083,30 @@ function buildOpenBrowserCommand(platform, url) {
23045
24083
  return { command: "xdg-open", args: [url] };
23046
24084
  }
23047
24085
  function openBrowser(url) {
23048
- return new Promise((resolve11) => {
24086
+ return new Promise((resolve12) => {
23049
24087
  try {
23050
24088
  const { command, args } = buildOpenBrowserCommand(process.platform, url);
23051
24089
  const child = spawn3(command, args, { stdio: "ignore", detached: true });
23052
- child.on("error", () => resolve11(false));
24090
+ child.on("error", () => resolve12(false));
23053
24091
  child.unref();
23054
- resolve11(true);
24092
+ resolve12(true);
23055
24093
  } catch {
23056
- resolve11(false);
24094
+ resolve12(false);
23057
24095
  }
23058
24096
  });
23059
24097
  }
23060
24098
  function promptPaste(prompt) {
23061
24099
  const rl = createInterface2({ input: process.stdin, output: process.stdout });
23062
- return new Promise((resolve11) => {
24100
+ return new Promise((resolve12) => {
23063
24101
  rl.question(prompt, (answer) => {
23064
24102
  rl.close();
23065
- resolve11(answer);
24103
+ resolve12(answer);
23066
24104
  });
23067
24105
  });
23068
24106
  }
23069
24107
 
23070
24108
  // src/commands/providers.ts
23071
- import { randomUUID as randomUUID7 } from "crypto";
24109
+ import { randomUUID as randomUUID8 } from "crypto";
23072
24110
  import { parseArgs as parseArgs8 } from "util";
23073
24111
  async function runProviders(argv) {
23074
24112
  const { values, positionals } = parseArgs8({
@@ -23190,7 +24228,7 @@ function providersAddKey(configPath, providerId, opts) {
23190
24228
  const cfg = loadConfig(configPath);
23191
24229
  const row = cfg.providers.find((p) => p.id === providerId);
23192
24230
  if (!row) throw new Error(`providers add-key: unknown provider '${providerId}'`);
23193
- const entry = { id: randomUUID7(), apiKey: opts.key };
24231
+ const entry = { id: randomUUID8(), apiKey: opts.key };
23194
24232
  if (opts.label) entry.label = opts.label;
23195
24233
  if (opts.weight !== void 0) {
23196
24234
  const w = Number(opts.weight);
@@ -23218,7 +24256,7 @@ function providersRmKey(configPath, providerId, keyId) {
23218
24256
  }
23219
24257
 
23220
24258
  // src/commands/secrets.ts
23221
- import { existsSync as existsSync32, readFileSync as readFileSync24 } from "fs";
24259
+ import { existsSync as existsSync33, readFileSync as readFileSync24 } from "fs";
23222
24260
  import { parseArgs as parseArgs9 } from "util";
23223
24261
  async function runSecrets(argv) {
23224
24262
  const { values, positionals } = parseArgs9({
@@ -23291,12 +24329,12 @@ function secretsStatus(args) {
23291
24329
  reportField("admin.token", cfg.admin.token);
23292
24330
  }
23293
24331
  const tokensPath = defaultTokensPath(args.config);
23294
- if (existsSync32(tokensPath)) {
24332
+ if (existsSync33(tokensPath)) {
23295
24333
  console.info(`Secret status for ${tokensPath}:`);
23296
24334
  reportTokenFields(tokensPath);
23297
24335
  }
23298
24336
  const integrationsPath = defaultIntegrationsPath(args.config);
23299
- if (existsSync32(integrationsPath)) {
24337
+ if (existsSync33(integrationsPath)) {
23300
24338
  const state = readRawJson(integrationsPath);
23301
24339
  const key = state.gatewayKey;
23302
24340
  if (key && typeof key === "object" && !Array.isArray(key)) {
@@ -23350,8 +24388,8 @@ async function secretsRotate(args) {
23350
24388
  const integrationsPath = defaultIntegrationsPath(args.config);
23351
24389
  try {
23352
24390
  cfg = loadConfig(args.config);
23353
- if (existsSync32(tokensPath)) tokensPlain = decryptTokensFile(tokensPath, oldBox);
23354
- if (existsSync32(integrationsPath)) {
24391
+ if (existsSync33(tokensPath)) tokensPlain = decryptTokensFile(tokensPath, oldBox);
24392
+ if (existsSync33(integrationsPath)) {
23355
24393
  integrationsPlain = new IntegrationStateStore(integrationsPath, oldBox).load();
23356
24394
  }
23357
24395
  } finally {
@@ -23386,7 +24424,7 @@ function secretsDecrypt(args) {
23386
24424
  let tokensPlain = null;
23387
24425
  try {
23388
24426
  cfg = loadConfig(args.config);
23389
- if (existsSync32(tokensPath)) tokensPlain = decryptTokensFile(tokensPath, box);
24427
+ if (existsSync33(tokensPath)) tokensPlain = decryptTokensFile(tokensPath, box);
23390
24428
  } finally {
23391
24429
  setSecretBox(null);
23392
24430
  }
@@ -23417,13 +24455,13 @@ function readRawJson(path2) {
23417
24455
  }
23418
24456
  function encryptTokensFileInPlace(configPath, box) {
23419
24457
  const tokensPath = defaultTokensPath(configPath);
23420
- if (!existsSync32(tokensPath)) return;
24458
+ if (!existsSync33(tokensPath)) return;
23421
24459
  const plain = decryptTokensFile(tokensPath, box);
23422
24460
  writeTokensEncrypted(tokensPath, plain, box);
23423
24461
  }
23424
24462
  function rewriteIntegrationState(configPath, readBox, writeBox) {
23425
24463
  const path2 = defaultIntegrationsPath(configPath);
23426
- if (!existsSync32(path2)) return;
24464
+ if (!existsSync33(path2)) return;
23427
24465
  const state = new IntegrationStateStore(path2, readBox).load();
23428
24466
  new IntegrationStateStore(path2, writeBox).save(state);
23429
24467
  }
@@ -23463,7 +24501,7 @@ function walkTokens(raw, fn) {
23463
24501
  return next;
23464
24502
  }
23465
24503
  function tokensSuffix(configPath) {
23466
- return existsSync32(defaultTokensPath(configPath)) ? " (+ tokens.json)" : "";
24504
+ return existsSync33(defaultTokensPath(configPath)) ? " (+ tokens.json)" : "";
23467
24505
  }
23468
24506
 
23469
24507
  // src/commands/start.ts
@@ -23599,7 +24637,7 @@ async function runStart(argv) {
23599
24637
  // src/commands/ui.ts
23600
24638
  async function runUi(argv, deps) {
23601
24639
  const start = deps?.start ?? runStart;
23602
- const open4 = deps?.openBrowser ?? openBrowser;
24640
+ const open5 = deps?.openBrowser ?? openBrowser;
23603
24641
  const noOpen = argv.includes("--no-open");
23604
24642
  const startArgv = argv.filter((a) => a !== "--no-open");
23605
24643
  if (!resolveUiDist()) {
@@ -23615,7 +24653,7 @@ async function runUi(argv, deps) {
23615
24653
  const uiUrl = `${dashboardUrl}/ui/`;
23616
24654
  console.info(`Control Panel: ${uiUrl}`);
23617
24655
  if (noOpen) return;
23618
- const launched = await open4(uiUrl).catch(() => false);
24656
+ const launched = await open5(uiUrl).catch(() => false);
23619
24657
  if (!launched) {
23620
24658
  console.info("(Could not open a browser automatically \u2014 open the URL above manually.)");
23621
24659
  }