@omnicross/daemon 0.1.7 → 0.1.8

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.cjs CHANGED
@@ -1765,10 +1765,12 @@ async function keysRevoke(db, id) {
1765
1765
 
1766
1766
  // src/commands/launch.ts
1767
1767
  var import_node_child_process2 = require("child_process");
1768
+ var import_node_crypto15 = require("crypto");
1768
1769
  var import_node_fs25 = require("fs");
1769
1770
  var import_node_path17 = require("path");
1770
1771
  var import_node_util4 = require("util");
1771
- var import_cli_launcher2 = require("@omnicross/cli-launcher");
1772
+ var import_cli_launcher3 = require("@omnicross/cli-launcher");
1773
+ var import_provider_proxy5 = require("@omnicross/core/provider-proxy");
1772
1774
 
1773
1775
  // src/bootstrap.ts
1774
1776
  var import_node_fs24 = require("fs");
@@ -1778,13 +1780,14 @@ var import_GeminiCodeAssistProjectResolver = require("@omnicross/core/auth/Gemin
1778
1780
  var import_ApiKeyPoolService = require("@omnicross/core/completion/ApiKeyPoolService");
1779
1781
  var import_outbound_api5 = require("@omnicross/core/outbound-api");
1780
1782
  var import_subscriptionRegistryPort = require("@omnicross/core/outbound-api/subscriptionRegistryPort");
1781
- var import_SubscriptionAccountHealth3 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
1783
+ var import_SubscriptionAccountHealth4 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
1782
1784
  var import_AccountAllowanceStore4 = require("@omnicross/core/pipeline/AccountAllowanceStore");
1783
- var import_AccountAllowanceScheduling4 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
1785
+ var import_AccountAllowanceScheduling5 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
1784
1786
  var import_upstreamFetch8 = require("@omnicross/core/pipeline/upstreamFetch");
1785
1787
  var import_SubscriptionIdentityStore3 = require("@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore");
1786
1788
  var import_gemini_code_assist_resolver = require("@omnicross/core/ports/gemini-code-assist-resolver");
1787
- var import_provider_proxy = require("@omnicross/core/provider-proxy");
1789
+ var import_provider_proxy4 = require("@omnicross/core/provider-proxy");
1790
+ var import_cli_launcher2 = require("@omnicross/cli-launcher");
1788
1791
  var import_outbound_api6 = require("@omnicross/core/outbound-api");
1789
1792
  var import_usage = require("@omnicross/core/usage");
1790
1793
  var import_subscriptions4 = require("@omnicross/subscriptions");
@@ -2467,6 +2470,88 @@ async function handleWebhookTest(req, res) {
2467
2470
  res.end(JSON.stringify({ result }));
2468
2471
  }
2469
2472
 
2473
+ // src/admin/routeLeaseApi.ts
2474
+ var import_provider_proxy = require("@omnicross/core/provider-proxy");
2475
+ var MAX_BODY_BYTES = 64 * 1024;
2476
+ var SAFE_LEASE_ID = /^[A-Za-z0-9-]{1,128}$/u;
2477
+ async function readJson(req) {
2478
+ const chunks = [];
2479
+ let bytes = 0;
2480
+ for await (const chunk of req) {
2481
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
2482
+ bytes += buffer.length;
2483
+ if (bytes > MAX_BODY_BYTES) throw new import_provider_proxy.RouteLeaseError("invalid_request", "request body is too large");
2484
+ chunks.push(buffer);
2485
+ }
2486
+ if (chunks.length === 0) return {};
2487
+ try {
2488
+ return JSON.parse(Buffer.concat(chunks).toString("utf8"));
2489
+ } catch {
2490
+ throw new import_provider_proxy.RouteLeaseError("invalid_request", "request body is not valid JSON");
2491
+ }
2492
+ }
2493
+ function json(res, status, body, noStore = false) {
2494
+ res.statusCode = status;
2495
+ res.setHeader("Content-Type", "application/json");
2496
+ if (noStore) res.setHeader("Cache-Control", "no-store");
2497
+ res.end(JSON.stringify(body));
2498
+ }
2499
+ function leaseId(value) {
2500
+ if (!value || !SAFE_LEASE_ID.test(value)) throw new import_provider_proxy.RouteLeaseError("invalid_request", "lease id is invalid");
2501
+ return value;
2502
+ }
2503
+ function header(req, name) {
2504
+ const value = req.headers[name.toLowerCase()];
2505
+ return Array.isArray(value) ? value[0] : value;
2506
+ }
2507
+ function writeError(res, error, noStore) {
2508
+ const safe = error instanceof import_provider_proxy.RouteLeaseError ? error : new import_provider_proxy.RouteLeaseError("upstream_unavailable", "route lease operation failed safely");
2509
+ if (safe.retryAfterSeconds !== void 0) res.setHeader("Retry-After", String(safe.retryAfterSeconds));
2510
+ json(res, safe.status, safe.toResponse(), noStore);
2511
+ }
2512
+ async function handleRouteLeaseApi(req, res, path2, deps) {
2513
+ const method = (req.method ?? "GET").toUpperCase();
2514
+ const noStore = method === "POST" && (path2 === "/admin/api/route-leases" || path2.endsWith("/renew"));
2515
+ try {
2516
+ if (!(0, import_provider_proxy.isLoopbackAddress)(req.socket.remoteAddress)) {
2517
+ throw new import_provider_proxy.RouteLeaseError("control_unauthorized", "route lease control plane is loopback only");
2518
+ }
2519
+ const manager = deps.routeLeaseManager;
2520
+ if (!manager) throw new import_provider_proxy.RouteLeaseError("daemon_not_ready", "route lease manager is unavailable");
2521
+ const base = "/admin/api/route-leases";
2522
+ const suffix = path2.slice(base.length).replace(/^\/+|\/+$/gu, "");
2523
+ const segments = suffix ? suffix.split("/") : [];
2524
+ if (segments.length === 1 && segments[0] === "capabilities") {
2525
+ if (method !== "GET" && method !== "HEAD") throw new import_provider_proxy.RouteLeaseError("invalid_request", "method is not allowed");
2526
+ return json(res, 200, import_provider_proxy.ROUTE_LEASE_CAPABILITIES);
2527
+ }
2528
+ if (segments.length === 0) {
2529
+ if (method === "GET") return json(res, 200, { leases: manager.list() });
2530
+ if (method === "POST") {
2531
+ const outcome = await manager.createFromRequest(await readJson(req), header(req, "idempotency-key"));
2532
+ return json(res, outcome.created ? 201 : 200, outcome.result, true);
2533
+ }
2534
+ throw new import_provider_proxy.RouteLeaseError("invalid_request", "method is not allowed");
2535
+ }
2536
+ const id = leaseId(segments[0]);
2537
+ if (segments.length === 1) {
2538
+ if (method === "GET") return json(res, 200, manager.get(id));
2539
+ if (method === "DELETE") return json(res, 200, manager.release(id));
2540
+ throw new import_provider_proxy.RouteLeaseError("invalid_request", "method is not allowed");
2541
+ }
2542
+ if (segments.length === 2 && segments[1] === "renew" && method === "POST") {
2543
+ const body = await readJson(req);
2544
+ const ttl = (0, import_provider_proxy.normalizeRouteLeaseTtl)(
2545
+ body && typeof body === "object" && !Array.isArray(body) ? body.ttlSeconds : void 0
2546
+ );
2547
+ return json(res, 200, manager.renew(id, ttl), true);
2548
+ }
2549
+ throw new import_provider_proxy.RouteLeaseError("lease_not_found", "route lease endpoint was not found");
2550
+ } catch (error) {
2551
+ writeError(res, error, noStore);
2552
+ }
2553
+ }
2554
+
2470
2555
  // src/admin/adminApi.ts
2471
2556
  var import_node_http = __toESM(require("http"), 1);
2472
2557
  var import_outbound_api3 = require("@omnicross/core/outbound-api");
@@ -3016,8 +3101,34 @@ async function exchangeGemini(code, codeVerifier, exchangeFetch) {
3016
3101
  var import_node_child_process = require("child_process");
3017
3102
  var import_node_crypto6 = require("crypto");
3018
3103
  var import_node_fs8 = require("fs");
3104
+ var import_node_net = require("net");
3105
+ var import_node_os3 = require("os");
3019
3106
  var import_node_path7 = require("path");
3020
3107
  var import_cli_launcher = require("@omnicross/cli-launcher");
3108
+ var import_provider_proxy2 = require("@omnicross/core/provider-proxy");
3109
+
3110
+ // src/routeLeaseRenewal.ts
3111
+ var TERMINAL_LEASE_TTL_SECONDS = 600;
3112
+ var TERMINAL_LEASE_RENEW_INTERVAL_MS = 5 * 60 * 1e3;
3113
+ var TERMINAL_LEASE_MAX_LIFETIME_MS = 24 * 60 * 60 * 1e3;
3114
+ function startTerminalLeaseRenewal(manager, leaseId2) {
3115
+ const stopAt = Date.now() + TERMINAL_LEASE_MAX_LIFETIME_MS;
3116
+ const timer = setInterval(() => {
3117
+ if (Date.now() >= stopAt) {
3118
+ clearInterval(timer);
3119
+ return;
3120
+ }
3121
+ try {
3122
+ manager.renew(leaseId2, TERMINAL_LEASE_TTL_SECONDS);
3123
+ } catch {
3124
+ clearInterval(timer);
3125
+ }
3126
+ }, TERMINAL_LEASE_RENEW_INTERVAL_MS);
3127
+ timer.unref?.();
3128
+ return () => clearInterval(timer);
3129
+ }
3130
+
3131
+ // src/admin/cliLaunch.ts
3021
3132
  var LAUNCHABLE_CLIS = [
3022
3133
  { id: "claude", displayName: "Claude Code", command: "claude" },
3023
3134
  { id: "codex", displayName: "Codex CLI", command: "codex" },
@@ -3098,34 +3209,183 @@ async function buildLaunchEnv(cli, llmConfig, target) {
3098
3209
  function shq(s) {
3099
3210
  return `'${s.replace(/'/g, `'\\''`)}'`;
3100
3211
  }
3101
- var defaultTerminalOpener = ({ cli, command, extraArgs, env, cwd, platform }) => {
3212
+ var MAC_TERMINAL_BOOTSTRAP_SOURCE = `
3213
+ 'use strict';
3214
+ const fs = require('node:fs');
3215
+ const net = require('node:net');
3216
+ const { spawn } = require('node:child_process');
3217
+ const [socketPath, launchDir, cwd, command, ...args] = process.argv.slice(2);
3218
+ let payload = '';
3219
+ const socket = net.createConnection(socketPath);
3220
+ socket.setEncoding('utf8');
3221
+ socket.on('data', (chunk) => { payload += chunk; });
3222
+ socket.on('end', () => {
3223
+ const descriptor = JSON.parse(payload);
3224
+ if (!descriptor || Array.isArray(descriptor) || Object.values(descriptor).some((value) => typeof value !== 'string')) {
3225
+ throw new Error('invalid terminal launch descriptor');
3226
+ }
3227
+ try { fs.rmSync(launchDir, { recursive: true, force: true }); } catch {}
3228
+ const child = spawn(command, args, {
3229
+ cwd: cwd || undefined,
3230
+ env: { ...process.env, ...descriptor },
3231
+ stdio: 'inherit',
3232
+ });
3233
+ child.on('error', (error) => { console.error(error.message); process.exitCode = 1; });
3234
+ child.on('exit', (code, signal) => {
3235
+ if (signal) process.kill(process.pid, signal);
3236
+ else process.exitCode = code == null ? 1 : code;
3237
+ });
3238
+ });
3239
+ socket.on('error', (error) => { console.error(error.message); process.exitCode = 1; });
3240
+ `;
3241
+ var MAC_TERMINAL_IPC_TIMEOUT_MS = 12e4;
3242
+ function openTerminal({ cli, command, extraArgs, env, cwd, platform, onFailure }, spawnProcess = import_node_child_process.spawn, macIpc = {}) {
3102
3243
  const childEnv = { ...process.env, ...env };
3103
3244
  if (platform === "win32") {
3104
3245
  const args = ["/c", "start", `"omnicross ${cli}"`];
3105
3246
  if (cwd) args.push("/D", `"${cwd}"`);
3106
3247
  args.push("cmd", "/k", command, ...extraArgs);
3107
- (0, import_node_child_process.spawn)(process.env["ComSpec"] || "cmd.exe", args, {
3248
+ spawnProcess(process.env["ComSpec"] || "cmd.exe", args, {
3108
3249
  env: childEnv,
3109
3250
  windowsVerbatimArguments: true,
3110
3251
  detached: true,
3111
3252
  stdio: "ignore"
3112
3253
  }).unref();
3113
- return;
3254
+ return () => {
3255
+ };
3114
3256
  }
3115
- const exportLine = Object.entries(env).map(([k, v]) => `export ${k}=${shq(v)}`).join("; ");
3116
3257
  const runLine = [command, ...extraArgs].map(shq).join(" ");
3117
- const script = `${exportLine}; ${cwd ? `cd ${shq(cwd)}; ` : ""}${runLine}`;
3258
+ const script = `${cwd ? `cd ${shq(cwd)}; ` : ""}${runLine}`;
3118
3259
  if (platform === "darwin") {
3119
- const osa = `tell application "Terminal" to do script ${JSON.stringify(script)}`;
3120
- (0, import_node_child_process.spawn)("osascript", ["-e", osa], { detached: true, stdio: "ignore" }).unref();
3121
- return;
3260
+ const launchDir = (0, import_node_fs8.mkdtempSync)((0, import_node_path7.join)((0, import_node_os3.tmpdir)(), "omnicross-terminal-"));
3261
+ const commandFile = (0, import_node_path7.join)(launchDir, "launch.command");
3262
+ const bootstrapFile = (0, import_node_path7.join)(launchDir, "bootstrap.cjs");
3263
+ const socketPath = macIpc.socketPath ?? (0, import_node_path7.join)(launchDir, "descriptor.sock");
3264
+ const openerEnv = { ...process.env };
3265
+ for (const key of Object.keys(env)) delete openerEnv[key];
3266
+ let claimed = false;
3267
+ let cleaned = false;
3268
+ let failureNotified = false;
3269
+ let timer;
3270
+ const notifyFailure = () => {
3271
+ cleanup();
3272
+ if (failureNotified) return;
3273
+ failureNotified = true;
3274
+ try {
3275
+ onFailure?.();
3276
+ } catch {
3277
+ }
3278
+ };
3279
+ const handleLaunchFailure = () => {
3280
+ if (claimed) cleanup();
3281
+ else notifyFailure();
3282
+ };
3283
+ const sockets = /* @__PURE__ */ new Set();
3284
+ const server = (0, import_node_net.createServer)((socket) => {
3285
+ socket.unref();
3286
+ sockets.add(socket);
3287
+ socket.once("close", () => sockets.delete(socket));
3288
+ try {
3289
+ macIpc.onAccepted?.(socket);
3290
+ } catch {
3291
+ cleanup();
3292
+ return;
3293
+ }
3294
+ if (claimed || cleaned) {
3295
+ socket.destroy();
3296
+ return;
3297
+ }
3298
+ claimed = true;
3299
+ try {
3300
+ macIpc.onClaimed?.();
3301
+ if (cleaned) return;
3302
+ socket.end(JSON.stringify(env), cleanup);
3303
+ } catch {
3304
+ cleanup();
3305
+ }
3306
+ });
3307
+ const cleanup = () => {
3308
+ if (!cleaned) {
3309
+ cleaned = true;
3310
+ if (timer) clearTimeout(timer);
3311
+ for (const socket of sockets) socket.destroy();
3312
+ sockets.clear();
3313
+ try {
3314
+ server.close();
3315
+ } catch {
3316
+ }
3317
+ }
3318
+ try {
3319
+ if (macIpc.removeArtifacts) {
3320
+ macIpc.removeArtifacts(launchDir);
3321
+ } else {
3322
+ (0, import_node_fs8.rmSync)(launchDir, {
3323
+ recursive: true,
3324
+ force: true,
3325
+ maxRetries: 3,
3326
+ retryDelay: 20
3327
+ });
3328
+ }
3329
+ } catch {
3330
+ }
3331
+ };
3332
+ try {
3333
+ (0, import_node_fs8.writeFileSync)(bootstrapFile, MAC_TERMINAL_BOOTSTRAP_SOURCE, { encoding: "utf8", mode: 448 });
3334
+ (0, import_node_fs8.writeFileSync)(commandFile, `#!/bin/bash
3335
+ rm -f -- "$0"
3336
+ exec ${shq(process.execPath)} ${shq(bootstrapFile)} ${shq(socketPath)} ${shq(launchDir)} ${shq(cwd ?? "")} ${runLine}
3337
+ `, {
3338
+ encoding: "utf8",
3339
+ mode: 448
3340
+ });
3341
+ (0, import_node_fs8.chmodSync)(commandFile, 448);
3342
+ (0, import_node_fs8.chmodSync)(bootstrapFile, 448);
3343
+ server.once("error", handleLaunchFailure);
3344
+ server.listen(socketPath, () => {
3345
+ if (cleaned) return;
3346
+ try {
3347
+ macIpc.onListening?.();
3348
+ if (cleaned) return;
3349
+ if (process.platform !== "win32") (0, import_node_fs8.chmodSync)(socketPath, 384);
3350
+ const opener = spawnProcess("open", ["-n", "-a", "Terminal", commandFile], {
3351
+ env: openerEnv,
3352
+ detached: true,
3353
+ stdio: "ignore"
3354
+ });
3355
+ opener.once("error", handleLaunchFailure);
3356
+ opener.unref();
3357
+ server.unref();
3358
+ } catch {
3359
+ handleLaunchFailure();
3360
+ }
3361
+ });
3362
+ timer = setTimeout(handleLaunchFailure, macIpc.timeoutMs ?? MAC_TERMINAL_IPC_TIMEOUT_MS);
3363
+ timer.unref?.();
3364
+ return cleanup;
3365
+ } catch (error) {
3366
+ cleanup();
3367
+ throw error;
3368
+ }
3122
3369
  }
3123
- (0, import_node_child_process.spawn)("x-terminal-emulator", ["-e", "bash", "-lc", `${script}; exec bash`], {
3370
+ spawnProcess("x-terminal-emulator", ["-e", "bash", "-lc", `${script}; exec bash`], {
3371
+ env: childEnv,
3124
3372
  detached: true,
3125
3373
  stdio: "ignore"
3126
3374
  }).unref();
3127
- };
3375
+ return () => {
3376
+ };
3377
+ }
3378
+ var defaultTerminalOpener = (input) => openTerminal(input);
3128
3379
  var sessions = /* @__PURE__ */ new Map();
3380
+ function resetCliSessions() {
3381
+ for (const s of sessions.values()) {
3382
+ try {
3383
+ s.onSessionEnd();
3384
+ } catch {
3385
+ }
3386
+ }
3387
+ sessions.clear();
3388
+ }
3129
3389
  function errBody(message) {
3130
3390
  return { error: { type: "admin_api_error", message } };
3131
3391
  }
@@ -3180,29 +3440,81 @@ async function handleCliLaunch(cli, body, ctx) {
3180
3440
  } catch (err5) {
3181
3441
  return { status: 400, body: errBody(err5 instanceof Error ? err5.message : "no launch target") };
3182
3442
  }
3443
+ const id = (0, import_node_crypto6.randomUUID)();
3444
+ let leaseId2;
3183
3445
  let launch;
3184
3446
  try {
3185
- launch = await buildLaunchEnv(cli, ctx.llmConfig, target);
3447
+ if ((cli === "claude" || cli === "codex") && ctx.routeLeaseManager) {
3448
+ const outcome = await ctx.routeLeaseManager.createFromRequest({
3449
+ schemaVersion: import_provider_proxy2.ROUTE_LEASE_REQUEST_SCHEMA,
3450
+ consumer: "omnicross-terminal",
3451
+ runtime: cli,
3452
+ upstream: { kind: "provider", providerId: target.providerId },
3453
+ model: target.model,
3454
+ execution: { sessionId: id }
3455
+ }, `omnicross-terminal:${id}`);
3456
+ leaseId2 = outcome.result.leaseId;
3457
+ const stopRenewal = startTerminalLeaseRenewal(ctx.routeLeaseManager, leaseId2);
3458
+ launch = {
3459
+ env: outcome.result.launch.env,
3460
+ extraArgs: outcome.result.launch.extraArgs,
3461
+ onSessionEnd: () => {
3462
+ stopRenewal();
3463
+ ctx.routeLeaseManager?.release(outcome.result.leaseId);
3464
+ }
3465
+ };
3466
+ } else {
3467
+ launch = await buildLaunchEnv(cli, ctx.llmConfig, target);
3468
+ }
3186
3469
  } catch (err5) {
3187
- return { status: 400, body: errBody(err5 instanceof Error ? err5.message : "failed to build launch env") };
3470
+ const status = err5 instanceof import_provider_proxy2.RouteLeaseError ? err5.status : 400;
3471
+ return { status, body: errBody(err5 instanceof Error ? err5.message : "failed to build launch env") };
3188
3472
  }
3189
3473
  const cwd = typeof body["cwd"] === "string" && body["cwd"].trim() ? body["cwd"].trim() : void 0;
3190
3474
  const opener = ctx.opener ?? defaultTerminalOpener;
3475
+ let openerCleanup;
3476
+ let ended = false;
3477
+ let published = false;
3478
+ const onSessionEnd = () => {
3479
+ if (ended) return;
3480
+ ended = true;
3481
+ if (published) sessions.delete(id);
3482
+ try {
3483
+ openerCleanup?.();
3484
+ } finally {
3485
+ launch.onSessionEnd();
3486
+ }
3487
+ };
3191
3488
  try {
3192
- opener({ cli, command: meta.command, extraArgs: launch.extraArgs ?? [], env: launch.env, cwd, platform });
3489
+ const cleanup = opener({
3490
+ cli,
3491
+ command: meta.command,
3492
+ extraArgs: launch.extraArgs ?? [],
3493
+ env: launch.env,
3494
+ cwd,
3495
+ platform,
3496
+ onFailure: onSessionEnd
3497
+ });
3498
+ if (cleanup) openerCleanup = cleanup;
3193
3499
  } catch (err5) {
3194
- launch.onSessionEnd();
3500
+ onSessionEnd();
3195
3501
  return { status: 500, body: errBody(err5 instanceof Error ? err5.message : "failed to open terminal") };
3196
3502
  }
3197
- const id = (0, import_node_crypto6.randomUUID)();
3503
+ if (ended) {
3504
+ openerCleanup?.();
3505
+ return { status: 500, body: errBody("failed to open terminal") };
3506
+ }
3198
3507
  sessions.set(id, {
3199
3508
  id,
3200
3509
  cli,
3201
3510
  providerId: target.providerId,
3202
3511
  model: target.model,
3512
+ ...leaseId2 ? { leaseId: leaseId2 } : {},
3203
3513
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
3204
- onSessionEnd: launch.onSessionEnd
3514
+ onSessionEnd
3205
3515
  });
3516
+ published = true;
3517
+ if (ended) sessions.delete(id);
3206
3518
  return { status: 200, body: { sessionId: id, providerId: target.providerId, model: target.model } };
3207
3519
  }
3208
3520
 
@@ -4079,7 +4391,7 @@ function sealPack(bundleJson, passphrase) {
4079
4391
  cipher.setAAD(aadFor(PACK_MAGIC, PACK_VERSION, KDF_ALGORITHM));
4080
4392
  const ciphertext = Buffer.concat([cipher.update(bundleJson, "utf8"), cipher.final()]);
4081
4393
  const tag = cipher.getAuthTag();
4082
- const header = {
4394
+ const header2 = {
4083
4395
  magic: PACK_MAGIC,
4084
4396
  v: PACK_VERSION,
4085
4397
  kdf: KDF_ALGORITHM,
@@ -4090,7 +4402,7 @@ function sealPack(bundleJson, passphrase) {
4090
4402
  iv: iv.toString("base64"),
4091
4403
  tag: tag.toString("base64")
4092
4404
  };
4093
- return `${PACK_PREFIX}${toB64Url(JSON.stringify(header))}.${ciphertext.toString("base64")}`;
4405
+ return `${PACK_PREFIX}${toB64Url(JSON.stringify(header2))}.${ciphertext.toString("base64")}`;
4094
4406
  }
4095
4407
  function parsePack(packString) {
4096
4408
  if (typeof packString !== "string" || !packString.startsWith(PACK_PREFIX)) {
@@ -4101,28 +4413,28 @@ function parsePack(packString) {
4101
4413
  if (dot < 0) throw new PackAuthError("migration pack is malformed (missing body)");
4102
4414
  const headerB64Url = rest.slice(0, dot);
4103
4415
  const ctB64 = rest.slice(dot + 1);
4104
- let header;
4416
+ let header2;
4105
4417
  try {
4106
- header = JSON.parse(fromB64Url(headerB64Url));
4418
+ header2 = JSON.parse(fromB64Url(headerB64Url));
4107
4419
  } catch {
4108
4420
  throw new PackAuthError("migration pack is malformed (unreadable header)");
4109
4421
  }
4110
- if (!header || header.magic !== PACK_MAGIC || header.v !== PACK_VERSION || header.kdf !== KDF_ALGORITHM || typeof header.salt !== "string" || typeof header.iv !== "string" || typeof header.tag !== "string" || typeof header.N !== "number" || typeof header.r !== "number" || typeof header.p !== "number") {
4422
+ if (!header2 || header2.magic !== PACK_MAGIC || header2.v !== PACK_VERSION || header2.kdf !== KDF_ALGORITHM || typeof header2.salt !== "string" || typeof header2.iv !== "string" || typeof header2.tag !== "string" || typeof header2.N !== "number" || typeof header2.r !== "number" || typeof header2.p !== "number") {
4111
4423
  throw new PackAuthError("migration pack is malformed (unsupported header)");
4112
4424
  }
4113
4425
  const ciphertext = Buffer.from(ctB64, "base64");
4114
- return { header, ciphertext };
4426
+ return { header: header2, ciphertext };
4115
4427
  }
4116
4428
  function openPack(packString, passphrase) {
4117
4429
  assertPassphraseStrength(passphrase);
4118
- const { header, ciphertext } = parsePack(packString);
4119
- const salt = Buffer.from(header.salt, "base64");
4120
- const iv = Buffer.from(header.iv, "base64");
4121
- const tag = Buffer.from(header.tag, "base64");
4430
+ const { header: header2, ciphertext } = parsePack(packString);
4431
+ const salt = Buffer.from(header2.salt, "base64");
4432
+ const iv = Buffer.from(header2.iv, "base64");
4433
+ const tag = Buffer.from(header2.tag, "base64");
4122
4434
  if (iv.length !== IV_BYTES2 || tag.length !== TAG_BYTES2) {
4123
4435
  throw new PackAuthError("migration pack is malformed (invalid iv/tag length)");
4124
4436
  }
4125
- const key = deriveKey(passphrase, salt, header.N, header.r, header.p);
4437
+ const key = deriveKey(passphrase, salt, header2.N, header2.r, header2.p);
4126
4438
  const decipher = (0, import_node_crypto8.createDecipheriv)("aes-256-gcm", key, iv);
4127
4439
  decipher.setAAD(aadFor(PACK_MAGIC, PACK_VERSION, KDF_ALGORITHM));
4128
4440
  decipher.setAuthTag(tag);
@@ -4458,10 +4770,10 @@ function writeJson2(res, status, body) {
4458
4770
  res.writeHead(status, { "Content-Type": "application/json" });
4459
4771
  res.end(JSON.stringify(body));
4460
4772
  }
4461
- function writeError(res, status, message) {
4773
+ function writeError2(res, status, message) {
4462
4774
  writeJson2(res, status, { error: { type: "account_allowance_error", message } });
4463
4775
  }
4464
- function readJson(req) {
4776
+ function readJson2(req) {
4465
4777
  return new Promise((resolve3, reject) => {
4466
4778
  const chunks = [];
4467
4779
  req.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
@@ -4487,10 +4799,10 @@ function allowanceProvider(value) {
4487
4799
  return value === "claude" || value === "codex" ? value : null;
4488
4800
  }
4489
4801
  async function handleAccountAllowanceApi(req, res, method, rest, service) {
4490
- if (!service) return writeError(res, 501, "account allowance service is not available");
4802
+ if (!service) return writeError2(res, 501, "account allowance service is not available");
4491
4803
  if (method === "GET" && rest.length === 1 && rest[0] === "scheduling") {
4492
4804
  if (!service.getSchedulingStatus) {
4493
- return writeError(res, 501, "allowance scheduling diagnostics are not available");
4805
+ return writeError2(res, 501, "allowance scheduling diagnostics are not available");
4494
4806
  }
4495
4807
  return writeJson2(res, 200, { scheduling: service.getSchedulingStatus() });
4496
4808
  }
@@ -4498,27 +4810,27 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
4498
4810
  const params = query(req);
4499
4811
  const pathProvider = rest.length >= 2 ? rest[0] : null;
4500
4812
  const providerId = allowanceProvider(pathProvider ?? params.get("providerId") ?? params.get("provider"));
4501
- if (providerId === null) return writeError(res, 400, "providerId must be claude or codex");
4813
+ if (providerId === null) return writeError2(res, 400, "providerId must be claude or codex");
4502
4814
  const accountId = rest.length >= 2 ? rest[1] : params.get("accountId") ?? void 0;
4503
4815
  const allowances = await service.list({ providerId, accountId });
4504
4816
  return writeJson2(res, 200, { allowances });
4505
4817
  }
4506
4818
  if (method === "POST" && rest[0] === "refresh") {
4507
- const body = await readJson(req);
4819
+ const body = await readJson2(req);
4508
4820
  const requestedProvider = allowanceProvider(
4509
4821
  typeof body["providerId"] === "string" ? body["providerId"] : "claude"
4510
4822
  );
4511
4823
  if (requestedProvider !== "claude") {
4512
- return writeError(res, 400, "only Claude allowances support explicit refresh");
4824
+ return writeError2(res, 400, "only Claude allowances support explicit refresh");
4513
4825
  }
4514
4826
  const accountId = typeof body["accountId"] === "string" && body["accountId"].trim() ? body["accountId"].trim() : void 0;
4515
4827
  const allowances = await service.refreshClaude(accountId);
4516
4828
  if (accountId && allowances.length === 0) {
4517
- return writeError(res, 404, `Claude account '${accountId}' not found`);
4829
+ return writeError2(res, 404, `Claude account '${accountId}' not found`);
4518
4830
  }
4519
4831
  return writeJson2(res, 200, { allowances });
4520
4832
  }
4521
- return writeError(res, 405, `method ${method} not allowed on account allowances`);
4833
+ return writeError2(res, 405, `method ${method} not allowed on account allowances`);
4522
4834
  }
4523
4835
 
4524
4836
  // src/admin/adminApi.ts
@@ -5750,6 +6062,7 @@ async function handleCli(req, res, method, rest, deps) {
5750
6062
  const result = await handleCliLaunch(cli, body, {
5751
6063
  llmConfig: deps.llmConfig,
5752
6064
  providers,
6065
+ routeLeaseManager: deps.routeLeaseManager,
5753
6066
  opener: deps.cliTerminalOpener,
5754
6067
  probe: deps.cliPathProbe
5755
6068
  });
@@ -6013,7 +6326,7 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
6013
6326
  }
6014
6327
 
6015
6328
  // src/admin/version.ts
6016
- var DAEMON_VERSION = true ? "0.1.7" : "0.0.0-dev";
6329
+ var DAEMON_VERSION = true ? "0.1.8" : "0.0.0-dev";
6017
6330
 
6018
6331
  // src/admin/AdminServer.ts
6019
6332
  var LOOPBACK_ADDR = "127.0.0.1";
@@ -6133,6 +6446,10 @@ var AdminServer = class {
6133
6446
  await handleWebhookTest(req, res);
6134
6447
  return;
6135
6448
  }
6449
+ if (path2 === "/admin/api/route-leases" || path2.startsWith("/admin/api/route-leases/")) {
6450
+ await handleRouteLeaseApi(req, res, path2, this.deps);
6451
+ return;
6452
+ }
6136
6453
  if (path2.startsWith("/admin/api/")) {
6137
6454
  await handleAdminApi(req, res, path2, this.deps);
6138
6455
  return;
@@ -6144,8 +6461,8 @@ var AdminServer = class {
6144
6461
  }
6145
6462
  /** Constant-time bearer/header check against the configured token. */
6146
6463
  isAuthorized(req, token) {
6147
- const header = req.headers["authorization"];
6148
- const bearer = typeof header === "string" && header.startsWith("Bearer ") ? header.slice("Bearer ".length).trim() : void 0;
6464
+ const header2 = req.headers["authorization"];
6465
+ const bearer = typeof header2 === "string" && header2.startsWith("Bearer ") ? header2.slice("Bearer ".length).trim() : void 0;
6149
6466
  const xToken = req.headers["x-admin-token"];
6150
6467
  const presented = bearer ?? (typeof xToken === "string" ? xToken.trim() : void 0);
6151
6468
  return constantTimeEquals(presented, token);
@@ -7510,9 +7827,9 @@ function findDuplicateCredentialIds(accounts) {
7510
7827
 
7511
7828
  // src/ports/external-cli-credentials.ts
7512
7829
  var import_node_fs16 = require("fs");
7513
- var import_node_os3 = require("os");
7830
+ var import_node_os4 = require("os");
7514
7831
  var import_node_path9 = require("path");
7515
- function externalStorePath(provider, home = (0, import_node_os3.homedir)()) {
7832
+ function externalStorePath(provider, home = (0, import_node_os4.homedir)()) {
7516
7833
  return provider === "claude" ? (0, import_node_path9.join)(home, ".claude", ".credentials.json") : (0, import_node_path9.join)(home, ".codex", "auth.json");
7517
7834
  }
7518
7835
  function decodeJwtExpiryMs(token) {
@@ -7560,7 +7877,7 @@ function parseCodexTokensEnvelope(raw) {
7560
7877
  }
7561
7878
  return parsed;
7562
7879
  }
7563
- function readExternalCliCredentials(provider, home = (0, import_node_os3.homedir)()) {
7880
+ function readExternalCliCredentials(provider, home = (0, import_node_os4.homedir)()) {
7564
7881
  const path2 = externalStorePath(provider, home);
7565
7882
  if (!(0, import_node_fs16.existsSync)(path2)) return null;
7566
7883
  let raw;
@@ -9445,6 +9762,76 @@ var TokenRefreshScheduler = class {
9445
9762
  }
9446
9763
  };
9447
9764
 
9765
+ // src/routeLeaseSubscriptionPreflight.ts
9766
+ var import_provider_proxy3 = require("@omnicross/core/provider-proxy");
9767
+ var import_AccountAllowanceScheduling4 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
9768
+ var import_SubscriptionAccountHealth3 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
9769
+ var import_accountModelMap = require("@omnicross/subscriptions/scheduler/accountModelMap");
9770
+ var PROVIDERS = /* @__PURE__ */ new Set(["claude", "codex", "gemini", "opencodego"]);
9771
+ function accountArray(config, providerId) {
9772
+ const record = config;
9773
+ const key = `${providerId}Accounts`;
9774
+ const accounts = record[key];
9775
+ if (Array.isArray(accounts)) return accounts;
9776
+ const legacy = record[providerId];
9777
+ if (!legacy || typeof legacy !== "object") return [];
9778
+ const activeKey = `active${providerId[0].toUpperCase()}${providerId.slice(1)}AccountId`;
9779
+ return [{ id: String(record[activeKey] ?? "active"), enabled: true, tokens: legacy }];
9780
+ }
9781
+ function hasCredential(providerId, account) {
9782
+ const tokens = account.tokens;
9783
+ if (providerId === "opencodego") return typeof tokens.apiKey === "string" && tokens.apiKey.length > 0;
9784
+ return typeof tokens.accessToken === "string" && tokens.accessToken.length > 0;
9785
+ }
9786
+ function safeProviderId(value) {
9787
+ if (!PROVIDERS.has(value)) {
9788
+ throw new import_provider_proxy3.RouteLeaseError("upstream_not_found", "subscription provider was not found");
9789
+ }
9790
+ return value;
9791
+ }
9792
+ function createRouteLeaseSubscriptionPreflight(credentials) {
9793
+ return {
9794
+ async assertAvailable(upstream, model) {
9795
+ const providerId = safeProviderId(upstream.providerId);
9796
+ const config = await credentials.getFullConfig();
9797
+ const all = accountArray(config, providerId);
9798
+ if (all.length === 0) {
9799
+ throw new import_provider_proxy3.RouteLeaseError("upstream_unavailable", "subscription provider has no configured account");
9800
+ }
9801
+ let bounded = all;
9802
+ if (upstream.kind === "account") {
9803
+ bounded = all.filter((account) => account.id === upstream.accountId);
9804
+ } else if (upstream.kind === "account-group") {
9805
+ bounded = all.filter((account) => account.group?.trim() === upstream.group);
9806
+ }
9807
+ if (bounded.length === 0) {
9808
+ throw new import_provider_proxy3.RouteLeaseError("upstream_not_found", "the selected subscription resource was not found");
9809
+ }
9810
+ const modelEligible = bounded.filter(
9811
+ (account) => (0, import_accountModelMap.accountSupportsModel)(account.supportedModels, model)
9812
+ );
9813
+ if (modelEligible.length === 0) {
9814
+ throw new import_provider_proxy3.RouteLeaseError("model_not_configured", "model is not supported by the selected subscription resource");
9815
+ }
9816
+ const credentialEligible = modelEligible.filter(
9817
+ (account) => account.enabled !== false && hasCredential(providerId, account)
9818
+ );
9819
+ const health2 = (0, import_SubscriptionAccountHealth3.getSharedAccountHealth)();
9820
+ const allowance = (0, import_AccountAllowanceScheduling4.getSharedAccountAllowanceScheduling)();
9821
+ const candidates = credentialEligible.filter(
9822
+ (account) => health2.isSchedulable(providerId, account.id) && allowance.preview(providerId, account.id, account.priority ?? 50).schedulable
9823
+ );
9824
+ if (candidates.length > 0) return;
9825
+ if (upstream.kind === "account") {
9826
+ throw new import_provider_proxy3.RouteLeaseError("upstream_unavailable", "the selected subscription account is unavailable");
9827
+ }
9828
+ throw new import_provider_proxy3.RouteLeaseError("upstream_exhausted", "the selected subscription pool has no eligible account", {
9829
+ retryAfterSeconds: 30
9830
+ });
9831
+ }
9832
+ };
9833
+ }
9834
+
9448
9835
  // src/webhook/WebhookDispatcher.ts
9449
9836
  var import_node_crypto14 = require("crypto");
9450
9837
  var import_upstreamFetch7 = require("@omnicross/core/pipeline/upstreamFetch");
@@ -9627,7 +10014,7 @@ function buildDaemon(config, paths) {
9627
10014
  new JsonAccountAllowancePersistence(defaultAccountAllowancePath(paths.configPath))
9628
10015
  );
9629
10016
  (0, import_AccountAllowanceStore4.setSharedAccountAllowanceStore)(accountAllowanceStore);
9630
- (0, import_AccountAllowanceScheduling4.getSharedAccountAllowanceScheduling)().configure(
10017
+ (0, import_AccountAllowanceScheduling5.getSharedAccountAllowanceScheduling)().configure(
9631
10018
  (0, import_outbound_api5.normalizeServerConfig)(decryptedConfig.server).allowanceScheduling
9632
10019
  );
9633
10020
  const llmConfig = new ConfigFileProviderConfigSource(decryptedConfig);
@@ -9694,11 +10081,22 @@ function buildDaemon(config, paths) {
9694
10081
  const usageRecorder = new import_usage.UsageRecorder(usageEventStore, pricingEngine, logger, {
9695
10082
  onRecord: (apiKeyId, costUsd, at) => keySpendTracker.add(apiKeyId, costUsd, at)
9696
10083
  });
9697
- const providerProxy = (0, import_provider_proxy.getProviderProxy)({ llmConfig, apiKeyPool, usageRecorder });
10084
+ const providerProxy = (0, import_provider_proxy4.getProviderProxy)({ llmConfig, apiKeyPool, usageRecorder });
10085
+ const routeLeaseManager = new import_provider_proxy4.RouteLeaseManager(
10086
+ providerProxy,
10087
+ new import_provider_proxy4.RouteLeaseTargetResolver(llmConfig, {
10088
+ providerKeys: apiKeyPool,
10089
+ subscriptions: createRouteLeaseSubscriptionPreflight(credentialStore)
10090
+ }),
10091
+ import_cli_launcher2.routeLeaseDescriptorPort,
10092
+ { logger }
10093
+ );
10094
+ providerProxy.registerBeforeStop(() => routeLeaseManager.shutdown());
10095
+ providerProxy.registerBeforeStop(() => resetCliSessions());
9698
10096
  llmConfig.setReloadHook(() => apiKeyPool.invalidateCache());
9699
10097
  const accountHealthProbeScheduler = new AccountHealthProbeScheduler(
9700
10098
  credentialStore,
9701
- (0, import_SubscriptionAccountHealth3.getSharedAccountHealth)(),
10099
+ (0, import_SubscriptionAccountHealth4.getSharedAccountHealth)(),
9702
10100
  logger,
9703
10101
  import_outbound_api5.DEFAULT_ACCOUNT_PROBE
9704
10102
  );
@@ -9745,6 +10143,7 @@ function buildDaemon(config, paths) {
9745
10143
  keySpendReader: keySpendTracker,
9746
10144
  settingsStore,
9747
10145
  outboundApiServer,
10146
+ routeLeaseManager,
9748
10147
  subscriptionAccounts,
9749
10148
  accountAllowanceService,
9750
10149
  allowanceRefreshScheduler: claudeAllowanceRefreshScheduler,
@@ -9837,7 +10236,7 @@ function buildDaemon(config, paths) {
9837
10236
  logger,
9838
10237
  fetchImpl: (url, init) => (0, import_upstreamFetch8.fetchUpstream)(url, init)
9839
10238
  });
9840
- setWebhookRuntime(webhookDispatcher, (0, import_SubscriptionAccountHealth3.getSharedAccountHealth)());
10239
+ setWebhookRuntime(webhookDispatcher, (0, import_SubscriptionAccountHealth4.getSharedAccountHealth)());
9841
10240
  const auditWriter = new AuditWriter(auditDir, logger);
9842
10241
  const auditPruneSweeper = new AuditPruneSweeper(auditDir, logger, import_audit_types.DEFAULT_AUDIT_CONFIG);
9843
10242
  setAuditRuntime(auditWriter, auditPruneSweeper);
@@ -9852,7 +10251,7 @@ function buildDaemon(config, paths) {
9852
10251
  const tokenRefreshScheduler = new TokenRefreshScheduler(credentialStore, logger);
9853
10252
  const accountHealthSweeper = new AccountHealthSweeper(
9854
10253
  credentialStore,
9855
- (0, import_SubscriptionAccountHealth3.getSharedAccountHealth)(),
10254
+ (0, import_SubscriptionAccountHealth4.getSharedAccountHealth)(),
9856
10255
  logger
9857
10256
  );
9858
10257
  return {
@@ -9861,6 +10260,7 @@ function buildDaemon(config, paths) {
9861
10260
  keyDb,
9862
10261
  settingsStore,
9863
10262
  providerProxy,
10263
+ routeLeaseManager,
9864
10264
  outboundApiServer,
9865
10265
  apiKeyPool,
9866
10266
  autoDisableStore,
@@ -9976,32 +10376,17 @@ async function runLaunch(argv, deps) {
9976
10376
  await daemon.llmConfig.ready();
9977
10377
  await daemon.providerProxy.start();
9978
10378
  } catch (err5) {
9979
- daemon.apiKeyPool.dispose();
9980
- daemon.tokenRefreshScheduler.dispose();
9981
- daemon.claudeAllowanceRefreshScheduler.dispose();
9982
- daemon.accountHealthSweeper.dispose();
9983
- daemon.accountHealthProbeScheduler.dispose();
9984
- daemon.auditPruneSweeper.dispose();
9985
- daemon.billingRetrySweeper.dispose();
9986
- daemon.pricingRefreshScheduler.dispose();
10379
+ await shutdownLaunchDaemon(daemon);
9987
10380
  throw err5;
9988
10381
  }
9989
10382
  let launch;
9990
10383
  try {
9991
- launch = await buildLaunchConfig(cli, daemon.llmConfig, {
10384
+ launch = await buildLaunchConfig(cli, daemon, {
9992
10385
  providerId: values.provider,
9993
10386
  model: values.model
9994
10387
  });
9995
10388
  } catch (err5) {
9996
- await daemon.providerProxy.stop();
9997
- daemon.apiKeyPool.dispose();
9998
- daemon.tokenRefreshScheduler.dispose();
9999
- daemon.claudeAllowanceRefreshScheduler.dispose();
10000
- daemon.accountHealthSweeper.dispose();
10001
- daemon.accountHealthProbeScheduler.dispose();
10002
- daemon.auditPruneSweeper.dispose();
10003
- daemon.billingRetrySweeper.dispose();
10004
- daemon.pricingRefreshScheduler.dispose();
10389
+ await shutdownLaunchDaemon(daemon);
10005
10390
  throw err5;
10006
10391
  }
10007
10392
  try {
@@ -10020,21 +10405,40 @@ async function runLaunch(argv, deps) {
10020
10405
  cwd: values.cwd
10021
10406
  });
10022
10407
  } finally {
10023
- launch.onSessionEnd();
10024
- await daemon.providerProxy.stop();
10025
- daemon.apiKeyPool.dispose();
10026
- daemon.tokenRefreshScheduler.dispose();
10027
- daemon.claudeAllowanceRefreshScheduler.dispose();
10028
- daemon.accountHealthSweeper.dispose();
10029
- daemon.accountHealthProbeScheduler.dispose();
10030
- daemon.auditPruneSweeper.dispose();
10031
- daemon.billingRetrySweeper.dispose();
10032
- daemon.pricingRefreshScheduler.dispose();
10033
- }
10034
- }
10035
- async function buildLaunchConfig(cli, llmConfig, opts) {
10408
+ try {
10409
+ launch.onSessionEnd();
10410
+ } finally {
10411
+ await shutdownLaunchDaemon(daemon);
10412
+ }
10413
+ }
10414
+ }
10415
+ async function buildLaunchConfig(cli, daemon, opts) {
10416
+ if (cli === "claude" || cli === "codex") {
10417
+ const internalId = (0, import_node_crypto15.randomUUID)();
10418
+ const outcome = await daemon.routeLeaseManager.createFromRequest({
10419
+ schemaVersion: import_provider_proxy5.ROUTE_LEASE_REQUEST_SCHEMA,
10420
+ consumer: "omnicross-terminal",
10421
+ runtime: cli,
10422
+ upstream: { kind: "provider", providerId: opts.providerId },
10423
+ model: opts.model,
10424
+ execution: { sessionId: `launch:${cli}:${internalId}` }
10425
+ }, `omnicross-launch:${internalId}`);
10426
+ const stopRenewal = startTerminalLeaseRenewal(
10427
+ daemon.routeLeaseManager,
10428
+ outcome.result.leaseId
10429
+ );
10430
+ return {
10431
+ baseUrl: daemon.providerProxy.getBaseUrl(),
10432
+ env: outcome.result.launch.env,
10433
+ extraArgs: outcome.result.launch.extraArgs,
10434
+ onSessionEnd: () => {
10435
+ stopRenewal();
10436
+ daemon.routeLeaseManager.release(outcome.result.leaseId);
10437
+ }
10438
+ };
10439
+ }
10036
10440
  const common = {
10037
- llmConfig,
10441
+ llmConfig: daemon.llmConfig,
10038
10442
  providerId: opts.providerId,
10039
10443
  model: opts.model,
10040
10444
  // Stable, bounded session id — pool failover (poolseam) fires on launch
@@ -10042,22 +10446,30 @@ async function buildLaunchConfig(cli, llmConfig, opts) {
10042
10446
  sessionId: `launch:${cli}`
10043
10447
  };
10044
10448
  switch (cli) {
10045
- case "claude":
10046
- return (0, import_cli_launcher2.buildClaudeCliLaunchConfig)(common);
10047
- case "codex":
10048
- return (0, import_cli_launcher2.buildCodexLaunchConfig)(common);
10049
10449
  case "gemini":
10050
- return (0, import_cli_launcher2.buildGeminiCliLaunchConfig)(common);
10450
+ return (0, import_cli_launcher3.buildGeminiCliLaunchConfig)(common);
10051
10451
  case "qwen":
10052
10452
  case "copilot":
10053
10453
  case "opencode":
10054
- return (0, import_cli_launcher2.buildChatCliLaunchConfig)({ backendId: cli, ...common });
10454
+ return (0, import_cli_launcher3.buildChatCliLaunchConfig)({ backendId: cli, ...common });
10055
10455
  default: {
10056
10456
  const _exhaustive = cli;
10057
10457
  throw new Error(`Unsupported launch CLI: ${String(_exhaustive)}`);
10058
10458
  }
10059
10459
  }
10060
10460
  }
10461
+ async function shutdownLaunchDaemon(daemon) {
10462
+ daemon.routeLeaseManager.shutdown();
10463
+ await daemon.providerProxy.stop();
10464
+ daemon.apiKeyPool.dispose();
10465
+ daemon.tokenRefreshScheduler.dispose();
10466
+ daemon.claudeAllowanceRefreshScheduler.dispose();
10467
+ daemon.accountHealthSweeper.dispose();
10468
+ daemon.accountHealthProbeScheduler.dispose();
10469
+ daemon.auditPruneSweeper.dispose();
10470
+ daemon.billingRetrySweeper.dispose();
10471
+ daemon.pricingRefreshScheduler.dispose();
10472
+ }
10061
10473
  function spawnCliInherit(plan) {
10062
10474
  return new Promise((resolve3, reject) => {
10063
10475
  const child = (0, import_node_child_process2.spawn)(plan.command, plan.args, {
@@ -10104,7 +10516,7 @@ var import_node_readline = require("readline");
10104
10516
  var import_node_util5 = require("util");
10105
10517
  var import_upstreamFetch9 = require("@omnicross/core/pipeline/upstreamFetch");
10106
10518
  var import_subscriptions5 = require("@omnicross/subscriptions");
10107
- var PROVIDERS = ["claude", "codex", "gemini"];
10519
+ var PROVIDERS2 = ["claude", "codex", "gemini"];
10108
10520
  async function runLogin(argv, deps) {
10109
10521
  const { values, positionals } = (0, import_node_util5.parseArgs)({
10110
10522
  args: argv,
@@ -10118,10 +10530,10 @@ async function runLogin(argv, deps) {
10118
10530
  });
10119
10531
  const provider = positionals[0];
10120
10532
  if (!provider) {
10121
- throw new Error(`login: a <provider> is required (one of ${PROVIDERS.join("|")})`);
10533
+ throw new Error(`login: a <provider> is required (one of ${PROVIDERS2.join("|")})`);
10122
10534
  }
10123
10535
  if (!isLoginProvider(provider)) {
10124
- throw new Error(`login: unknown provider '${provider}' (expected ${PROVIDERS.join("|")})`);
10536
+ throw new Error(`login: unknown provider '${provider}' (expected ${PROVIDERS2.join("|")})`);
10125
10537
  }
10126
10538
  if (!values.config) {
10127
10539
  throw new Error("login: --config <path> is required");
@@ -10227,7 +10639,7 @@ async function loginGemini(store, deps, exchangeFetch, label) {
10227
10639
  return expiresAt;
10228
10640
  }
10229
10641
  function isLoginProvider(value) {
10230
- return PROVIDERS.includes(value);
10642
+ return PROVIDERS2.includes(value);
10231
10643
  }
10232
10644
  async function presentUrl(authUrl, deps) {
10233
10645
  console.info("Open this URL in your browser to authorize:");
@@ -10273,7 +10685,7 @@ function promptPaste(prompt) {
10273
10685
  }
10274
10686
 
10275
10687
  // src/commands/providers.ts
10276
- var import_node_crypto15 = require("crypto");
10688
+ var import_node_crypto16 = require("crypto");
10277
10689
  var import_node_util6 = require("util");
10278
10690
  async function runProviders(argv) {
10279
10691
  const { values, positionals } = (0, import_node_util6.parseArgs)({
@@ -10395,7 +10807,7 @@ function providersAddKey(configPath, providerId, opts) {
10395
10807
  const cfg = loadConfig(configPath);
10396
10808
  const row = cfg.providers.find((p) => p.id === providerId);
10397
10809
  if (!row) throw new Error(`providers add-key: unknown provider '${providerId}'`);
10398
- const entry = { id: (0, import_node_crypto15.randomUUID)(), apiKey: opts.key };
10810
+ const entry = { id: (0, import_node_crypto16.randomUUID)(), apiKey: opts.key };
10399
10811
  if (opts.label) entry.label = opts.label;
10400
10812
  if (opts.weight !== void 0) {
10401
10813
  const w = Number(opts.weight);
@@ -10670,8 +11082,8 @@ function tokensSuffix(configPath) {
10670
11082
  // src/commands/start.ts
10671
11083
  var import_node_util8 = require("util");
10672
11084
  var import_outbound_api7 = require("@omnicross/core/outbound-api");
10673
- var import_SubscriptionAccountHealth4 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
10674
- var import_AccountAllowanceScheduling5 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
11085
+ var import_SubscriptionAccountHealth5 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
11086
+ var import_AccountAllowanceScheduling6 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
10675
11087
 
10676
11088
  // src/identity/identityRuntime.ts
10677
11089
  var import_SubscriptionIdentityStore4 = require("@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore");
@@ -10731,11 +11143,11 @@ async function runStart(argv) {
10731
11143
  await daemon.llmConfig.ready();
10732
11144
  await daemon.providerProxy.start();
10733
11145
  const serverConfig = await (0, import_outbound_api7.loadServerConfig)(daemon.settingsStore);
10734
- (0, import_SubscriptionAccountHealth4.getSharedAccountHealth)().configure({
11146
+ (0, import_SubscriptionAccountHealth5.getSharedAccountHealth)().configure({
10735
11147
  overloadEnabled: serverConfig.accountHealth?.overloadCooldownEnabled,
10736
11148
  overloadTtlMs: serverConfig.accountHealth?.overloadCooldownMs
10737
11149
  });
10738
- (0, import_AccountAllowanceScheduling5.getSharedAccountAllowanceScheduling)().configure(serverConfig.allowanceScheduling);
11150
+ (0, import_AccountAllowanceScheduling6.getSharedAccountAllowanceScheduling)().configure(serverConfig.allowanceScheduling);
10739
11151
  daemon.claudeAllowanceRefreshScheduler.configure(serverConfig.allowanceScheduling);
10740
11152
  await daemon.outboundApiServer.applyConfig({
10741
11153
  enabled: true,