@omnicross/daemon 0.1.7 → 0.1.9
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 +559 -99
- package/dist/cli.js +584 -114
- package/dist/index.cjs +498 -52
- package/dist/index.d.cts +20 -7
- package/dist/index.d.ts +20 -7
- package/dist/index.js +523 -65
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -520,6 +520,35 @@ function validateApiKeys(raw) {
|
|
|
520
520
|
}
|
|
521
521
|
return out.length > 0 ? out : void 0;
|
|
522
522
|
}
|
|
523
|
+
var THINK_LEVELS = /* @__PURE__ */ new Set([
|
|
524
|
+
"none",
|
|
525
|
+
"minimal",
|
|
526
|
+
"low",
|
|
527
|
+
"medium",
|
|
528
|
+
"high",
|
|
529
|
+
"xhigh",
|
|
530
|
+
"max"
|
|
531
|
+
]);
|
|
532
|
+
function validateThinkingLevels(raw) {
|
|
533
|
+
if (!Array.isArray(raw)) return void 0;
|
|
534
|
+
if (!raw.every((level) => typeof level === "string" && THINK_LEVELS.has(level))) {
|
|
535
|
+
return void 0;
|
|
536
|
+
}
|
|
537
|
+
return [...raw];
|
|
538
|
+
}
|
|
539
|
+
function validateThinkingTokenLimit(raw) {
|
|
540
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
|
|
541
|
+
const bounds = raw;
|
|
542
|
+
const min = bounds["min"];
|
|
543
|
+
const max = bounds["max"];
|
|
544
|
+
if (typeof min !== "number" || !Number.isFinite(min) || !Number.isInteger(min) || min < 0) {
|
|
545
|
+
return void 0;
|
|
546
|
+
}
|
|
547
|
+
if (typeof max !== "number" || !Number.isFinite(max) || !Number.isInteger(max) || max < min) {
|
|
548
|
+
return void 0;
|
|
549
|
+
}
|
|
550
|
+
return { min, max };
|
|
551
|
+
}
|
|
523
552
|
function validateModelConfigs(raw) {
|
|
524
553
|
if (!Array.isArray(raw)) return void 0;
|
|
525
554
|
const out = [];
|
|
@@ -534,6 +563,10 @@ function validateModelConfigs(raw) {
|
|
|
534
563
|
if (typeof m["enabled"] === "boolean") entry.enabled = m["enabled"];
|
|
535
564
|
if (typeof m["vision"] === "boolean") entry.vision = m["vision"];
|
|
536
565
|
if (typeof m["reasoning"] === "boolean") entry.reasoning = m["reasoning"];
|
|
566
|
+
const thinkingLevels = validateThinkingLevels(m["thinkingLevels"]);
|
|
567
|
+
if (thinkingLevels) entry.thinkingLevels = thinkingLevels;
|
|
568
|
+
const thinkingTokenLimit = validateThinkingTokenLimit(m["thinkingTokenLimit"]);
|
|
569
|
+
if (thinkingTokenLimit) entry.thinkingTokenLimit = thinkingTokenLimit;
|
|
537
570
|
out.push(entry);
|
|
538
571
|
}
|
|
539
572
|
return out.length > 0 ? out : void 0;
|
|
@@ -1765,10 +1798,12 @@ async function keysRevoke(db, id) {
|
|
|
1765
1798
|
|
|
1766
1799
|
// src/commands/launch.ts
|
|
1767
1800
|
var import_node_child_process2 = require("child_process");
|
|
1801
|
+
var import_node_crypto15 = require("crypto");
|
|
1768
1802
|
var import_node_fs25 = require("fs");
|
|
1769
1803
|
var import_node_path17 = require("path");
|
|
1770
1804
|
var import_node_util4 = require("util");
|
|
1771
|
-
var
|
|
1805
|
+
var import_cli_launcher3 = require("@omnicross/cli-launcher");
|
|
1806
|
+
var import_provider_proxy5 = require("@omnicross/core/provider-proxy");
|
|
1772
1807
|
|
|
1773
1808
|
// src/bootstrap.ts
|
|
1774
1809
|
var import_node_fs24 = require("fs");
|
|
@@ -1778,13 +1813,14 @@ var import_GeminiCodeAssistProjectResolver = require("@omnicross/core/auth/Gemin
|
|
|
1778
1813
|
var import_ApiKeyPoolService = require("@omnicross/core/completion/ApiKeyPoolService");
|
|
1779
1814
|
var import_outbound_api5 = require("@omnicross/core/outbound-api");
|
|
1780
1815
|
var import_subscriptionRegistryPort = require("@omnicross/core/outbound-api/subscriptionRegistryPort");
|
|
1781
|
-
var
|
|
1816
|
+
var import_SubscriptionAccountHealth4 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
|
|
1782
1817
|
var import_AccountAllowanceStore4 = require("@omnicross/core/pipeline/AccountAllowanceStore");
|
|
1783
|
-
var
|
|
1818
|
+
var import_AccountAllowanceScheduling5 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
|
|
1784
1819
|
var import_upstreamFetch8 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
1785
1820
|
var import_SubscriptionIdentityStore3 = require("@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore");
|
|
1786
1821
|
var import_gemini_code_assist_resolver = require("@omnicross/core/ports/gemini-code-assist-resolver");
|
|
1787
|
-
var
|
|
1822
|
+
var import_provider_proxy4 = require("@omnicross/core/provider-proxy");
|
|
1823
|
+
var import_cli_launcher2 = require("@omnicross/cli-launcher");
|
|
1788
1824
|
var import_outbound_api6 = require("@omnicross/core/outbound-api");
|
|
1789
1825
|
var import_usage = require("@omnicross/core/usage");
|
|
1790
1826
|
var import_subscriptions4 = require("@omnicross/subscriptions");
|
|
@@ -2467,6 +2503,88 @@ async function handleWebhookTest(req, res) {
|
|
|
2467
2503
|
res.end(JSON.stringify({ result }));
|
|
2468
2504
|
}
|
|
2469
2505
|
|
|
2506
|
+
// src/admin/routeLeaseApi.ts
|
|
2507
|
+
var import_provider_proxy = require("@omnicross/core/provider-proxy");
|
|
2508
|
+
var MAX_BODY_BYTES = 64 * 1024;
|
|
2509
|
+
var SAFE_LEASE_ID = /^[A-Za-z0-9-]{1,128}$/u;
|
|
2510
|
+
async function readJson(req) {
|
|
2511
|
+
const chunks = [];
|
|
2512
|
+
let bytes = 0;
|
|
2513
|
+
for await (const chunk of req) {
|
|
2514
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
2515
|
+
bytes += buffer.length;
|
|
2516
|
+
if (bytes > MAX_BODY_BYTES) throw new import_provider_proxy.RouteLeaseError("invalid_request", "request body is too large");
|
|
2517
|
+
chunks.push(buffer);
|
|
2518
|
+
}
|
|
2519
|
+
if (chunks.length === 0) return {};
|
|
2520
|
+
try {
|
|
2521
|
+
return JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
2522
|
+
} catch {
|
|
2523
|
+
throw new import_provider_proxy.RouteLeaseError("invalid_request", "request body is not valid JSON");
|
|
2524
|
+
}
|
|
2525
|
+
}
|
|
2526
|
+
function json(res, status, body, noStore = false) {
|
|
2527
|
+
res.statusCode = status;
|
|
2528
|
+
res.setHeader("Content-Type", "application/json");
|
|
2529
|
+
if (noStore) res.setHeader("Cache-Control", "no-store");
|
|
2530
|
+
res.end(JSON.stringify(body));
|
|
2531
|
+
}
|
|
2532
|
+
function leaseId(value) {
|
|
2533
|
+
if (!value || !SAFE_LEASE_ID.test(value)) throw new import_provider_proxy.RouteLeaseError("invalid_request", "lease id is invalid");
|
|
2534
|
+
return value;
|
|
2535
|
+
}
|
|
2536
|
+
function header(req, name) {
|
|
2537
|
+
const value = req.headers[name.toLowerCase()];
|
|
2538
|
+
return Array.isArray(value) ? value[0] : value;
|
|
2539
|
+
}
|
|
2540
|
+
function writeError(res, error, noStore) {
|
|
2541
|
+
const safe = error instanceof import_provider_proxy.RouteLeaseError ? error : new import_provider_proxy.RouteLeaseError("upstream_unavailable", "route lease operation failed safely");
|
|
2542
|
+
if (safe.retryAfterSeconds !== void 0) res.setHeader("Retry-After", String(safe.retryAfterSeconds));
|
|
2543
|
+
json(res, safe.status, safe.toResponse(), noStore);
|
|
2544
|
+
}
|
|
2545
|
+
async function handleRouteLeaseApi(req, res, path2, deps) {
|
|
2546
|
+
const method = (req.method ?? "GET").toUpperCase();
|
|
2547
|
+
const noStore = method === "POST" && (path2 === "/admin/api/route-leases" || path2.endsWith("/renew"));
|
|
2548
|
+
try {
|
|
2549
|
+
if (!(0, import_provider_proxy.isLoopbackAddress)(req.socket.remoteAddress)) {
|
|
2550
|
+
throw new import_provider_proxy.RouteLeaseError("control_unauthorized", "route lease control plane is loopback only");
|
|
2551
|
+
}
|
|
2552
|
+
const manager = deps.routeLeaseManager;
|
|
2553
|
+
if (!manager) throw new import_provider_proxy.RouteLeaseError("daemon_not_ready", "route lease manager is unavailable");
|
|
2554
|
+
const base = "/admin/api/route-leases";
|
|
2555
|
+
const suffix = path2.slice(base.length).replace(/^\/+|\/+$/gu, "");
|
|
2556
|
+
const segments = suffix ? suffix.split("/") : [];
|
|
2557
|
+
if (segments.length === 1 && segments[0] === "capabilities") {
|
|
2558
|
+
if (method !== "GET" && method !== "HEAD") throw new import_provider_proxy.RouteLeaseError("invalid_request", "method is not allowed");
|
|
2559
|
+
return json(res, 200, import_provider_proxy.ROUTE_LEASE_CAPABILITIES);
|
|
2560
|
+
}
|
|
2561
|
+
if (segments.length === 0) {
|
|
2562
|
+
if (method === "GET") return json(res, 200, { leases: manager.list() });
|
|
2563
|
+
if (method === "POST") {
|
|
2564
|
+
const outcome = await manager.createFromRequest(await readJson(req), header(req, "idempotency-key"));
|
|
2565
|
+
return json(res, outcome.created ? 201 : 200, outcome.result, true);
|
|
2566
|
+
}
|
|
2567
|
+
throw new import_provider_proxy.RouteLeaseError("invalid_request", "method is not allowed");
|
|
2568
|
+
}
|
|
2569
|
+
const id = leaseId(segments[0]);
|
|
2570
|
+
if (segments.length === 1) {
|
|
2571
|
+
if (method === "GET") return json(res, 200, manager.get(id));
|
|
2572
|
+
if (method === "DELETE") return json(res, 200, manager.release(id));
|
|
2573
|
+
throw new import_provider_proxy.RouteLeaseError("invalid_request", "method is not allowed");
|
|
2574
|
+
}
|
|
2575
|
+
if (segments.length === 2 && segments[1] === "renew" && method === "POST") {
|
|
2576
|
+
const body = await readJson(req);
|
|
2577
|
+
const ttl = (0, import_provider_proxy.normalizeRouteLeaseTtl)(
|
|
2578
|
+
body && typeof body === "object" && !Array.isArray(body) ? body.ttlSeconds : void 0
|
|
2579
|
+
);
|
|
2580
|
+
return json(res, 200, manager.renew(id, ttl), true);
|
|
2581
|
+
}
|
|
2582
|
+
throw new import_provider_proxy.RouteLeaseError("lease_not_found", "route lease endpoint was not found");
|
|
2583
|
+
} catch (error) {
|
|
2584
|
+
writeError(res, error, noStore);
|
|
2585
|
+
}
|
|
2586
|
+
}
|
|
2587
|
+
|
|
2470
2588
|
// src/admin/adminApi.ts
|
|
2471
2589
|
var import_node_http = __toESM(require("http"), 1);
|
|
2472
2590
|
var import_outbound_api3 = require("@omnicross/core/outbound-api");
|
|
@@ -3016,8 +3134,34 @@ async function exchangeGemini(code, codeVerifier, exchangeFetch) {
|
|
|
3016
3134
|
var import_node_child_process = require("child_process");
|
|
3017
3135
|
var import_node_crypto6 = require("crypto");
|
|
3018
3136
|
var import_node_fs8 = require("fs");
|
|
3137
|
+
var import_node_net = require("net");
|
|
3138
|
+
var import_node_os3 = require("os");
|
|
3019
3139
|
var import_node_path7 = require("path");
|
|
3020
3140
|
var import_cli_launcher = require("@omnicross/cli-launcher");
|
|
3141
|
+
var import_provider_proxy2 = require("@omnicross/core/provider-proxy");
|
|
3142
|
+
|
|
3143
|
+
// src/routeLeaseRenewal.ts
|
|
3144
|
+
var TERMINAL_LEASE_TTL_SECONDS = 600;
|
|
3145
|
+
var TERMINAL_LEASE_RENEW_INTERVAL_MS = 5 * 60 * 1e3;
|
|
3146
|
+
var TERMINAL_LEASE_MAX_LIFETIME_MS = 24 * 60 * 60 * 1e3;
|
|
3147
|
+
function startTerminalLeaseRenewal(manager, leaseId2) {
|
|
3148
|
+
const stopAt = Date.now() + TERMINAL_LEASE_MAX_LIFETIME_MS;
|
|
3149
|
+
const timer = setInterval(() => {
|
|
3150
|
+
if (Date.now() >= stopAt) {
|
|
3151
|
+
clearInterval(timer);
|
|
3152
|
+
return;
|
|
3153
|
+
}
|
|
3154
|
+
try {
|
|
3155
|
+
manager.renew(leaseId2, TERMINAL_LEASE_TTL_SECONDS);
|
|
3156
|
+
} catch {
|
|
3157
|
+
clearInterval(timer);
|
|
3158
|
+
}
|
|
3159
|
+
}, TERMINAL_LEASE_RENEW_INTERVAL_MS);
|
|
3160
|
+
timer.unref?.();
|
|
3161
|
+
return () => clearInterval(timer);
|
|
3162
|
+
}
|
|
3163
|
+
|
|
3164
|
+
// src/admin/cliLaunch.ts
|
|
3021
3165
|
var LAUNCHABLE_CLIS = [
|
|
3022
3166
|
{ id: "claude", displayName: "Claude Code", command: "claude" },
|
|
3023
3167
|
{ id: "codex", displayName: "Codex CLI", command: "codex" },
|
|
@@ -3098,34 +3242,183 @@ async function buildLaunchEnv(cli, llmConfig, target) {
|
|
|
3098
3242
|
function shq(s) {
|
|
3099
3243
|
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
3100
3244
|
}
|
|
3101
|
-
var
|
|
3245
|
+
var MAC_TERMINAL_BOOTSTRAP_SOURCE = `
|
|
3246
|
+
'use strict';
|
|
3247
|
+
const fs = require('node:fs');
|
|
3248
|
+
const net = require('node:net');
|
|
3249
|
+
const { spawn } = require('node:child_process');
|
|
3250
|
+
const [socketPath, launchDir, cwd, command, ...args] = process.argv.slice(2);
|
|
3251
|
+
let payload = '';
|
|
3252
|
+
const socket = net.createConnection(socketPath);
|
|
3253
|
+
socket.setEncoding('utf8');
|
|
3254
|
+
socket.on('data', (chunk) => { payload += chunk; });
|
|
3255
|
+
socket.on('end', () => {
|
|
3256
|
+
const descriptor = JSON.parse(payload);
|
|
3257
|
+
if (!descriptor || Array.isArray(descriptor) || Object.values(descriptor).some((value) => typeof value !== 'string')) {
|
|
3258
|
+
throw new Error('invalid terminal launch descriptor');
|
|
3259
|
+
}
|
|
3260
|
+
try { fs.rmSync(launchDir, { recursive: true, force: true }); } catch {}
|
|
3261
|
+
const child = spawn(command, args, {
|
|
3262
|
+
cwd: cwd || undefined,
|
|
3263
|
+
env: { ...process.env, ...descriptor },
|
|
3264
|
+
stdio: 'inherit',
|
|
3265
|
+
});
|
|
3266
|
+
child.on('error', (error) => { console.error(error.message); process.exitCode = 1; });
|
|
3267
|
+
child.on('exit', (code, signal) => {
|
|
3268
|
+
if (signal) process.kill(process.pid, signal);
|
|
3269
|
+
else process.exitCode = code == null ? 1 : code;
|
|
3270
|
+
});
|
|
3271
|
+
});
|
|
3272
|
+
socket.on('error', (error) => { console.error(error.message); process.exitCode = 1; });
|
|
3273
|
+
`;
|
|
3274
|
+
var MAC_TERMINAL_IPC_TIMEOUT_MS = 12e4;
|
|
3275
|
+
function openTerminal({ cli, command, extraArgs, env, cwd, platform, onFailure }, spawnProcess = import_node_child_process.spawn, macIpc = {}) {
|
|
3102
3276
|
const childEnv = { ...process.env, ...env };
|
|
3103
3277
|
if (platform === "win32") {
|
|
3104
3278
|
const args = ["/c", "start", `"omnicross ${cli}"`];
|
|
3105
3279
|
if (cwd) args.push("/D", `"${cwd}"`);
|
|
3106
3280
|
args.push("cmd", "/k", command, ...extraArgs);
|
|
3107
|
-
(
|
|
3281
|
+
spawnProcess(process.env["ComSpec"] || "cmd.exe", args, {
|
|
3108
3282
|
env: childEnv,
|
|
3109
3283
|
windowsVerbatimArguments: true,
|
|
3110
3284
|
detached: true,
|
|
3111
3285
|
stdio: "ignore"
|
|
3112
3286
|
}).unref();
|
|
3113
|
-
return
|
|
3287
|
+
return () => {
|
|
3288
|
+
};
|
|
3114
3289
|
}
|
|
3115
|
-
const exportLine = Object.entries(env).map(([k, v]) => `export ${k}=${shq(v)}`).join("; ");
|
|
3116
3290
|
const runLine = [command, ...extraArgs].map(shq).join(" ");
|
|
3117
|
-
const script = `${
|
|
3291
|
+
const script = `${cwd ? `cd ${shq(cwd)}; ` : ""}${runLine}`;
|
|
3118
3292
|
if (platform === "darwin") {
|
|
3119
|
-
const
|
|
3120
|
-
(0,
|
|
3121
|
-
|
|
3293
|
+
const launchDir = (0, import_node_fs8.mkdtempSync)((0, import_node_path7.join)((0, import_node_os3.tmpdir)(), "omnicross-terminal-"));
|
|
3294
|
+
const commandFile = (0, import_node_path7.join)(launchDir, "launch.command");
|
|
3295
|
+
const bootstrapFile = (0, import_node_path7.join)(launchDir, "bootstrap.cjs");
|
|
3296
|
+
const socketPath = macIpc.socketPath ?? (0, import_node_path7.join)(launchDir, "descriptor.sock");
|
|
3297
|
+
const openerEnv = { ...process.env };
|
|
3298
|
+
for (const key of Object.keys(env)) delete openerEnv[key];
|
|
3299
|
+
let claimed = false;
|
|
3300
|
+
let cleaned = false;
|
|
3301
|
+
let failureNotified = false;
|
|
3302
|
+
let timer;
|
|
3303
|
+
const notifyFailure = () => {
|
|
3304
|
+
cleanup();
|
|
3305
|
+
if (failureNotified) return;
|
|
3306
|
+
failureNotified = true;
|
|
3307
|
+
try {
|
|
3308
|
+
onFailure?.();
|
|
3309
|
+
} catch {
|
|
3310
|
+
}
|
|
3311
|
+
};
|
|
3312
|
+
const handleLaunchFailure = () => {
|
|
3313
|
+
if (claimed) cleanup();
|
|
3314
|
+
else notifyFailure();
|
|
3315
|
+
};
|
|
3316
|
+
const sockets = /* @__PURE__ */ new Set();
|
|
3317
|
+
const server = (0, import_node_net.createServer)((socket) => {
|
|
3318
|
+
socket.unref();
|
|
3319
|
+
sockets.add(socket);
|
|
3320
|
+
socket.once("close", () => sockets.delete(socket));
|
|
3321
|
+
try {
|
|
3322
|
+
macIpc.onAccepted?.(socket);
|
|
3323
|
+
} catch {
|
|
3324
|
+
cleanup();
|
|
3325
|
+
return;
|
|
3326
|
+
}
|
|
3327
|
+
if (claimed || cleaned) {
|
|
3328
|
+
socket.destroy();
|
|
3329
|
+
return;
|
|
3330
|
+
}
|
|
3331
|
+
claimed = true;
|
|
3332
|
+
try {
|
|
3333
|
+
macIpc.onClaimed?.();
|
|
3334
|
+
if (cleaned) return;
|
|
3335
|
+
socket.end(JSON.stringify(env), cleanup);
|
|
3336
|
+
} catch {
|
|
3337
|
+
cleanup();
|
|
3338
|
+
}
|
|
3339
|
+
});
|
|
3340
|
+
const cleanup = () => {
|
|
3341
|
+
if (!cleaned) {
|
|
3342
|
+
cleaned = true;
|
|
3343
|
+
if (timer) clearTimeout(timer);
|
|
3344
|
+
for (const socket of sockets) socket.destroy();
|
|
3345
|
+
sockets.clear();
|
|
3346
|
+
try {
|
|
3347
|
+
server.close();
|
|
3348
|
+
} catch {
|
|
3349
|
+
}
|
|
3350
|
+
}
|
|
3351
|
+
try {
|
|
3352
|
+
if (macIpc.removeArtifacts) {
|
|
3353
|
+
macIpc.removeArtifacts(launchDir);
|
|
3354
|
+
} else {
|
|
3355
|
+
(0, import_node_fs8.rmSync)(launchDir, {
|
|
3356
|
+
recursive: true,
|
|
3357
|
+
force: true,
|
|
3358
|
+
maxRetries: 3,
|
|
3359
|
+
retryDelay: 20
|
|
3360
|
+
});
|
|
3361
|
+
}
|
|
3362
|
+
} catch {
|
|
3363
|
+
}
|
|
3364
|
+
};
|
|
3365
|
+
try {
|
|
3366
|
+
(0, import_node_fs8.writeFileSync)(bootstrapFile, MAC_TERMINAL_BOOTSTRAP_SOURCE, { encoding: "utf8", mode: 448 });
|
|
3367
|
+
(0, import_node_fs8.writeFileSync)(commandFile, `#!/bin/bash
|
|
3368
|
+
rm -f -- "$0"
|
|
3369
|
+
exec ${shq(process.execPath)} ${shq(bootstrapFile)} ${shq(socketPath)} ${shq(launchDir)} ${shq(cwd ?? "")} ${runLine}
|
|
3370
|
+
`, {
|
|
3371
|
+
encoding: "utf8",
|
|
3372
|
+
mode: 448
|
|
3373
|
+
});
|
|
3374
|
+
(0, import_node_fs8.chmodSync)(commandFile, 448);
|
|
3375
|
+
(0, import_node_fs8.chmodSync)(bootstrapFile, 448);
|
|
3376
|
+
server.once("error", handleLaunchFailure);
|
|
3377
|
+
server.listen(socketPath, () => {
|
|
3378
|
+
if (cleaned) return;
|
|
3379
|
+
try {
|
|
3380
|
+
macIpc.onListening?.();
|
|
3381
|
+
if (cleaned) return;
|
|
3382
|
+
if (process.platform !== "win32") (0, import_node_fs8.chmodSync)(socketPath, 384);
|
|
3383
|
+
const opener = spawnProcess("open", ["-n", "-a", "Terminal", commandFile], {
|
|
3384
|
+
env: openerEnv,
|
|
3385
|
+
detached: true,
|
|
3386
|
+
stdio: "ignore"
|
|
3387
|
+
});
|
|
3388
|
+
opener.once("error", handleLaunchFailure);
|
|
3389
|
+
opener.unref();
|
|
3390
|
+
server.unref();
|
|
3391
|
+
} catch {
|
|
3392
|
+
handleLaunchFailure();
|
|
3393
|
+
}
|
|
3394
|
+
});
|
|
3395
|
+
timer = setTimeout(handleLaunchFailure, macIpc.timeoutMs ?? MAC_TERMINAL_IPC_TIMEOUT_MS);
|
|
3396
|
+
timer.unref?.();
|
|
3397
|
+
return cleanup;
|
|
3398
|
+
} catch (error) {
|
|
3399
|
+
cleanup();
|
|
3400
|
+
throw error;
|
|
3401
|
+
}
|
|
3122
3402
|
}
|
|
3123
|
-
(
|
|
3403
|
+
spawnProcess("x-terminal-emulator", ["-e", "bash", "-lc", `${script}; exec bash`], {
|
|
3404
|
+
env: childEnv,
|
|
3124
3405
|
detached: true,
|
|
3125
3406
|
stdio: "ignore"
|
|
3126
3407
|
}).unref();
|
|
3127
|
-
|
|
3408
|
+
return () => {
|
|
3409
|
+
};
|
|
3410
|
+
}
|
|
3411
|
+
var defaultTerminalOpener = (input) => openTerminal(input);
|
|
3128
3412
|
var sessions = /* @__PURE__ */ new Map();
|
|
3413
|
+
function resetCliSessions() {
|
|
3414
|
+
for (const s of sessions.values()) {
|
|
3415
|
+
try {
|
|
3416
|
+
s.onSessionEnd();
|
|
3417
|
+
} catch {
|
|
3418
|
+
}
|
|
3419
|
+
}
|
|
3420
|
+
sessions.clear();
|
|
3421
|
+
}
|
|
3129
3422
|
function errBody(message) {
|
|
3130
3423
|
return { error: { type: "admin_api_error", message } };
|
|
3131
3424
|
}
|
|
@@ -3180,29 +3473,81 @@ async function handleCliLaunch(cli, body, ctx) {
|
|
|
3180
3473
|
} catch (err5) {
|
|
3181
3474
|
return { status: 400, body: errBody(err5 instanceof Error ? err5.message : "no launch target") };
|
|
3182
3475
|
}
|
|
3476
|
+
const id = (0, import_node_crypto6.randomUUID)();
|
|
3477
|
+
let leaseId2;
|
|
3183
3478
|
let launch;
|
|
3184
3479
|
try {
|
|
3185
|
-
|
|
3480
|
+
if ((cli === "claude" || cli === "codex") && ctx.routeLeaseManager) {
|
|
3481
|
+
const outcome = await ctx.routeLeaseManager.createFromRequest({
|
|
3482
|
+
schemaVersion: import_provider_proxy2.ROUTE_LEASE_REQUEST_SCHEMA,
|
|
3483
|
+
consumer: "omnicross-terminal",
|
|
3484
|
+
runtime: cli,
|
|
3485
|
+
upstream: { kind: "provider", providerId: target.providerId },
|
|
3486
|
+
model: target.model,
|
|
3487
|
+
execution: { sessionId: id }
|
|
3488
|
+
}, `omnicross-terminal:${id}`);
|
|
3489
|
+
leaseId2 = outcome.result.leaseId;
|
|
3490
|
+
const stopRenewal = startTerminalLeaseRenewal(ctx.routeLeaseManager, leaseId2);
|
|
3491
|
+
launch = {
|
|
3492
|
+
env: outcome.result.launch.env,
|
|
3493
|
+
extraArgs: outcome.result.launch.extraArgs,
|
|
3494
|
+
onSessionEnd: () => {
|
|
3495
|
+
stopRenewal();
|
|
3496
|
+
ctx.routeLeaseManager?.release(outcome.result.leaseId);
|
|
3497
|
+
}
|
|
3498
|
+
};
|
|
3499
|
+
} else {
|
|
3500
|
+
launch = await buildLaunchEnv(cli, ctx.llmConfig, target);
|
|
3501
|
+
}
|
|
3186
3502
|
} catch (err5) {
|
|
3187
|
-
|
|
3503
|
+
const status = err5 instanceof import_provider_proxy2.RouteLeaseError ? err5.status : 400;
|
|
3504
|
+
return { status, body: errBody(err5 instanceof Error ? err5.message : "failed to build launch env") };
|
|
3188
3505
|
}
|
|
3189
3506
|
const cwd = typeof body["cwd"] === "string" && body["cwd"].trim() ? body["cwd"].trim() : void 0;
|
|
3190
3507
|
const opener = ctx.opener ?? defaultTerminalOpener;
|
|
3508
|
+
let openerCleanup;
|
|
3509
|
+
let ended = false;
|
|
3510
|
+
let published = false;
|
|
3511
|
+
const onSessionEnd = () => {
|
|
3512
|
+
if (ended) return;
|
|
3513
|
+
ended = true;
|
|
3514
|
+
if (published) sessions.delete(id);
|
|
3515
|
+
try {
|
|
3516
|
+
openerCleanup?.();
|
|
3517
|
+
} finally {
|
|
3518
|
+
launch.onSessionEnd();
|
|
3519
|
+
}
|
|
3520
|
+
};
|
|
3191
3521
|
try {
|
|
3192
|
-
opener({
|
|
3522
|
+
const cleanup = opener({
|
|
3523
|
+
cli,
|
|
3524
|
+
command: meta.command,
|
|
3525
|
+
extraArgs: launch.extraArgs ?? [],
|
|
3526
|
+
env: launch.env,
|
|
3527
|
+
cwd,
|
|
3528
|
+
platform,
|
|
3529
|
+
onFailure: onSessionEnd
|
|
3530
|
+
});
|
|
3531
|
+
if (cleanup) openerCleanup = cleanup;
|
|
3193
3532
|
} catch (err5) {
|
|
3194
|
-
|
|
3533
|
+
onSessionEnd();
|
|
3195
3534
|
return { status: 500, body: errBody(err5 instanceof Error ? err5.message : "failed to open terminal") };
|
|
3196
3535
|
}
|
|
3197
|
-
|
|
3536
|
+
if (ended) {
|
|
3537
|
+
openerCleanup?.();
|
|
3538
|
+
return { status: 500, body: errBody("failed to open terminal") };
|
|
3539
|
+
}
|
|
3198
3540
|
sessions.set(id, {
|
|
3199
3541
|
id,
|
|
3200
3542
|
cli,
|
|
3201
3543
|
providerId: target.providerId,
|
|
3202
3544
|
model: target.model,
|
|
3545
|
+
...leaseId2 ? { leaseId: leaseId2 } : {},
|
|
3203
3546
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3204
|
-
onSessionEnd
|
|
3547
|
+
onSessionEnd
|
|
3205
3548
|
});
|
|
3549
|
+
published = true;
|
|
3550
|
+
if (ended) sessions.delete(id);
|
|
3206
3551
|
return { status: 200, body: { sessionId: id, providerId: target.providerId, model: target.model } };
|
|
3207
3552
|
}
|
|
3208
3553
|
|
|
@@ -4079,7 +4424,7 @@ function sealPack(bundleJson, passphrase) {
|
|
|
4079
4424
|
cipher.setAAD(aadFor(PACK_MAGIC, PACK_VERSION, KDF_ALGORITHM));
|
|
4080
4425
|
const ciphertext = Buffer.concat([cipher.update(bundleJson, "utf8"), cipher.final()]);
|
|
4081
4426
|
const tag = cipher.getAuthTag();
|
|
4082
|
-
const
|
|
4427
|
+
const header2 = {
|
|
4083
4428
|
magic: PACK_MAGIC,
|
|
4084
4429
|
v: PACK_VERSION,
|
|
4085
4430
|
kdf: KDF_ALGORITHM,
|
|
@@ -4090,7 +4435,7 @@ function sealPack(bundleJson, passphrase) {
|
|
|
4090
4435
|
iv: iv.toString("base64"),
|
|
4091
4436
|
tag: tag.toString("base64")
|
|
4092
4437
|
};
|
|
4093
|
-
return `${PACK_PREFIX}${toB64Url(JSON.stringify(
|
|
4438
|
+
return `${PACK_PREFIX}${toB64Url(JSON.stringify(header2))}.${ciphertext.toString("base64")}`;
|
|
4094
4439
|
}
|
|
4095
4440
|
function parsePack(packString) {
|
|
4096
4441
|
if (typeof packString !== "string" || !packString.startsWith(PACK_PREFIX)) {
|
|
@@ -4101,28 +4446,28 @@ function parsePack(packString) {
|
|
|
4101
4446
|
if (dot < 0) throw new PackAuthError("migration pack is malformed (missing body)");
|
|
4102
4447
|
const headerB64Url = rest.slice(0, dot);
|
|
4103
4448
|
const ctB64 = rest.slice(dot + 1);
|
|
4104
|
-
let
|
|
4449
|
+
let header2;
|
|
4105
4450
|
try {
|
|
4106
|
-
|
|
4451
|
+
header2 = JSON.parse(fromB64Url(headerB64Url));
|
|
4107
4452
|
} catch {
|
|
4108
4453
|
throw new PackAuthError("migration pack is malformed (unreadable header)");
|
|
4109
4454
|
}
|
|
4110
|
-
if (!
|
|
4455
|
+
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
4456
|
throw new PackAuthError("migration pack is malformed (unsupported header)");
|
|
4112
4457
|
}
|
|
4113
4458
|
const ciphertext = Buffer.from(ctB64, "base64");
|
|
4114
|
-
return { header, ciphertext };
|
|
4459
|
+
return { header: header2, ciphertext };
|
|
4115
4460
|
}
|
|
4116
4461
|
function openPack(packString, passphrase) {
|
|
4117
4462
|
assertPassphraseStrength(passphrase);
|
|
4118
|
-
const { header, ciphertext } = parsePack(packString);
|
|
4119
|
-
const salt = Buffer.from(
|
|
4120
|
-
const iv = Buffer.from(
|
|
4121
|
-
const tag = Buffer.from(
|
|
4463
|
+
const { header: header2, ciphertext } = parsePack(packString);
|
|
4464
|
+
const salt = Buffer.from(header2.salt, "base64");
|
|
4465
|
+
const iv = Buffer.from(header2.iv, "base64");
|
|
4466
|
+
const tag = Buffer.from(header2.tag, "base64");
|
|
4122
4467
|
if (iv.length !== IV_BYTES2 || tag.length !== TAG_BYTES2) {
|
|
4123
4468
|
throw new PackAuthError("migration pack is malformed (invalid iv/tag length)");
|
|
4124
4469
|
}
|
|
4125
|
-
const key = deriveKey(passphrase, salt,
|
|
4470
|
+
const key = deriveKey(passphrase, salt, header2.N, header2.r, header2.p);
|
|
4126
4471
|
const decipher = (0, import_node_crypto8.createDecipheriv)("aes-256-gcm", key, iv);
|
|
4127
4472
|
decipher.setAAD(aadFor(PACK_MAGIC, PACK_VERSION, KDF_ALGORITHM));
|
|
4128
4473
|
decipher.setAuthTag(tag);
|
|
@@ -4458,10 +4803,10 @@ function writeJson2(res, status, body) {
|
|
|
4458
4803
|
res.writeHead(status, { "Content-Type": "application/json" });
|
|
4459
4804
|
res.end(JSON.stringify(body));
|
|
4460
4805
|
}
|
|
4461
|
-
function
|
|
4806
|
+
function writeError2(res, status, message) {
|
|
4462
4807
|
writeJson2(res, status, { error: { type: "account_allowance_error", message } });
|
|
4463
4808
|
}
|
|
4464
|
-
function
|
|
4809
|
+
function readJson2(req) {
|
|
4465
4810
|
return new Promise((resolve3, reject) => {
|
|
4466
4811
|
const chunks = [];
|
|
4467
4812
|
req.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
|
|
@@ -4487,10 +4832,10 @@ function allowanceProvider(value) {
|
|
|
4487
4832
|
return value === "claude" || value === "codex" ? value : null;
|
|
4488
4833
|
}
|
|
4489
4834
|
async function handleAccountAllowanceApi(req, res, method, rest, service) {
|
|
4490
|
-
if (!service) return
|
|
4835
|
+
if (!service) return writeError2(res, 501, "account allowance service is not available");
|
|
4491
4836
|
if (method === "GET" && rest.length === 1 && rest[0] === "scheduling") {
|
|
4492
4837
|
if (!service.getSchedulingStatus) {
|
|
4493
|
-
return
|
|
4838
|
+
return writeError2(res, 501, "allowance scheduling diagnostics are not available");
|
|
4494
4839
|
}
|
|
4495
4840
|
return writeJson2(res, 200, { scheduling: service.getSchedulingStatus() });
|
|
4496
4841
|
}
|
|
@@ -4498,27 +4843,27 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
|
|
|
4498
4843
|
const params = query(req);
|
|
4499
4844
|
const pathProvider = rest.length >= 2 ? rest[0] : null;
|
|
4500
4845
|
const providerId = allowanceProvider(pathProvider ?? params.get("providerId") ?? params.get("provider"));
|
|
4501
|
-
if (providerId === null) return
|
|
4846
|
+
if (providerId === null) return writeError2(res, 400, "providerId must be claude or codex");
|
|
4502
4847
|
const accountId = rest.length >= 2 ? rest[1] : params.get("accountId") ?? void 0;
|
|
4503
4848
|
const allowances = await service.list({ providerId, accountId });
|
|
4504
4849
|
return writeJson2(res, 200, { allowances });
|
|
4505
4850
|
}
|
|
4506
4851
|
if (method === "POST" && rest[0] === "refresh") {
|
|
4507
|
-
const body = await
|
|
4852
|
+
const body = await readJson2(req);
|
|
4508
4853
|
const requestedProvider = allowanceProvider(
|
|
4509
4854
|
typeof body["providerId"] === "string" ? body["providerId"] : "claude"
|
|
4510
4855
|
);
|
|
4511
4856
|
if (requestedProvider !== "claude") {
|
|
4512
|
-
return
|
|
4857
|
+
return writeError2(res, 400, "only Claude allowances support explicit refresh");
|
|
4513
4858
|
}
|
|
4514
4859
|
const accountId = typeof body["accountId"] === "string" && body["accountId"].trim() ? body["accountId"].trim() : void 0;
|
|
4515
4860
|
const allowances = await service.refreshClaude(accountId);
|
|
4516
4861
|
if (accountId && allowances.length === 0) {
|
|
4517
|
-
return
|
|
4862
|
+
return writeError2(res, 404, `Claude account '${accountId}' not found`);
|
|
4518
4863
|
}
|
|
4519
4864
|
return writeJson2(res, 200, { allowances });
|
|
4520
4865
|
}
|
|
4521
|
-
return
|
|
4866
|
+
return writeError2(res, 405, `method ${method} not allowed on account allowances`);
|
|
4522
4867
|
}
|
|
4523
4868
|
|
|
4524
4869
|
// src/admin/adminApi.ts
|
|
@@ -5093,6 +5438,12 @@ function parseModelConfigsInput(raw, existing) {
|
|
|
5093
5438
|
else if (typeof prior?.vision === "boolean") entry.vision = prior.vision;
|
|
5094
5439
|
if (typeof m["reasoning"] === "boolean") entry.reasoning = m["reasoning"];
|
|
5095
5440
|
else if (typeof prior?.reasoning === "boolean") entry.reasoning = prior.reasoning;
|
|
5441
|
+
const thinkingLevels = validateThinkingLevels(m["thinkingLevels"]);
|
|
5442
|
+
if (thinkingLevels) entry.thinkingLevels = thinkingLevels;
|
|
5443
|
+
else if (prior?.thinkingLevels) entry.thinkingLevels = prior.thinkingLevels;
|
|
5444
|
+
const thinkingTokenLimit = validateThinkingTokenLimit(m["thinkingTokenLimit"]);
|
|
5445
|
+
if (thinkingTokenLimit) entry.thinkingTokenLimit = thinkingTokenLimit;
|
|
5446
|
+
else if (prior?.thinkingTokenLimit) entry.thinkingTokenLimit = prior.thinkingTokenLimit;
|
|
5096
5447
|
out.push(entry);
|
|
5097
5448
|
}
|
|
5098
5449
|
return out.length > 0 ? out : void 0;
|
|
@@ -5750,6 +6101,7 @@ async function handleCli(req, res, method, rest, deps) {
|
|
|
5750
6101
|
const result = await handleCliLaunch(cli, body, {
|
|
5751
6102
|
llmConfig: deps.llmConfig,
|
|
5752
6103
|
providers,
|
|
6104
|
+
routeLeaseManager: deps.routeLeaseManager,
|
|
5753
6105
|
opener: deps.cliTerminalOpener,
|
|
5754
6106
|
probe: deps.cliPathProbe
|
|
5755
6107
|
});
|
|
@@ -6013,7 +6365,7 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
|
|
|
6013
6365
|
}
|
|
6014
6366
|
|
|
6015
6367
|
// src/admin/version.ts
|
|
6016
|
-
var DAEMON_VERSION = true ? "0.1.
|
|
6368
|
+
var DAEMON_VERSION = true ? "0.1.9" : "0.0.0-dev";
|
|
6017
6369
|
|
|
6018
6370
|
// src/admin/AdminServer.ts
|
|
6019
6371
|
var LOOPBACK_ADDR = "127.0.0.1";
|
|
@@ -6133,6 +6485,10 @@ var AdminServer = class {
|
|
|
6133
6485
|
await handleWebhookTest(req, res);
|
|
6134
6486
|
return;
|
|
6135
6487
|
}
|
|
6488
|
+
if (path2 === "/admin/api/route-leases" || path2.startsWith("/admin/api/route-leases/")) {
|
|
6489
|
+
await handleRouteLeaseApi(req, res, path2, this.deps);
|
|
6490
|
+
return;
|
|
6491
|
+
}
|
|
6136
6492
|
if (path2.startsWith("/admin/api/")) {
|
|
6137
6493
|
await handleAdminApi(req, res, path2, this.deps);
|
|
6138
6494
|
return;
|
|
@@ -6144,8 +6500,8 @@ var AdminServer = class {
|
|
|
6144
6500
|
}
|
|
6145
6501
|
/** Constant-time bearer/header check against the configured token. */
|
|
6146
6502
|
isAuthorized(req, token) {
|
|
6147
|
-
const
|
|
6148
|
-
const bearer = typeof
|
|
6503
|
+
const header2 = req.headers["authorization"];
|
|
6504
|
+
const bearer = typeof header2 === "string" && header2.startsWith("Bearer ") ? header2.slice("Bearer ".length).trim() : void 0;
|
|
6149
6505
|
const xToken = req.headers["x-admin-token"];
|
|
6150
6506
|
const presented = bearer ?? (typeof xToken === "string" ? xToken.trim() : void 0);
|
|
6151
6507
|
return constantTimeEquals(presented, token);
|
|
@@ -6550,6 +6906,15 @@ function toLLMProvider(row) {
|
|
|
6550
6906
|
api_base_url: row.baseUrl,
|
|
6551
6907
|
api_key: resolvePreferredApiKey(row),
|
|
6552
6908
|
models,
|
|
6909
|
+
modelConfigs: row.modelConfigs?.map((config) => ({
|
|
6910
|
+
id: config.id,
|
|
6911
|
+
name: config.name ?? config.id,
|
|
6912
|
+
enabled: config.enabled ?? true,
|
|
6913
|
+
vision: config.vision,
|
|
6914
|
+
reasoning: config.reasoning,
|
|
6915
|
+
thinkingLevels: config.thinkingLevels,
|
|
6916
|
+
thinkingTokenLimit: config.thinkingTokenLimit
|
|
6917
|
+
})),
|
|
6553
6918
|
enabled: true,
|
|
6554
6919
|
transformer,
|
|
6555
6920
|
// app-parity-2 child 3: POPULATE the coding-plan endpoint onto the core
|
|
@@ -7510,9 +7875,9 @@ function findDuplicateCredentialIds(accounts) {
|
|
|
7510
7875
|
|
|
7511
7876
|
// src/ports/external-cli-credentials.ts
|
|
7512
7877
|
var import_node_fs16 = require("fs");
|
|
7513
|
-
var
|
|
7878
|
+
var import_node_os4 = require("os");
|
|
7514
7879
|
var import_node_path9 = require("path");
|
|
7515
|
-
function externalStorePath(provider, home = (0,
|
|
7880
|
+
function externalStorePath(provider, home = (0, import_node_os4.homedir)()) {
|
|
7516
7881
|
return provider === "claude" ? (0, import_node_path9.join)(home, ".claude", ".credentials.json") : (0, import_node_path9.join)(home, ".codex", "auth.json");
|
|
7517
7882
|
}
|
|
7518
7883
|
function decodeJwtExpiryMs(token) {
|
|
@@ -7560,7 +7925,7 @@ function parseCodexTokensEnvelope(raw) {
|
|
|
7560
7925
|
}
|
|
7561
7926
|
return parsed;
|
|
7562
7927
|
}
|
|
7563
|
-
function readExternalCliCredentials(provider, home = (0,
|
|
7928
|
+
function readExternalCliCredentials(provider, home = (0, import_node_os4.homedir)()) {
|
|
7564
7929
|
const path2 = externalStorePath(provider, home);
|
|
7565
7930
|
if (!(0, import_node_fs16.existsSync)(path2)) return null;
|
|
7566
7931
|
let raw;
|
|
@@ -9445,6 +9810,76 @@ var TokenRefreshScheduler = class {
|
|
|
9445
9810
|
}
|
|
9446
9811
|
};
|
|
9447
9812
|
|
|
9813
|
+
// src/routeLeaseSubscriptionPreflight.ts
|
|
9814
|
+
var import_provider_proxy3 = require("@omnicross/core/provider-proxy");
|
|
9815
|
+
var import_AccountAllowanceScheduling4 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
|
|
9816
|
+
var import_SubscriptionAccountHealth3 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
|
|
9817
|
+
var import_accountModelMap = require("@omnicross/subscriptions/scheduler/accountModelMap");
|
|
9818
|
+
var PROVIDERS = /* @__PURE__ */ new Set(["claude", "codex", "gemini", "opencodego"]);
|
|
9819
|
+
function accountArray(config, providerId) {
|
|
9820
|
+
const record = config;
|
|
9821
|
+
const key = `${providerId}Accounts`;
|
|
9822
|
+
const accounts = record[key];
|
|
9823
|
+
if (Array.isArray(accounts)) return accounts;
|
|
9824
|
+
const legacy = record[providerId];
|
|
9825
|
+
if (!legacy || typeof legacy !== "object") return [];
|
|
9826
|
+
const activeKey = `active${providerId[0].toUpperCase()}${providerId.slice(1)}AccountId`;
|
|
9827
|
+
return [{ id: String(record[activeKey] ?? "active"), enabled: true, tokens: legacy }];
|
|
9828
|
+
}
|
|
9829
|
+
function hasCredential(providerId, account) {
|
|
9830
|
+
const tokens = account.tokens;
|
|
9831
|
+
if (providerId === "opencodego") return typeof tokens.apiKey === "string" && tokens.apiKey.length > 0;
|
|
9832
|
+
return typeof tokens.accessToken === "string" && tokens.accessToken.length > 0;
|
|
9833
|
+
}
|
|
9834
|
+
function safeProviderId(value) {
|
|
9835
|
+
if (!PROVIDERS.has(value)) {
|
|
9836
|
+
throw new import_provider_proxy3.RouteLeaseError("upstream_not_found", "subscription provider was not found");
|
|
9837
|
+
}
|
|
9838
|
+
return value;
|
|
9839
|
+
}
|
|
9840
|
+
function createRouteLeaseSubscriptionPreflight(credentials) {
|
|
9841
|
+
return {
|
|
9842
|
+
async assertAvailable(upstream, model) {
|
|
9843
|
+
const providerId = safeProviderId(upstream.providerId);
|
|
9844
|
+
const config = await credentials.getFullConfig();
|
|
9845
|
+
const all = accountArray(config, providerId);
|
|
9846
|
+
if (all.length === 0) {
|
|
9847
|
+
throw new import_provider_proxy3.RouteLeaseError("upstream_unavailable", "subscription provider has no configured account");
|
|
9848
|
+
}
|
|
9849
|
+
let bounded = all;
|
|
9850
|
+
if (upstream.kind === "account") {
|
|
9851
|
+
bounded = all.filter((account) => account.id === upstream.accountId);
|
|
9852
|
+
} else if (upstream.kind === "account-group") {
|
|
9853
|
+
bounded = all.filter((account) => account.group?.trim() === upstream.group);
|
|
9854
|
+
}
|
|
9855
|
+
if (bounded.length === 0) {
|
|
9856
|
+
throw new import_provider_proxy3.RouteLeaseError("upstream_not_found", "the selected subscription resource was not found");
|
|
9857
|
+
}
|
|
9858
|
+
const modelEligible = bounded.filter(
|
|
9859
|
+
(account) => (0, import_accountModelMap.accountSupportsModel)(account.supportedModels, model)
|
|
9860
|
+
);
|
|
9861
|
+
if (modelEligible.length === 0) {
|
|
9862
|
+
throw new import_provider_proxy3.RouteLeaseError("model_not_configured", "model is not supported by the selected subscription resource");
|
|
9863
|
+
}
|
|
9864
|
+
const credentialEligible = modelEligible.filter(
|
|
9865
|
+
(account) => account.enabled !== false && hasCredential(providerId, account)
|
|
9866
|
+
);
|
|
9867
|
+
const health2 = (0, import_SubscriptionAccountHealth3.getSharedAccountHealth)();
|
|
9868
|
+
const allowance = (0, import_AccountAllowanceScheduling4.getSharedAccountAllowanceScheduling)();
|
|
9869
|
+
const candidates = credentialEligible.filter(
|
|
9870
|
+
(account) => health2.isSchedulable(providerId, account.id) && allowance.preview(providerId, account.id, account.priority ?? 50).schedulable
|
|
9871
|
+
);
|
|
9872
|
+
if (candidates.length > 0) return;
|
|
9873
|
+
if (upstream.kind === "account") {
|
|
9874
|
+
throw new import_provider_proxy3.RouteLeaseError("upstream_unavailable", "the selected subscription account is unavailable");
|
|
9875
|
+
}
|
|
9876
|
+
throw new import_provider_proxy3.RouteLeaseError("upstream_exhausted", "the selected subscription pool has no eligible account", {
|
|
9877
|
+
retryAfterSeconds: 30
|
|
9878
|
+
});
|
|
9879
|
+
}
|
|
9880
|
+
};
|
|
9881
|
+
}
|
|
9882
|
+
|
|
9448
9883
|
// src/webhook/WebhookDispatcher.ts
|
|
9449
9884
|
var import_node_crypto14 = require("crypto");
|
|
9450
9885
|
var import_upstreamFetch7 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
@@ -9627,7 +10062,7 @@ function buildDaemon(config, paths) {
|
|
|
9627
10062
|
new JsonAccountAllowancePersistence(defaultAccountAllowancePath(paths.configPath))
|
|
9628
10063
|
);
|
|
9629
10064
|
(0, import_AccountAllowanceStore4.setSharedAccountAllowanceStore)(accountAllowanceStore);
|
|
9630
|
-
(0,
|
|
10065
|
+
(0, import_AccountAllowanceScheduling5.getSharedAccountAllowanceScheduling)().configure(
|
|
9631
10066
|
(0, import_outbound_api5.normalizeServerConfig)(decryptedConfig.server).allowanceScheduling
|
|
9632
10067
|
);
|
|
9633
10068
|
const llmConfig = new ConfigFileProviderConfigSource(decryptedConfig);
|
|
@@ -9694,11 +10129,22 @@ function buildDaemon(config, paths) {
|
|
|
9694
10129
|
const usageRecorder = new import_usage.UsageRecorder(usageEventStore, pricingEngine, logger, {
|
|
9695
10130
|
onRecord: (apiKeyId, costUsd, at) => keySpendTracker.add(apiKeyId, costUsd, at)
|
|
9696
10131
|
});
|
|
9697
|
-
const providerProxy = (0,
|
|
10132
|
+
const providerProxy = (0, import_provider_proxy4.getProviderProxy)({ llmConfig, apiKeyPool, usageRecorder });
|
|
10133
|
+
const routeLeaseManager = new import_provider_proxy4.RouteLeaseManager(
|
|
10134
|
+
providerProxy,
|
|
10135
|
+
new import_provider_proxy4.RouteLeaseTargetResolver(llmConfig, {
|
|
10136
|
+
providerKeys: apiKeyPool,
|
|
10137
|
+
subscriptions: createRouteLeaseSubscriptionPreflight(credentialStore)
|
|
10138
|
+
}),
|
|
10139
|
+
import_cli_launcher2.routeLeaseDescriptorPort,
|
|
10140
|
+
{ logger }
|
|
10141
|
+
);
|
|
10142
|
+
providerProxy.registerBeforeStop(() => routeLeaseManager.shutdown());
|
|
10143
|
+
providerProxy.registerBeforeStop(() => resetCliSessions());
|
|
9698
10144
|
llmConfig.setReloadHook(() => apiKeyPool.invalidateCache());
|
|
9699
10145
|
const accountHealthProbeScheduler = new AccountHealthProbeScheduler(
|
|
9700
10146
|
credentialStore,
|
|
9701
|
-
(0,
|
|
10147
|
+
(0, import_SubscriptionAccountHealth4.getSharedAccountHealth)(),
|
|
9702
10148
|
logger,
|
|
9703
10149
|
import_outbound_api5.DEFAULT_ACCOUNT_PROBE
|
|
9704
10150
|
);
|
|
@@ -9745,6 +10191,7 @@ function buildDaemon(config, paths) {
|
|
|
9745
10191
|
keySpendReader: keySpendTracker,
|
|
9746
10192
|
settingsStore,
|
|
9747
10193
|
outboundApiServer,
|
|
10194
|
+
routeLeaseManager,
|
|
9748
10195
|
subscriptionAccounts,
|
|
9749
10196
|
accountAllowanceService,
|
|
9750
10197
|
allowanceRefreshScheduler: claudeAllowanceRefreshScheduler,
|
|
@@ -9837,7 +10284,7 @@ function buildDaemon(config, paths) {
|
|
|
9837
10284
|
logger,
|
|
9838
10285
|
fetchImpl: (url, init) => (0, import_upstreamFetch8.fetchUpstream)(url, init)
|
|
9839
10286
|
});
|
|
9840
|
-
setWebhookRuntime(webhookDispatcher, (0,
|
|
10287
|
+
setWebhookRuntime(webhookDispatcher, (0, import_SubscriptionAccountHealth4.getSharedAccountHealth)());
|
|
9841
10288
|
const auditWriter = new AuditWriter(auditDir, logger);
|
|
9842
10289
|
const auditPruneSweeper = new AuditPruneSweeper(auditDir, logger, import_audit_types.DEFAULT_AUDIT_CONFIG);
|
|
9843
10290
|
setAuditRuntime(auditWriter, auditPruneSweeper);
|
|
@@ -9852,7 +10299,7 @@ function buildDaemon(config, paths) {
|
|
|
9852
10299
|
const tokenRefreshScheduler = new TokenRefreshScheduler(credentialStore, logger);
|
|
9853
10300
|
const accountHealthSweeper = new AccountHealthSweeper(
|
|
9854
10301
|
credentialStore,
|
|
9855
|
-
(0,
|
|
10302
|
+
(0, import_SubscriptionAccountHealth4.getSharedAccountHealth)(),
|
|
9856
10303
|
logger
|
|
9857
10304
|
);
|
|
9858
10305
|
return {
|
|
@@ -9861,6 +10308,7 @@ function buildDaemon(config, paths) {
|
|
|
9861
10308
|
keyDb,
|
|
9862
10309
|
settingsStore,
|
|
9863
10310
|
providerProxy,
|
|
10311
|
+
routeLeaseManager,
|
|
9864
10312
|
outboundApiServer,
|
|
9865
10313
|
apiKeyPool,
|
|
9866
10314
|
autoDisableStore,
|
|
@@ -9976,32 +10424,17 @@ async function runLaunch(argv, deps) {
|
|
|
9976
10424
|
await daemon.llmConfig.ready();
|
|
9977
10425
|
await daemon.providerProxy.start();
|
|
9978
10426
|
} catch (err5) {
|
|
9979
|
-
daemon
|
|
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();
|
|
10427
|
+
await shutdownLaunchDaemon(daemon);
|
|
9987
10428
|
throw err5;
|
|
9988
10429
|
}
|
|
9989
10430
|
let launch;
|
|
9990
10431
|
try {
|
|
9991
|
-
launch = await buildLaunchConfig(cli, daemon
|
|
10432
|
+
launch = await buildLaunchConfig(cli, daemon, {
|
|
9992
10433
|
providerId: values.provider,
|
|
9993
10434
|
model: values.model
|
|
9994
10435
|
});
|
|
9995
10436
|
} catch (err5) {
|
|
9996
|
-
await daemon
|
|
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();
|
|
10437
|
+
await shutdownLaunchDaemon(daemon);
|
|
10005
10438
|
throw err5;
|
|
10006
10439
|
}
|
|
10007
10440
|
try {
|
|
@@ -10020,21 +10453,40 @@ async function runLaunch(argv, deps) {
|
|
|
10020
10453
|
cwd: values.cwd
|
|
10021
10454
|
});
|
|
10022
10455
|
} finally {
|
|
10023
|
-
|
|
10024
|
-
|
|
10025
|
-
|
|
10026
|
-
|
|
10027
|
-
|
|
10028
|
-
|
|
10029
|
-
|
|
10030
|
-
|
|
10031
|
-
|
|
10032
|
-
|
|
10033
|
-
|
|
10034
|
-
|
|
10035
|
-
|
|
10456
|
+
try {
|
|
10457
|
+
launch.onSessionEnd();
|
|
10458
|
+
} finally {
|
|
10459
|
+
await shutdownLaunchDaemon(daemon);
|
|
10460
|
+
}
|
|
10461
|
+
}
|
|
10462
|
+
}
|
|
10463
|
+
async function buildLaunchConfig(cli, daemon, opts) {
|
|
10464
|
+
if (cli === "claude" || cli === "codex") {
|
|
10465
|
+
const internalId = (0, import_node_crypto15.randomUUID)();
|
|
10466
|
+
const outcome = await daemon.routeLeaseManager.createFromRequest({
|
|
10467
|
+
schemaVersion: import_provider_proxy5.ROUTE_LEASE_REQUEST_SCHEMA,
|
|
10468
|
+
consumer: "omnicross-terminal",
|
|
10469
|
+
runtime: cli,
|
|
10470
|
+
upstream: { kind: "provider", providerId: opts.providerId },
|
|
10471
|
+
model: opts.model,
|
|
10472
|
+
execution: { sessionId: `launch:${cli}:${internalId}` }
|
|
10473
|
+
}, `omnicross-launch:${internalId}`);
|
|
10474
|
+
const stopRenewal = startTerminalLeaseRenewal(
|
|
10475
|
+
daemon.routeLeaseManager,
|
|
10476
|
+
outcome.result.leaseId
|
|
10477
|
+
);
|
|
10478
|
+
return {
|
|
10479
|
+
baseUrl: daemon.providerProxy.getBaseUrl(),
|
|
10480
|
+
env: outcome.result.launch.env,
|
|
10481
|
+
extraArgs: outcome.result.launch.extraArgs,
|
|
10482
|
+
onSessionEnd: () => {
|
|
10483
|
+
stopRenewal();
|
|
10484
|
+
daemon.routeLeaseManager.release(outcome.result.leaseId);
|
|
10485
|
+
}
|
|
10486
|
+
};
|
|
10487
|
+
}
|
|
10036
10488
|
const common = {
|
|
10037
|
-
llmConfig,
|
|
10489
|
+
llmConfig: daemon.llmConfig,
|
|
10038
10490
|
providerId: opts.providerId,
|
|
10039
10491
|
model: opts.model,
|
|
10040
10492
|
// Stable, bounded session id — pool failover (poolseam) fires on launch
|
|
@@ -10042,22 +10494,30 @@ async function buildLaunchConfig(cli, llmConfig, opts) {
|
|
|
10042
10494
|
sessionId: `launch:${cli}`
|
|
10043
10495
|
};
|
|
10044
10496
|
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
10497
|
case "gemini":
|
|
10050
|
-
return (0,
|
|
10498
|
+
return (0, import_cli_launcher3.buildGeminiCliLaunchConfig)(common);
|
|
10051
10499
|
case "qwen":
|
|
10052
10500
|
case "copilot":
|
|
10053
10501
|
case "opencode":
|
|
10054
|
-
return (0,
|
|
10502
|
+
return (0, import_cli_launcher3.buildChatCliLaunchConfig)({ backendId: cli, ...common });
|
|
10055
10503
|
default: {
|
|
10056
10504
|
const _exhaustive = cli;
|
|
10057
10505
|
throw new Error(`Unsupported launch CLI: ${String(_exhaustive)}`);
|
|
10058
10506
|
}
|
|
10059
10507
|
}
|
|
10060
10508
|
}
|
|
10509
|
+
async function shutdownLaunchDaemon(daemon) {
|
|
10510
|
+
daemon.routeLeaseManager.shutdown();
|
|
10511
|
+
await daemon.providerProxy.stop();
|
|
10512
|
+
daemon.apiKeyPool.dispose();
|
|
10513
|
+
daemon.tokenRefreshScheduler.dispose();
|
|
10514
|
+
daemon.claudeAllowanceRefreshScheduler.dispose();
|
|
10515
|
+
daemon.accountHealthSweeper.dispose();
|
|
10516
|
+
daemon.accountHealthProbeScheduler.dispose();
|
|
10517
|
+
daemon.auditPruneSweeper.dispose();
|
|
10518
|
+
daemon.billingRetrySweeper.dispose();
|
|
10519
|
+
daemon.pricingRefreshScheduler.dispose();
|
|
10520
|
+
}
|
|
10061
10521
|
function spawnCliInherit(plan) {
|
|
10062
10522
|
return new Promise((resolve3, reject) => {
|
|
10063
10523
|
const child = (0, import_node_child_process2.spawn)(plan.command, plan.args, {
|
|
@@ -10104,7 +10564,7 @@ var import_node_readline = require("readline");
|
|
|
10104
10564
|
var import_node_util5 = require("util");
|
|
10105
10565
|
var import_upstreamFetch9 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
10106
10566
|
var import_subscriptions5 = require("@omnicross/subscriptions");
|
|
10107
|
-
var
|
|
10567
|
+
var PROVIDERS2 = ["claude", "codex", "gemini"];
|
|
10108
10568
|
async function runLogin(argv, deps) {
|
|
10109
10569
|
const { values, positionals } = (0, import_node_util5.parseArgs)({
|
|
10110
10570
|
args: argv,
|
|
@@ -10118,10 +10578,10 @@ async function runLogin(argv, deps) {
|
|
|
10118
10578
|
});
|
|
10119
10579
|
const provider = positionals[0];
|
|
10120
10580
|
if (!provider) {
|
|
10121
|
-
throw new Error(`login: a <provider> is required (one of ${
|
|
10581
|
+
throw new Error(`login: a <provider> is required (one of ${PROVIDERS2.join("|")})`);
|
|
10122
10582
|
}
|
|
10123
10583
|
if (!isLoginProvider(provider)) {
|
|
10124
|
-
throw new Error(`login: unknown provider '${provider}' (expected ${
|
|
10584
|
+
throw new Error(`login: unknown provider '${provider}' (expected ${PROVIDERS2.join("|")})`);
|
|
10125
10585
|
}
|
|
10126
10586
|
if (!values.config) {
|
|
10127
10587
|
throw new Error("login: --config <path> is required");
|
|
@@ -10227,7 +10687,7 @@ async function loginGemini(store, deps, exchangeFetch, label) {
|
|
|
10227
10687
|
return expiresAt;
|
|
10228
10688
|
}
|
|
10229
10689
|
function isLoginProvider(value) {
|
|
10230
|
-
return
|
|
10690
|
+
return PROVIDERS2.includes(value);
|
|
10231
10691
|
}
|
|
10232
10692
|
async function presentUrl(authUrl, deps) {
|
|
10233
10693
|
console.info("Open this URL in your browser to authorize:");
|
|
@@ -10273,7 +10733,7 @@ function promptPaste(prompt) {
|
|
|
10273
10733
|
}
|
|
10274
10734
|
|
|
10275
10735
|
// src/commands/providers.ts
|
|
10276
|
-
var
|
|
10736
|
+
var import_node_crypto16 = require("crypto");
|
|
10277
10737
|
var import_node_util6 = require("util");
|
|
10278
10738
|
async function runProviders(argv) {
|
|
10279
10739
|
const { values, positionals } = (0, import_node_util6.parseArgs)({
|
|
@@ -10395,7 +10855,7 @@ function providersAddKey(configPath, providerId, opts) {
|
|
|
10395
10855
|
const cfg = loadConfig(configPath);
|
|
10396
10856
|
const row = cfg.providers.find((p) => p.id === providerId);
|
|
10397
10857
|
if (!row) throw new Error(`providers add-key: unknown provider '${providerId}'`);
|
|
10398
|
-
const entry = { id: (0,
|
|
10858
|
+
const entry = { id: (0, import_node_crypto16.randomUUID)(), apiKey: opts.key };
|
|
10399
10859
|
if (opts.label) entry.label = opts.label;
|
|
10400
10860
|
if (opts.weight !== void 0) {
|
|
10401
10861
|
const w = Number(opts.weight);
|
|
@@ -10670,8 +11130,8 @@ function tokensSuffix(configPath) {
|
|
|
10670
11130
|
// src/commands/start.ts
|
|
10671
11131
|
var import_node_util8 = require("util");
|
|
10672
11132
|
var import_outbound_api7 = require("@omnicross/core/outbound-api");
|
|
10673
|
-
var
|
|
10674
|
-
var
|
|
11133
|
+
var import_SubscriptionAccountHealth5 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
|
|
11134
|
+
var import_AccountAllowanceScheduling6 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
|
|
10675
11135
|
|
|
10676
11136
|
// src/identity/identityRuntime.ts
|
|
10677
11137
|
var import_SubscriptionIdentityStore4 = require("@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore");
|
|
@@ -10731,11 +11191,11 @@ async function runStart(argv) {
|
|
|
10731
11191
|
await daemon.llmConfig.ready();
|
|
10732
11192
|
await daemon.providerProxy.start();
|
|
10733
11193
|
const serverConfig = await (0, import_outbound_api7.loadServerConfig)(daemon.settingsStore);
|
|
10734
|
-
(0,
|
|
11194
|
+
(0, import_SubscriptionAccountHealth5.getSharedAccountHealth)().configure({
|
|
10735
11195
|
overloadEnabled: serverConfig.accountHealth?.overloadCooldownEnabled,
|
|
10736
11196
|
overloadTtlMs: serverConfig.accountHealth?.overloadCooldownMs
|
|
10737
11197
|
});
|
|
10738
|
-
(0,
|
|
11198
|
+
(0, import_AccountAllowanceScheduling6.getSharedAccountAllowanceScheduling)().configure(serverConfig.allowanceScheduling);
|
|
10739
11199
|
daemon.claudeAllowanceRefreshScheduler.configure(serverConfig.allowanceScheduling);
|
|
10740
11200
|
await daemon.outboundApiServer.applyConfig({
|
|
10741
11201
|
enabled: true,
|