@cortexkit/anthropic-auth-core 2.2.1 → 2.2.3
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/claude-code.d.ts +2 -1
- package/dist/constants.d.ts +5 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +1575 -913
- package/dist/internal-types/claustrum/consumer.d.ts +3 -1
- package/dist/internal-types/claustrum/enrollment.d.ts +5 -0
- package/dist/internal-types/claustrum/index.d.ts +1 -0
- package/dist/internal-types/claustrum/quota-writer.d.ts +18 -0
- package/dist/internal-types/claustrum/roster.d.ts +18 -2
- package/dist/internal-types/fs/private-files.d.ts +2 -0
- package/dist/internal-types/fs/with-lock.d.ts +1 -0
- package/dist/internal-types/quota/format.d.ts +19 -0
- package/dist/internal-types/quota/index.d.ts +3 -3
- package/dist/internal-types/quota/map.d.ts +24 -1
- package/dist/internal-types/quota/merge.d.ts +6 -1
- package/dist/internal-types/quota/projection.d.ts +3 -1
- package/dist/internal-types/setup/enroll.d.ts +34 -0
- package/dist/internal-types/setup/index.d.ts +1 -0
- package/dist/internal-types/setup/process-fence.d.ts +14 -0
- package/dist/internal-types/setup/types.d.ts +5 -0
- package/dist/mid-conversation-output-config.d.ts +19 -15
- package/dist/model-capabilities.d.ts +136 -0
- package/dist/models.d.ts +28 -59
- package/dist/native-enrollment-authority.d.ts +19 -0
- package/dist/native-ui.d.ts +10 -1
- package/dist/native-vault-runtime.d.ts +1 -1
- package/dist/turn-end-note.d.ts +4 -3
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -241,7 +241,7 @@ async function select(terminal, items, options) {
|
|
|
241
241
|
import { createHash, randomBytes, randomUUID as randomUUID4 } from "node:crypto";
|
|
242
242
|
import { constants as fsConstants } from "node:fs";
|
|
243
243
|
import { chmod, mkdir as mkdir3, open as open3, readFile as readFile3, realpath, rename as rename4, stat as stat2, unlink as unlink2 } from "node:fs/promises";
|
|
244
|
-
import { basename, dirname as dirname4, extname, isAbsolute, join as
|
|
244
|
+
import { basename, dirname as dirname4, extname, isAbsolute, join as join3, resolve as resolve2 } from "node:path";
|
|
245
245
|
import { ClaustrumCredentialError, ClaustrumClient as ClaustrumWireClient, writeEnrollmentTokenFile } from "@cortexkit/claustrum-client";
|
|
246
246
|
|
|
247
247
|
// ../../node_modules/@cortexkit/common-auth/dist/fs/atomic-write.js
|
|
@@ -252,7 +252,8 @@ import { dirname as dirname2 } from "node:path";
|
|
|
252
252
|
// ../../node_modules/@cortexkit/common-auth/dist/fs/private-files.js
|
|
253
253
|
import { randomUUID } from "node:crypto";
|
|
254
254
|
import { lstat, readFile, rename, unlink } from "node:fs/promises";
|
|
255
|
-
import {
|
|
255
|
+
import { tmpdir } from "node:os";
|
|
256
|
+
import { dirname, join, resolve } from "node:path";
|
|
256
257
|
var windowsPrivateFiles = process.platform === "win32";
|
|
257
258
|
var migrationNotices = new Set;
|
|
258
259
|
function ioCode(detail) {
|
|
@@ -265,8 +266,32 @@ function ioCode(detail) {
|
|
|
265
266
|
return detail?.code ?? "ERR_PRIVATE_FILE";
|
|
266
267
|
}
|
|
267
268
|
var backend;
|
|
269
|
+
var PRIVATE_FILES_UNAVAILABLE_REASON = "native-addon-unavailable";
|
|
270
|
+
function privateFilesUnavailable(cause) {
|
|
271
|
+
return Object.assign(new Error("Windows private-files native addon is unavailable", { cause }), {
|
|
272
|
+
code: "ERR_PRIVATE_FILES_UNAVAILABLE",
|
|
273
|
+
reason: PRIVATE_FILES_UNAVAILABLE_REASON
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
function isUnavailable(api, error) {
|
|
277
|
+
return error instanceof api.PrivateFilesUnavailableError || error?.code === "ERR_PRIVATE_FILES_UNAVAILABLE";
|
|
278
|
+
}
|
|
279
|
+
async function assertNativeAddonLoads(api) {
|
|
280
|
+
try {
|
|
281
|
+
await api.verifyPrivatePath(join(tmpdir(), `.common-auth-private-files-probe-${randomUUID()}`), "file");
|
|
282
|
+
} catch (error) {
|
|
283
|
+
if (isUnavailable(api, error))
|
|
284
|
+
throw privateFilesUnavailable(error);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
268
287
|
function loadBackend() {
|
|
269
|
-
backend ??= import("@cortexkit/private-files")
|
|
288
|
+
backend ??= import("@cortexkit/private-files").then(async (api) => {
|
|
289
|
+
if (windowsPrivateFiles)
|
|
290
|
+
await assertNativeAddonLoads(api);
|
|
291
|
+
return api;
|
|
292
|
+
}, (cause) => {
|
|
293
|
+
throw windowsPrivateFiles ? privateFilesUnavailable(cause) : cause;
|
|
294
|
+
});
|
|
270
295
|
return backend;
|
|
271
296
|
}
|
|
272
297
|
|
|
@@ -284,7 +309,7 @@ class PrivateFileError extends Error {
|
|
|
284
309
|
orphanPath;
|
|
285
310
|
constructor(path, stage, cause) {
|
|
286
311
|
const detail = cause;
|
|
287
|
-
super(`Private file refused at ${stage}: ${path} (${detail?.reason ?? detail?.code ?? "io-error"}).
|
|
312
|
+
super(detail?.code === "ERR_PRIVATE_FILES_UNAVAILABLE" ? `Private file refused at ${stage}: ${path} (${PRIVATE_FILES_UNAVAILABLE_REASON}). The Windows native addon of @cortexkit/private-files could not be loaded, so owner-only access cannot be enforced and nothing was read or written. Reinstall the plugin so the private-files Windows prebuild for this architecture is present; Windows has no safe fallback to permission bits.` : `Private file refused at ${stage}: ${path} (${detail?.reason ?? detail?.code ?? "io-error"}). Keep this file in a folder that only you, the system or administrators can change, such as a folder in your home directory. If other users could read the file before, sign in again to replace the credentials it held. On Windows the file must also be on a local drive that keeps Windows file permissions, such as NTFS.`, { cause });
|
|
288
313
|
this.path = path;
|
|
289
314
|
this.stage = stage;
|
|
290
315
|
this.name = "PrivateFileError";
|
|
@@ -617,7 +642,7 @@ var WRITER_LOCK_CONSTANTS = Object.freeze({
|
|
|
617
642
|
// ../../node_modules/@cortexkit/common-auth/dist/fs/refresh-file-lock.js
|
|
618
643
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
619
644
|
import { mkdir as mkdir2, open as open2, readFile as readFile2, rename as rename3, rm as rm2, stat } from "node:fs/promises";
|
|
620
|
-
import { dirname as dirname3, join } from "node:path";
|
|
645
|
+
import { dirname as dirname3, join as join2 } from "node:path";
|
|
621
646
|
|
|
622
647
|
// ../../node_modules/@cortexkit/common-auth/dist/fs/with-lock.js
|
|
623
648
|
function lockPathFor(target, name) {
|
|
@@ -644,6 +669,7 @@ class LockOwnershipError extends Error {
|
|
|
644
669
|
async function withLock(target, options, fn) {
|
|
645
670
|
const started = performance.now();
|
|
646
671
|
for (;; ) {
|
|
672
|
+
options.signal?.throwIfAborted();
|
|
647
673
|
const lock = await acquireRefreshFileLock({
|
|
648
674
|
path: target,
|
|
649
675
|
name: options.name,
|
|
@@ -654,6 +680,7 @@ async function withLock(target, options, fn) {
|
|
|
654
680
|
});
|
|
655
681
|
if (lock) {
|
|
656
682
|
try {
|
|
683
|
+
options.signal?.throwIfAborted();
|
|
657
684
|
return await fn(lock);
|
|
658
685
|
} finally {
|
|
659
686
|
await lock.release();
|
|
@@ -691,7 +718,7 @@ function acquireRefreshFileLock(options) {
|
|
|
691
718
|
}
|
|
692
719
|
async function acquireRefreshFileLockWithClock(options) {
|
|
693
720
|
const lockPath = lockPathFor(options.path, options.name);
|
|
694
|
-
const legacyOwnerPath =
|
|
721
|
+
const legacyOwnerPath = join2(lockPath, "owner.json");
|
|
695
722
|
const ownerId = randomUUID3();
|
|
696
723
|
const now = options.now ?? Date.now;
|
|
697
724
|
let renewTimer = null;
|
|
@@ -732,7 +759,7 @@ async function acquireRefreshFileLockWithClock(options) {
|
|
|
732
759
|
let terminalIOError;
|
|
733
760
|
let renewalInFlight = null;
|
|
734
761
|
const evictPath = `${lockPath}.evicting`;
|
|
735
|
-
const evictOwnerPath =
|
|
762
|
+
const evictOwnerPath = join2(evictPath, "owner.json");
|
|
736
763
|
const evictOwnerId = randomUUID3();
|
|
737
764
|
const EVICT_TTL = 5000;
|
|
738
765
|
const MAX_STEAL_ATTEMPTS = 8;
|
|
@@ -1296,7 +1323,9 @@ var ENROLLMENT_SCHEMA = 1;
|
|
|
1296
1323
|
var ENROLLMENT_FILE_MAX_BYTES = 16 * 1024;
|
|
1297
1324
|
var ENROLLMENT_LOCK_TTL_MS = 30000;
|
|
1298
1325
|
var TOKEN_RE = /^[0-9a-f]{64}$/;
|
|
1326
|
+
var UNSUPPORTED_ENROLLMENT_CODE = "unknown_method";
|
|
1299
1327
|
var TERMINAL_ENROLLMENT_CODES = new Set([
|
|
1328
|
+
UNSUPPORTED_ENROLLMENT_CODE,
|
|
1300
1329
|
"invalid_params",
|
|
1301
1330
|
"pending_exists",
|
|
1302
1331
|
"not_found",
|
|
@@ -1326,7 +1355,7 @@ function getClaustrumEnrollmentPaths(tokenPath) {
|
|
|
1326
1355
|
const extension = extname(tokenPath) || ".json";
|
|
1327
1356
|
const stem = basename(tokenPath, extname(tokenPath));
|
|
1328
1357
|
return {
|
|
1329
|
-
statePath:
|
|
1358
|
+
statePath: join3(dirname4(tokenPath), `${stem}-state${extension}`),
|
|
1330
1359
|
tokenPath
|
|
1331
1360
|
};
|
|
1332
1361
|
}
|
|
@@ -1334,7 +1363,7 @@ function hostEnrollmentPaths(input) {
|
|
|
1334
1363
|
const override = input.override?.trim();
|
|
1335
1364
|
if (override && !isAbsolute(override) && !input.cwd)
|
|
1336
1365
|
throw new ClaustrumConsumerError("invalid-state", "A relative Claustrum enrollment override needs a base directory");
|
|
1337
|
-
const tokenPath = override ? isAbsolute(override) ? override : resolve2(input.cwd, override) :
|
|
1366
|
+
const tokenPath = override ? isAbsolute(override) ? override : resolve2(input.cwd, override) : join3(input.stateDir, `${input.host}-enrollment.json`);
|
|
1338
1367
|
return getClaustrumEnrollmentPaths(tokenPath);
|
|
1339
1368
|
}
|
|
1340
1369
|
function isRecord(value) {
|
|
@@ -1570,7 +1599,7 @@ async function writeStateAtomic(path, state, ancestorOptions = {}) {
|
|
|
1570
1599
|
}
|
|
1571
1600
|
if (windowsPrivateFiles)
|
|
1572
1601
|
return writePrivateAtomic(path, bytes);
|
|
1573
|
-
const temporary =
|
|
1602
|
+
const temporary = join3(parent, `.${basename(path)}.${process.pid}.${randomUUID4()}.tmp`);
|
|
1574
1603
|
let descriptor;
|
|
1575
1604
|
let created = false;
|
|
1576
1605
|
try {
|
|
@@ -1799,6 +1828,18 @@ class ClaustrumEnrollmentManager {
|
|
|
1799
1828
|
retryCode: refusal.code
|
|
1800
1829
|
};
|
|
1801
1830
|
}
|
|
1831
|
+
if (refusal.code === UNSUPPORTED_ENROLLMENT_CODE) {
|
|
1832
|
+
await lock.assertOwned();
|
|
1833
|
+
await unlink2(this.#paths.statePath).catch((cause) => {
|
|
1834
|
+
if (cause.code !== "ENOENT")
|
|
1835
|
+
throw cause;
|
|
1836
|
+
});
|
|
1837
|
+
return {
|
|
1838
|
+
state: "unavailable",
|
|
1839
|
+
proposedName: state.proposedName,
|
|
1840
|
+
code: refusal.code
|
|
1841
|
+
};
|
|
1842
|
+
}
|
|
1802
1843
|
return this.#block(state, refusal.code);
|
|
1803
1844
|
}
|
|
1804
1845
|
}
|
|
@@ -2187,8 +2228,8 @@ function setupEnrollment(error) {
|
|
|
2187
2228
|
// ../../node_modules/@cortexkit/common-auth/dist/setup/detect.js
|
|
2188
2229
|
import { accessSync, constants, existsSync, readFileSync, realpathSync, statSync } from "node:fs";
|
|
2189
2230
|
import { mkdtemp, rm as rm3 } from "node:fs/promises";
|
|
2190
|
-
import { tmpdir } from "node:os";
|
|
2191
|
-
import { join as
|
|
2231
|
+
import { tmpdir as tmpdir2 } from "node:os";
|
|
2232
|
+
import { join as join4 } from "node:path";
|
|
2192
2233
|
import { parse } from "jsonc-parser";
|
|
2193
2234
|
|
|
2194
2235
|
// ../../node_modules/@cortexkit/common-auth/dist/setup/paths.js
|
|
@@ -2357,7 +2398,7 @@ async function detectHosts(plugin, io = {}) {
|
|
|
2357
2398
|
return null;
|
|
2358
2399
|
let root;
|
|
2359
2400
|
try {
|
|
2360
|
-
root = await mkdtemp(
|
|
2401
|
+
root = await mkdtemp(join4(tmpdir2(), "common-auth-setup-version-"));
|
|
2361
2402
|
const probeEnv = {
|
|
2362
2403
|
...env,
|
|
2363
2404
|
HOME: root,
|
|
@@ -2425,6 +2466,8 @@ import { writeEnrollmentTokenFile as writeEnrollmentTokenFile2 } from "@cortexki
|
|
|
2425
2466
|
var WINDOWS_CIM_TIMEOUT_MS = 45000;
|
|
2426
2467
|
var HOSTS = new Set(["opencode", "litecode", "opencode2", "pi"]);
|
|
2427
2468
|
var RUNTIMES = new Set(["node", "bun"]);
|
|
2469
|
+
var WINDOWS_FENCE_FILTER = [...HOSTS, ...RUNTIMES].map((name) => `Name LIKE '${name}%'`).join(" OR ");
|
|
2470
|
+
var WINDOWS_FENCE_QUERY = `$ErrorActionPreference = 'Stop'; $rows = @(Get-CimInstance Win32_Process -Filter "${WINDOWS_FENCE_FILTER}" | Select-Object Name,ProcessId,CommandLine); ConvertTo-Json -Compress -Depth 3 -InputObject @{ complete = $true; processes = $rows }`;
|
|
2428
2471
|
var PI_SCRIPT_PATTERN = /(?:^|[/\\])pi-coding-agent[/\\]dist[/\\](?:(?:bundle|bun)[/\\])?cli\.m?js$/i;
|
|
2429
2472
|
function commandArguments(command) {
|
|
2430
2473
|
return [...command.matchAll(/"([^"]*)"|(\S+)/g)].map((match) => match[1] ?? match[2] ?? "");
|
|
@@ -2530,6 +2573,7 @@ Please quit all OpenCode, LiteCode, and Pi processes before running setup.`);
|
|
|
2530
2573
|
}
|
|
2531
2574
|
async function listSetupProcesses(runner = defaultCommandRunner, options = {}) {
|
|
2532
2575
|
const windows = (options.platform ?? process.platform) === "win32";
|
|
2576
|
+
const selfPid = options.selfPid ?? process.pid;
|
|
2533
2577
|
let inspection = {
|
|
2534
2578
|
step: windows ? "tasklist" : "ps",
|
|
2535
2579
|
exitCode: null,
|
|
@@ -2566,6 +2610,29 @@ async function listSetupProcesses(runner = defaultCommandRunner, options = {}) {
|
|
|
2566
2610
|
}
|
|
2567
2611
|
};
|
|
2568
2612
|
try {
|
|
2613
|
+
if (windows && options.hostImagesOnly) {
|
|
2614
|
+
const details = await inspect("CIM", "powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", WINDOWS_FENCE_QUERY], WINDOWS_CIM_TIMEOUT_MS);
|
|
2615
|
+
if (details.exitCode !== 0)
|
|
2616
|
+
throw new ProcessInspectionError(inspection);
|
|
2617
|
+
const value = JSON.parse(details.stdout);
|
|
2618
|
+
if (!value || typeof value !== "object" || !("complete" in value) || value.complete !== true || !("processes" in value))
|
|
2619
|
+
throw new ProcessInspectionError(inspection);
|
|
2620
|
+
const listed = value.processes;
|
|
2621
|
+
const rows = listed === null ? [] : Array.isArray(listed) ? listed : [listed];
|
|
2622
|
+
const processes2 = [];
|
|
2623
|
+
for (const row of rows) {
|
|
2624
|
+
if (!row || typeof row !== "object" || !("Name" in row) || typeof row.Name !== "string" || !("ProcessId" in row) || !Number.isSafeInteger(row.ProcessId) || row.ProcessId < 0 || !("CommandLine" in row))
|
|
2625
|
+
throw new ProcessInspectionError(inspection);
|
|
2626
|
+
const pid = row.ProcessId;
|
|
2627
|
+
if (!/^(?:node|bun)\.exe$/i.test(row.Name))
|
|
2628
|
+
processes2.push({ pid, command: row.Name });
|
|
2629
|
+
else if (typeof row.CommandLine === "string")
|
|
2630
|
+
processes2.push({ pid, command: row.CommandLine });
|
|
2631
|
+
else if (pid !== selfPid)
|
|
2632
|
+
throw new ProcessInspectionError(inspection);
|
|
2633
|
+
}
|
|
2634
|
+
return processes2;
|
|
2635
|
+
}
|
|
2569
2636
|
const result = await inspect(windows ? "tasklist" : "ps", windows ? "tasklist.exe" : "ps", windows ? ["/fo", "csv", "/nh"] : ["-eo", "pid,command"]);
|
|
2570
2637
|
if (result.exitCode !== 0)
|
|
2571
2638
|
throw new ProcessInspectionError(inspection);
|
|
@@ -2598,7 +2665,7 @@ async function listSetupProcesses(runner = defaultCommandRunner, options = {}) {
|
|
|
2598
2665
|
}
|
|
2599
2666
|
if (!processes.length)
|
|
2600
2667
|
throw new ProcessInspectionError(inspection);
|
|
2601
|
-
const runtimes = processes.filter((entry) => entry.pid !==
|
|
2668
|
+
const runtimes = processes.filter((entry) => entry.pid !== selfPid && /^(?:node|bun)\.exe$/i.test(entry.command));
|
|
2602
2669
|
if (windows && runtimes.length && options.inspectRuntimes !== false) {
|
|
2603
2670
|
const details = await inspect("CIM", "powershell.exe", [
|
|
2604
2671
|
"-NoProfile",
|
|
@@ -2631,10 +2698,15 @@ async function listSetupProcesses(runner = defaultCommandRunner, options = {}) {
|
|
|
2631
2698
|
}
|
|
2632
2699
|
}
|
|
2633
2700
|
function createProcessFence(runner = defaultCommandRunner, options = {}) {
|
|
2634
|
-
const
|
|
2701
|
+
const selfPid = options.selfPid ?? process.pid;
|
|
2702
|
+
const isHost = (entry) => entry.pid !== selfPid && hostName(entry.command) !== null;
|
|
2635
2703
|
return {
|
|
2636
2704
|
async listRunningHosts(env) {
|
|
2637
|
-
return (await listSetupProcesses(runner, {
|
|
2705
|
+
return (await listSetupProcesses(runner, {
|
|
2706
|
+
...options,
|
|
2707
|
+
env,
|
|
2708
|
+
hostImagesOnly: true
|
|
2709
|
+
})).filter(isHost);
|
|
2638
2710
|
},
|
|
2639
2711
|
async previewRunningHosts(env) {
|
|
2640
2712
|
const processes = await listSetupProcesses(runner, {
|
|
@@ -2645,7 +2717,7 @@ function createProcessFence(runner = defaultCommandRunner, options = {}) {
|
|
|
2645
2717
|
const windows = (options.platform ?? process.platform) === "win32";
|
|
2646
2718
|
return {
|
|
2647
2719
|
hosts: processes.filter(isHost),
|
|
2648
|
-
uncheckedRuntimes: windows ? processes.filter((entry) => entry.pid !==
|
|
2720
|
+
uncheckedRuntimes: windows ? processes.filter((entry) => entry.pid !== selfPid && /^(?:node|bun)\.exe$/i.test(entry.command)).length : 0
|
|
2649
2721
|
};
|
|
2650
2722
|
}
|
|
2651
2723
|
};
|
|
@@ -2658,8 +2730,27 @@ async function assertHostsStopped(fence, env) {
|
|
|
2658
2730
|
|
|
2659
2731
|
// ../../node_modules/@cortexkit/common-auth/dist/setup/enroll.js
|
|
2660
2732
|
var ENROLLMENT_INCOMPLETE_MESSAGE = "Claustrum enrollment did not complete. Inspect and approve with ck, then rerun setup.";
|
|
2733
|
+
var UNSUPPORTED_VAULT_MESSAGE = "This Claustrum vault does not support connecting plugins yet, so setup cannot connect to it. Run setup without --claustrum to use local accounts.";
|
|
2734
|
+
var ENROLLMENT_WAIT_MS = 300000;
|
|
2735
|
+
var APPROVAL_POLL_MS = 1000;
|
|
2736
|
+
var PROPOSE_BACKOFF_MS = [1000, 2000, 4000, 8000, 16000, 30000];
|
|
2737
|
+
function safeCode(code) {
|
|
2738
|
+
return code && /^[a-z][a-z0-9_]{0,63}$/.test(code) ? code : "unknown";
|
|
2739
|
+
}
|
|
2661
2740
|
|
|
2662
2741
|
class HostNotEnrolledError extends Error {
|
|
2742
|
+
reason;
|
|
2743
|
+
lastErrorCode;
|
|
2744
|
+
constructor(message, details) {
|
|
2745
|
+
super(message);
|
|
2746
|
+
this.name = "HostNotEnrolledError";
|
|
2747
|
+
this.reason = details.reason;
|
|
2748
|
+
if (details.lastErrorCode !== undefined)
|
|
2749
|
+
this.lastErrorCode = safeCode(details.lastErrorCode);
|
|
2750
|
+
}
|
|
2751
|
+
}
|
|
2752
|
+
function approveCommand(requestId, name) {
|
|
2753
|
+
return `ck auth enroll approve --request-id ${requestId} --name ${name}`;
|
|
2663
2754
|
}
|
|
2664
2755
|
async function connectSetupHost(plugin, host, io, terminal, fence) {
|
|
2665
2756
|
const { name, paths: input } = plugin.vault.hosts[host];
|
|
@@ -2669,54 +2760,89 @@ async function connectSetupHost(plugin, host, io, terminal, fence) {
|
|
|
2669
2760
|
connectionFile: plugin.vault.connectionFile,
|
|
2670
2761
|
handshakeTimeoutMs: 2000
|
|
2671
2762
|
}).catch(() => {
|
|
2672
|
-
throw new HostNotEnrolledError("Claustrum connection failed; start ck and rerun setup.");
|
|
2763
|
+
throw new HostNotEnrolledError("Claustrum connection failed; start ck and rerun setup.", { reason: "connection-failed" });
|
|
2673
2764
|
});
|
|
2765
|
+
const now = io.now ?? (() => performance.now());
|
|
2766
|
+
const wait = io.wait ?? delay;
|
|
2674
2767
|
try {
|
|
2675
2768
|
const manager = new ClaustrumEnrollmentManager({
|
|
2676
2769
|
proposedName: name,
|
|
2677
2770
|
paths,
|
|
2678
|
-
client
|
|
2679
|
-
enrollPropose: async (input2) => {
|
|
2680
|
-
await fence();
|
|
2681
|
-
return client.enrollPropose(input2);
|
|
2682
|
-
},
|
|
2683
|
-
enrollPoll: async (input2) => {
|
|
2684
|
-
await fence();
|
|
2685
|
-
return client.enrollPoll(input2);
|
|
2686
|
-
}
|
|
2687
|
-
},
|
|
2771
|
+
client,
|
|
2688
2772
|
writeTokenFile: async (path, file) => {
|
|
2689
2773
|
await fence();
|
|
2690
2774
|
await writeEnrollmentTokenFile2(path, file);
|
|
2691
2775
|
}
|
|
2692
2776
|
});
|
|
2777
|
+
printLine(terminal, `Asking the vault to connect ${name}…`);
|
|
2778
|
+
const deadline = now() + ENROLLMENT_WAIT_MS;
|
|
2693
2779
|
let printedRequest;
|
|
2694
|
-
|
|
2780
|
+
let lastCode;
|
|
2781
|
+
let reportedCode;
|
|
2782
|
+
let failedProposals = 0;
|
|
2783
|
+
for (;; ) {
|
|
2695
2784
|
await fence();
|
|
2696
2785
|
const status = await manager.reconcile();
|
|
2697
2786
|
if (status.state === "approved") {
|
|
2698
2787
|
printLine(terminal, `Connected ${host} to Claustrum.`);
|
|
2699
2788
|
return;
|
|
2700
2789
|
}
|
|
2790
|
+
if (status.state === "unavailable" && status.code === UNSUPPORTED_ENROLLMENT_CODE)
|
|
2791
|
+
throw new HostNotEnrolledError(UNSUPPORTED_VAULT_MESSAGE, {
|
|
2792
|
+
reason: "unsupported-vault",
|
|
2793
|
+
lastErrorCode: status.code
|
|
2794
|
+
});
|
|
2701
2795
|
if (status.state !== "pending" && status.state !== "busy")
|
|
2702
|
-
throw new HostNotEnrolledError("Claustrum enrollment refused; inspect its status with ck before rerunning setup."
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2796
|
+
throw new HostNotEnrolledError("Claustrum enrollment refused; inspect its status with ck before rerunning setup.", {
|
|
2797
|
+
reason: "refused",
|
|
2798
|
+
..."code" in status && { lastErrorCode: status.code }
|
|
2799
|
+
});
|
|
2800
|
+
let pause = APPROVAL_POLL_MS;
|
|
2801
|
+
if (status.state === "busy")
|
|
2802
|
+
lastCode = "busy";
|
|
2803
|
+
else if (status.retryCode)
|
|
2804
|
+
lastCode = status.retryCode;
|
|
2805
|
+
if (status.state === "pending" && status.requestId) {
|
|
2806
|
+
failedProposals = 0;
|
|
2807
|
+
if (status.requestId !== printedRequest) {
|
|
2808
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(status.requestId))
|
|
2809
|
+
throw new HostNotEnrolledError("Invalid enrollment request id.", {
|
|
2810
|
+
reason: "invalid-request"
|
|
2811
|
+
});
|
|
2812
|
+
printedRequest = status.requestId;
|
|
2813
|
+
printLine(terminal, "Waiting for approval. In another terminal, run:");
|
|
2814
|
+
printLine(terminal, ` ${approveCommand(status.requestId, name)}`);
|
|
2815
|
+
printLine(terminal, `Enrollment files: ${paths.statePath}, ${paths.tokenPath}`);
|
|
2816
|
+
}
|
|
2817
|
+
} else if (status.state === "pending" && status.retryCode) {
|
|
2818
|
+
pause = PROPOSE_BACKOFF_MS[Math.min(failedProposals, PROPOSE_BACKOFF_MS.length - 1)] ?? APPROVAL_POLL_MS;
|
|
2819
|
+
failedProposals++;
|
|
2820
|
+
const code2 = safeCode(status.retryCode);
|
|
2821
|
+
if (code2 !== reportedCode) {
|
|
2822
|
+
reportedCode = code2;
|
|
2823
|
+
printLine(terminal, `The vault has not created the request yet (${code2}); retrying.`);
|
|
2824
|
+
}
|
|
2825
|
+
}
|
|
2826
|
+
const remaining = deadline - now();
|
|
2827
|
+
if (remaining <= 0)
|
|
2828
|
+
break;
|
|
2829
|
+
await wait(Math.min(pause, remaining));
|
|
2830
|
+
}
|
|
2831
|
+
if (printedRequest)
|
|
2832
|
+
throw new HostNotEnrolledError(`Claustrum approval is still pending. In another terminal, run: ${approveCommand(printedRequest, name)} and then rerun setup.`, {
|
|
2833
|
+
reason: "approval-pending",
|
|
2834
|
+
...lastCode !== undefined && { lastErrorCode: lastCode }
|
|
2835
|
+
});
|
|
2836
|
+
const code = safeCode(lastCode);
|
|
2837
|
+
throw new HostNotEnrolledError(`The vault never created the enrollment request (last error: ${code}). Check that ck is running, then rerun setup.`, { reason: "request-not-created", lastErrorCode: code });
|
|
2714
2838
|
} catch (error) {
|
|
2715
|
-
if (error instanceof ProcessFenceViolationError || error instanceof ProcessInspectionError)
|
|
2839
|
+
if (error instanceof ProcessFenceViolationError || error instanceof ProcessInspectionError || error instanceof HostNotEnrolledError)
|
|
2716
2840
|
throw error;
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2841
|
+
const code = error?.code;
|
|
2842
|
+
throw new HostNotEnrolledError(ENROLLMENT_INCOMPLETE_MESSAGE, {
|
|
2843
|
+
reason: "incomplete",
|
|
2844
|
+
...typeof code === "string" && { lastErrorCode: code }
|
|
2845
|
+
});
|
|
2720
2846
|
} finally {
|
|
2721
2847
|
client.close();
|
|
2722
2848
|
}
|
|
@@ -2754,7 +2880,7 @@ import { applyEdits, createScanner, findNodeAtLocation, modify, parse as parse2,
|
|
|
2754
2880
|
// ../../node_modules/@cortexkit/common-auth/dist/setup/config-write.js
|
|
2755
2881
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
2756
2882
|
import { mkdir as mkdir4, open as open4, rename as rename5, stat as stat4, unlink as unlink3 } from "node:fs/promises";
|
|
2757
|
-
import { basename as basename2, dirname as dirname5, join as
|
|
2883
|
+
import { basename as basename2, dirname as dirname5, join as join5 } from "node:path";
|
|
2758
2884
|
import { setTimeout as delay2 } from "node:timers/promises";
|
|
2759
2885
|
async function writeHostConfigAtomic(file, content, options = {}) {
|
|
2760
2886
|
const windows = (options.platform ?? process.platform) === "win32";
|
|
@@ -2769,7 +2895,7 @@ async function writeHostConfigAtomic(file, content, options = {}) {
|
|
|
2769
2895
|
throw error;
|
|
2770
2896
|
}
|
|
2771
2897
|
}
|
|
2772
|
-
const stage =
|
|
2898
|
+
const stage = join5(parent, `.${basename2(file)}.${(options.stageName ?? randomUUID5)()}.tmp`);
|
|
2773
2899
|
let created = false;
|
|
2774
2900
|
try {
|
|
2775
2901
|
const handle = await open4(stage, "wx", mode ?? 438);
|
|
@@ -3137,13 +3263,13 @@ ${write.content}`);
|
|
|
3137
3263
|
import { createHash as createHash2, randomUUID as randomUUID6 } from "node:crypto";
|
|
3138
3264
|
import { mkdir as mkdir5, readFile as readFile5, rename as rename6, rm as rm4, stat as stat5, writeFile } from "node:fs/promises";
|
|
3139
3265
|
import { homedir as homedir2 } from "node:os";
|
|
3140
|
-
import { dirname as dirname6, join as
|
|
3266
|
+
import { dirname as dirname6, join as join7 } from "node:path";
|
|
3141
3267
|
|
|
3142
3268
|
// src/claustrum.ts
|
|
3143
3269
|
import { readdirSync, statSync as statSync2 } from "node:fs";
|
|
3144
3270
|
import * as fs from "node:fs/promises";
|
|
3145
|
-
import { tmpdir as
|
|
3146
|
-
import { join as
|
|
3271
|
+
import { tmpdir as tmpdir3, userInfo } from "node:os";
|
|
3272
|
+
import { join as join6 } from "node:path";
|
|
3147
3273
|
function errorCode(error) {
|
|
3148
3274
|
return error && typeof error === "object" && "code" in error && typeof error.code === "string" ? error.code : "unknown";
|
|
3149
3275
|
}
|
|
@@ -3171,7 +3297,7 @@ function listSubcTempConnectionFiles(dir) {
|
|
|
3171
3297
|
if (!name.startsWith(CLAUSTRUM_TEMP_PREFIX) || !name.endsWith(CLAUSTRUM_TEMP_SUFFIX)) {
|
|
3172
3298
|
continue;
|
|
3173
3299
|
}
|
|
3174
|
-
const candidate =
|
|
3300
|
+
const candidate = join6(dir, name);
|
|
3175
3301
|
if (safeIsFile(candidate))
|
|
3176
3302
|
matches.push(candidate);
|
|
3177
3303
|
}
|
|
@@ -3181,13 +3307,13 @@ function listSubcTempConnectionFiles(dir) {
|
|
|
3181
3307
|
function findExistingClaustrumConnectionPath(env = process.env) {
|
|
3182
3308
|
const runtime = env.XDG_RUNTIME_DIR?.trim();
|
|
3183
3309
|
if (runtime) {
|
|
3184
|
-
const candidate =
|
|
3310
|
+
const candidate = join6(runtime, PRODUCTION_CLAUSTRUM_CONNECTION_FILE_NAME);
|
|
3185
3311
|
if (safeIsFile(candidate))
|
|
3186
3312
|
return candidate;
|
|
3187
3313
|
}
|
|
3188
3314
|
const home = env.HOME?.trim();
|
|
3189
3315
|
if (home) {
|
|
3190
|
-
const candidate =
|
|
3316
|
+
const candidate = join6(home, ".local", "share", "cortexkit", "run", PRODUCTION_CLAUSTRUM_CONNECTION_FILE_NAME);
|
|
3191
3317
|
if (safeIsFile(candidate))
|
|
3192
3318
|
return candidate;
|
|
3193
3319
|
}
|
|
@@ -3195,7 +3321,7 @@ function findExistingClaustrumConnectionPath(env = process.env) {
|
|
|
3195
3321
|
const linuxRun = `/run/user/${uid}/${PRODUCTION_CLAUSTRUM_CONNECTION_FILE_NAME}`;
|
|
3196
3322
|
if (safeIsFile(linuxRun))
|
|
3197
3323
|
return linuxRun;
|
|
3198
|
-
const tempMatches = listSubcTempConnectionFiles(
|
|
3324
|
+
const tempMatches = listSubcTempConnectionFiles(tmpdir3());
|
|
3199
3325
|
if (tempMatches.length === 1)
|
|
3200
3326
|
return tempMatches[0];
|
|
3201
3327
|
return;
|
|
@@ -3206,11 +3332,11 @@ function getDefaultClaustrumConnectionPath(env = process.env) {
|
|
|
3206
3332
|
return existing;
|
|
3207
3333
|
const runtime = env.XDG_RUNTIME_DIR?.trim();
|
|
3208
3334
|
if (runtime && (process.platform !== "darwin" || safeIsFile(runtime))) {
|
|
3209
|
-
return
|
|
3335
|
+
return join6(runtime, PRODUCTION_CLAUSTRUM_CONNECTION_FILE_NAME);
|
|
3210
3336
|
}
|
|
3211
3337
|
if (process.platform === "darwin") {
|
|
3212
3338
|
const home = env.HOME?.trim() || userInfo().homedir;
|
|
3213
|
-
return
|
|
3339
|
+
return join6(home, ".local", "share", "cortexkit", "run", PRODUCTION_CLAUSTRUM_CONNECTION_FILE_NAME);
|
|
3214
3340
|
}
|
|
3215
3341
|
const uid = process.getuid?.() ?? userInfo().uid;
|
|
3216
3342
|
return `/run/user/${uid}/${PRODUCTION_CLAUSTRUM_CONNECTION_FILE_NAME}`;
|
|
@@ -3312,6 +3438,345 @@ function assertNotCustodyTombstone(refreshToken, provider) {
|
|
|
3312
3438
|
}
|
|
3313
3439
|
}
|
|
3314
3440
|
|
|
3441
|
+
// src/model-capabilities.ts
|
|
3442
|
+
var PER_TURN_CONTROL_BETA = "per-turn-control-2026-07-01";
|
|
3443
|
+
var TURN_END_NOTE_BETA = "mid-conversation-system-clear-at-2026-08-21";
|
|
3444
|
+
var CLAUDE_CODE_BETA = "claude-code-20250219";
|
|
3445
|
+
var PROMPT_CACHING_SCOPE_BETA = "prompt-caching-scope-2026-01-05";
|
|
3446
|
+
var CLAUDE_CODE_FULL_AGENT_BETAS = [
|
|
3447
|
+
CLAUDE_CODE_BETA,
|
|
3448
|
+
"oauth-2025-04-20",
|
|
3449
|
+
"interleaved-thinking-2025-05-14",
|
|
3450
|
+
"thinking-token-count-2026-05-13",
|
|
3451
|
+
"context-management-2025-06-27",
|
|
3452
|
+
PROMPT_CACHING_SCOPE_BETA,
|
|
3453
|
+
"mid-conversation-tool-changes-2026-07-01",
|
|
3454
|
+
"advanced-tool-use-2025-11-20",
|
|
3455
|
+
TURN_END_NOTE_BETA,
|
|
3456
|
+
"effort-2025-11-24",
|
|
3457
|
+
"thinking-binding-controls-2026-08-01",
|
|
3458
|
+
"thinking-display-updates-2026-08-18",
|
|
3459
|
+
"extended-cache-ttl-2025-04-11",
|
|
3460
|
+
"cache-diagnosis-2026-04-07"
|
|
3461
|
+
];
|
|
3462
|
+
var CLAUDE_CODE_TITLE_BETAS = [
|
|
3463
|
+
"oauth-2025-04-20",
|
|
3464
|
+
"interleaved-thinking-2025-05-14",
|
|
3465
|
+
"redact-thinking-2026-02-12",
|
|
3466
|
+
"thinking-token-count-2026-05-13",
|
|
3467
|
+
"context-management-2025-06-27",
|
|
3468
|
+
PROMPT_CACHING_SCOPE_BETA,
|
|
3469
|
+
"mid-conversation-tool-changes-2026-07-01",
|
|
3470
|
+
TURN_END_NOTE_BETA,
|
|
3471
|
+
"effort-2025-11-24",
|
|
3472
|
+
"cache-diagnosis-2026-04-07"
|
|
3473
|
+
];
|
|
3474
|
+
var CLAUDE_CODE_QUOTA_BETAS = [
|
|
3475
|
+
"oauth-2025-04-20",
|
|
3476
|
+
"interleaved-thinking-2025-05-14",
|
|
3477
|
+
"redact-thinking-2026-02-12",
|
|
3478
|
+
"thinking-token-count-2026-05-13",
|
|
3479
|
+
"context-management-2025-06-27",
|
|
3480
|
+
PROMPT_CACHING_SCOPE_BETA
|
|
3481
|
+
];
|
|
3482
|
+
var CLAUDE_CODE_DEFAULT_BETAS = {
|
|
3483
|
+
main: CLAUDE_CODE_FULL_AGENT_BETAS,
|
|
3484
|
+
title: CLAUDE_CODE_TITLE_BETAS,
|
|
3485
|
+
quota: CLAUDE_CODE_QUOTA_BETAS
|
|
3486
|
+
};
|
|
3487
|
+
function claudeCodeBetaLists(options) {
|
|
3488
|
+
const adjust = (list) => {
|
|
3489
|
+
const selected = [...list];
|
|
3490
|
+
if (options.claudeCodeBetaAfterCachingScope) {
|
|
3491
|
+
const codeIndex = selected.indexOf(CLAUDE_CODE_BETA);
|
|
3492
|
+
if (codeIndex >= 0) {
|
|
3493
|
+
selected.splice(codeIndex, 1);
|
|
3494
|
+
selected.splice(selected.indexOf(PROMPT_CACHING_SCOPE_BETA) + 1, 0, CLAUDE_CODE_BETA);
|
|
3495
|
+
}
|
|
3496
|
+
}
|
|
3497
|
+
if (options.perTurnControl) {
|
|
3498
|
+
let index = selected.indexOf(PROMPT_CACHING_SCOPE_BETA);
|
|
3499
|
+
if (index >= 0 && selected[index + 1] === CLAUDE_CODE_BETA)
|
|
3500
|
+
index += 1;
|
|
3501
|
+
if (index >= 0)
|
|
3502
|
+
selected.splice(index + 1, 0, PER_TURN_CONTROL_BETA);
|
|
3503
|
+
else
|
|
3504
|
+
selected.push(PER_TURN_CONTROL_BETA);
|
|
3505
|
+
}
|
|
3506
|
+
return selected;
|
|
3507
|
+
};
|
|
3508
|
+
return {
|
|
3509
|
+
main: adjust(CLAUDE_CODE_FULL_AGENT_BETAS),
|
|
3510
|
+
title: adjust(CLAUDE_CODE_TITLE_BETAS),
|
|
3511
|
+
quota: adjust(CLAUDE_CODE_QUOTA_BETAS)
|
|
3512
|
+
};
|
|
3513
|
+
}
|
|
3514
|
+
var ALL_ADAPTIVE_EFFORTS = ["low", "medium", "high", "xhigh", "max"];
|
|
3515
|
+
var FABLE_MYTHOS_5_CATALOGUE = {
|
|
3516
|
+
releaseDate: "2026-06-09",
|
|
3517
|
+
contextWindow: 1e6,
|
|
3518
|
+
maxOutputTokens: 128000,
|
|
3519
|
+
pricing: {
|
|
3520
|
+
input: 10,
|
|
3521
|
+
output: 50,
|
|
3522
|
+
cacheRead: 1,
|
|
3523
|
+
cacheWrite5m: 12.5,
|
|
3524
|
+
cacheWrite1h: 20
|
|
3525
|
+
}
|
|
3526
|
+
};
|
|
3527
|
+
var FABLE_MYTHOS_5_1_CATALOGUE = {
|
|
3528
|
+
releaseDate: "2026-09-01",
|
|
3529
|
+
contextWindow: 1e6,
|
|
3530
|
+
maxOutputTokens: 128000,
|
|
3531
|
+
pricing: {
|
|
3532
|
+
input: 10,
|
|
3533
|
+
output: 50,
|
|
3534
|
+
cacheRead: 0.25,
|
|
3535
|
+
cacheWrite5m: 12.5,
|
|
3536
|
+
cacheWrite1h: 20
|
|
3537
|
+
}
|
|
3538
|
+
};
|
|
3539
|
+
var CLAUDE_MODEL_CAPABILITIES = [
|
|
3540
|
+
{
|
|
3541
|
+
id: "claude-fable-5",
|
|
3542
|
+
name: "Claude Fable 5",
|
|
3543
|
+
family: "fable",
|
|
3544
|
+
idSuffixes: "any",
|
|
3545
|
+
catalogue: FABLE_MYTHOS_5_CATALOGUE,
|
|
3546
|
+
thinkingModes: ["adaptive"],
|
|
3547
|
+
rejectsForcedToolChoice: false,
|
|
3548
|
+
efforts: { default: "high" },
|
|
3549
|
+
effortMarkers: "none",
|
|
3550
|
+
turnEndNote: false,
|
|
3551
|
+
thinkingBindingControls: false,
|
|
3552
|
+
claudeCodeBetas: CLAUDE_CODE_DEFAULT_BETAS,
|
|
3553
|
+
serverSideFallback: true,
|
|
3554
|
+
refusalRecoveryFamily: "fable-5",
|
|
3555
|
+
scopedQuota: "fable",
|
|
3556
|
+
fastMode: false
|
|
3557
|
+
},
|
|
3558
|
+
{
|
|
3559
|
+
id: "claude-mythos-5",
|
|
3560
|
+
name: "Claude Mythos 5",
|
|
3561
|
+
family: "mythos",
|
|
3562
|
+
idSuffixes: "any",
|
|
3563
|
+
limited: true,
|
|
3564
|
+
catalogue: FABLE_MYTHOS_5_CATALOGUE,
|
|
3565
|
+
thinkingModes: ["adaptive"],
|
|
3566
|
+
rejectsForcedToolChoice: false,
|
|
3567
|
+
efforts: { default: "high" },
|
|
3568
|
+
effortMarkers: "none",
|
|
3569
|
+
turnEndNote: false,
|
|
3570
|
+
thinkingBindingControls: false,
|
|
3571
|
+
claudeCodeBetas: CLAUDE_CODE_DEFAULT_BETAS,
|
|
3572
|
+
serverSideFallback: false,
|
|
3573
|
+
scopedQuota: "mythos",
|
|
3574
|
+
fastMode: false
|
|
3575
|
+
},
|
|
3576
|
+
{
|
|
3577
|
+
id: "claude-fable-5-1",
|
|
3578
|
+
name: "Claude Fable 5.1",
|
|
3579
|
+
family: "fable",
|
|
3580
|
+
idSuffixes: "any",
|
|
3581
|
+
catalogue: FABLE_MYTHOS_5_1_CATALOGUE,
|
|
3582
|
+
thinkingModes: ["adaptive"],
|
|
3583
|
+
rejectsForcedToolChoice: true,
|
|
3584
|
+
efforts: { variants: ALL_ADAPTIVE_EFFORTS, default: "high" },
|
|
3585
|
+
effortMarkers: "always",
|
|
3586
|
+
turnEndNote: true,
|
|
3587
|
+
thinkingBindingControls: true,
|
|
3588
|
+
claudeCodeBetas: claudeCodeBetaLists({ perTurnControl: true }),
|
|
3589
|
+
serverSideFallback: true,
|
|
3590
|
+
refusalRecoveryFamily: "fable-5-1",
|
|
3591
|
+
scopedQuota: "fable",
|
|
3592
|
+
fastMode: false
|
|
3593
|
+
},
|
|
3594
|
+
{
|
|
3595
|
+
id: "claude-mythos-5-1",
|
|
3596
|
+
name: "Claude Mythos 5.1",
|
|
3597
|
+
family: "mythos",
|
|
3598
|
+
idSuffixes: "any",
|
|
3599
|
+
limited: true,
|
|
3600
|
+
catalogue: FABLE_MYTHOS_5_1_CATALOGUE,
|
|
3601
|
+
thinkingModes: ["adaptive"],
|
|
3602
|
+
rejectsForcedToolChoice: true,
|
|
3603
|
+
efforts: { default: "high" },
|
|
3604
|
+
effortMarkers: "none",
|
|
3605
|
+
turnEndNote: false,
|
|
3606
|
+
thinkingBindingControls: false,
|
|
3607
|
+
claudeCodeBetas: CLAUDE_CODE_DEFAULT_BETAS,
|
|
3608
|
+
serverSideFallback: false,
|
|
3609
|
+
scopedQuota: "mythos",
|
|
3610
|
+
fastMode: false
|
|
3611
|
+
},
|
|
3612
|
+
{
|
|
3613
|
+
id: "claude-opus-5",
|
|
3614
|
+
name: "Claude Opus 5",
|
|
3615
|
+
family: "opus",
|
|
3616
|
+
idSuffixes: "any",
|
|
3617
|
+
thinkingModes: ["adaptive", "disabled"],
|
|
3618
|
+
rejectsForcedToolChoice: false,
|
|
3619
|
+
efforts: { variants: ALL_ADAPTIVE_EFFORTS, default: "high" },
|
|
3620
|
+
effortMarkers: "none",
|
|
3621
|
+
turnEndNote: false,
|
|
3622
|
+
thinkingBindingControls: false,
|
|
3623
|
+
claudeCodeBetas: CLAUDE_CODE_DEFAULT_BETAS,
|
|
3624
|
+
serverSideFallback: true,
|
|
3625
|
+
refusalRecoveryFamily: "opus-5",
|
|
3626
|
+
fastMode: true
|
|
3627
|
+
},
|
|
3628
|
+
{
|
|
3629
|
+
id: "claude-opus-5-5",
|
|
3630
|
+
name: "Claude Opus 5.5",
|
|
3631
|
+
family: "opus",
|
|
3632
|
+
idSuffixes: "any",
|
|
3633
|
+
catalogue: {
|
|
3634
|
+
releaseDate: "2026-09-18",
|
|
3635
|
+
contextWindow: 1e6,
|
|
3636
|
+
maxOutputTokens: 128000,
|
|
3637
|
+
pricing: {
|
|
3638
|
+
input: 4,
|
|
3639
|
+
output: 20,
|
|
3640
|
+
cacheRead: 0.2,
|
|
3641
|
+
cacheWrite5m: 5,
|
|
3642
|
+
cacheWrite1h: 8
|
|
3643
|
+
}
|
|
3644
|
+
},
|
|
3645
|
+
thinkingModes: ["adaptive"],
|
|
3646
|
+
rejectsForcedToolChoice: true,
|
|
3647
|
+
efforts: { variants: ALL_ADAPTIVE_EFFORTS, default: "medium" },
|
|
3648
|
+
effortMarkers: "with-adaptive-thinking",
|
|
3649
|
+
turnEndNote: true,
|
|
3650
|
+
thinkingBindingControls: true,
|
|
3651
|
+
claudeCodeBetas: claudeCodeBetaLists({ perTurnControl: true }),
|
|
3652
|
+
serverSideFallback: true,
|
|
3653
|
+
refusalRecoveryFamily: "opus-5-5",
|
|
3654
|
+
fastMode: true
|
|
3655
|
+
},
|
|
3656
|
+
{
|
|
3657
|
+
id: "claude-sonnet-5",
|
|
3658
|
+
name: "Claude Sonnet 5",
|
|
3659
|
+
family: "sonnet",
|
|
3660
|
+
idSuffixes: "any",
|
|
3661
|
+
thinkingModes: ["adaptive", "disabled"],
|
|
3662
|
+
rejectsForcedToolChoice: false,
|
|
3663
|
+
efforts: { default: "high" },
|
|
3664
|
+
effortMarkers: "none",
|
|
3665
|
+
turnEndNote: false,
|
|
3666
|
+
thinkingBindingControls: false,
|
|
3667
|
+
claudeCodeBetas: CLAUDE_CODE_DEFAULT_BETAS,
|
|
3668
|
+
serverSideFallback: false,
|
|
3669
|
+
fastMode: false
|
|
3670
|
+
},
|
|
3671
|
+
{
|
|
3672
|
+
id: "claude-sonnet-5-5",
|
|
3673
|
+
name: "Claude Sonnet 5.5",
|
|
3674
|
+
family: "sonnet",
|
|
3675
|
+
idSuffixes: "any",
|
|
3676
|
+
catalogue: {
|
|
3677
|
+
releaseDate: "2026-09-28",
|
|
3678
|
+
contextWindow: 1e6,
|
|
3679
|
+
maxOutputTokens: 128000,
|
|
3680
|
+
pricing: {
|
|
3681
|
+
input: 2,
|
|
3682
|
+
output: 10,
|
|
3683
|
+
cacheRead: 0.2,
|
|
3684
|
+
cacheWrite5m: 2.5,
|
|
3685
|
+
cacheWrite1h: 4
|
|
3686
|
+
}
|
|
3687
|
+
},
|
|
3688
|
+
thinkingModes: ["adaptive", "between_tools"],
|
|
3689
|
+
rejectsForcedToolChoice: true,
|
|
3690
|
+
efforts: { variants: ALL_ADAPTIVE_EFFORTS, default: "high" },
|
|
3691
|
+
effortMarkers: "with-adaptive-thinking",
|
|
3692
|
+
turnEndNote: true,
|
|
3693
|
+
thinkingBindingControls: true,
|
|
3694
|
+
claudeCodeBetas: claudeCodeBetaLists({ perTurnControl: true }),
|
|
3695
|
+
serverSideFallback: false,
|
|
3696
|
+
fastMode: false
|
|
3697
|
+
},
|
|
3698
|
+
{
|
|
3699
|
+
id: "claude-haiku-5-5",
|
|
3700
|
+
name: "Claude Haiku 5.5",
|
|
3701
|
+
family: "haiku",
|
|
3702
|
+
idSuffixes: "dated",
|
|
3703
|
+
catalogue: {
|
|
3704
|
+
releaseDate: "2026-10-07",
|
|
3705
|
+
contextWindow: 1e6,
|
|
3706
|
+
maxOutputTokens: 128000,
|
|
3707
|
+
pricing: {
|
|
3708
|
+
input: 0.1,
|
|
3709
|
+
output: 0.5,
|
|
3710
|
+
cacheRead: 0.01,
|
|
3711
|
+
cacheWrite5m: 0.125,
|
|
3712
|
+
cacheWrite1h: 0.2
|
|
3713
|
+
},
|
|
3714
|
+
longContext: {
|
|
3715
|
+
inputTokensAbove: 1e5,
|
|
3716
|
+
pricing: {
|
|
3717
|
+
input: 0.5,
|
|
3718
|
+
output: 2.5,
|
|
3719
|
+
cacheRead: 0.05,
|
|
3720
|
+
cacheWrite5m: 0.625,
|
|
3721
|
+
cacheWrite1h: 1
|
|
3722
|
+
}
|
|
3723
|
+
}
|
|
3724
|
+
},
|
|
3725
|
+
thinkingModes: ["adaptive", "disabled"],
|
|
3726
|
+
rejectsForcedToolChoice: false,
|
|
3727
|
+
efforts: { variants: ALL_ADAPTIVE_EFFORTS, default: "medium" },
|
|
3728
|
+
effortMarkers: "none",
|
|
3729
|
+
turnEndNote: true,
|
|
3730
|
+
thinkingBindingControls: true,
|
|
3731
|
+
claudeCodeBetas: claudeCodeBetaLists({
|
|
3732
|
+
perTurnControl: true,
|
|
3733
|
+
claudeCodeBetaAfterCachingScope: true
|
|
3734
|
+
}),
|
|
3735
|
+
serverSideFallback: false,
|
|
3736
|
+
fastMode: false
|
|
3737
|
+
}
|
|
3738
|
+
];
|
|
3739
|
+
function normalizeAnthropicModelId(model) {
|
|
3740
|
+
return model.endsWith("[1m]") ? model.slice(0, -4) : model;
|
|
3741
|
+
}
|
|
3742
|
+
function matchesRow(row, normalized) {
|
|
3743
|
+
if (normalized === row.id)
|
|
3744
|
+
return true;
|
|
3745
|
+
if (!normalized.startsWith(`${row.id}-`))
|
|
3746
|
+
return false;
|
|
3747
|
+
if (row.idSuffixes === "any")
|
|
3748
|
+
return true;
|
|
3749
|
+
return /^\d{8}$/.test(normalized.slice(row.id.length + 1));
|
|
3750
|
+
}
|
|
3751
|
+
function resolveClaudeModelCapabilities(model) {
|
|
3752
|
+
if (typeof model !== "string")
|
|
3753
|
+
return;
|
|
3754
|
+
const normalized = normalizeAnthropicModelId(model);
|
|
3755
|
+
let resolved;
|
|
3756
|
+
for (const row of CLAUDE_MODEL_CAPABILITIES) {
|
|
3757
|
+
if (!matchesRow(row, normalized))
|
|
3758
|
+
continue;
|
|
3759
|
+
if (!resolved || row.id.length > resolved.id.length)
|
|
3760
|
+
resolved = row;
|
|
3761
|
+
}
|
|
3762
|
+
return resolved;
|
|
3763
|
+
}
|
|
3764
|
+
function getClaudeModelCapabilities(id) {
|
|
3765
|
+
const row = CLAUDE_MODEL_CAPABILITIES.find((entry) => entry.id === id);
|
|
3766
|
+
if (!row)
|
|
3767
|
+
throw new Error(`No model capability row for ${id}`);
|
|
3768
|
+
return row;
|
|
3769
|
+
}
|
|
3770
|
+
function getClaudeModelCatalogue(id) {
|
|
3771
|
+
const catalogue = getClaudeModelCapabilities(id).catalogue;
|
|
3772
|
+
if (!catalogue)
|
|
3773
|
+
throw new Error(`No catalogue facts for ${id}`);
|
|
3774
|
+
return catalogue;
|
|
3775
|
+
}
|
|
3776
|
+
function pinsEffortOnEveryRequest(model) {
|
|
3777
|
+
return resolveClaudeModelCapabilities(model)?.effortMarkers === "always";
|
|
3778
|
+
}
|
|
3779
|
+
|
|
3315
3780
|
// src/constants.ts
|
|
3316
3781
|
var CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
|
|
3317
3782
|
var AUTHORIZE_URLS = {
|
|
@@ -3342,7 +3807,7 @@ function mergeAnthropicBetas(existing, betas) {
|
|
|
3342
3807
|
return [...new Set([...incoming, ...betas])].join(",");
|
|
3343
3808
|
}
|
|
3344
3809
|
function isFastModeSupportedModel(model) {
|
|
3345
|
-
return typeof model === "string" && (model.startsWith("claude-opus-4-8") || model.startsWith("claude-opus-5"));
|
|
3810
|
+
return typeof model === "string" && (model.startsWith("claude-opus-4-8") || model.startsWith("claude-opus-5") || resolveClaudeModelCapabilities(model)?.fastMode === true);
|
|
3346
3811
|
}
|
|
3347
3812
|
var OPENCODE_IDENTITY_PREFIX = "You are OpenCode";
|
|
3348
3813
|
var CLAUDE_CODE_IDENTITY = "You are Claude Code, Anthropic's official CLI for Claude.";
|
|
@@ -3659,16 +4124,16 @@ function getConfigDir() {
|
|
|
3659
4124
|
if (process.env.OPENCODE_CONFIG_DIR?.trim()) {
|
|
3660
4125
|
return process.env.OPENCODE_CONFIG_DIR.trim();
|
|
3661
4126
|
}
|
|
3662
|
-
return
|
|
4127
|
+
return join7(process.env.XDG_CONFIG_HOME || join7(homedir2(), ".config"), "opencode");
|
|
3663
4128
|
}
|
|
3664
4129
|
function getAccountStoragePath() {
|
|
3665
|
-
return process.env.OPENCODE_ANTHROPIC_AUTH_FILE?.trim() ||
|
|
4130
|
+
return process.env.OPENCODE_ANTHROPIC_AUTH_FILE?.trim() || join7(getConfigDir(), ACCOUNT_FILE_NAME);
|
|
3666
4131
|
}
|
|
3667
4132
|
function getAccountStatePath(configPath = getAccountStoragePath()) {
|
|
3668
4133
|
const explicit = process.env.OPENCODE_ANTHROPIC_AUTH_STATE_FILE?.trim();
|
|
3669
4134
|
if (explicit)
|
|
3670
4135
|
return explicit;
|
|
3671
|
-
return configPath.endsWith(ACCOUNT_FILE_NAME) ?
|
|
4136
|
+
return configPath.endsWith(ACCOUNT_FILE_NAME) ? join7(dirname6(configPath), ACCOUNT_STATE_FILE_NAME) : `${configPath}.state.json`;
|
|
3672
4137
|
}
|
|
3673
4138
|
function createEmptyStorage() {
|
|
3674
4139
|
return {
|
|
@@ -3789,7 +4254,7 @@ function getClaustrumMode(storage) {
|
|
|
3789
4254
|
async function acquireRefreshFileLock2(options) {
|
|
3790
4255
|
const accountPath = options.path ?? getAccountStoragePath();
|
|
3791
4256
|
const lockPath = `${accountPath}.${options.name}.lock`;
|
|
3792
|
-
const legacyOwnerPath =
|
|
4257
|
+
const legacyOwnerPath = join7(lockPath, "owner.json");
|
|
3793
4258
|
const ownerId = randomUUID6();
|
|
3794
4259
|
const now = Date.now;
|
|
3795
4260
|
let renewTimer = null;
|
|
@@ -3843,7 +4308,7 @@ async function acquireRefreshFileLock2(options) {
|
|
|
3843
4308
|
let acquired = await tryAcquire();
|
|
3844
4309
|
if (!acquired) {
|
|
3845
4310
|
const evictPath = `${lockPath}.evicting`;
|
|
3846
|
-
const evictOwnerPath =
|
|
4311
|
+
const evictOwnerPath = join7(evictPath, "owner.json");
|
|
3847
4312
|
const evictOwnerId = randomUUID6();
|
|
3848
4313
|
const EVICT_TTL = 5000;
|
|
3849
4314
|
const MAX_STEAL_ATTEMPTS = 8;
|
|
@@ -4789,374 +5254,32 @@ function extractBillingPromptId(body) {
|
|
|
4789
5254
|
}
|
|
4790
5255
|
function stripBillingLineageFields(value) {
|
|
4791
5256
|
return value.replace(BILLING_LINEAGE_FIELD_PATTERN, "");
|
|
4792
|
-
}
|
|
4793
|
-
function stripBillingLineageFromBody(body) {
|
|
4794
|
-
if (!body || typeof body !== "object")
|
|
4795
|
-
return 0;
|
|
4796
|
-
const system = body.system;
|
|
4797
|
-
if (!Array.isArray(system))
|
|
4798
|
-
return 0;
|
|
4799
|
-
let stripped = 0;
|
|
4800
|
-
for (const block of system) {
|
|
4801
|
-
if (!block || typeof block !== "object")
|
|
4802
|
-
continue;
|
|
4803
|
-
const text = block.text;
|
|
4804
|
-
if (typeof text !== "string" || !text.startsWith("x-anthropic-billing-header:")) {
|
|
4805
|
-
continue;
|
|
4806
|
-
}
|
|
4807
|
-
const clean = stripBillingLineageFields(text);
|
|
4808
|
-
if (clean === text)
|
|
4809
|
-
continue;
|
|
4810
|
-
block.text = clean;
|
|
4811
|
-
stripped += 1;
|
|
4812
|
-
}
|
|
4813
|
-
return stripped;
|
|
4814
|
-
}
|
|
4815
|
-
|
|
4816
|
-
// src/claude-code.ts
|
|
4817
|
-
import { randomBytes as randomBytes2, randomUUID as randomUUID7 } from "node:crypto";
|
|
4818
|
-
|
|
4819
|
-
// src/models.ts
|
|
4820
|
-
var CLAUDE_FABLE_5_MODEL_ID = "claude-fable-5";
|
|
4821
|
-
var CLAUDE_MYTHOS_5_MODEL_ID = "claude-mythos-5";
|
|
4822
|
-
var CLAUDE_FABLE_5_1_MODEL_ID = "claude-fable-5-1";
|
|
4823
|
-
var CLAUDE_MYTHOS_5_1_MODEL_ID = "claude-mythos-5-1";
|
|
4824
|
-
var CLAUDE_HAIKU_4_5_MODEL_ID = "claude-haiku-4-5";
|
|
4825
|
-
function normalizeAnthropicModelId(model) {
|
|
4826
|
-
return model.endsWith("[1m]") ? model.slice(0, -4) : model;
|
|
4827
|
-
}
|
|
4828
|
-
var CLAUDE_HAIKU_4_5_PRICING = {
|
|
4829
|
-
input: 1,
|
|
4830
|
-
output: 5
|
|
4831
|
-
};
|
|
4832
|
-
var CLAUDE_FABLE_MYTHOS_5_1_MODEL_IDS = [
|
|
4833
|
-
CLAUDE_FABLE_5_1_MODEL_ID,
|
|
4834
|
-
CLAUDE_MYTHOS_5_1_MODEL_ID
|
|
4835
|
-
];
|
|
4836
|
-
var CLAUDE_FABLE_MYTHOS_5_MODEL_IDS = [
|
|
4837
|
-
CLAUDE_FABLE_5_MODEL_ID,
|
|
4838
|
-
CLAUDE_MYTHOS_5_MODEL_ID,
|
|
4839
|
-
...CLAUDE_FABLE_MYTHOS_5_1_MODEL_IDS
|
|
4840
|
-
];
|
|
4841
|
-
var CLAUDE_FABLE_MYTHOS_5_SUMMARIZED_THINKING = {
|
|
4842
|
-
type: "adaptive",
|
|
4843
|
-
display: "summarized"
|
|
4844
|
-
};
|
|
4845
|
-
var CLAUDE_FABLE_MYTHOS_5_PRICING = {
|
|
4846
|
-
input: 10,
|
|
4847
|
-
output: 50,
|
|
4848
|
-
cacheRead: 1,
|
|
4849
|
-
cacheWrite5m: 12.5,
|
|
4850
|
-
cacheWrite1h: 20
|
|
4851
|
-
};
|
|
4852
|
-
var CLAUDE_FABLE_MYTHOS_5_1_PRICING = {
|
|
4853
|
-
input: 10,
|
|
4854
|
-
output: 50,
|
|
4855
|
-
cacheRead: 0.25,
|
|
4856
|
-
cacheWrite5m: 12.5,
|
|
4857
|
-
cacheWrite1h: 20
|
|
4858
|
-
};
|
|
4859
|
-
var CLAUDE_FABLE_MYTHOS_5_CONTEXT_WINDOW = 1e6;
|
|
4860
|
-
var CLAUDE_FABLE_MYTHOS_5_MAX_OUTPUT_TOKENS = 128000;
|
|
4861
|
-
var CLAUDE_FABLE_MYTHOS_5_RELEASE_DATE = "2026-06-09";
|
|
4862
|
-
var CLAUDE_FABLE_MYTHOS_5_1_RELEASE_DATE = "2026-09-01";
|
|
4863
|
-
var CLAUDE_FABLE_MYTHOS_5_MODEL_SPECS = {
|
|
4864
|
-
[CLAUDE_FABLE_5_MODEL_ID]: {
|
|
4865
|
-
id: CLAUDE_FABLE_5_MODEL_ID,
|
|
4866
|
-
name: "Claude Fable 5"
|
|
4867
|
-
},
|
|
4868
|
-
[CLAUDE_MYTHOS_5_MODEL_ID]: {
|
|
4869
|
-
id: CLAUDE_MYTHOS_5_MODEL_ID,
|
|
4870
|
-
name: "Claude Mythos 5",
|
|
4871
|
-
limited: true
|
|
4872
|
-
},
|
|
4873
|
-
[CLAUDE_FABLE_5_1_MODEL_ID]: {
|
|
4874
|
-
id: CLAUDE_FABLE_5_1_MODEL_ID,
|
|
4875
|
-
name: "Claude Fable 5.1"
|
|
4876
|
-
},
|
|
4877
|
-
[CLAUDE_MYTHOS_5_1_MODEL_ID]: {
|
|
4878
|
-
id: CLAUDE_MYTHOS_5_1_MODEL_ID,
|
|
4879
|
-
name: "Claude Mythos 5.1",
|
|
4880
|
-
limited: true
|
|
4881
|
-
}
|
|
4882
|
-
};
|
|
4883
|
-
var CLAUDE_FABLE_MYTHOS_5_1_MODEL_SPECS = {
|
|
4884
|
-
[CLAUDE_FABLE_5_1_MODEL_ID]: CLAUDE_FABLE_MYTHOS_5_MODEL_SPECS[CLAUDE_FABLE_5_1_MODEL_ID],
|
|
4885
|
-
[CLAUDE_MYTHOS_5_1_MODEL_ID]: CLAUDE_FABLE_MYTHOS_5_MODEL_SPECS[CLAUDE_MYTHOS_5_1_MODEL_ID]
|
|
4886
|
-
};
|
|
4887
|
-
function isClaudeFableOrMythos5Model(model) {
|
|
4888
|
-
if (typeof model !== "string")
|
|
4889
|
-
return false;
|
|
4890
|
-
const normalized = normalizeAnthropicModelId(model);
|
|
4891
|
-
return CLAUDE_FABLE_MYTHOS_5_MODEL_IDS.some((id) => normalized === id || normalized.startsWith(`${id}-`));
|
|
4892
|
-
}
|
|
4893
|
-
function isClaudeFableOrMythos51Model(model) {
|
|
4894
|
-
if (typeof model !== "string")
|
|
4895
|
-
return false;
|
|
4896
|
-
const normalized = normalizeAnthropicModelId(model);
|
|
4897
|
-
return CLAUDE_FABLE_MYTHOS_5_1_MODEL_IDS.some((id) => normalized === id || normalized.startsWith(`${id}-`));
|
|
4898
|
-
}
|
|
4899
|
-
function isClaudeFable51Model(model) {
|
|
4900
|
-
if (typeof model !== "string")
|
|
4901
|
-
return false;
|
|
4902
|
-
const normalized = normalizeAnthropicModelId(model);
|
|
4903
|
-
return normalized === CLAUDE_FABLE_5_1_MODEL_ID || normalized.startsWith(`${CLAUDE_FABLE_5_1_MODEL_ID}-`);
|
|
4904
|
-
}
|
|
4905
|
-
function getClaudeFableMythos5ReleaseDate(model) {
|
|
4906
|
-
return isClaudeFableOrMythos51Model(model) ? CLAUDE_FABLE_MYTHOS_5_1_RELEASE_DATE : CLAUDE_FABLE_MYTHOS_5_RELEASE_DATE;
|
|
4907
|
-
}
|
|
4908
|
-
var CLAUDE_SONNET_5_MODEL_ID = "claude-sonnet-5";
|
|
4909
|
-
var CLAUDE_SONNET_5_ADAPTIVE_THINKING = CLAUDE_FABLE_MYTHOS_5_SUMMARIZED_THINKING;
|
|
4910
|
-
function isClaudeSonnet5Model(model) {
|
|
4911
|
-
if (typeof model !== "string")
|
|
4912
|
-
return false;
|
|
4913
|
-
const normalized = normalizeAnthropicModelId(model);
|
|
4914
|
-
return !isClaudeSonnet55Model(normalized) && (normalized === CLAUDE_SONNET_5_MODEL_ID || normalized.startsWith(`${CLAUDE_SONNET_5_MODEL_ID}-`));
|
|
4915
|
-
}
|
|
4916
|
-
var CLAUDE_SONNET_5_5_MODEL_ID = "claude-sonnet-5-5";
|
|
4917
|
-
var CLAUDE_SONNET_5_5_RELEASE_DATE = "2026-09-28";
|
|
4918
|
-
var CLAUDE_SONNET_5_5_CONTEXT_WINDOW = 1e6;
|
|
4919
|
-
var CLAUDE_SONNET_5_5_MAX_OUTPUT_TOKENS = 128000;
|
|
4920
|
-
var CLAUDE_SONNET_5_5_PRICING = {
|
|
4921
|
-
input: 2,
|
|
4922
|
-
output: 10,
|
|
4923
|
-
cacheRead: 0.2,
|
|
4924
|
-
cacheWrite5m: 2.5,
|
|
4925
|
-
cacheWrite1h: 4
|
|
4926
|
-
};
|
|
4927
|
-
var CLAUDE_SONNET_5_5_ADAPTIVE_THINKING = CLAUDE_FABLE_MYTHOS_5_SUMMARIZED_THINKING;
|
|
4928
|
-
function isClaudeSonnet55Model(model) {
|
|
4929
|
-
if (typeof model !== "string")
|
|
4930
|
-
return false;
|
|
4931
|
-
const normalized = normalizeAnthropicModelId(model);
|
|
4932
|
-
return normalized === CLAUDE_SONNET_5_5_MODEL_ID || normalized.startsWith(`${CLAUDE_SONNET_5_5_MODEL_ID}-`);
|
|
4933
|
-
}
|
|
4934
|
-
var CLAUDE_HAIKU_5_5_MODEL_ID = "claude-haiku-5-5";
|
|
4935
|
-
var CLAUDE_HAIKU_5_5_RELEASE_DATE = "2026-10-07";
|
|
4936
|
-
var CLAUDE_HAIKU_5_5_CONTEXT_WINDOW = 1e6;
|
|
4937
|
-
var CLAUDE_HAIKU_5_5_MAX_OUTPUT_TOKENS = 128000;
|
|
4938
|
-
var CLAUDE_HAIKU_5_5_LONG_CONTEXT_THRESHOLD = 1e5;
|
|
4939
|
-
var CLAUDE_HAIKU_5_5_PRICING = {
|
|
4940
|
-
input: 0.1,
|
|
4941
|
-
output: 0.5,
|
|
4942
|
-
cacheRead: 0.01,
|
|
4943
|
-
cacheWrite5m: 0.125,
|
|
4944
|
-
cacheWrite1h: 0.2
|
|
4945
|
-
};
|
|
4946
|
-
var CLAUDE_HAIKU_5_5_LONG_CONTEXT_PRICING = {
|
|
4947
|
-
input: 0.5,
|
|
4948
|
-
output: 2.5,
|
|
4949
|
-
cacheRead: 0.05,
|
|
4950
|
-
cacheWrite5m: 0.625,
|
|
4951
|
-
cacheWrite1h: 1
|
|
4952
|
-
};
|
|
4953
|
-
var CLAUDE_HAIKU_5_5_ADAPTIVE_THINKING = CLAUDE_FABLE_MYTHOS_5_SUMMARIZED_THINKING;
|
|
4954
|
-
function isClaudeHaiku55Model(model) {
|
|
4955
|
-
if (typeof model !== "string")
|
|
4956
|
-
return false;
|
|
4957
|
-
const normalized = normalizeAnthropicModelId(model);
|
|
4958
|
-
return normalized === CLAUDE_HAIKU_5_5_MODEL_ID || /^claude-haiku-5-5-\d{8}$/.test(normalized);
|
|
4959
|
-
}
|
|
4960
|
-
var CLAUDE_OPUS_5_MODEL_ID = "claude-opus-5";
|
|
4961
|
-
var CLAUDE_OPUS_5_ADAPTIVE_THINKING = CLAUDE_FABLE_MYTHOS_5_SUMMARIZED_THINKING;
|
|
4962
|
-
function isClaudeOpus5Model(model) {
|
|
4963
|
-
if (typeof model !== "string")
|
|
4964
|
-
return false;
|
|
4965
|
-
const normalized = normalizeAnthropicModelId(model);
|
|
4966
|
-
return !isClaudeOpus55Model(normalized) && (normalized === CLAUDE_OPUS_5_MODEL_ID || normalized.startsWith(`${CLAUDE_OPUS_5_MODEL_ID}-`));
|
|
4967
|
-
}
|
|
4968
|
-
var CLAUDE_OPUS_5_5_MODEL_ID = "claude-opus-5-5";
|
|
4969
|
-
var CLAUDE_OPUS_5_5_RELEASE_DATE = "2026-09-18";
|
|
4970
|
-
var CLAUDE_OPUS_5_5_CONTEXT_WINDOW = 1e6;
|
|
4971
|
-
var CLAUDE_OPUS_5_5_MAX_OUTPUT_TOKENS = 128000;
|
|
4972
|
-
var CLAUDE_OPUS_5_5_PRICING = {
|
|
4973
|
-
input: 4,
|
|
4974
|
-
output: 20,
|
|
4975
|
-
cacheRead: 0.2,
|
|
4976
|
-
cacheWrite5m: 5,
|
|
4977
|
-
cacheWrite1h: 8
|
|
4978
|
-
};
|
|
4979
|
-
var CLAUDE_OPUS_5_5_ADAPTIVE_THINKING = CLAUDE_FABLE_MYTHOS_5_SUMMARIZED_THINKING;
|
|
4980
|
-
function isClaudeOpus55Model(model) {
|
|
4981
|
-
if (typeof model !== "string")
|
|
4982
|
-
return false;
|
|
4983
|
-
const normalized = normalizeAnthropicModelId(model);
|
|
4984
|
-
return normalized === CLAUDE_OPUS_5_5_MODEL_ID || normalized.startsWith(`${CLAUDE_OPUS_5_5_MODEL_ID}-`);
|
|
4985
|
-
}
|
|
4986
|
-
function isClaudeOpus5FamilyModel(model) {
|
|
4987
|
-
return isClaudeOpus5Model(model) || isClaudeOpus55Model(model);
|
|
4988
|
-
}
|
|
4989
|
-
function isOpenAIReasoningSignature(value) {
|
|
4990
|
-
if (typeof value !== "string")
|
|
4991
|
-
return false;
|
|
4992
|
-
if (value.startsWith("gAAAA"))
|
|
4993
|
-
return true;
|
|
4994
|
-
if (!value.startsWith("{"))
|
|
4995
|
-
return false;
|
|
4996
|
-
try {
|
|
4997
|
-
const parsed = JSON.parse(value);
|
|
4998
|
-
return parsed.type === "reasoning" && typeof parsed.id === "string" && parsed.id.startsWith("rs_") && typeof parsed.encrypted_content === "string" && parsed.encrypted_content.startsWith("gAAAA");
|
|
4999
|
-
} catch {
|
|
5000
|
-
return false;
|
|
5001
|
-
}
|
|
5002
|
-
}
|
|
5003
|
-
|
|
5004
|
-
// src/mid-conversation-output-config.ts
|
|
5005
|
-
var PER_TURN_CONTROL_BETA = "per-turn-control-2026-07-01";
|
|
5006
|
-
function isRecord3(value) {
|
|
5007
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5008
|
-
}
|
|
5009
|
-
function normalizeAdaptiveEffort(value) {
|
|
5010
|
-
if (value === "minimal")
|
|
5011
|
-
return "low";
|
|
5012
|
-
if (value === "low" || value === "medium" || value === "high" || value === "xhigh" || value === "max") {
|
|
5013
|
-
return value;
|
|
5014
|
-
}
|
|
5015
|
-
return;
|
|
5016
|
-
}
|
|
5017
|
-
function usesPerTurnControl(model) {
|
|
5018
|
-
return isClaudeOpus55Model(model) || isClaudeSonnet55Model(model);
|
|
5019
|
-
}
|
|
5020
|
-
function sendsPerTurnControlBeta(model) {
|
|
5021
|
-
return usesPerTurnControl(model) || isClaudeFable51Model(model) || isClaudeHaiku55Model(model);
|
|
5022
|
-
}
|
|
5023
|
-
function supportsPerMessageEffort(body) {
|
|
5024
|
-
if (isClaudeFable51Model(body.model))
|
|
5025
|
-
return true;
|
|
5026
|
-
return usesPerTurnControl(body.model) && isRecord3(body.thinking) && body.thinking.type === "adaptive";
|
|
5027
|
-
}
|
|
5028
|
-
function defaultAdaptiveEffort(model) {
|
|
5029
|
-
return isClaudeOpus55Model(model) || isClaudeHaiku55Model(model) ? "medium" : "high";
|
|
5030
|
-
}
|
|
5031
|
-
function compactTransitions(transitions) {
|
|
5032
|
-
const compacted = [];
|
|
5033
|
-
for (const transition of transitions) {
|
|
5034
|
-
if (!Number.isSafeInteger(transition.afterAssistantMessages) || transition.afterAssistantMessages < 0 || !normalizeAdaptiveEffort(transition.effort)) {
|
|
5035
|
-
continue;
|
|
5036
|
-
}
|
|
5037
|
-
const normalized = {
|
|
5038
|
-
afterAssistantMessages: transition.afterAssistantMessages,
|
|
5039
|
-
effort: transition.effort
|
|
5040
|
-
};
|
|
5041
|
-
const previous = compacted.at(-1);
|
|
5042
|
-
if (previous && previous.afterAssistantMessages === normalized.afterAssistantMessages) {
|
|
5043
|
-
previous.effort = normalized.effort;
|
|
5044
|
-
continue;
|
|
5045
|
-
}
|
|
5046
|
-
if (previous?.effort === normalized.effort)
|
|
5047
|
-
continue;
|
|
5048
|
-
compacted.push(normalized);
|
|
5049
|
-
}
|
|
5050
|
-
return compacted;
|
|
5051
|
-
}
|
|
5052
|
-
function applyMidConversationOutputConfig(body, transitions) {
|
|
5053
|
-
if (!supportsPerMessageEffort(body) || !Array.isArray(body.messages)) {
|
|
5054
|
-
return { applied: false, inserted: 0 };
|
|
5055
|
-
}
|
|
5056
|
-
const compacted = compactTransitions(transitions);
|
|
5057
|
-
const pinsEveryRequest = isClaudeFable51Model(body.model);
|
|
5058
|
-
if (!pinsEveryRequest && compacted.length < 2) {
|
|
5059
|
-
return { applied: false, inserted: 0 };
|
|
5060
|
-
}
|
|
5061
|
-
const currentOutputConfig = isRecord3(body.output_config) ? body.output_config : {};
|
|
5062
|
-
const baseline = compacted[0]?.effort ?? normalizeAdaptiveEffort(currentOutputConfig.effort) ?? defaultAdaptiveEffort(body.model);
|
|
5063
|
-
const pinnedOutputConfig = { ...currentOutputConfig, effort: baseline };
|
|
5064
|
-
if (pinsEveryRequest)
|
|
5065
|
-
body.output_config = pinnedOutputConfig;
|
|
5066
|
-
if (compacted.length < 2)
|
|
5067
|
-
return { applied: true, inserted: 0 };
|
|
5068
|
-
const messages = body.messages;
|
|
5069
|
-
const transitionsByBoundary = new Map;
|
|
5070
|
-
for (const transition of compacted.slice(1)) {
|
|
5071
|
-
transitionsByBoundary.set(transition.afterAssistantMessages, transition.effort);
|
|
5072
|
-
}
|
|
5073
|
-
let assistantMessages = 0;
|
|
5074
|
-
let activeEffort = baseline;
|
|
5075
|
-
let inserted = 0;
|
|
5076
|
-
const rewritten = [];
|
|
5077
|
-
for (const message of messages) {
|
|
5078
|
-
if (isRecord3(message) && message.role === "user" && transitionsByBoundary.has(assistantMessages)) {
|
|
5079
|
-
const effort = transitionsByBoundary.get(assistantMessages);
|
|
5080
|
-
if (effort && effort !== activeEffort) {
|
|
5081
|
-
rewritten.push({
|
|
5082
|
-
role: "system",
|
|
5083
|
-
content: [],
|
|
5084
|
-
output_config: { effort }
|
|
5085
|
-
});
|
|
5086
|
-
activeEffort = effort;
|
|
5087
|
-
inserted++;
|
|
5088
|
-
}
|
|
5089
|
-
}
|
|
5090
|
-
rewritten.push(message);
|
|
5091
|
-
if (isRecord3(message) && message.role === "assistant")
|
|
5092
|
-
assistantMessages++;
|
|
5093
|
-
}
|
|
5094
|
-
if (!pinsEveryRequest && inserted === 0) {
|
|
5095
|
-
return { applied: false, inserted: 0 };
|
|
5096
|
-
}
|
|
5097
|
-
body.output_config = pinnedOutputConfig;
|
|
5098
|
-
body.messages = rewritten;
|
|
5099
|
-
return { applied: true, inserted };
|
|
5100
|
-
}
|
|
5101
|
-
|
|
5102
|
-
// src/turn-end-note.ts
|
|
5103
|
-
var TURN_END_NOTE_BETA = "mid-conversation-system-clear-at-2026-08-21";
|
|
5104
|
-
var TURN_END_NOTE_MIN_VISIBLE_CHARACTERS = 350;
|
|
5105
|
-
var TURN_END_NOTE_CONTENT = "Your reply above has already reached the user. The tool call after it was housekeeping and changed nothing they need to know. Do not repeat, summarize or rewrite that reply. If no new work remains, end the turn without restating anything.";
|
|
5106
|
-
var DEFAULT_TOOLS = ["board", "ctx_reduce"];
|
|
5107
|
-
function isRecord4(value) {
|
|
5108
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
5109
|
-
}
|
|
5110
|
-
function supportsTurnEndNote(model) {
|
|
5111
|
-
return isClaudeFable51Model(model) || isClaudeHaiku55Model(model) || isClaudeOpus55Model(model) || isClaudeSonnet55Model(model);
|
|
5112
|
-
}
|
|
5113
|
-
function applyTurnEndNotes(body, options = {}) {
|
|
5114
|
-
if (!supportsTurnEndNote(body.model) || !Array.isArray(body.messages))
|
|
5257
|
+
}
|
|
5258
|
+
function stripBillingLineageFromBody(body) {
|
|
5259
|
+
if (!body || typeof body !== "object")
|
|
5115
5260
|
return 0;
|
|
5116
|
-
const
|
|
5117
|
-
if (!
|
|
5261
|
+
const system = body.system;
|
|
5262
|
+
if (!Array.isArray(system))
|
|
5118
5263
|
return 0;
|
|
5119
|
-
|
|
5120
|
-
const
|
|
5121
|
-
|
|
5122
|
-
for (let index = 0;index < messages.length; index++) {
|
|
5123
|
-
const results = messages[index];
|
|
5124
|
-
rewritten.push(results);
|
|
5125
|
-
let preceding = index - 1;
|
|
5126
|
-
while (preceding >= 0) {
|
|
5127
|
-
const control = messages[preceding];
|
|
5128
|
-
if (!isRecord4(control) || control.role !== "system" || !Array.isArray(control.content) || control.content.length !== 0 || !isRecord4(control.output_config))
|
|
5129
|
-
break;
|
|
5130
|
-
preceding--;
|
|
5131
|
-
}
|
|
5132
|
-
const assistant = messages[preceding];
|
|
5133
|
-
if (!isRecord4(assistant) || assistant.role !== "assistant" || !Array.isArray(assistant.content) || !isRecord4(results) || results.role !== "user" || !Array.isArray(results.content))
|
|
5134
|
-
continue;
|
|
5135
|
-
const visible = options.visibleText ? options.visibleText(assistant) : assistant.content.filter((block) => isRecord4(block) && block.type === "text" && typeof block.text === "string" && block.text.trim().length > 0).map((block) => block.text).join("");
|
|
5136
|
-
if (visible.length < TURN_END_NOTE_MIN_VISIBLE_CHARACTERS)
|
|
5137
|
-
continue;
|
|
5138
|
-
const calls = assistant.content.filter((block) => isRecord4(block) && block.type === "tool_use");
|
|
5139
|
-
if (!calls.length || !calls.every((call) => allowed.has(call.name)))
|
|
5264
|
+
let stripped = 0;
|
|
5265
|
+
for (const block of system) {
|
|
5266
|
+
if (!block || typeof block !== "object")
|
|
5140
5267
|
continue;
|
|
5141
|
-
const
|
|
5142
|
-
if (
|
|
5268
|
+
const text = block.text;
|
|
5269
|
+
if (typeof text !== "string" || !text.startsWith("x-anthropic-billing-header:")) {
|
|
5143
5270
|
continue;
|
|
5144
|
-
|
|
5145
|
-
|
|
5271
|
+
}
|
|
5272
|
+
const clean = stripBillingLineageFields(text);
|
|
5273
|
+
if (clean === text)
|
|
5146
5274
|
continue;
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
clear_at: "next_user_message",
|
|
5150
|
-
content: TURN_END_NOTE_CONTENT
|
|
5151
|
-
});
|
|
5152
|
-
inserted++;
|
|
5275
|
+
block.text = clean;
|
|
5276
|
+
stripped += 1;
|
|
5153
5277
|
}
|
|
5154
|
-
|
|
5155
|
-
body.messages = rewritten;
|
|
5156
|
-
return inserted;
|
|
5278
|
+
return stripped;
|
|
5157
5279
|
}
|
|
5158
5280
|
|
|
5159
5281
|
// src/claude-code.ts
|
|
5282
|
+
import { randomBytes as randomBytes2, randomUUID as randomUUID7 } from "node:crypto";
|
|
5160
5283
|
var IDENTITY_CACHE_LIMIT = 1000;
|
|
5161
5284
|
var identityCache = new Map;
|
|
5162
5285
|
function setBounded(map, key, value, limit = IDENTITY_CACHE_LIMIT) {
|
|
@@ -5369,7 +5492,7 @@ async function resolveClaudeCodeAccountIdentity(accessToken, model, accountIdent
|
|
|
5369
5492
|
throw new ClaudeUnsupportedAccessError;
|
|
5370
5493
|
return resolveClaudeCodeIdentity(accessToken, model, accountIdentity);
|
|
5371
5494
|
}
|
|
5372
|
-
function
|
|
5495
|
+
function isRecord3(value) {
|
|
5373
5496
|
return value != null && typeof value === "object" && !Array.isArray(value);
|
|
5374
5497
|
}
|
|
5375
5498
|
function buildClaudeCodeMetadataUserId(identity) {
|
|
@@ -5384,55 +5507,17 @@ function buildClaudeCodeMetadataUserId(identity) {
|
|
|
5384
5507
|
function applyClaudeCodeMetadata(body, identity) {
|
|
5385
5508
|
const userId = buildClaudeCodeMetadataUserId(identity);
|
|
5386
5509
|
if (!userId) {
|
|
5387
|
-
if (
|
|
5510
|
+
if (isRecord3(body.metadata))
|
|
5388
5511
|
delete body.metadata.user_id;
|
|
5389
5512
|
return false;
|
|
5390
5513
|
}
|
|
5391
|
-
if (!
|
|
5514
|
+
if (!isRecord3(body.metadata))
|
|
5392
5515
|
body.metadata = {};
|
|
5393
5516
|
const metadata = body.metadata;
|
|
5394
|
-
if (
|
|
5517
|
+
if (isRecord3(metadata))
|
|
5395
5518
|
metadata.user_id = userId;
|
|
5396
5519
|
return true;
|
|
5397
5520
|
}
|
|
5398
|
-
var CLAUDE_CODE_FULL_AGENT_BETAS = [
|
|
5399
|
-
"claude-code-20250219",
|
|
5400
|
-
"oauth-2025-04-20",
|
|
5401
|
-
"interleaved-thinking-2025-05-14",
|
|
5402
|
-
"thinking-token-count-2026-05-13",
|
|
5403
|
-
"context-management-2025-06-27",
|
|
5404
|
-
"prompt-caching-scope-2026-01-05",
|
|
5405
|
-
"mid-conversation-tool-changes-2026-07-01",
|
|
5406
|
-
"advanced-tool-use-2025-11-20",
|
|
5407
|
-
TURN_END_NOTE_BETA,
|
|
5408
|
-
"effort-2025-11-24",
|
|
5409
|
-
"thinking-binding-controls-2026-08-01",
|
|
5410
|
-
"thinking-display-updates-2026-08-18",
|
|
5411
|
-
"extended-cache-ttl-2025-04-11",
|
|
5412
|
-
"cache-diagnosis-2026-04-07"
|
|
5413
|
-
];
|
|
5414
|
-
var CLAUDE_CODE_TITLE_BETAS = [
|
|
5415
|
-
"oauth-2025-04-20",
|
|
5416
|
-
"interleaved-thinking-2025-05-14",
|
|
5417
|
-
"redact-thinking-2026-02-12",
|
|
5418
|
-
"thinking-token-count-2026-05-13",
|
|
5419
|
-
"context-management-2025-06-27",
|
|
5420
|
-
"prompt-caching-scope-2026-01-05",
|
|
5421
|
-
"mid-conversation-tool-changes-2026-07-01",
|
|
5422
|
-
"mid-conversation-system-clear-at-2026-08-21",
|
|
5423
|
-
"effort-2025-11-24",
|
|
5424
|
-
"cache-diagnosis-2026-04-07"
|
|
5425
|
-
];
|
|
5426
|
-
var CLAUDE_CODE_QUOTA_BETAS = [
|
|
5427
|
-
"oauth-2025-04-20",
|
|
5428
|
-
"interleaved-thinking-2025-05-14",
|
|
5429
|
-
"redact-thinking-2026-02-12",
|
|
5430
|
-
"thinking-token-count-2026-05-13",
|
|
5431
|
-
"context-management-2025-06-27",
|
|
5432
|
-
"prompt-caching-scope-2026-01-05"
|
|
5433
|
-
];
|
|
5434
|
-
var CLAUDE_CODE_BETA = "claude-code-20250219";
|
|
5435
|
-
var PROMPT_CACHING_SCOPE_BETA = "prompt-caching-scope-2026-01-05";
|
|
5436
5521
|
function hasStructuredOutput(body) {
|
|
5437
5522
|
const outputConfig = body.output_config;
|
|
5438
5523
|
const format = outputConfig?.format;
|
|
@@ -5442,25 +5527,10 @@ function isQuotaProbe(body) {
|
|
|
5442
5527
|
return body.max_tokens === 1 && !body.stream && !body.thinking && (!Array.isArray(body.tools) || body.tools.length === 0) && !hasStructuredOutput(body);
|
|
5443
5528
|
}
|
|
5444
5529
|
function selectClaudeCodeBetas(body, extraBetas = [], requestClass = "main") {
|
|
5445
|
-
const
|
|
5446
|
-
|
|
5530
|
+
const lists = body && resolveClaudeModelCapabilities(body.model)?.claudeCodeBetas || CLAUDE_CODE_DEFAULT_BETAS;
|
|
5531
|
+
const selected = requestClass === "main" ? [...lists.main] : body && isQuotaProbe(body) ? [...lists.quota] : [...lists.title];
|
|
5532
|
+
if (Array.isArray(body?.messages) && body.messages.some((message) => isRecord3(message) && message.clear_at === "next_user_message") && !selected.includes(TURN_END_NOTE_BETA))
|
|
5447
5533
|
selected.push(TURN_END_NOTE_BETA);
|
|
5448
|
-
if (body && isClaudeHaiku55Model(body.model)) {
|
|
5449
|
-
const codeIndex = selected.indexOf(CLAUDE_CODE_BETA);
|
|
5450
|
-
if (codeIndex >= 0) {
|
|
5451
|
-
selected.splice(codeIndex, 1);
|
|
5452
|
-
selected.splice(selected.indexOf(PROMPT_CACHING_SCOPE_BETA) + 1, 0, CLAUDE_CODE_BETA);
|
|
5453
|
-
}
|
|
5454
|
-
}
|
|
5455
|
-
if (body && sendsPerTurnControlBeta(body.model)) {
|
|
5456
|
-
let index = selected.indexOf(PROMPT_CACHING_SCOPE_BETA);
|
|
5457
|
-
if (index >= 0 && selected[index + 1] === CLAUDE_CODE_BETA)
|
|
5458
|
-
index += 1;
|
|
5459
|
-
if (index >= 0)
|
|
5460
|
-
selected.splice(index + 1, 0, PER_TURN_CONTROL_BETA);
|
|
5461
|
-
else
|
|
5462
|
-
selected.push(PER_TURN_CONTROL_BETA);
|
|
5463
|
-
}
|
|
5464
5534
|
if (body && hasStructuredOutput(body)) {
|
|
5465
5535
|
const index = selected.indexOf("cache-diagnosis-2026-04-07");
|
|
5466
5536
|
selected.splice(index < 0 ? selected.length : index, 0, "structured-outputs-2025-12-15");
|
|
@@ -5574,8 +5644,8 @@ import {
|
|
|
5574
5644
|
unlink as unlink4,
|
|
5575
5645
|
writeFile as writeFile2
|
|
5576
5646
|
} from "node:fs/promises";
|
|
5577
|
-
import { tmpdir as
|
|
5578
|
-
import { join as
|
|
5647
|
+
import { tmpdir as tmpdir5 } from "node:os";
|
|
5648
|
+
import { join as join9, resolve as resolve3 } from "node:path";
|
|
5579
5649
|
|
|
5580
5650
|
// src/json.ts
|
|
5581
5651
|
function parseJsonRedacted(text) {
|
|
@@ -5846,7 +5916,7 @@ var DUMP_USAGE_TITLE = "## Claude Dump Usage";
|
|
|
5846
5916
|
var DUMP_USAGE = "Usage: `/claude-dump`, `/claude-dump on`, or `/claude-dump off`.";
|
|
5847
5917
|
var DUMP_DIR_ENV = "OPENCODE_ANTHROPIC_AUTH_DUMP_DIR";
|
|
5848
5918
|
var DUMP_MAX_BYTES_ENV = "OPENCODE_ANTHROPIC_AUTH_DUMP_MAX_BYTES";
|
|
5849
|
-
var DEFAULT_DUMP_DIR =
|
|
5919
|
+
var DEFAULT_DUMP_DIR = join9(tmpdir5(), "opencode-anthropic-auth-dumps");
|
|
5850
5920
|
var DEFAULT_DUMP_MAX_BYTES = 512 * 1024 * 1024;
|
|
5851
5921
|
var DUMP_SWEEP_INTERVAL_MS = 5 * 60 * 1000;
|
|
5852
5922
|
var DUMP_SWEEP_NEWNESS_FLOOR_MS = 60 * 1000;
|
|
@@ -5949,7 +6019,7 @@ async function sweepDumpDirectory(options) {
|
|
|
5949
6019
|
const partial = isDumpPartialFileName(entry.name);
|
|
5950
6020
|
if (!partial && !isDumpArtifactFileName(entry.name))
|
|
5951
6021
|
return;
|
|
5952
|
-
const path2 =
|
|
6022
|
+
const path2 = join9(dumpDir, entry.name);
|
|
5953
6023
|
try {
|
|
5954
6024
|
const stats = await lstat2(path2);
|
|
5955
6025
|
if (!stats.isFile() || stats.isSymbolicLink())
|
|
@@ -6154,7 +6224,7 @@ async function loadLatestDumpBody(input) {
|
|
|
6154
6224
|
const candidates = names.map((name) => ({ name, tag: dumpBodyTagForAffinity(name, affinity) })).filter((candidate) => candidate.tag !== undefined).sort((a, b) => b.name.localeCompare(a.name));
|
|
6155
6225
|
for (const candidate of candidates) {
|
|
6156
6226
|
try {
|
|
6157
|
-
const path2 =
|
|
6227
|
+
const path2 = join9(dumpDir, candidate.name);
|
|
6158
6228
|
const metadataPath = path2.replace(/\.body\.json$/, ".meta.json");
|
|
6159
6229
|
if (!(await lstat2(path2)).isFile())
|
|
6160
6230
|
continue;
|
|
@@ -6281,7 +6351,7 @@ async function dumpRequest(input) {
|
|
|
6281
6351
|
const tagSegment = dumpTagSegment(input.tag);
|
|
6282
6352
|
const id = `${new Date().toISOString().replace(/[:.]/g, "-")}-${String(nextDumpId).padStart(6, "0")}-${dumpFileSessionSegment(affinity, 80 - tagSegment.length)}${tagSegment}-${dumpRequestSegment(input)}`;
|
|
6283
6353
|
const dumpDir = getDumpDirectory();
|
|
6284
|
-
const prefix =
|
|
6354
|
+
const prefix = join9(dumpDir, id);
|
|
6285
6355
|
const files = {
|
|
6286
6356
|
body: `${prefix}.body.json`,
|
|
6287
6357
|
metadata: `${prefix}.meta.json`,
|
|
@@ -8491,8 +8561,8 @@ import {
|
|
|
8491
8561
|
rm as rm5,
|
|
8492
8562
|
writeFile as writeFile3
|
|
8493
8563
|
} from "node:fs/promises";
|
|
8494
|
-
import { tmpdir as
|
|
8495
|
-
import { join as
|
|
8564
|
+
import { tmpdir as tmpdir6 } from "node:os";
|
|
8565
|
+
import { join as join10 } from "node:path";
|
|
8496
8566
|
var CACHE_KEEP_REGISTRY_LEASE_MS = 3 * 60000;
|
|
8497
8567
|
function normalizeSession(value) {
|
|
8498
8568
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
@@ -8527,7 +8597,7 @@ function isExpiredRecord(record, now, leaseMs) {
|
|
|
8527
8597
|
return record.updatedAt <= now && now - record.updatedAt > leaseMs;
|
|
8528
8598
|
}
|
|
8529
8599
|
function getDefaultCacheKeepRegistryDirectory(scope) {
|
|
8530
|
-
return
|
|
8600
|
+
return join10(tmpdir6(), "opencode-anthropic-auth", "cachekeep-sessions", scope);
|
|
8531
8601
|
}
|
|
8532
8602
|
|
|
8533
8603
|
class CacheKeepSessionRegistry {
|
|
@@ -8538,7 +8608,7 @@ class CacheKeepSessionRegistry {
|
|
|
8538
8608
|
constructor(options) {
|
|
8539
8609
|
this.options = options;
|
|
8540
8610
|
const instanceId = options.instanceId ?? `${process.pid}-${randomUUID8()}`;
|
|
8541
|
-
this.filePath =
|
|
8611
|
+
this.filePath = join10(options.directory, `${instanceId}.json`);
|
|
8542
8612
|
}
|
|
8543
8613
|
publish(sessions) {
|
|
8544
8614
|
const snapshot = sessions.map((session) => ({ ...session }));
|
|
@@ -8578,7 +8648,7 @@ class CacheKeepSessionRegistry {
|
|
|
8578
8648
|
}
|
|
8579
8649
|
const records = await Promise.all(names.map(async (name) => {
|
|
8580
8650
|
try {
|
|
8581
|
-
const raw = await readFile7(
|
|
8651
|
+
const raw = await readFile7(join10(this.options.directory, name), "utf8");
|
|
8582
8652
|
return normalizeRecord(JSON.parse(raw));
|
|
8583
8653
|
} catch {
|
|
8584
8654
|
return;
|
|
@@ -8620,7 +8690,7 @@ class CacheKeepSessionRegistry {
|
|
|
8620
8690
|
return;
|
|
8621
8691
|
}
|
|
8622
8692
|
await Promise.all(names.map(async (name) => {
|
|
8623
|
-
const recordPath =
|
|
8693
|
+
const recordPath = join10(this.options.directory, name);
|
|
8624
8694
|
if (recordPath === this.filePath)
|
|
8625
8695
|
return;
|
|
8626
8696
|
let initialRecord;
|
|
@@ -8701,7 +8771,7 @@ import {
|
|
|
8701
8771
|
dirname as dirname8,
|
|
8702
8772
|
extname as extname2,
|
|
8703
8773
|
isAbsolute as isAbsolute2,
|
|
8704
|
-
join as
|
|
8774
|
+
join as join11,
|
|
8705
8775
|
resolve as resolve4
|
|
8706
8776
|
} from "node:path";
|
|
8707
8777
|
import {
|
|
@@ -8855,16 +8925,16 @@ function getClaustrumEnrollmentPaths2(tokenPath) {
|
|
|
8855
8925
|
const extension = extname2(tokenPath) || ".json";
|
|
8856
8926
|
const stem = basename3(tokenPath, extname2(tokenPath));
|
|
8857
8927
|
return {
|
|
8858
|
-
statePath:
|
|
8928
|
+
statePath: join11(dirname8(tokenPath), `${stem}-state${extension}`),
|
|
8859
8929
|
tokenPath
|
|
8860
8930
|
};
|
|
8861
8931
|
}
|
|
8862
8932
|
function getHostClaustrumEnrollmentPaths(host, env = process.env, cwd = process.cwd()) {
|
|
8863
8933
|
const configured = env[`${host.toUpperCase()}_ANTHROPIC_AUTH_CLAUSTRUM_ENROLLMENT_FILE`]?.trim();
|
|
8864
|
-
const tokenPath = configured ? isAbsolute2(configured) ? configured : resolve4(cwd, configured) :
|
|
8934
|
+
const tokenPath = configured ? isAbsolute2(configured) ? configured : resolve4(cwd, configured) : join11(env.XDG_STATE_HOME || join11(homedir3(), ".local", "state"), "cortexkit", "anthropic-auth", `${host}-enrollment.json`);
|
|
8865
8935
|
return getClaustrumEnrollmentPaths2(tokenPath);
|
|
8866
8936
|
}
|
|
8867
|
-
function
|
|
8937
|
+
function isRecord4(value) {
|
|
8868
8938
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8869
8939
|
}
|
|
8870
8940
|
function validTimestamp2(value) {
|
|
@@ -8874,7 +8944,7 @@ function validGeneration2(value) {
|
|
|
8874
8944
|
return typeof value === "number" && Number.isSafeInteger(value) && value >= 1;
|
|
8875
8945
|
}
|
|
8876
8946
|
function decodeEnrollmentState2(value) {
|
|
8877
|
-
if (!
|
|
8947
|
+
if (!isRecord4(value) || value.version !== ENROLLMENT_SCHEMA2 || typeof value.proposedName !== "string" || value.proposedName.length === 0) {
|
|
8878
8948
|
throw new Error("invalid Claustrum enrollment state");
|
|
8879
8949
|
}
|
|
8880
8950
|
if (value.phase === "pending") {
|
|
@@ -8925,7 +8995,7 @@ function decodeEnrollmentState2(value) {
|
|
|
8925
8995
|
throw new Error("invalid Claustrum enrollment state");
|
|
8926
8996
|
}
|
|
8927
8997
|
function decodeTokenFile2(value) {
|
|
8928
|
-
if (!
|
|
8998
|
+
if (!isRecord4(value) || !TOKEN_RE2.test(String(value.token ?? "")) || !validGeneration2(value.token_generation)) {
|
|
8929
8999
|
throw new Error("invalid Claustrum enrollment token file");
|
|
8930
9000
|
}
|
|
8931
9001
|
return {
|
|
@@ -9006,7 +9076,7 @@ async function writeStateAtomic2(path2, state, beforeRename) {
|
|
|
9006
9076
|
if (Buffer.byteLength(bytes) > ENROLLMENT_FILE_MAX_BYTES2) {
|
|
9007
9077
|
throw new Error("Claustrum enrollment state is too large");
|
|
9008
9078
|
}
|
|
9009
|
-
const temporary =
|
|
9079
|
+
const temporary = join11(parent, `.${basename3(path2)}.${process.pid}.${randomUUID9()}.tmp`);
|
|
9010
9080
|
let descriptor;
|
|
9011
9081
|
try {
|
|
9012
9082
|
const nativeCreated = await createWindowsOwnerOnly(temporary, bytes);
|
|
@@ -9025,7 +9095,7 @@ async function writeStateAtomic2(path2, state, beforeRename) {
|
|
|
9025
9095
|
}
|
|
9026
9096
|
}
|
|
9027
9097
|
async function writeTokenAtomic(path2, value, writeTokenFile, beforeRename) {
|
|
9028
|
-
const staged =
|
|
9098
|
+
const staged = join11(dirname8(path2), `.${basename3(path2)}.${process.pid}.${randomUUID9()}.tmp`);
|
|
9029
9099
|
try {
|
|
9030
9100
|
await writeTokenFile(staged, value);
|
|
9031
9101
|
await beforeRename();
|
|
@@ -9487,7 +9557,9 @@ function formatEnrollmentStatus(status, scopedServing = false) {
|
|
|
9487
9557
|
case "busy":
|
|
9488
9558
|
return ["- Enrollment: setup is busy"];
|
|
9489
9559
|
case "unavailable":
|
|
9490
|
-
return [
|
|
9560
|
+
return [
|
|
9561
|
+
"- Enrollment: this Claustrum vault does not support connecting plugins"
|
|
9562
|
+
];
|
|
9491
9563
|
case "pending":
|
|
9492
9564
|
return status.requestId && /^[A-Za-z0-9_-]{1,128}$/.test(status.requestId) ? [`- Enrollment: pending approval (${status.requestId})`, setup] : [
|
|
9493
9565
|
status.requestId ? "- Enrollment: pending approval" : "- Enrollment: request not sent",
|
|
@@ -10069,6 +10141,102 @@ function executeLoggingCommand(input) {
|
|
|
10069
10141
|
].join(`
|
|
10070
10142
|
`);
|
|
10071
10143
|
}
|
|
10144
|
+
// src/mid-conversation-output-config.ts
|
|
10145
|
+
function isRecord5(value) {
|
|
10146
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
10147
|
+
}
|
|
10148
|
+
function normalizeAdaptiveEffort(value) {
|
|
10149
|
+
if (value === "minimal")
|
|
10150
|
+
return "low";
|
|
10151
|
+
if (value === "low" || value === "medium" || value === "high" || value === "xhigh" || value === "max") {
|
|
10152
|
+
return value;
|
|
10153
|
+
}
|
|
10154
|
+
return;
|
|
10155
|
+
}
|
|
10156
|
+
function usesPerTurnControl(model) {
|
|
10157
|
+
return resolveClaudeModelCapabilities(model)?.effortMarkers === "with-adaptive-thinking";
|
|
10158
|
+
}
|
|
10159
|
+
function sendsPerTurnControlBeta(model) {
|
|
10160
|
+
return resolveClaudeModelCapabilities(model)?.claudeCodeBetas.main.includes(PER_TURN_CONTROL_BETA) ?? false;
|
|
10161
|
+
}
|
|
10162
|
+
function supportsPerMessageEffort(body) {
|
|
10163
|
+
if (pinsEffortOnEveryRequest(body.model))
|
|
10164
|
+
return true;
|
|
10165
|
+
return usesPerTurnControl(body.model) && isRecord5(body.thinking) && body.thinking.type === "adaptive";
|
|
10166
|
+
}
|
|
10167
|
+
function defaultAdaptiveEffort(model) {
|
|
10168
|
+
return resolveClaudeModelCapabilities(model)?.efforts.default ?? "high";
|
|
10169
|
+
}
|
|
10170
|
+
function compactTransitions(transitions) {
|
|
10171
|
+
const compacted = [];
|
|
10172
|
+
for (const transition of transitions) {
|
|
10173
|
+
if (!Number.isSafeInteger(transition.afterAssistantMessages) || transition.afterAssistantMessages < 0 || !normalizeAdaptiveEffort(transition.effort)) {
|
|
10174
|
+
continue;
|
|
10175
|
+
}
|
|
10176
|
+
const normalized = {
|
|
10177
|
+
afterAssistantMessages: transition.afterAssistantMessages,
|
|
10178
|
+
effort: transition.effort
|
|
10179
|
+
};
|
|
10180
|
+
const previous = compacted.at(-1);
|
|
10181
|
+
if (previous && previous.afterAssistantMessages === normalized.afterAssistantMessages) {
|
|
10182
|
+
previous.effort = normalized.effort;
|
|
10183
|
+
continue;
|
|
10184
|
+
}
|
|
10185
|
+
if (previous?.effort === normalized.effort)
|
|
10186
|
+
continue;
|
|
10187
|
+
compacted.push(normalized);
|
|
10188
|
+
}
|
|
10189
|
+
return compacted;
|
|
10190
|
+
}
|
|
10191
|
+
function applyMidConversationOutputConfig(body, transitions) {
|
|
10192
|
+
if (!supportsPerMessageEffort(body) || !Array.isArray(body.messages)) {
|
|
10193
|
+
return { applied: false, inserted: 0 };
|
|
10194
|
+
}
|
|
10195
|
+
const compacted = compactTransitions(transitions);
|
|
10196
|
+
const pinsEveryRequest = pinsEffortOnEveryRequest(body.model);
|
|
10197
|
+
if (!pinsEveryRequest && compacted.length < 2) {
|
|
10198
|
+
return { applied: false, inserted: 0 };
|
|
10199
|
+
}
|
|
10200
|
+
const currentOutputConfig = isRecord5(body.output_config) ? body.output_config : {};
|
|
10201
|
+
const baseline = compacted[0]?.effort ?? normalizeAdaptiveEffort(currentOutputConfig.effort) ?? defaultAdaptiveEffort(body.model);
|
|
10202
|
+
const pinnedOutputConfig = { ...currentOutputConfig, effort: baseline };
|
|
10203
|
+
if (pinsEveryRequest)
|
|
10204
|
+
body.output_config = pinnedOutputConfig;
|
|
10205
|
+
if (compacted.length < 2)
|
|
10206
|
+
return { applied: true, inserted: 0 };
|
|
10207
|
+
const messages = body.messages;
|
|
10208
|
+
const transitionsByBoundary = new Map;
|
|
10209
|
+
for (const transition of compacted.slice(1)) {
|
|
10210
|
+
transitionsByBoundary.set(transition.afterAssistantMessages, transition.effort);
|
|
10211
|
+
}
|
|
10212
|
+
let assistantMessages = 0;
|
|
10213
|
+
let activeEffort = baseline;
|
|
10214
|
+
let inserted = 0;
|
|
10215
|
+
const rewritten = [];
|
|
10216
|
+
for (const message of messages) {
|
|
10217
|
+
if (isRecord5(message) && message.role === "user" && transitionsByBoundary.has(assistantMessages)) {
|
|
10218
|
+
const effort = transitionsByBoundary.get(assistantMessages);
|
|
10219
|
+
if (effort && effort !== activeEffort) {
|
|
10220
|
+
rewritten.push({
|
|
10221
|
+
role: "system",
|
|
10222
|
+
content: [],
|
|
10223
|
+
output_config: { effort }
|
|
10224
|
+
});
|
|
10225
|
+
activeEffort = effort;
|
|
10226
|
+
inserted++;
|
|
10227
|
+
}
|
|
10228
|
+
}
|
|
10229
|
+
rewritten.push(message);
|
|
10230
|
+
if (isRecord5(message) && message.role === "assistant")
|
|
10231
|
+
assistantMessages++;
|
|
10232
|
+
}
|
|
10233
|
+
if (!pinsEveryRequest && inserted === 0) {
|
|
10234
|
+
return { applied: false, inserted: 0 };
|
|
10235
|
+
}
|
|
10236
|
+
body.output_config = pinnedOutputConfig;
|
|
10237
|
+
body.messages = rewritten;
|
|
10238
|
+
return { applied: true, inserted };
|
|
10239
|
+
}
|
|
10072
10240
|
// src/model-remap.ts
|
|
10073
10241
|
function getEnv(name) {
|
|
10074
10242
|
const value = process.env[name]?.trim();
|
|
@@ -10116,6 +10284,130 @@ function remapRequestBodyModel(parsed) {
|
|
|
10116
10284
|
parsed.model = remapped;
|
|
10117
10285
|
return true;
|
|
10118
10286
|
}
|
|
10287
|
+
// src/models.ts
|
|
10288
|
+
var CLAUDE_FABLE_5_MODEL_ID = "claude-fable-5";
|
|
10289
|
+
var CLAUDE_MYTHOS_5_MODEL_ID = "claude-mythos-5";
|
|
10290
|
+
var CLAUDE_FABLE_5_1_MODEL_ID = "claude-fable-5-1";
|
|
10291
|
+
var CLAUDE_MYTHOS_5_1_MODEL_ID = "claude-mythos-5-1";
|
|
10292
|
+
var CLAUDE_HAIKU_4_5_MODEL_ID = "claude-haiku-4-5";
|
|
10293
|
+
var CLAUDE_HAIKU_4_5_PRICING = {
|
|
10294
|
+
input: 1,
|
|
10295
|
+
output: 5
|
|
10296
|
+
};
|
|
10297
|
+
var CLAUDE_FABLE_MYTHOS_5_1_MODEL_IDS = [
|
|
10298
|
+
CLAUDE_FABLE_5_1_MODEL_ID,
|
|
10299
|
+
CLAUDE_MYTHOS_5_1_MODEL_ID
|
|
10300
|
+
];
|
|
10301
|
+
var CLAUDE_FABLE_MYTHOS_5_MODEL_IDS = [
|
|
10302
|
+
CLAUDE_FABLE_5_MODEL_ID,
|
|
10303
|
+
CLAUDE_MYTHOS_5_MODEL_ID,
|
|
10304
|
+
...CLAUDE_FABLE_MYTHOS_5_1_MODEL_IDS
|
|
10305
|
+
];
|
|
10306
|
+
var CLAUDE_FABLE_MYTHOS_5_SUMMARIZED_THINKING = {
|
|
10307
|
+
type: "adaptive",
|
|
10308
|
+
display: "summarized"
|
|
10309
|
+
};
|
|
10310
|
+
var FABLE_5_CATALOGUE = getClaudeModelCatalogue(CLAUDE_FABLE_5_MODEL_ID);
|
|
10311
|
+
var FABLE_5_1_CATALOGUE = getClaudeModelCatalogue(CLAUDE_FABLE_5_1_MODEL_ID);
|
|
10312
|
+
var CLAUDE_FABLE_MYTHOS_5_PRICING = FABLE_5_CATALOGUE.pricing;
|
|
10313
|
+
var CLAUDE_FABLE_MYTHOS_5_1_PRICING = FABLE_5_1_CATALOGUE.pricing;
|
|
10314
|
+
var CLAUDE_FABLE_MYTHOS_5_CONTEXT_WINDOW = FABLE_5_CATALOGUE.contextWindow;
|
|
10315
|
+
var CLAUDE_FABLE_MYTHOS_5_MAX_OUTPUT_TOKENS = FABLE_5_CATALOGUE.maxOutputTokens;
|
|
10316
|
+
var CLAUDE_FABLE_MYTHOS_5_RELEASE_DATE = FABLE_5_CATALOGUE.releaseDate;
|
|
10317
|
+
var CLAUDE_FABLE_MYTHOS_5_1_RELEASE_DATE = FABLE_5_1_CATALOGUE.releaseDate;
|
|
10318
|
+
function isFableOrMythosRow(row) {
|
|
10319
|
+
return row?.family === "fable" || row?.family === "mythos";
|
|
10320
|
+
}
|
|
10321
|
+
var CLAUDE_FABLE_MYTHOS_5_MODEL_SPECS = Object.fromEntries(CLAUDE_FABLE_MYTHOS_5_MODEL_IDS.map((id) => {
|
|
10322
|
+
const row = getClaudeModelCapabilities(id);
|
|
10323
|
+
return [
|
|
10324
|
+
id,
|
|
10325
|
+
{ id, name: row.name, ...row.limited && { limited: true } }
|
|
10326
|
+
];
|
|
10327
|
+
}));
|
|
10328
|
+
var CLAUDE_FABLE_MYTHOS_5_1_MODEL_SPECS = {
|
|
10329
|
+
[CLAUDE_FABLE_5_1_MODEL_ID]: CLAUDE_FABLE_MYTHOS_5_MODEL_SPECS[CLAUDE_FABLE_5_1_MODEL_ID],
|
|
10330
|
+
[CLAUDE_MYTHOS_5_1_MODEL_ID]: CLAUDE_FABLE_MYTHOS_5_MODEL_SPECS[CLAUDE_MYTHOS_5_1_MODEL_ID]
|
|
10331
|
+
};
|
|
10332
|
+
function resolvedModelId(model) {
|
|
10333
|
+
return resolveClaudeModelCapabilities(model)?.id;
|
|
10334
|
+
}
|
|
10335
|
+
function isClaudeFableOrMythos5Model(model) {
|
|
10336
|
+
return isFableOrMythosRow(resolveClaudeModelCapabilities(model));
|
|
10337
|
+
}
|
|
10338
|
+
function isClaudeFableOrMythos51Model(model) {
|
|
10339
|
+
const id = resolvedModelId(model);
|
|
10340
|
+
return CLAUDE_FABLE_MYTHOS_5_1_MODEL_IDS.includes(id);
|
|
10341
|
+
}
|
|
10342
|
+
function isClaudeFable51Model(model) {
|
|
10343
|
+
return resolvedModelId(model) === CLAUDE_FABLE_5_1_MODEL_ID;
|
|
10344
|
+
}
|
|
10345
|
+
function getClaudeFableMythos5ReleaseDate(model) {
|
|
10346
|
+
return isClaudeFableOrMythos51Model(model) ? CLAUDE_FABLE_MYTHOS_5_1_RELEASE_DATE : CLAUDE_FABLE_MYTHOS_5_RELEASE_DATE;
|
|
10347
|
+
}
|
|
10348
|
+
var CLAUDE_SONNET_5_MODEL_ID = "claude-sonnet-5";
|
|
10349
|
+
var CLAUDE_SONNET_5_ADAPTIVE_THINKING = CLAUDE_FABLE_MYTHOS_5_SUMMARIZED_THINKING;
|
|
10350
|
+
function isClaudeSonnet5Model(model) {
|
|
10351
|
+
return resolvedModelId(model) === CLAUDE_SONNET_5_MODEL_ID;
|
|
10352
|
+
}
|
|
10353
|
+
var CLAUDE_SONNET_5_5_MODEL_ID = "claude-sonnet-5-5";
|
|
10354
|
+
var SONNET_5_5_CATALOGUE = getClaudeModelCatalogue(CLAUDE_SONNET_5_5_MODEL_ID);
|
|
10355
|
+
var CLAUDE_SONNET_5_5_RELEASE_DATE = SONNET_5_5_CATALOGUE.releaseDate;
|
|
10356
|
+
var CLAUDE_SONNET_5_5_CONTEXT_WINDOW = SONNET_5_5_CATALOGUE.contextWindow;
|
|
10357
|
+
var CLAUDE_SONNET_5_5_MAX_OUTPUT_TOKENS = SONNET_5_5_CATALOGUE.maxOutputTokens;
|
|
10358
|
+
var CLAUDE_SONNET_5_5_PRICING = SONNET_5_5_CATALOGUE.pricing;
|
|
10359
|
+
var CLAUDE_SONNET_5_5_ADAPTIVE_THINKING = CLAUDE_FABLE_MYTHOS_5_SUMMARIZED_THINKING;
|
|
10360
|
+
function isClaudeSonnet55Model(model) {
|
|
10361
|
+
return resolvedModelId(model) === CLAUDE_SONNET_5_5_MODEL_ID;
|
|
10362
|
+
}
|
|
10363
|
+
var CLAUDE_HAIKU_5_5_MODEL_ID = "claude-haiku-5-5";
|
|
10364
|
+
var HAIKU_5_5_CATALOGUE = getClaudeModelCatalogue(CLAUDE_HAIKU_5_5_MODEL_ID);
|
|
10365
|
+
var HAIKU_5_5_LONG_CONTEXT = HAIKU_5_5_CATALOGUE.longContext;
|
|
10366
|
+
if (!HAIKU_5_5_LONG_CONTEXT) {
|
|
10367
|
+
throw new Error("Haiku 5.5 capability row lacks long-context pricing");
|
|
10368
|
+
}
|
|
10369
|
+
var CLAUDE_HAIKU_5_5_RELEASE_DATE = HAIKU_5_5_CATALOGUE.releaseDate;
|
|
10370
|
+
var CLAUDE_HAIKU_5_5_CONTEXT_WINDOW = HAIKU_5_5_CATALOGUE.contextWindow;
|
|
10371
|
+
var CLAUDE_HAIKU_5_5_MAX_OUTPUT_TOKENS = HAIKU_5_5_CATALOGUE.maxOutputTokens;
|
|
10372
|
+
var CLAUDE_HAIKU_5_5_LONG_CONTEXT_THRESHOLD = HAIKU_5_5_LONG_CONTEXT.inputTokensAbove;
|
|
10373
|
+
var CLAUDE_HAIKU_5_5_PRICING = HAIKU_5_5_CATALOGUE.pricing;
|
|
10374
|
+
var CLAUDE_HAIKU_5_5_LONG_CONTEXT_PRICING = HAIKU_5_5_LONG_CONTEXT.pricing;
|
|
10375
|
+
var CLAUDE_HAIKU_5_5_ADAPTIVE_THINKING = CLAUDE_FABLE_MYTHOS_5_SUMMARIZED_THINKING;
|
|
10376
|
+
function isClaudeHaiku55Model(model) {
|
|
10377
|
+
return resolvedModelId(model) === CLAUDE_HAIKU_5_5_MODEL_ID;
|
|
10378
|
+
}
|
|
10379
|
+
var CLAUDE_OPUS_5_MODEL_ID = "claude-opus-5";
|
|
10380
|
+
var CLAUDE_OPUS_5_ADAPTIVE_THINKING = CLAUDE_FABLE_MYTHOS_5_SUMMARIZED_THINKING;
|
|
10381
|
+
function isClaudeOpus5Model(model) {
|
|
10382
|
+
return resolvedModelId(model) === CLAUDE_OPUS_5_MODEL_ID;
|
|
10383
|
+
}
|
|
10384
|
+
var CLAUDE_OPUS_5_5_MODEL_ID = "claude-opus-5-5";
|
|
10385
|
+
var OPUS_5_5_CATALOGUE = getClaudeModelCatalogue(CLAUDE_OPUS_5_5_MODEL_ID);
|
|
10386
|
+
var CLAUDE_OPUS_5_5_RELEASE_DATE = OPUS_5_5_CATALOGUE.releaseDate;
|
|
10387
|
+
var CLAUDE_OPUS_5_5_CONTEXT_WINDOW = OPUS_5_5_CATALOGUE.contextWindow;
|
|
10388
|
+
var CLAUDE_OPUS_5_5_MAX_OUTPUT_TOKENS = OPUS_5_5_CATALOGUE.maxOutputTokens;
|
|
10389
|
+
var CLAUDE_OPUS_5_5_PRICING = OPUS_5_5_CATALOGUE.pricing;
|
|
10390
|
+
var CLAUDE_OPUS_5_5_ADAPTIVE_THINKING = CLAUDE_FABLE_MYTHOS_5_SUMMARIZED_THINKING;
|
|
10391
|
+
function isClaudeOpus55Model(model) {
|
|
10392
|
+
return resolvedModelId(model) === CLAUDE_OPUS_5_5_MODEL_ID;
|
|
10393
|
+
}
|
|
10394
|
+
function isClaudeOpus5FamilyModel(model) {
|
|
10395
|
+
return isClaudeOpus5Model(model) || isClaudeOpus55Model(model);
|
|
10396
|
+
}
|
|
10397
|
+
function isOpenAIReasoningSignature(value) {
|
|
10398
|
+
if (typeof value !== "string")
|
|
10399
|
+
return false;
|
|
10400
|
+
if (value.startsWith("gAAAA"))
|
|
10401
|
+
return true;
|
|
10402
|
+
if (!value.startsWith("{"))
|
|
10403
|
+
return false;
|
|
10404
|
+
try {
|
|
10405
|
+
const parsed = JSON.parse(value);
|
|
10406
|
+
return parsed.type === "reasoning" && typeof parsed.id === "string" && parsed.id.startsWith("rs_") && typeof parsed.encrypted_content === "string" && parsed.encrypted_content.startsWith("gAAAA");
|
|
10407
|
+
} catch {
|
|
10408
|
+
return false;
|
|
10409
|
+
}
|
|
10410
|
+
}
|
|
10119
10411
|
// src/native-account-runtime.ts
|
|
10120
10412
|
import { randomUUID as randomUUID15 } from "node:crypto";
|
|
10121
10413
|
|
|
@@ -10356,7 +10648,7 @@ function canonicalJson(value) {
|
|
|
10356
10648
|
const encode = (item) => {
|
|
10357
10649
|
if (Array.isArray(item))
|
|
10358
10650
|
return `[${item.map(encode).join(",")}]`;
|
|
10359
|
-
if (
|
|
10651
|
+
if (isRecord6(item))
|
|
10360
10652
|
return `{${Object.keys(item).sort().map((key) => `${JSON.stringify(key)}:${encode(item[key])}`).join(",")}}`;
|
|
10361
10653
|
return JSON.stringify(item);
|
|
10362
10654
|
};
|
|
@@ -10366,12 +10658,12 @@ function canonicalDigest(value) {
|
|
|
10366
10658
|
return createHash6("sha256").update(canonicalJson(value)).digest("hex");
|
|
10367
10659
|
}
|
|
10368
10660
|
function parseReservation(raw) {
|
|
10369
|
-
if (!
|
|
10661
|
+
if (!isRecord6(raw) || Object.keys(raw).length !== 1 || typeof raw.reservation !== "string" || !raw.reservation)
|
|
10370
10662
|
return;
|
|
10371
10663
|
return { reservation: raw.reservation };
|
|
10372
10664
|
}
|
|
10373
10665
|
function parseStagedStamp(raw) {
|
|
10374
|
-
if (!
|
|
10666
|
+
if (!isRecord6(raw) || typeof raw.reservation !== "string" || !raw.reservation || typeof raw.disabledReason !== "string")
|
|
10375
10667
|
return;
|
|
10376
10668
|
if (Object.keys(raw).some((key) => !["reservation", "label", "disabledReason", "providerState"].includes(key)))
|
|
10377
10669
|
return;
|
|
@@ -10382,7 +10674,7 @@ function parseStagedStamp(raw) {
|
|
|
10382
10674
|
return raw;
|
|
10383
10675
|
}
|
|
10384
10676
|
var PROVIDER_STATE_KEY = "commonAuthProviderState";
|
|
10385
|
-
function
|
|
10677
|
+
function isRecord6(value) {
|
|
10386
10678
|
return value != null && typeof value === "object" && !Array.isArray(value);
|
|
10387
10679
|
}
|
|
10388
10680
|
var UNSAFE_IDS = new Set(["__proto__", "constructor", "prototype"]);
|
|
@@ -10446,7 +10738,7 @@ function providerStateDigest(codec, value) {
|
|
|
10446
10738
|
function boundProviderStateDigest(account, credential, credentialEpoch, identity) {
|
|
10447
10739
|
if (!credential || credentialEpoch === undefined)
|
|
10448
10740
|
return;
|
|
10449
|
-
if (!
|
|
10741
|
+
if (!isRecord6(account) || !Object.hasOwn(account, PROVIDER_STATE_KEY))
|
|
10450
10742
|
return;
|
|
10451
10743
|
const stamp = parseStamp(account[CREDENTIAL_STAMP_KEY]);
|
|
10452
10744
|
if (!stamp || stamp.providerState === undefined || stamp.digest !== credentialDigest(credential) || stamp.credentialEpoch !== credentialEpoch || stamp.binding?.identity !== identity)
|
|
@@ -10457,7 +10749,7 @@ function isCredentialEpoch(value) {
|
|
|
10457
10749
|
return Number.isSafeInteger(value) && value >= 1;
|
|
10458
10750
|
}
|
|
10459
10751
|
function parseStamp(raw) {
|
|
10460
|
-
if (!
|
|
10752
|
+
if (!isRecord6(raw))
|
|
10461
10753
|
return;
|
|
10462
10754
|
const epoch = raw.credentialEpoch;
|
|
10463
10755
|
if (!isCredentialEpoch(epoch))
|
|
@@ -10482,7 +10774,7 @@ function parseStamp(raw) {
|
|
|
10482
10774
|
if (!("binding" in raw))
|
|
10483
10775
|
return "dispatch" in raw || "replace" in raw || "providerState" in raw || "staged" in raw ? undefined : { credentialEpoch: epoch, digest: raw.digest };
|
|
10484
10776
|
const binding = raw.binding;
|
|
10485
|
-
if (!
|
|
10777
|
+
if (!isRecord6(binding))
|
|
10486
10778
|
return;
|
|
10487
10779
|
if ("identity" in binding && (typeof binding.identity !== "string" || !binding.identity))
|
|
10488
10780
|
return;
|
|
@@ -10513,7 +10805,7 @@ function bindingAgrees(binding, credential, identity) {
|
|
|
10513
10805
|
function stampStatusOf(credential, credentialEpoch, identity, account) {
|
|
10514
10806
|
if (!credential)
|
|
10515
10807
|
return "none";
|
|
10516
|
-
if (!
|
|
10808
|
+
if (!isRecord6(account) || !Object.hasOwn(account, CREDENTIAL_STAMP_KEY))
|
|
10517
10809
|
return "missing";
|
|
10518
10810
|
const stamp = parseStamp(account[CREDENTIAL_STAMP_KEY]);
|
|
10519
10811
|
if (!stamp)
|
|
@@ -10536,7 +10828,7 @@ function classifyConfig(read) {
|
|
|
10536
10828
|
if ("parseError" in read)
|
|
10537
10829
|
return { status: "error", reason: "config file is not valid JSON" };
|
|
10538
10830
|
const value = read.value;
|
|
10539
|
-
if (!
|
|
10831
|
+
if (!isRecord6(value))
|
|
10540
10832
|
return { status: "error", reason: "config root is not an object" };
|
|
10541
10833
|
if ("accounts" in value && !Array.isArray(value.accounts))
|
|
10542
10834
|
return { status: "error", reason: "config accounts is not an array" };
|
|
@@ -10544,7 +10836,7 @@ function classifyConfig(read) {
|
|
|
10544
10836
|
return Array.isArray(value.accounts) ? { status: "pending-migration", config: value } : { status: "ready", exists: true, config: value };
|
|
10545
10837
|
}
|
|
10546
10838
|
const pool = value[POOL_KEY];
|
|
10547
|
-
if (!
|
|
10839
|
+
if (!isRecord6(pool))
|
|
10548
10840
|
return { status: "error", reason: `${POOL_KEY} is not an object` };
|
|
10549
10841
|
const version = pool.schemaVersion;
|
|
10550
10842
|
if (typeof version !== "number" || !Number.isInteger(version) || version < 1)
|
|
@@ -10554,7 +10846,7 @@ function classifyConfig(read) {
|
|
|
10554
10846
|
status: "error",
|
|
10555
10847
|
reason: `${POOL_KEY}.schemaVersion ${version} is newer than ${POOL_SCHEMA_VERSION}`
|
|
10556
10848
|
};
|
|
10557
|
-
if (POOL_ROWS_KEY in pool && !
|
|
10849
|
+
if (POOL_ROWS_KEY in pool && !isRecord6(pool[POOL_ROWS_KEY]))
|
|
10558
10850
|
return {
|
|
10559
10851
|
status: "error",
|
|
10560
10852
|
reason: `${POOL_KEY}.${POOL_ROWS_KEY} is not an object`
|
|
@@ -10566,9 +10858,9 @@ function classifyState(read) {
|
|
|
10566
10858
|
return { status: "ready", exists: false, state: {} };
|
|
10567
10859
|
if ("parseError" in read)
|
|
10568
10860
|
return { status: "error", reason: "state file is not valid JSON" };
|
|
10569
|
-
if (!
|
|
10861
|
+
if (!isRecord6(read.value))
|
|
10570
10862
|
return { status: "error", reason: "state root is not an object" };
|
|
10571
|
-
if ("accounts" in read.value && !
|
|
10863
|
+
if ("accounts" in read.value && !isRecord6(read.value.accounts))
|
|
10572
10864
|
return { status: "error", reason: "state accounts is not an object" };
|
|
10573
10865
|
return { status: "ready", exists: true, state: read.value };
|
|
10574
10866
|
}
|
|
@@ -10577,16 +10869,16 @@ function rosterOf(config) {
|
|
|
10577
10869
|
}
|
|
10578
10870
|
function entriesOf(config) {
|
|
10579
10871
|
const pool = config[POOL_KEY];
|
|
10580
|
-
if (!
|
|
10872
|
+
if (!isRecord6(pool))
|
|
10581
10873
|
return {};
|
|
10582
10874
|
const rows = pool[POOL_ROWS_KEY];
|
|
10583
|
-
return
|
|
10875
|
+
return isRecord6(rows) ? rows : {};
|
|
10584
10876
|
}
|
|
10585
10877
|
function stateAccountsOf(state) {
|
|
10586
|
-
return
|
|
10878
|
+
return isRecord6(state.accounts) ? state.accounts : {};
|
|
10587
10879
|
}
|
|
10588
10880
|
function rosterRowProblem(raw) {
|
|
10589
|
-
if (!
|
|
10881
|
+
if (!isRecord6(raw))
|
|
10590
10882
|
return "not an object";
|
|
10591
10883
|
const problem = idProblem(raw.id);
|
|
10592
10884
|
if (problem)
|
|
@@ -10598,7 +10890,7 @@ function rosterRowProblem(raw) {
|
|
|
10598
10890
|
return "unknown type";
|
|
10599
10891
|
}
|
|
10600
10892
|
function parseEntry(raw, codec) {
|
|
10601
|
-
if (!
|
|
10893
|
+
if (!isRecord6(raw))
|
|
10602
10894
|
return;
|
|
10603
10895
|
const epoch = raw.credentialEpoch;
|
|
10604
10896
|
if (!isCredentialEpoch(epoch))
|
|
@@ -10620,7 +10912,7 @@ function parseEntry(raw, codec) {
|
|
|
10620
10912
|
};
|
|
10621
10913
|
}
|
|
10622
10914
|
function credentialFor(raw, stateEntry) {
|
|
10623
|
-
if (!
|
|
10915
|
+
if (!isRecord6(stateEntry))
|
|
10624
10916
|
return;
|
|
10625
10917
|
if (raw.type === "api") {
|
|
10626
10918
|
const apiKey = typeof stateEntry.apiKey === "string" ? stateEntry.apiKey.trim() : "";
|
|
@@ -10647,23 +10939,23 @@ function credentialFor(raw, stateEntry) {
|
|
|
10647
10939
|
};
|
|
10648
10940
|
}
|
|
10649
10941
|
function rosterRowIn(config, id) {
|
|
10650
|
-
return rosterOf(config).find((raw) =>
|
|
10942
|
+
return rosterOf(config).find((raw) => isRecord6(raw) && raw.id === id);
|
|
10651
10943
|
}
|
|
10652
10944
|
function ensurePool(config) {
|
|
10653
|
-
if (!
|
|
10945
|
+
if (!isRecord6(config[POOL_KEY]))
|
|
10654
10946
|
config[POOL_KEY] = {};
|
|
10655
10947
|
return config[POOL_KEY];
|
|
10656
10948
|
}
|
|
10657
10949
|
function ensureEntries(config) {
|
|
10658
10950
|
const pool = ensurePool(config);
|
|
10659
|
-
if (!
|
|
10951
|
+
if (!isRecord6(pool[POOL_ROWS_KEY]))
|
|
10660
10952
|
pool[POOL_ROWS_KEY] = {};
|
|
10661
10953
|
return pool[POOL_ROWS_KEY];
|
|
10662
10954
|
}
|
|
10663
10955
|
function entryIn(config, id) {
|
|
10664
10956
|
const entries = entriesOf(config);
|
|
10665
10957
|
const entry = Object.hasOwn(entries, id) ? entries[id] : undefined;
|
|
10666
|
-
return
|
|
10958
|
+
return isRecord6(entry) ? entry : undefined;
|
|
10667
10959
|
}
|
|
10668
10960
|
function setEntryIn(config, id, entry) {
|
|
10669
10961
|
Object.defineProperty(ensureEntries(config), id, {
|
|
@@ -10675,10 +10967,10 @@ function setEntryIn(config, id, entry) {
|
|
|
10675
10967
|
}
|
|
10676
10968
|
function retiredEpochIn(config, id) {
|
|
10677
10969
|
const pool = config[POOL_KEY];
|
|
10678
|
-
if (!
|
|
10970
|
+
if (!isRecord6(pool))
|
|
10679
10971
|
return;
|
|
10680
10972
|
const retired = pool[POOL_RETIRED_EPOCHS_KEY];
|
|
10681
|
-
if (!
|
|
10973
|
+
if (!isRecord6(retired) || !Object.hasOwn(retired, id))
|
|
10682
10974
|
return;
|
|
10683
10975
|
const epoch = retired[id];
|
|
10684
10976
|
return isCredentialEpoch(epoch) ? epoch : undefined;
|
|
@@ -10695,7 +10987,7 @@ function retireEpochsIn(config, dropped) {
|
|
|
10695
10987
|
if (ids.length === 0)
|
|
10696
10988
|
return;
|
|
10697
10989
|
const pool = ensurePool(config);
|
|
10698
|
-
const previous =
|
|
10990
|
+
const previous = isRecord6(pool[POOL_RETIRED_EPOCHS_KEY]) ? pool[POOL_RETIRED_EPOCHS_KEY] : {};
|
|
10699
10991
|
const next = {};
|
|
10700
10992
|
const define = (id, epoch) => Object.defineProperty(next, id, {
|
|
10701
10993
|
value: epoch,
|
|
@@ -10717,17 +11009,17 @@ function buildRawRows(config, state, codec, providerCodec) {
|
|
|
10717
11009
|
const rows = [];
|
|
10718
11010
|
for (const raw of rosterOf(config)) {
|
|
10719
11011
|
const problem = rosterRowProblem(raw);
|
|
10720
|
-
const id =
|
|
11012
|
+
const id = isRecord6(raw) && typeof raw.id === "string" ? raw.id : undefined;
|
|
10721
11013
|
const rawEntry = id === undefined ? undefined : entries[id];
|
|
10722
|
-
const reserved =
|
|
11014
|
+
const reserved = isRecord6(rawEntry) && Object.hasOwn(rawEntry, "staged");
|
|
10723
11015
|
const staged = reserved ? parseReservation(rawEntry.staged) : undefined;
|
|
10724
|
-
if (problem || !
|
|
11016
|
+
if (problem || !isRecord6(raw) || id === undefined || seen.has(id)) {
|
|
10725
11017
|
if (id !== undefined && !seen.has(id))
|
|
10726
11018
|
seen.add(id);
|
|
10727
11019
|
if (id !== undefined)
|
|
10728
11020
|
rows.push({
|
|
10729
11021
|
id,
|
|
10730
|
-
type:
|
|
11022
|
+
type: isRecord6(raw) && raw.type === "api" ? "api" : "oauth",
|
|
10731
11023
|
enabled: false,
|
|
10732
11024
|
needsFirstReading: true,
|
|
10733
11025
|
hasEntry: Object.hasOwn(entries, id),
|
|
@@ -10774,7 +11066,7 @@ function buildRawRows(config, state, codec, providerCodec) {
|
|
|
10774
11066
|
return rows;
|
|
10775
11067
|
}
|
|
10776
11068
|
function providerStateFields(account, credential, credentialEpoch, identity, codec) {
|
|
10777
|
-
if (!
|
|
11069
|
+
if (!isRecord6(account) || !Object.hasOwn(account, PROVIDER_STATE_KEY))
|
|
10778
11070
|
return {};
|
|
10779
11071
|
const digest = boundProviderStateDigest(account, credential, credentialEpoch, identity);
|
|
10780
11072
|
if (digest === undefined)
|
|
@@ -10834,7 +11126,7 @@ function storedCredential(credential, lastRefreshedAt) {
|
|
|
10834
11126
|
};
|
|
10835
11127
|
}
|
|
10836
11128
|
function credentialProblem(credential, options = {}) {
|
|
10837
|
-
if (!
|
|
11129
|
+
if (!isRecord6(credential))
|
|
10838
11130
|
return "credential must be an object";
|
|
10839
11131
|
if (credential.type === "oauth") {
|
|
10840
11132
|
if (typeof credential.refresh !== "string" || !credential.refresh.trim())
|
|
@@ -10858,10 +11150,10 @@ function credentialProblem(credential, options = {}) {
|
|
|
10858
11150
|
var TRANSITION_STAMP_KEY = "transition";
|
|
10859
11151
|
var TRANSITION_MARK_KEY = "transitionMark";
|
|
10860
11152
|
function stampedTransition(rawStamp) {
|
|
10861
|
-
if (!
|
|
11153
|
+
if (!isRecord6(rawStamp))
|
|
10862
11154
|
return;
|
|
10863
11155
|
const raw = rawStamp[TRANSITION_STAMP_KEY];
|
|
10864
|
-
if (!
|
|
11156
|
+
if (!isRecord6(raw))
|
|
10865
11157
|
return;
|
|
10866
11158
|
if (typeof raw.mark !== "string" || raw.mark.length === 0)
|
|
10867
11159
|
return;
|
|
@@ -10904,13 +11196,13 @@ function isReplaceStamp(stamp) {
|
|
|
10904
11196
|
return stamp.replace === true || stamp.dispatch === undefined;
|
|
10905
11197
|
}
|
|
10906
11198
|
function tornStamps(config, state, codec, options = {}) {
|
|
10907
|
-
const accounts =
|
|
11199
|
+
const accounts = isRecord6(state.accounts) ? state.accounts : {};
|
|
10908
11200
|
const torn = new Map;
|
|
10909
11201
|
for (const row of buildRawRows(config, state, codec)) {
|
|
10910
11202
|
if (row.invalid || row.staged || !row.credential)
|
|
10911
11203
|
continue;
|
|
10912
11204
|
const account = Object.hasOwn(accounts, row.id) ? accounts[row.id] : undefined;
|
|
10913
|
-
if (!
|
|
11205
|
+
if (!isRecord6(account))
|
|
10914
11206
|
continue;
|
|
10915
11207
|
const stamp = parseStamp(account[CREDENTIAL_STAMP_KEY]);
|
|
10916
11208
|
if (!stamp?.binding)
|
|
@@ -11115,7 +11407,7 @@ class Transaction {
|
|
|
11115
11407
|
return entry && Object.hasOwn(entry, "staged") ? entry.staged : undefined;
|
|
11116
11408
|
}
|
|
11117
11409
|
const stamp = this.stateAccount(id)?.[CREDENTIAL_STAMP_KEY];
|
|
11118
|
-
return
|
|
11410
|
+
return isRecord6(stamp) && Object.hasOwn(stamp, "staged") ? stamp.staged : undefined;
|
|
11119
11411
|
}
|
|
11120
11412
|
assertNotStaged(id) {
|
|
11121
11413
|
assertNotReserved(this.info.operation, id, this.reservation(id));
|
|
@@ -11131,7 +11423,7 @@ class Transaction {
|
|
|
11131
11423
|
}
|
|
11132
11424
|
dropRosterRows(id) {
|
|
11133
11425
|
const roster = this.roster();
|
|
11134
|
-
const kept = roster.filter((raw) => !(
|
|
11426
|
+
const kept = roster.filter((raw) => !(isRecord6(raw) && raw.id === id));
|
|
11135
11427
|
this.config.accounts = kept;
|
|
11136
11428
|
return roster.length - kept.length;
|
|
11137
11429
|
}
|
|
@@ -11153,16 +11445,16 @@ class Transaction {
|
|
|
11153
11445
|
await this.commitConfig({ counted: false });
|
|
11154
11446
|
}
|
|
11155
11447
|
stateAccount(id) {
|
|
11156
|
-
const accounts =
|
|
11448
|
+
const accounts = isRecord6(this.state.accounts) ? this.state.accounts : {};
|
|
11157
11449
|
const entry = Object.hasOwn(accounts, id) ? accounts[id] : undefined;
|
|
11158
|
-
return
|
|
11450
|
+
return isRecord6(entry) ? entry : undefined;
|
|
11159
11451
|
}
|
|
11160
11452
|
dropStateAccount(id) {
|
|
11161
|
-
if (
|
|
11453
|
+
if (isRecord6(this.state.accounts) && Object.hasOwn(this.state.accounts, id))
|
|
11162
11454
|
delete this.state.accounts[id];
|
|
11163
11455
|
}
|
|
11164
11456
|
setStateAccount(id, fields) {
|
|
11165
|
-
if (!
|
|
11457
|
+
if (!isRecord6(this.state.accounts))
|
|
11166
11458
|
this.state.accounts = {};
|
|
11167
11459
|
Object.defineProperty(this.state.accounts, id, {
|
|
11168
11460
|
value: fields,
|
|
@@ -11175,11 +11467,11 @@ class Transaction {
|
|
|
11175
11467
|
const roster = this.roster();
|
|
11176
11468
|
const rosterIds = new Set;
|
|
11177
11469
|
for (const raw of roster)
|
|
11178
|
-
if (
|
|
11470
|
+
if (isRecord6(raw) && typeof raw.id === "string")
|
|
11179
11471
|
rosterIds.add(raw.id);
|
|
11180
11472
|
const dropped = new Set;
|
|
11181
11473
|
for (const raw of rosterOf(this.snapshot.config))
|
|
11182
|
-
if (
|
|
11474
|
+
if (isRecord6(raw) && typeof raw.id === "string" && !rosterIds.has(raw.id))
|
|
11183
11475
|
dropped.add(raw.id);
|
|
11184
11476
|
for (const id of Object.keys(this.entries()))
|
|
11185
11477
|
if (!rosterIds.has(id))
|
|
@@ -11221,7 +11513,7 @@ class Transaction {
|
|
|
11221
11513
|
const next = {
|
|
11222
11514
|
...this.state,
|
|
11223
11515
|
version: LEGACY_STORE_VERSION,
|
|
11224
|
-
accounts:
|
|
11516
|
+
accounts: isRecord6(this.state.accounts) ? this.state.accounts : {}
|
|
11225
11517
|
};
|
|
11226
11518
|
await this.write(this.ctx.statePath, next, "state", true, options.durable ?? false);
|
|
11227
11519
|
this.state = next;
|
|
@@ -11416,11 +11708,11 @@ async function readRow(rt, operation, id) {
|
|
|
11416
11708
|
const row = result.rows.find((candidate) => candidate.id === id);
|
|
11417
11709
|
const entry = entryIn(result.config, id);
|
|
11418
11710
|
const accounts = result.state.accounts;
|
|
11419
|
-
const account =
|
|
11420
|
-
const stamp =
|
|
11711
|
+
const account = isRecord6(accounts) && Object.hasOwn(accounts, id) ? accounts[id] : undefined;
|
|
11712
|
+
const stamp = isRecord6(account) ? account[CREDENTIAL_STAMP_KEY] : undefined;
|
|
11421
11713
|
if (row && !["enable", "disable"].includes(operation) && entry && Object.hasOwn(entry, "staged"))
|
|
11422
11714
|
assertNotReserved(operation, id, entry.staged);
|
|
11423
|
-
if (!row &&
|
|
11715
|
+
if (!row && isRecord6(stamp) && Object.hasOwn(stamp, "staged"))
|
|
11424
11716
|
assertNotReserved(operation, id, stamp.staged);
|
|
11425
11717
|
if (!row)
|
|
11426
11718
|
throw unknownRow(operation, id);
|
|
@@ -11552,7 +11844,7 @@ async function updateProviderStateRow(rt, id, fence, mutator, options = {}) {
|
|
|
11552
11844
|
throw refusal(operation, id, "invalid-input", "the store was opened without a provider-state codec");
|
|
11553
11845
|
if (typeof mutator !== "function")
|
|
11554
11846
|
throw refusal(operation, id, "invalid-input", "a mutator is required");
|
|
11555
|
-
const captured =
|
|
11847
|
+
const captured = isRecord6(fence) ? fence.credentialEpoch : undefined;
|
|
11556
11848
|
if (!isCredentialEpoch(captured))
|
|
11557
11849
|
throw refusal(operation, id, "invalid-input", "the credential epoch the provider state was read at is required");
|
|
11558
11850
|
const { row: seen } = await readRow(rt, operation, id);
|
|
@@ -11596,7 +11888,7 @@ async function planProviderStateIn(tx, codec, operation, row, mutator, declinabl
|
|
|
11596
11888
|
const account = tx.stateAccount(id);
|
|
11597
11889
|
const rawStamp = account?.[CREDENTIAL_STAMP_KEY];
|
|
11598
11890
|
const stamp = parseStamp(rawStamp);
|
|
11599
|
-
if (!
|
|
11891
|
+
if (!isRecord6(rawStamp) || !stamp?.binding || stamp.digest !== credentialDigest(credential) || stamp.credentialEpoch !== epoch || stamp.binding.identity !== row.identity)
|
|
11600
11892
|
throw refusal(operation, id, "unbound-credential", `row ${id}'s credential carries no stamp of this store to bind a provider state to (stamp ${row.stamp}); rotate or replace it first`);
|
|
11601
11893
|
const current = row.providerState === undefined ? undefined : structuredClone(row.providerState);
|
|
11602
11894
|
const returned = await runInsideHook(operation, () => mutator(current, row));
|
|
@@ -11672,7 +11964,7 @@ function onRowEndpoint(tx, id, credential) {
|
|
|
11672
11964
|
if (credential.type !== "api")
|
|
11673
11965
|
return credential;
|
|
11674
11966
|
const raw = tx.rosterRow(id);
|
|
11675
|
-
if (!
|
|
11967
|
+
if (!isRecord6(raw)) {
|
|
11676
11968
|
if (credential.baseURL === undefined)
|
|
11677
11969
|
throw refusal(tx.info.operation, id, "invalid-input", "api credential needs a valid baseURL");
|
|
11678
11970
|
return { ...credential, baseURL: credential.baseURL };
|
|
@@ -11691,7 +11983,7 @@ function onRowEndpoint(tx, id, credential) {
|
|
|
11691
11983
|
function bindingInTx(tx, id, stored, learnt) {
|
|
11692
11984
|
const raw = tx.rosterRow(id);
|
|
11693
11985
|
const projected = tx.row(id);
|
|
11694
|
-
const identity = learnt ?? (projected ? projected.identity :
|
|
11986
|
+
const identity = learnt ?? (projected ? projected.identity : isRecord6(raw) && typeof raw.accountId === "string" && raw.accountId ? raw.accountId : undefined);
|
|
11695
11987
|
return {
|
|
11696
11988
|
...identity !== undefined ? { identity } : {},
|
|
11697
11989
|
...stored.type === "api" ? {
|
|
@@ -11775,7 +12067,7 @@ function requireUsableRow(operation, id, row, credential) {
|
|
|
11775
12067
|
return row;
|
|
11776
12068
|
}
|
|
11777
12069
|
function validateAttribution(operation, id, fence) {
|
|
11778
|
-
if (fence !== undefined && !isCredentialEpoch(
|
|
12070
|
+
if (fence !== undefined && !isCredentialEpoch(isRecord6(fence) ? fence.credentialEpoch : undefined))
|
|
11779
12071
|
throw refusal(operation, id, "invalid-input", "the attribution must name a credential epoch that is a positive safe integer");
|
|
11780
12072
|
}
|
|
11781
12073
|
function assertRowAttribution(operation, id, row, fence) {
|
|
@@ -11930,7 +12222,7 @@ async function addRow(rt, input, options = {}) {
|
|
|
11930
12222
|
const mode = options.onExisting ?? "rotate";
|
|
11931
12223
|
if (input.stage !== undefined && mode === "rotate")
|
|
11932
12224
|
throw refusal("add", id, "invalid-input", "a staged add needs onExisting: 'refuse' or 'stage-duplicate'");
|
|
11933
|
-
if (!["rotate", "refuse", "stage-duplicate"].includes(mode) || input.stage !== undefined && (label !== undefined && typeof label !== "string" || identity !== undefined && (typeof identity !== "string" || !identity)) || input.disabled !== undefined && (!
|
|
12225
|
+
if (!["rotate", "refuse", "stage-duplicate"].includes(mode) || input.stage !== undefined && (label !== undefined && typeof label !== "string" || identity !== undefined && (typeof identity !== "string" || !identity)) || input.disabled !== undefined && (!isRecord6(input.disabled) || typeof input.disabled.reason !== "string") || input.stage !== undefined && (!isRecord6(input.stage) || typeof input.stage.reservation !== "string" || !input.stage.reservation || !input.disabled) || mode === "stage-duplicate" && (!input.disabled || !input.stage))
|
|
11934
12226
|
throw refusal("add", id, "invalid-input", "staging requires a reservation and a disabled reason");
|
|
11935
12227
|
const incoming = input.providerState === undefined ? undefined : acceptProviderState(ctx.providerState, "add", id, input.providerState);
|
|
11936
12228
|
await locks.acquire(rowLockSpec(rt, { id, identity }));
|
|
@@ -11940,12 +12232,12 @@ async function addRow(rt, input, options = {}) {
|
|
|
11940
12232
|
await locks.acquire(extra);
|
|
11941
12233
|
return withTransaction(ctx, locks, progress, { operation: "add", rowId: id }, async (tx) => {
|
|
11942
12234
|
await protectIn(tx, id, options.protect);
|
|
11943
|
-
const stateAccounts =
|
|
12235
|
+
const stateAccounts = isRecord6(tx.state.accounts) ? tx.state.accounts : {};
|
|
11944
12236
|
const stagedOrphan = Object.entries(stateAccounts).find(([orphanId, account]) => {
|
|
11945
|
-
if (orphanId === id || tx.rosterRow(orphanId) || !
|
|
12237
|
+
if (orphanId === id || tx.rosterRow(orphanId) || !isRecord6(account))
|
|
11946
12238
|
return false;
|
|
11947
12239
|
const stamp = account[CREDENTIAL_STAMP_KEY];
|
|
11948
|
-
if (!
|
|
12240
|
+
if (!isRecord6(stamp) || !Object.hasOwn(stamp, "staged"))
|
|
11949
12241
|
return false;
|
|
11950
12242
|
return credential.type === "oauth" ? account.refresh === credential.refresh : typeof account.apiKey === "string" && account.apiKey.trim() === credential.apiKey.trim();
|
|
11951
12243
|
});
|
|
@@ -11963,9 +12255,9 @@ async function addRow(rt, input, options = {}) {
|
|
|
11963
12255
|
}
|
|
11964
12256
|
if (mode === "refuse") {
|
|
11965
12257
|
const holder = tx.rows().find((row) => row.fingerprint === fingerprintOf(credential) || row.id === id && row.credential);
|
|
11966
|
-
const accounts =
|
|
12258
|
+
const accounts = isRecord6(tx.state.accounts) ? tx.state.accounts : {};
|
|
11967
12259
|
const stateHolder = Object.entries(accounts).find(([, account]) => {
|
|
11968
|
-
if (!
|
|
12260
|
+
if (!isRecord6(account))
|
|
11969
12261
|
return false;
|
|
11970
12262
|
if (credential.type === "oauth")
|
|
11971
12263
|
return account.refresh === credential.refresh;
|
|
@@ -12298,7 +12590,7 @@ async function removeRow(rt, id, options = {}) {
|
|
|
12298
12590
|
throw refusal("remove", id, "invalid-input", "id must be non-empty");
|
|
12299
12591
|
const fence = options.attribution;
|
|
12300
12592
|
validateAttribution("remove", id, fence);
|
|
12301
|
-
if (options.staged !== undefined && (!
|
|
12593
|
+
if (options.staged !== undefined && (!isRecord6(options.staged) || typeof options.staged.reservation !== "string" || !options.staged.reservation))
|
|
12302
12594
|
throw refusal("remove", id, "invalid-input", "a staged removal needs a reservation");
|
|
12303
12595
|
const result = await readPool(ctx);
|
|
12304
12596
|
if (result.status !== "ready")
|
|
@@ -12313,7 +12605,7 @@ async function removeRow(rt, id, options = {}) {
|
|
|
12313
12605
|
return withTransaction(ctx, locks, progress, { operation: "remove", rowId: id }, async (tx) => {
|
|
12314
12606
|
const reservation = tx.reservation(id);
|
|
12315
12607
|
if (reservation !== undefined) {
|
|
12316
|
-
if (!
|
|
12608
|
+
if (!isRecord6(reservation) || !options.staged || reservation.reservation !== options.staged.reservation)
|
|
12317
12609
|
throw refusal("remove", id, "row-staged", `row ${id} is reserved for roster publication`);
|
|
12318
12610
|
} else if (options.staged)
|
|
12319
12611
|
throw refusal("remove", id, "attribution", `row ${id} is no longer reserved`);
|
|
@@ -12401,10 +12693,10 @@ function assertOrphanAttribution(rt, tx, id, fence) {
|
|
|
12401
12693
|
}
|
|
12402
12694
|
function hasStateAccount(state, id) {
|
|
12403
12695
|
const accounts = state.accounts;
|
|
12404
|
-
return
|
|
12696
|
+
return isRecord6(accounts) && Object.hasOwn(accounts, id);
|
|
12405
12697
|
}
|
|
12406
12698
|
function rosterIdOf(raw) {
|
|
12407
|
-
return
|
|
12699
|
+
return isRecord6(raw) && typeof raw.id === "string" ? raw.id : undefined;
|
|
12408
12700
|
}
|
|
12409
12701
|
function orderProblem(roster, ids) {
|
|
12410
12702
|
if (!Array.isArray(ids))
|
|
@@ -12479,7 +12771,7 @@ async function recordRowIdentity(rt, id, identity, attribution, options = {}) {
|
|
|
12479
12771
|
return runOperation(rt.ctx, "recordIdentity", id, options.onFailure, async (locks, progress) => {
|
|
12480
12772
|
if (typeof identity !== "string" || identity.length === 0)
|
|
12481
12773
|
throw refusal("recordIdentity", id, "invalid-input", "identity must be non-empty");
|
|
12482
|
-
const captured =
|
|
12774
|
+
const captured = isRecord6(attribution) ? attribution.credentialEpoch : undefined;
|
|
12483
12775
|
if (!isCredentialEpoch(captured))
|
|
12484
12776
|
throw refusal("recordIdentity", id, "invalid-input", "the credential epoch the identity lookup was issued for is required");
|
|
12485
12777
|
const { row: seen } = await readRow(rt, "recordIdentity", id);
|
|
@@ -12508,14 +12800,14 @@ async function recordRowIdentity(rt, id, identity, attribution, options = {}) {
|
|
|
12508
12800
|
// ../../node_modules/@cortexkit/common-auth/dist/store/publication.js
|
|
12509
12801
|
function receiptsIn(config) {
|
|
12510
12802
|
const pool = config[POOL_KEY];
|
|
12511
|
-
return
|
|
12803
|
+
return isRecord6(pool) && isRecord6(pool.publications) ? pool.publications : {};
|
|
12512
12804
|
}
|
|
12513
12805
|
function receiptIn(config, operationId) {
|
|
12514
12806
|
const receipts = receiptsIn(config);
|
|
12515
12807
|
if (!Object.hasOwn(receipts, operationId))
|
|
12516
12808
|
return;
|
|
12517
12809
|
const raw = receipts[operationId];
|
|
12518
|
-
if (!
|
|
12810
|
+
if (!isRecord6(raw) || raw.operationId !== operationId || typeof raw.planDigest !== "string" || !/^[a-f0-9]{64}$/.test(raw.planDigest) || !["committed", "cleaned"].includes(String(raw.phase)) || !Array.isArray(raw.removed) || !Array.isArray(raw.finalized) || raw.removed.some((ref) => !isRecord6(ref) || typeof ref.id !== "string" || !isCredentialEpoch(ref.credentialEpoch)) || raw.finalized.some((ref) => !isRecord6(ref) || typeof ref.id !== "string" || !isCredentialEpoch(ref.credentialEpoch) || typeof ref.reservation !== "string" || !ref.reservation || typeof ref.enabled !== "boolean"))
|
|
12519
12811
|
throw refusal("publishRoster", operationId, "invalid-input", "the stored publication receipt is malformed");
|
|
12520
12812
|
return structuredClone(raw);
|
|
12521
12813
|
}
|
|
@@ -12529,11 +12821,11 @@ function validatePlan(rt, plan) {
|
|
|
12529
12821
|
const fail = () => {
|
|
12530
12822
|
throw refusal("publishRoster", plan?.operationId ?? "", "invalid-input", "the publication plan is invalid");
|
|
12531
12823
|
};
|
|
12532
|
-
if (!
|
|
12824
|
+
if (!isRecord6(plan) || typeof plan.operationId !== "string" || !plan.operationId || !Array.isArray(plan.remove) || !Array.isArray(plan.finalize) || !Array.isArray(plan.order))
|
|
12533
12825
|
fail();
|
|
12534
12826
|
const ids = new Set;
|
|
12535
12827
|
for (const ref of [...plan.remove, ...plan.finalize]) {
|
|
12536
|
-
if (!
|
|
12828
|
+
if (!isRecord6(ref) || typeof ref.id !== "string" || idProblem(ref.id) || ids.has(ref.id) || !ref.attribution)
|
|
12537
12829
|
fail();
|
|
12538
12830
|
ids.add(ref.id);
|
|
12539
12831
|
validateAttribution("publishRoster", ref.id, ref.attribution);
|
|
@@ -12565,7 +12857,7 @@ function saveReceipt(tx, receipt) {
|
|
|
12565
12857
|
function publicationSurvivors(tx, plan, rows) {
|
|
12566
12858
|
const rosterIds = new Set;
|
|
12567
12859
|
for (const raw of rosterOf(tx.config)) {
|
|
12568
|
-
if (!
|
|
12860
|
+
if (!isRecord6(raw) || typeof raw.id !== "string")
|
|
12569
12861
|
continue;
|
|
12570
12862
|
if (rosterIds.has(raw.id))
|
|
12571
12863
|
throw refusal("publishRoster", plan.operationId, "invalid-input", "publication needs a roster of unique named rows");
|
|
@@ -12604,14 +12896,14 @@ async function cleanup(tx, receipt) {
|
|
|
12604
12896
|
async function publishRoster(rt, plan, options = {}) {
|
|
12605
12897
|
assertNotInsideHook("publishRoster");
|
|
12606
12898
|
return runOperation(rt.ctx, "publishRoster", plan?.operationId ?? "", options.onFailure, async (locks, progress) => {
|
|
12607
|
-
if (!
|
|
12899
|
+
if (!isRecord6(plan) || typeof plan.operationId !== "string" || !plan.operationId)
|
|
12608
12900
|
throw refusal("publishRoster", plan?.operationId ?? "", "invalid-input", "the publication needs an operation id");
|
|
12609
12901
|
plan = structuredClone(plan);
|
|
12610
12902
|
const planDigest = canonicalDigest(plan);
|
|
12611
12903
|
const named = [
|
|
12612
12904
|
...Array.isArray(plan.remove) ? plan.remove : [],
|
|
12613
12905
|
...Array.isArray(plan.finalize) ? plan.finalize : []
|
|
12614
|
-
].filter((ref) =>
|
|
12906
|
+
].filter((ref) => isRecord6(ref) && typeof ref.id === "string");
|
|
12615
12907
|
for (let attempt = 0;; attempt++) {
|
|
12616
12908
|
const seen = await readPool(rt.ctx);
|
|
12617
12909
|
if (seen.status !== "ready")
|
|
@@ -12715,7 +13007,7 @@ async function publishRoster(rt, plan, options = {}) {
|
|
|
12715
13007
|
entry.disabledReason = ref.disabledReason;
|
|
12716
13008
|
tx.setEntry(ref.id, entry);
|
|
12717
13009
|
}
|
|
12718
|
-
const preserved = tx.roster().filter((raw) => !
|
|
13010
|
+
const preserved = tx.roster().filter((raw) => !isRecord6(raw) || typeof raw.id !== "string" || rows.find((row) => row.id === raw.id)?.invalid === "roster");
|
|
12719
13011
|
tx.config.accounts = [
|
|
12720
13012
|
...plan.order.map((id) => tx.rosterRow(id)),
|
|
12721
13013
|
...preserved
|
|
@@ -13089,7 +13381,7 @@ async function updatePoolSettings(rt, mutator, options = {}) {
|
|
|
13089
13381
|
const draft = structuredClone(current);
|
|
13090
13382
|
const returned = await runInsideHook("updateSettings", () => mutator(draft));
|
|
13091
13383
|
const next = returned === undefined ? draft : returned;
|
|
13092
|
-
if (!
|
|
13384
|
+
if (!isRecord6(next))
|
|
13093
13385
|
throw settingsRefusal("the settings mutator must produce an object");
|
|
13094
13386
|
const owned = POOL_OWNED_KEYS.filter((key) => Object.hasOwn(next, key));
|
|
13095
13387
|
if (owned.length > 0)
|
|
@@ -13226,7 +13518,7 @@ function entryTime(entry) {
|
|
|
13226
13518
|
function limitKey(scope, label) {
|
|
13227
13519
|
return JSON.stringify([scope, label]);
|
|
13228
13520
|
}
|
|
13229
|
-
function
|
|
13521
|
+
function isRecord7(value) {
|
|
13230
13522
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
13231
13523
|
}
|
|
13232
13524
|
function isFiniteNumber(value) {
|
|
@@ -13245,7 +13537,7 @@ function isString(value) {
|
|
|
13245
13537
|
return typeof value === "string";
|
|
13246
13538
|
}
|
|
13247
13539
|
function isQuotaEntry(value) {
|
|
13248
|
-
if (!
|
|
13540
|
+
if (!isRecord7(value) || !isName(value.scope) || !isName(value.label)) {
|
|
13249
13541
|
return false;
|
|
13250
13542
|
}
|
|
13251
13543
|
switch (value.kind) {
|
|
@@ -13260,20 +13552,26 @@ function isQuotaEntry(value) {
|
|
|
13260
13552
|
}
|
|
13261
13553
|
}
|
|
13262
13554
|
function isCreditBudgetEntry(value) {
|
|
13263
|
-
if (!
|
|
13555
|
+
if (!isRecord7(value) || !isFiniteNumber(value.checkedAt))
|
|
13264
13556
|
return false;
|
|
13265
13557
|
if (value.kind === "cleared")
|
|
13266
13558
|
return true;
|
|
13267
13559
|
return value.kind === "reading" && typeof value.reached === "boolean" && optional(value, "remainingPercent", isFiniteNumber) && optional(value, "usedPercent", isFiniteNumber) && optional(value, "resetsAt", isString) && optional(value, "limit", isFiniteNumber) && optional(value, "used", isFiniteNumber) && optional(value, "remaining", isFiniteNumber) && optional(value, "unit", isString);
|
|
13268
13560
|
}
|
|
13269
13561
|
function isQuotaCounter(value) {
|
|
13270
|
-
return
|
|
13562
|
+
return isRecord7(value) && isFiniteNumber(value.value) && Number.isInteger(value.value) && value.value >= 0 && isFiniteNumber(value.checkedAt);
|
|
13271
13563
|
}
|
|
13272
13564
|
function isQuotaCounters(value) {
|
|
13273
|
-
return
|
|
13565
|
+
return isRecord7(value) && Object.values(value).every(isQuotaCounter);
|
|
13566
|
+
}
|
|
13567
|
+
function isBoolean(value) {
|
|
13568
|
+
return typeof value === "boolean";
|
|
13569
|
+
}
|
|
13570
|
+
function isQuotaCredits(value) {
|
|
13571
|
+
return isRecord7(value) && typeof value.hasCredits === "boolean" && typeof value.unlimited === "boolean" && optional(value, "balance", isFiniteNumber) && optional(value, "overageLimitReached", isBoolean) && isFiniteNumber(value.checkedAt);
|
|
13274
13572
|
}
|
|
13275
13573
|
function readQuotaCounters(value) {
|
|
13276
|
-
if (!
|
|
13574
|
+
if (!isRecord7(value))
|
|
13277
13575
|
return;
|
|
13278
13576
|
const entries = Object.entries(value).filter(([, entry]) => isQuotaCounter(entry));
|
|
13279
13577
|
return entries.length === 0 ? undefined : Object.fromEntries(entries);
|
|
@@ -13281,16 +13579,21 @@ function readQuotaCounters(value) {
|
|
|
13281
13579
|
function decodeQuotaMap(value) {
|
|
13282
13580
|
if (isQuotaMap(value))
|
|
13283
13581
|
return value;
|
|
13284
|
-
if (!
|
|
13582
|
+
if (!isRecord7(value))
|
|
13285
13583
|
return;
|
|
13286
|
-
const { counters: rawCounters, ...rest } = value;
|
|
13584
|
+
const { counters: rawCounters, credits: rawCredits, ...rest } = value;
|
|
13287
13585
|
if (!isQuotaMap(rest))
|
|
13288
13586
|
return;
|
|
13289
13587
|
const counters = readQuotaCounters(rawCounters);
|
|
13290
|
-
|
|
13588
|
+
const credits = isQuotaCredits(rawCredits) ? rawCredits : undefined;
|
|
13589
|
+
return {
|
|
13590
|
+
...rest,
|
|
13591
|
+
...counters === undefined ? {} : { counters },
|
|
13592
|
+
...credits === undefined ? {} : { credits }
|
|
13593
|
+
};
|
|
13291
13594
|
}
|
|
13292
13595
|
function isQuotaMap(value) {
|
|
13293
|
-
if (!
|
|
13596
|
+
if (!isRecord7(value) || !Array.isArray(value.limits))
|
|
13294
13597
|
return false;
|
|
13295
13598
|
const seen = new Set;
|
|
13296
13599
|
for (const entry of value.limits) {
|
|
@@ -13301,7 +13604,7 @@ function isQuotaMap(value) {
|
|
|
13301
13604
|
return false;
|
|
13302
13605
|
seen.add(key);
|
|
13303
13606
|
}
|
|
13304
|
-
return optional(value, "budget", isCreditBudgetEntry) && optional(value, "counters", isQuotaCounters);
|
|
13607
|
+
return optional(value, "budget", isCreditBudgetEntry) && optional(value, "counters", isQuotaCounters) && optional(value, "credits", isQuotaCredits);
|
|
13305
13608
|
}
|
|
13306
13609
|
|
|
13307
13610
|
// ../../node_modules/@cortexkit/common-auth/dist/quota/merge.js
|
|
@@ -13311,7 +13614,7 @@ class QuotaCodecError extends TypeError {
|
|
|
13311
13614
|
this.name = "QuotaCodecError";
|
|
13312
13615
|
}
|
|
13313
13616
|
}
|
|
13314
|
-
function
|
|
13617
|
+
function isRecord8(value) {
|
|
13315
13618
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
13316
13619
|
}
|
|
13317
13620
|
function isFiniteNumber2(value) {
|
|
@@ -13330,20 +13633,20 @@ function optionalString(record, key) {
|
|
|
13330
13633
|
return record[key] === undefined || typeof record[key] === "string";
|
|
13331
13634
|
}
|
|
13332
13635
|
function isObservedReading(value) {
|
|
13333
|
-
return
|
|
13636
|
+
return isRecord8(value) && isScope(value.scope) && isLabel(value.label) && isFiniteNumber2(value.usedPercent) && optionalString(value, "resetsAt") && (value.windowMinutes === undefined || isFiniteNumber2(value.windowMinutes) && value.windowMinutes > 0);
|
|
13334
13637
|
}
|
|
13335
13638
|
function isObservedPair(value) {
|
|
13336
|
-
return
|
|
13639
|
+
return isRecord8(value) && isScope(value.scope) && isLabel(value.label);
|
|
13337
13640
|
}
|
|
13338
13641
|
function isObservedBudget(value) {
|
|
13339
|
-
if (!
|
|
13642
|
+
if (!isRecord8(value))
|
|
13340
13643
|
return false;
|
|
13341
13644
|
if (value.kind === "cleared")
|
|
13342
13645
|
return true;
|
|
13343
13646
|
return value.kind === "reading" && typeof value.reached === "boolean" && optionalFinite(value, "remainingPercent") && optionalFinite(value, "usedPercent") && optionalString(value, "resetsAt") && optionalFinite(value, "limit") && optionalFinite(value, "used") && optionalFinite(value, "remaining") && optionalString(value, "unit");
|
|
13344
13647
|
}
|
|
13345
13648
|
function isQuotaObservation(value) {
|
|
13346
|
-
if (!
|
|
13649
|
+
if (!isRecord8(value) || !isFiniteNumber2(value.checkedAt))
|
|
13347
13650
|
return false;
|
|
13348
13651
|
const readings = value.readings ?? [];
|
|
13349
13652
|
const coverage = value.coverage ?? [];
|
|
@@ -13360,7 +13663,7 @@ function isQuotaObservation(value) {
|
|
|
13360
13663
|
}
|
|
13361
13664
|
if (!coverage.every(isObservedPair))
|
|
13362
13665
|
return false;
|
|
13363
|
-
return (value.budget === undefined || isObservedBudget(value.budget)) && (value.counters === undefined || isQuotaCounters(value.counters));
|
|
13666
|
+
return (value.budget === undefined || isObservedBudget(value.budget)) && (value.counters === undefined || isQuotaCounters(value.counters)) && (value.credits === undefined || isQuotaCredits(value.credits));
|
|
13364
13667
|
}
|
|
13365
13668
|
function compareEntries(left, right) {
|
|
13366
13669
|
if (left.scope !== right.scope)
|
|
@@ -13386,6 +13689,14 @@ function mergeCounters(stored, observed) {
|
|
|
13386
13689
|
}
|
|
13387
13690
|
return counters.size === 0 ? undefined : Object.fromEntries(counters);
|
|
13388
13691
|
}
|
|
13692
|
+
function mergeCredits(stored, observed) {
|
|
13693
|
+
if (observed === undefined)
|
|
13694
|
+
return stored;
|
|
13695
|
+
if (stored !== undefined && observed.checkedAt < stored.checkedAt) {
|
|
13696
|
+
return stored;
|
|
13697
|
+
}
|
|
13698
|
+
return { ...observed };
|
|
13699
|
+
}
|
|
13389
13700
|
function mergeQuotaObservation(stored, observation) {
|
|
13390
13701
|
const decoded = stored === undefined ? undefined : decodeQuotaMap(stored);
|
|
13391
13702
|
if (stored !== undefined && decoded === undefined) {
|
|
@@ -13429,14 +13740,16 @@ function mergeQuotaObservation(stored, observation) {
|
|
|
13429
13740
|
const existing = entries.get(key);
|
|
13430
13741
|
entries.set(key, existing === undefined || existing.kind === "absent" ? { scope, label: pair.label, kind: "absent", checkedAt: at } : { scope, label: pair.label, kind: "retired", retiredAt: at });
|
|
13431
13742
|
}
|
|
13432
|
-
const { limits: _limits, budget: _budget, counters: _counters, ...unknownKeys } = base;
|
|
13743
|
+
const { limits: _limits, budget: _budget, counters: _counters, credits: _credits, ...unknownKeys } = base;
|
|
13433
13744
|
const budget = mergeBudget(base.budget, observation.budget, at);
|
|
13434
13745
|
const counters = mergeCounters(base.counters, observation.counters);
|
|
13746
|
+
const credits = mergeCredits(base.credits, observation.credits);
|
|
13435
13747
|
return {
|
|
13436
13748
|
...unknownKeys,
|
|
13437
13749
|
limits: [...entries.values()].sort(compareEntries),
|
|
13438
13750
|
...budget === undefined ? {} : { budget },
|
|
13439
|
-
...counters === undefined ? {} : { counters }
|
|
13751
|
+
...counters === undefined ? {} : { counters },
|
|
13752
|
+
...credits === undefined ? {} : { credits }
|
|
13440
13753
|
};
|
|
13441
13754
|
}
|
|
13442
13755
|
|
|
@@ -13512,6 +13825,13 @@ function quotaWindowParts(quota, options) {
|
|
|
13512
13825
|
const parts = windows.map(({ part }) => part);
|
|
13513
13826
|
return age === undefined ? { windows: parts } : { windows: parts, age };
|
|
13514
13827
|
}
|
|
13828
|
+
function withShortNames(windows) {
|
|
13829
|
+
const abbreviations = scopeAbbreviations(windows.filter(({ part, scope }) => part.kind === "window" && scope !== ALL_SCOPE).map(({ scope }) => scope));
|
|
13830
|
+
for (const window of windows) {
|
|
13831
|
+
window.part.short = window.part.kind === "budget" ? "cr" : window.scope === ALL_SCOPE ? window.part.name : abbreviations.get(window.scope) ?? window.scope;
|
|
13832
|
+
}
|
|
13833
|
+
return windows;
|
|
13834
|
+
}
|
|
13515
13835
|
function scopedWindowParts(quota, options) {
|
|
13516
13836
|
if (!quota)
|
|
13517
13837
|
return { windows: [] };
|
|
@@ -13525,6 +13845,7 @@ function scopedWindowParts(quota, options) {
|
|
|
13525
13845
|
part: {
|
|
13526
13846
|
kind: "window",
|
|
13527
13847
|
name: quotaWindowName(limit),
|
|
13848
|
+
short: "",
|
|
13528
13849
|
figure: percentLeft(limit.remainingPercent ?? 0),
|
|
13529
13850
|
remainingPercent,
|
|
13530
13851
|
checkedAt: limit.checkedAt,
|
|
@@ -13542,6 +13863,7 @@ function scopedWindowParts(quota, options) {
|
|
|
13542
13863
|
part: {
|
|
13543
13864
|
kind: "budget",
|
|
13544
13865
|
name: "credits",
|
|
13866
|
+
short: "",
|
|
13545
13867
|
figure,
|
|
13546
13868
|
...remainingPercent === undefined ? {} : { remainingPercent: clampPercent2(remainingPercent) },
|
|
13547
13869
|
checkedAt: budget.checkedAt,
|
|
@@ -13549,6 +13871,7 @@ function scopedWindowParts(quota, options) {
|
|
|
13549
13871
|
}
|
|
13550
13872
|
});
|
|
13551
13873
|
}
|
|
13874
|
+
withShortNames(windows);
|
|
13552
13875
|
if (windows.length > 0) {
|
|
13553
13876
|
const age = now - Math.min(...windows.map(({ part }) => part.checkedAt));
|
|
13554
13877
|
if (age > (options.staleAfterMs ?? QUOTA_STALE_AFTER_MS)) {
|
|
@@ -13629,15 +13952,14 @@ function narrowTextParts(quota, options) {
|
|
|
13629
13952
|
return grouped;
|
|
13630
13953
|
const general = windows.filter(({ part, scope }) => part.kind === "window" && scope === ALL_SCOPE);
|
|
13631
13954
|
const scoped = windows.filter(({ part, scope }) => part.kind === "window" && scope !== ALL_SCOPE);
|
|
13632
|
-
const abbreviations = scopeAbbreviations(scoped.map(({ scope }) => scope));
|
|
13633
13955
|
const budget = windows.find(({ part }) => part.kind === "budget");
|
|
13634
13956
|
const budgetLeft = budget?.spent ? 0 : budget?.part.remainingPercent;
|
|
13635
13957
|
const extras = [
|
|
13636
|
-
...scoped.map(({
|
|
13637
|
-
label:
|
|
13958
|
+
...scoped.map(({ part }) => ({
|
|
13959
|
+
label: part.short,
|
|
13638
13960
|
remaining: part.remainingPercent ?? 0
|
|
13639
13961
|
})),
|
|
13640
|
-
...budgetLeft === undefined ? [] : [{ label:
|
|
13962
|
+
...budgetLeft === undefined || budget === undefined ? [] : [{ label: budget.part.short, remaining: budgetLeft }]
|
|
13641
13963
|
];
|
|
13642
13964
|
const tightest = extras.reduce((best, item) => best === undefined || item.remaining < best.remaining ? item : best, undefined);
|
|
13643
13965
|
const pieces = general.map(({ part }) => `${part.name} ${wholePercent(part.remainingPercent ?? 0)}%`);
|
|
@@ -13894,7 +14216,7 @@ var nativeQuotaCodec = {
|
|
|
13894
14216
|
import { randomUUID as randomUUID12 } from "node:crypto";
|
|
13895
14217
|
import { constants as constants2 } from "node:fs";
|
|
13896
14218
|
import { lstat as lstat5, mkdir as mkdir9, open as open6, rename as rename11, rm as rm6 } from "node:fs/promises";
|
|
13897
|
-
import { basename as basename4, dirname as dirname9, isAbsolute as isAbsolute3, join as
|
|
14219
|
+
import { basename as basename4, dirname as dirname9, isAbsolute as isAbsolute3, join as join12 } from "node:path";
|
|
13898
14220
|
import { types as utilTypes5 } from "node:util";
|
|
13899
14221
|
|
|
13900
14222
|
// src/pool-binding.ts
|
|
@@ -15354,7 +15676,7 @@ async function writeNativeRuntimeOutcome(path2, storageId, change, hooks, firstI
|
|
|
15354
15676
|
assertTransitions(current, next, firstIdentity);
|
|
15355
15677
|
const bytes = `${JSON.stringify(next, null, 2)}
|
|
15356
15678
|
`;
|
|
15357
|
-
const stage =
|
|
15679
|
+
const stage = join12(dirname9(path2), `${basename4(path2)}.native-runtime.${randomUUID12()}.partial`);
|
|
15358
15680
|
let ownsStage = false;
|
|
15359
15681
|
try {
|
|
15360
15682
|
const nativeCreated = await createWindowsOwnerOnly(stage, bytes);
|
|
@@ -17774,8 +18096,12 @@ class ClaustrumScopedCustody {
|
|
|
17774
18096
|
}
|
|
17775
18097
|
}
|
|
17776
18098
|
|
|
18099
|
+
// ../../node_modules/@cortexkit/common-auth/dist/claustrum/quota-writer.js
|
|
18100
|
+
import { resolve as resolve8 } from "node:path";
|
|
18101
|
+
|
|
17777
18102
|
// ../../node_modules/@cortexkit/common-auth/dist/claustrum/roster.js
|
|
17778
18103
|
import { createHash as createHash12 } from "node:crypto";
|
|
18104
|
+
import { resolve as resolve7 } from "node:path";
|
|
17779
18105
|
|
|
17780
18106
|
// ../../node_modules/@cortexkit/common-auth/dist/claustrum/interlock.js
|
|
17781
18107
|
function matches(entry2, credentialId, accountIdentity) {
|
|
@@ -17950,15 +18276,15 @@ function vaultRoutingRows(roster) {
|
|
|
17950
18276
|
...row.quota !== undefined && { quota: row.quota }
|
|
17951
18277
|
}));
|
|
17952
18278
|
}
|
|
17953
|
-
function
|
|
18279
|
+
function isRecord9(value) {
|
|
17954
18280
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
17955
18281
|
}
|
|
17956
18282
|
function optionalString2(value) {
|
|
17957
18283
|
return value === undefined || typeof value === "string";
|
|
17958
18284
|
}
|
|
17959
18285
|
function decodeRow(value) {
|
|
17960
|
-
const quota2 =
|
|
17961
|
-
if (!
|
|
18286
|
+
const quota2 = isRecord9(value) ? decodeQuotaMap(value.quota) : undefined;
|
|
18287
|
+
if (!isRecord9(value) || typeof value.routeId !== "string" || typeof value.credentialId !== "string" || value.credentialType !== "oauth" && value.credentialType !== "api_key" || typeof value.state !== "string" || typeof value.label !== "string" || typeof value.enabled !== "boolean" || typeof value.addedAt !== "number" || !optionalString2(value.accountIdentity) || !optionalString2(value.email) || !optionalString2(value.orgName) || value.aliases !== undefined && (!Array.isArray(value.aliases) || !value.aliases.every((alias) => typeof alias === "string")) || value.quota !== undefined && quota2 === undefined || value.stale !== undefined && value.stale !== true || value.unclaimed !== undefined && value.unclaimed !== true)
|
|
17962
18288
|
return;
|
|
17963
18289
|
return {
|
|
17964
18290
|
...value,
|
|
@@ -17976,14 +18302,14 @@ function decodeRejected(value) {
|
|
|
17976
18302
|
return;
|
|
17977
18303
|
const records = [];
|
|
17978
18304
|
for (const entry2 of value) {
|
|
17979
|
-
if (!
|
|
18305
|
+
if (!isRecord9(entry2) || !optionalString2(entry2.credentialId) || typeof entry2.reason !== "string" || !SKIPPED_REASONS.has(entry2.reason))
|
|
17980
18306
|
return;
|
|
17981
18307
|
records.push(entry2);
|
|
17982
18308
|
}
|
|
17983
18309
|
return records;
|
|
17984
18310
|
}
|
|
17985
18311
|
function decodeRoster(value) {
|
|
17986
|
-
if (!
|
|
18312
|
+
if (!isRecord9(value) || value.version !== 1 || !optionalString2(value.view) || !Array.isArray(value.rows) || !Array.isArray(value.declined) || value.complete !== undefined && typeof value.complete !== "boolean" || value.rejected !== undefined && !decodeRejected(value.rejected))
|
|
17987
18313
|
throw new ClaustrumConsumerError("invalid-state", "Claustrum roster file is not valid");
|
|
17988
18314
|
const rows = [];
|
|
17989
18315
|
for (const entry2 of value.rows) {
|
|
@@ -17994,7 +18320,7 @@ function decodeRoster(value) {
|
|
|
17994
18320
|
}
|
|
17995
18321
|
const declined = [];
|
|
17996
18322
|
for (const entry2 of value.declined) {
|
|
17997
|
-
if (!
|
|
18323
|
+
if (!isRecord9(entry2) || typeof entry2.credentialId !== "string" || !optionalString2(entry2.accountIdentity))
|
|
17998
18324
|
throw new ClaustrumConsumerError("invalid-state", "Claustrum roster file is not valid");
|
|
17999
18325
|
declined.push(entry2);
|
|
18000
18326
|
}
|
|
@@ -18028,11 +18354,12 @@ async function readVaultRoster(path2) {
|
|
|
18028
18354
|
var WRITE_LOCK = {
|
|
18029
18355
|
name: "claustrum-roster-write",
|
|
18030
18356
|
ttlMs: 1e4,
|
|
18031
|
-
timeoutMs: 5000
|
|
18357
|
+
timeoutMs: 5000,
|
|
18358
|
+
renew: true
|
|
18032
18359
|
};
|
|
18033
18360
|
var DISCOVERY_LEASE = { name: "claustrum-roster", ttlMs: 30000 };
|
|
18034
18361
|
async function mutateVaultRoster(path2, change, options = {}) {
|
|
18035
|
-
return withLock(path2, WRITE_LOCK, async (lock) => {
|
|
18362
|
+
return withLock(path2, { ...WRITE_LOCK, signal: options.signal }, async (lock) => {
|
|
18036
18363
|
const current = await readVaultRoster(path2);
|
|
18037
18364
|
const { next, result } = await change(current, {
|
|
18038
18365
|
assertOwned: () => lock.assertOwned()
|
|
@@ -18042,6 +18369,7 @@ async function mutateVaultRoster(path2, change, options = {}) {
|
|
|
18042
18369
|
await writeJsonAtomic(path2, next, {
|
|
18043
18370
|
beforeRename: async () => {
|
|
18044
18371
|
await options.beforePublish?.();
|
|
18372
|
+
options.signal?.throwIfAborted();
|
|
18045
18373
|
await lock.assertOwned();
|
|
18046
18374
|
}
|
|
18047
18375
|
});
|
|
@@ -18091,43 +18419,52 @@ function receiptFence(row, receipt) {
|
|
|
18091
18419
|
return "bind";
|
|
18092
18420
|
return "refuse";
|
|
18093
18421
|
}
|
|
18094
|
-
function recordVaultQuota(path2, input) {
|
|
18095
|
-
|
|
18096
|
-
|
|
18097
|
-
|
|
18098
|
-
|
|
18099
|
-
|
|
18100
|
-
|
|
18101
|
-
const bound = fence === "bind" ? { accountIdentity: input.accountIdentity, unclaimed: true } : {};
|
|
18102
|
-
return {
|
|
18103
|
-
next: {
|
|
18104
|
-
...current,
|
|
18105
|
-
rows: current.rows.map((entry2) => entry2 === row ? { ...entry2, ...bound, quota: quota2 } : entry2)
|
|
18106
|
-
},
|
|
18107
|
-
result: true
|
|
18108
|
-
};
|
|
18422
|
+
async function recordVaultQuota(path2, input) {
|
|
18423
|
+
const { routeId, observation, ...receipt } = input;
|
|
18424
|
+
return enqueueFencedVaultQuota(path2, {
|
|
18425
|
+
routeId,
|
|
18426
|
+
observation,
|
|
18427
|
+
accountIdentity: receipt.accountIdentity,
|
|
18428
|
+
receipt
|
|
18109
18429
|
});
|
|
18110
18430
|
}
|
|
18431
|
+
async function enqueueFencedVaultQuota(path2, publication2) {
|
|
18432
|
+
if (!isQuotaObservation(publication2.observation))
|
|
18433
|
+
return false;
|
|
18434
|
+
const current = pendingVaultQuota(path2, await readVaultRoster(path2));
|
|
18435
|
+
if (!applyVaultQuota(current, publication2).kept)
|
|
18436
|
+
return false;
|
|
18437
|
+
return enqueueVaultQuota(path2, publication2);
|
|
18438
|
+
}
|
|
18111
18439
|
function recordVaultAccountQuota(path2, input) {
|
|
18112
|
-
return
|
|
18113
|
-
|
|
18114
|
-
|
|
18115
|
-
|
|
18116
|
-
|
|
18117
|
-
|
|
18118
|
-
|
|
18119
|
-
|
|
18120
|
-
|
|
18121
|
-
|
|
18122
|
-
|
|
18123
|
-
|
|
18124
|
-
|
|
18440
|
+
return enqueueFencedVaultQuota(path2, input);
|
|
18441
|
+
}
|
|
18442
|
+
function applyVaultQuota(current, input) {
|
|
18443
|
+
const row = current?.rows.find((entry2) => entry2.routeId === input.routeId);
|
|
18444
|
+
const fence = !row ? "refuse" : input.receipt ? receiptFence(row, input.receipt) : row.accountIdentity !== undefined && row.accountIdentity === input.accountIdentity ? "hold" : "refuse";
|
|
18445
|
+
if (!current || !row || fence === "refuse")
|
|
18446
|
+
return { roster: current, kept: false };
|
|
18447
|
+
const quota2 = mergeQuotaObservation(row.quota, input.observation);
|
|
18448
|
+
const bound = fence === "bind" ? { accountIdentity: input.accountIdentity, unclaimed: true } : {};
|
|
18449
|
+
return {
|
|
18450
|
+
roster: {
|
|
18451
|
+
...current,
|
|
18452
|
+
rows: current.rows.map((entry2) => entry2 === row ? { ...entry2, ...bound, quota: quota2 } : entry2)
|
|
18453
|
+
},
|
|
18454
|
+
kept: true
|
|
18455
|
+
};
|
|
18456
|
+
}
|
|
18457
|
+
var pendingDiscoveries = new Map;
|
|
18458
|
+
function forgetPendingVaultDiscovery(path2) {
|
|
18459
|
+
pendingDiscoveries.delete(resolve7(path2));
|
|
18125
18460
|
}
|
|
18126
18461
|
async function refreshVaultRoster(options) {
|
|
18127
18462
|
options.signal?.throwIfAborted();
|
|
18128
18463
|
const active = async () => await options.isActive?.() ?? true;
|
|
18129
|
-
if (!await active())
|
|
18464
|
+
if (!await active()) {
|
|
18465
|
+
forgetPendingVaultDiscovery(options.path);
|
|
18130
18466
|
return;
|
|
18467
|
+
}
|
|
18131
18468
|
const lease = await acquireRefreshFileLock({
|
|
18132
18469
|
...DISCOVERY_LEASE,
|
|
18133
18470
|
path: options.path,
|
|
@@ -18140,8 +18477,18 @@ async function refreshVaultRoster(options) {
|
|
|
18140
18477
|
throw new ClaustrumConsumerError("roster-busy", "Claustrum account discovery is already in progress");
|
|
18141
18478
|
return persisted;
|
|
18142
18479
|
}
|
|
18480
|
+
const key = resolve7(options.path);
|
|
18481
|
+
let discovered;
|
|
18143
18482
|
try {
|
|
18144
|
-
const
|
|
18483
|
+
const previous = await readVaultRoster(options.path);
|
|
18484
|
+
const pending = pendingDiscoveries.get(key);
|
|
18485
|
+
discovered = pending && (pending.previousView === previous?.view || pending.inventory.view === previous?.view) ? pending : {
|
|
18486
|
+
inventory: await options.custody.discover(options.signal),
|
|
18487
|
+
previousView: previous?.view
|
|
18488
|
+
};
|
|
18489
|
+
pendingDiscoveries.delete(key);
|
|
18490
|
+
const { inventory } = discovered;
|
|
18491
|
+
options.onInventory?.(inventory);
|
|
18145
18492
|
options.signal?.throwIfAborted();
|
|
18146
18493
|
return await mutateVaultRoster(options.path, async (current) => {
|
|
18147
18494
|
if (!await active())
|
|
@@ -18152,12 +18499,238 @@ async function refreshVaultRoster(options) {
|
|
|
18152
18499
|
const next = projectVaultRoster(current, inventory, projection);
|
|
18153
18500
|
const changed = JSON.stringify(current) !== JSON.stringify(next);
|
|
18154
18501
|
return { ...changed && { next }, result: next };
|
|
18502
|
+
}, {
|
|
18503
|
+
beforePublish: async () => {
|
|
18504
|
+
options.signal?.throwIfAborted();
|
|
18505
|
+
await lease.assertOwned();
|
|
18506
|
+
}
|
|
18155
18507
|
});
|
|
18508
|
+
} catch (error) {
|
|
18509
|
+
if (error instanceof LockContentionError && discovered && !options.signal?.aborted && await active())
|
|
18510
|
+
pendingDiscoveries.set(key, discovered);
|
|
18511
|
+
throw error;
|
|
18156
18512
|
} finally {
|
|
18157
18513
|
await lease.release();
|
|
18158
18514
|
}
|
|
18159
18515
|
}
|
|
18160
18516
|
|
|
18517
|
+
// ../../node_modules/@cortexkit/common-auth/dist/claustrum/quota-writer.js
|
|
18518
|
+
var writers = new Map;
|
|
18519
|
+
var logger2 = createLogger("claustrum");
|
|
18520
|
+
var COALESCE_MS = 100;
|
|
18521
|
+
function writerFor(path2) {
|
|
18522
|
+
const key = resolve8(path2);
|
|
18523
|
+
let writer = writers.get(key);
|
|
18524
|
+
if (!writer) {
|
|
18525
|
+
writer = {
|
|
18526
|
+
path: key,
|
|
18527
|
+
pending: new Map,
|
|
18528
|
+
listeners: new Set,
|
|
18529
|
+
wake: new Set,
|
|
18530
|
+
abort: new AbortController,
|
|
18531
|
+
failures: 0,
|
|
18532
|
+
draining: false,
|
|
18533
|
+
order: 0
|
|
18534
|
+
};
|
|
18535
|
+
writers.set(key, writer);
|
|
18536
|
+
}
|
|
18537
|
+
return writer;
|
|
18538
|
+
}
|
|
18539
|
+
function retainVaultQuotaWriter(path2, listener) {
|
|
18540
|
+
const writer = writerFor(path2);
|
|
18541
|
+
writer.listeners.add(listener);
|
|
18542
|
+
let released;
|
|
18543
|
+
return () => released ??= (() => {
|
|
18544
|
+
writer.listeners.delete(listener);
|
|
18545
|
+
return writer.listeners.size ? Promise.resolve() : drainVaultQuota(path2);
|
|
18546
|
+
})();
|
|
18547
|
+
}
|
|
18548
|
+
function fields(publication2) {
|
|
18549
|
+
const result = new Map;
|
|
18550
|
+
const { observation } = publication2;
|
|
18551
|
+
const witness = JSON.stringify([
|
|
18552
|
+
publication2.routeId,
|
|
18553
|
+
publication2.receipt?.credentialId,
|
|
18554
|
+
publication2.receipt?.accountIdentitySource,
|
|
18555
|
+
publication2.receipt?.expectedAccountIdentity
|
|
18556
|
+
]);
|
|
18557
|
+
const add = (key, at, part) => result.set(`${witness}:${key}`, {
|
|
18558
|
+
at,
|
|
18559
|
+
order: 0,
|
|
18560
|
+
publication: { ...publication2, observation: part }
|
|
18561
|
+
});
|
|
18562
|
+
const keyFor = (scope, label) => JSON.stringify([scope ?? "all", label]);
|
|
18563
|
+
const read = new Set;
|
|
18564
|
+
for (const reading2 of observation.readings ?? []) {
|
|
18565
|
+
const key = keyFor(reading2.scope, reading2.label);
|
|
18566
|
+
read.add(key);
|
|
18567
|
+
add(key, observation.checkedAt, {
|
|
18568
|
+
checkedAt: observation.checkedAt,
|
|
18569
|
+
readings: [{ ...reading2 }]
|
|
18570
|
+
});
|
|
18571
|
+
}
|
|
18572
|
+
for (const pair of observation.coverage ?? []) {
|
|
18573
|
+
const key = keyFor(pair.scope, pair.label);
|
|
18574
|
+
if (!read.has(key))
|
|
18575
|
+
add(key, observation.checkedAt, {
|
|
18576
|
+
checkedAt: observation.checkedAt,
|
|
18577
|
+
coverage: [{ ...pair }]
|
|
18578
|
+
});
|
|
18579
|
+
}
|
|
18580
|
+
if (observation.budget)
|
|
18581
|
+
add("budget", observation.checkedAt, {
|
|
18582
|
+
checkedAt: observation.checkedAt,
|
|
18583
|
+
budget: { ...observation.budget }
|
|
18584
|
+
});
|
|
18585
|
+
for (const [name, counter2] of Object.entries(observation.counters ?? {})) {
|
|
18586
|
+
add(`counter:${name}`, counter2.checkedAt, {
|
|
18587
|
+
checkedAt: observation.checkedAt,
|
|
18588
|
+
counters: { [name]: { ...counter2 } }
|
|
18589
|
+
});
|
|
18590
|
+
}
|
|
18591
|
+
if (observation.credits)
|
|
18592
|
+
add("credits", observation.credits.checkedAt, {
|
|
18593
|
+
checkedAt: observation.checkedAt,
|
|
18594
|
+
credits: { ...observation.credits }
|
|
18595
|
+
});
|
|
18596
|
+
if (!result.size)
|
|
18597
|
+
add("empty", observation.checkedAt, { checkedAt: observation.checkedAt });
|
|
18598
|
+
return result;
|
|
18599
|
+
}
|
|
18600
|
+
function enqueueVaultQuota(path2, publication2) {
|
|
18601
|
+
if (!isQuotaObservation(publication2.observation))
|
|
18602
|
+
return Promise.resolve(false);
|
|
18603
|
+
const writer = writerFor(path2);
|
|
18604
|
+
const account = JSON.stringify([
|
|
18605
|
+
publication2.accountIdentity ?? null,
|
|
18606
|
+
publication2.accountIdentity === undefined ? publication2.routeId : null
|
|
18607
|
+
]);
|
|
18608
|
+
const pending = writer.pending.get(account) ?? new Map;
|
|
18609
|
+
for (const [key, field] of fields(publication2)) {
|
|
18610
|
+
const previous = pending.get(key);
|
|
18611
|
+
if (!previous || field.at >= previous.at) {
|
|
18612
|
+
field.order = ++writer.order;
|
|
18613
|
+
if (field.publication.observation.coverage)
|
|
18614
|
+
field.priorReading = previous?.publication.observation.readings ? previous.publication : previous?.priorReading;
|
|
18615
|
+
pending.set(key, field);
|
|
18616
|
+
}
|
|
18617
|
+
}
|
|
18618
|
+
if (pending.size)
|
|
18619
|
+
writer.pending.set(account, pending);
|
|
18620
|
+
for (const listener of writer.listeners)
|
|
18621
|
+
listener(publication2);
|
|
18622
|
+
schedule(writer, COALESCE_MS);
|
|
18623
|
+
return Promise.resolve(true);
|
|
18624
|
+
}
|
|
18625
|
+
function orderedFields(pending) {
|
|
18626
|
+
return [...pending.values()].flatMap((account) => [...account.values()]).sort((a, b) => a.order - b.order);
|
|
18627
|
+
}
|
|
18628
|
+
function pendingVaultQuota(path2, roster) {
|
|
18629
|
+
const writer = writers.get(resolve8(path2));
|
|
18630
|
+
if (writer) {
|
|
18631
|
+
for (const field of orderedFields(writer.pending)) {
|
|
18632
|
+
if (field.priorReading)
|
|
18633
|
+
roster = applyVaultQuota(roster, field.priorReading).roster;
|
|
18634
|
+
roster = applyVaultQuota(roster, field.publication).roster;
|
|
18635
|
+
}
|
|
18636
|
+
}
|
|
18637
|
+
return roster;
|
|
18638
|
+
}
|
|
18639
|
+
function schedule(writer, delay3) {
|
|
18640
|
+
if (writer.running || writer.timer || !writer.pending.size || writer.abort.signal.aborted)
|
|
18641
|
+
return;
|
|
18642
|
+
writer.timer = setTimeout(() => {
|
|
18643
|
+
writer.timer = undefined;
|
|
18644
|
+
flush2(writer);
|
|
18645
|
+
}, delay3);
|
|
18646
|
+
if (!writer.draining)
|
|
18647
|
+
writer.timer.unref?.();
|
|
18648
|
+
}
|
|
18649
|
+
function flush2(writer) {
|
|
18650
|
+
if (writer.running || writer.abort.signal.aborted)
|
|
18651
|
+
return;
|
|
18652
|
+
const batch = new Map([...writer.pending].map(([account, pending]) => [
|
|
18653
|
+
account,
|
|
18654
|
+
new Map(pending)
|
|
18655
|
+
]));
|
|
18656
|
+
writer.running = (async () => {
|
|
18657
|
+
try {
|
|
18658
|
+
await mutateVaultRoster(writer.path, (current) => {
|
|
18659
|
+
let next = current;
|
|
18660
|
+
for (const field of orderedFields(batch)) {
|
|
18661
|
+
if (field.priorReading)
|
|
18662
|
+
next = applyVaultQuota(next, field.priorReading).roster;
|
|
18663
|
+
next = applyVaultQuota(next, field.publication).roster;
|
|
18664
|
+
}
|
|
18665
|
+
return { ...next !== current && { next }, result: undefined };
|
|
18666
|
+
}, { signal: writer.abort.signal });
|
|
18667
|
+
for (const [account, fields2] of batch) {
|
|
18668
|
+
const pending = writer.pending.get(account);
|
|
18669
|
+
for (const [key, field] of fields2) {
|
|
18670
|
+
if (pending?.get(key) === field)
|
|
18671
|
+
pending.delete(key);
|
|
18672
|
+
}
|
|
18673
|
+
if (!pending?.size)
|
|
18674
|
+
writer.pending.delete(account);
|
|
18675
|
+
}
|
|
18676
|
+
writer.failures = 0;
|
|
18677
|
+
} catch (error) {
|
|
18678
|
+
if (!writer.abort.signal.aborted && writer.failures++ === 0) {
|
|
18679
|
+
logger2.warn("vault quota publication delayed; retrying", {
|
|
18680
|
+
error: error instanceof Error ? error.message : String(error)
|
|
18681
|
+
});
|
|
18682
|
+
}
|
|
18683
|
+
} finally {
|
|
18684
|
+
writer.running = undefined;
|
|
18685
|
+
for (const wake of writer.wake)
|
|
18686
|
+
wake();
|
|
18687
|
+
const backoff = writer.failures ? Math.min(5000, 100 * 2 ** Math.min(writer.failures, 6)) * (0.5 + Math.random()) : COALESCE_MS;
|
|
18688
|
+
schedule(writer, backoff);
|
|
18689
|
+
}
|
|
18690
|
+
})();
|
|
18691
|
+
}
|
|
18692
|
+
async function drainVaultQuota(path2, timeoutMs = 1000) {
|
|
18693
|
+
const key = resolve8(path2);
|
|
18694
|
+
const writer = writers.get(key);
|
|
18695
|
+
if (!writer)
|
|
18696
|
+
return;
|
|
18697
|
+
writer.draining = true;
|
|
18698
|
+
clearTimeout(writer.timer);
|
|
18699
|
+
writer.timer = undefined;
|
|
18700
|
+
let deadline;
|
|
18701
|
+
let wake;
|
|
18702
|
+
const drained = new Promise((done) => {
|
|
18703
|
+
wake = () => {
|
|
18704
|
+
if (!writer.pending.size || writer.abort.signal.aborted)
|
|
18705
|
+
done();
|
|
18706
|
+
};
|
|
18707
|
+
writer.wake.add(wake);
|
|
18708
|
+
wake();
|
|
18709
|
+
});
|
|
18710
|
+
try {
|
|
18711
|
+
if (writer.pending.size)
|
|
18712
|
+
flush2(writer);
|
|
18713
|
+
await Promise.race([
|
|
18714
|
+
drained,
|
|
18715
|
+
new Promise((done) => {
|
|
18716
|
+
deadline = setTimeout(done, Math.max(0, timeoutMs));
|
|
18717
|
+
})
|
|
18718
|
+
]);
|
|
18719
|
+
} finally {
|
|
18720
|
+
clearTimeout(deadline);
|
|
18721
|
+
if (wake)
|
|
18722
|
+
writer.wake.delete(wake);
|
|
18723
|
+
writer.draining = false;
|
|
18724
|
+
if (!writer.listeners.size) {
|
|
18725
|
+
writer.abort.abort();
|
|
18726
|
+
clearTimeout(writer.timer);
|
|
18727
|
+
writer.pending.clear();
|
|
18728
|
+
if (writers.get(key) === writer)
|
|
18729
|
+
writers.delete(key);
|
|
18730
|
+
}
|
|
18731
|
+
}
|
|
18732
|
+
}
|
|
18733
|
+
|
|
18161
18734
|
// ../../node_modules/@cortexkit/common-auth/dist/claustrum/consumer.js
|
|
18162
18735
|
class ClaustrumConsumer {
|
|
18163
18736
|
#options;
|
|
@@ -18175,9 +18748,13 @@ class ClaustrumConsumer {
|
|
|
18175
18748
|
#releaseInsulaWatch;
|
|
18176
18749
|
#insulaSkips = new Map;
|
|
18177
18750
|
#discoveredAt;
|
|
18751
|
+
#releaseQuotaWriter;
|
|
18178
18752
|
constructor(options) {
|
|
18179
18753
|
this.#options = options;
|
|
18180
18754
|
this.#logger = options.logger ?? createLogger("claustrum");
|
|
18755
|
+
this.#releaseQuotaWriter = retainVaultQuotaWriter(options.rosterPath, (publication2) => {
|
|
18756
|
+
this.#roster = applyVaultQuota(this.#roster, publication2).roster;
|
|
18757
|
+
});
|
|
18181
18758
|
}
|
|
18182
18759
|
#assertOpen(signal) {
|
|
18183
18760
|
this.#shutdown.signal.throwIfAborted();
|
|
@@ -18191,7 +18768,7 @@ class ClaustrumConsumer {
|
|
|
18191
18768
|
this.#shutdown.signal,
|
|
18192
18769
|
...signal ? [signal] : []
|
|
18193
18770
|
]);
|
|
18194
|
-
return new Promise((
|
|
18771
|
+
return new Promise((resolve9, reject) => {
|
|
18195
18772
|
const cleanup2 = () => {
|
|
18196
18773
|
combined.signal.removeEventListener("abort", abort);
|
|
18197
18774
|
combined.dispose();
|
|
@@ -18206,7 +18783,7 @@ class ClaustrumConsumer {
|
|
|
18206
18783
|
if (combined.signal.aborted)
|
|
18207
18784
|
reject(combined.signal.reason);
|
|
18208
18785
|
else
|
|
18209
|
-
|
|
18786
|
+
resolve9(value);
|
|
18210
18787
|
}, (error) => {
|
|
18211
18788
|
cleanup2();
|
|
18212
18789
|
reject(error);
|
|
@@ -18292,11 +18869,9 @@ class ClaustrumConsumer {
|
|
|
18292
18869
|
let discovered;
|
|
18293
18870
|
const roster = await refreshVaultRoster({
|
|
18294
18871
|
path: this.#options.rosterPath,
|
|
18295
|
-
custody
|
|
18296
|
-
|
|
18297
|
-
|
|
18298
|
-
return discovered;
|
|
18299
|
-
}
|
|
18872
|
+
custody,
|
|
18873
|
+
onInventory: (inventory) => {
|
|
18874
|
+
discovered = inventory;
|
|
18300
18875
|
},
|
|
18301
18876
|
isActive: () => this.#active(),
|
|
18302
18877
|
signal: this.#shutdown.signal,
|
|
@@ -18309,7 +18884,7 @@ class ClaustrumConsumer {
|
|
|
18309
18884
|
});
|
|
18310
18885
|
this.#assertOpen();
|
|
18311
18886
|
const changed = roster?.view !== this.#roster?.view;
|
|
18312
|
-
this.#roster = roster;
|
|
18887
|
+
this.#roster = pendingVaultQuota(this.#options.rosterPath, roster);
|
|
18313
18888
|
custody.retain(roster?.rows ?? []);
|
|
18314
18889
|
if (discovered && roster?.view !== undefined)
|
|
18315
18890
|
this.#grantReach = discovered.grantReach ? { view: roster.view, reach: discovered.grantReach } : undefined;
|
|
@@ -18406,7 +18981,7 @@ class ClaustrumConsumer {
|
|
|
18406
18981
|
return;
|
|
18407
18982
|
try {
|
|
18408
18983
|
await readClaustrumEnrollmentToken(this.#options.tokenPath);
|
|
18409
|
-
const roster = await readVaultRoster(this.#options.rosterPath);
|
|
18984
|
+
const roster = pendingVaultQuota(this.#options.rosterPath, await readVaultRoster(this.#options.rosterPath));
|
|
18410
18985
|
const row = roster?.rows.find((entry2) => entry2.routeId === routeId);
|
|
18411
18986
|
return this.#normalizeInsulaQuota(row?.accountIdentity);
|
|
18412
18987
|
} catch {
|
|
@@ -18419,7 +18994,7 @@ class ClaustrumConsumer {
|
|
|
18419
18994
|
return { miss: "unreachable" };
|
|
18420
18995
|
try {
|
|
18421
18996
|
await readClaustrumEnrollmentToken(this.#options.tokenPath);
|
|
18422
|
-
const roster = await readVaultRoster(this.#options.rosterPath);
|
|
18997
|
+
const roster = pendingVaultQuota(this.#options.rosterPath, await readVaultRoster(this.#options.rosterPath));
|
|
18423
18998
|
const account = roster?.rows.find((row) => row.routeId === routeId)?.accountIdentity;
|
|
18424
18999
|
if (!account || !this.#insula)
|
|
18425
19000
|
return { miss: "unreachable" };
|
|
@@ -18463,7 +19038,7 @@ class ClaustrumConsumer {
|
|
|
18463
19038
|
this.#insula = undefined;
|
|
18464
19039
|
throw new ClaustrumConsumerError("not-active", "Claustrum scoped custody is not active");
|
|
18465
19040
|
}
|
|
18466
|
-
const current = await readVaultRoster(this.#options.rosterPath);
|
|
19041
|
+
const current = pendingVaultQuota(this.#options.rosterPath, await readVaultRoster(this.#options.rosterPath));
|
|
18467
19042
|
this.#assertOpen(signal);
|
|
18468
19043
|
const observed = roster.rows.find((row) => row.routeId === routeId);
|
|
18469
19044
|
const configured = current?.rows.find((row) => row.routeId === routeId);
|
|
@@ -18531,17 +19106,17 @@ class ClaustrumConsumer {
|
|
|
18531
19106
|
async decline(routeId) {
|
|
18532
19107
|
this.#assertOpen();
|
|
18533
19108
|
await declineVaultRoute(this.#options.rosterPath, routeId);
|
|
18534
|
-
this.#roster = await readVaultRoster(this.#options.rosterPath);
|
|
19109
|
+
this.#roster = pendingVaultQuota(this.#options.rosterPath, await readVaultRoster(this.#options.rosterPath));
|
|
18535
19110
|
this.#custody?.retain(this.#roster?.rows ?? []);
|
|
18536
19111
|
}
|
|
18537
19112
|
async accept(routeId) {
|
|
18538
19113
|
this.#assertOpen();
|
|
18539
19114
|
await acceptVaultRoute(this.#options.rosterPath, routeId);
|
|
18540
|
-
this.#roster = await readVaultRoster(this.#options.rosterPath);
|
|
19115
|
+
this.#roster = pendingVaultQuota(this.#options.rosterPath, await readVaultRoster(this.#options.rosterPath));
|
|
18541
19116
|
}
|
|
18542
19117
|
async recordQuota(routeId, observation, attempt) {
|
|
18543
19118
|
this.#assertOpen();
|
|
18544
|
-
|
|
19119
|
+
return recordVaultQuota(this.#options.rosterPath, {
|
|
18545
19120
|
routeId,
|
|
18546
19121
|
observation,
|
|
18547
19122
|
credentialId: attempt.credentialId,
|
|
@@ -18553,20 +19128,14 @@ class ClaustrumConsumer {
|
|
|
18553
19128
|
expectedAccountIdentity: attempt.expectedAccountIdentity
|
|
18554
19129
|
}
|
|
18555
19130
|
});
|
|
18556
|
-
if (kept)
|
|
18557
|
-
this.#roster = await readVaultRoster(this.#options.rosterPath);
|
|
18558
|
-
return kept;
|
|
18559
19131
|
}
|
|
18560
19132
|
async recordAccountQuota(routeId, accountIdentity, observation) {
|
|
18561
19133
|
this.#assertOpen();
|
|
18562
|
-
|
|
19134
|
+
return recordVaultAccountQuota(this.#options.rosterPath, {
|
|
18563
19135
|
routeId,
|
|
18564
19136
|
accountIdentity,
|
|
18565
19137
|
observation
|
|
18566
19138
|
});
|
|
18567
|
-
if (kept)
|
|
18568
|
-
this.#roster = await readVaultRoster(this.#options.rosterPath);
|
|
18569
|
-
return kept;
|
|
18570
19139
|
}
|
|
18571
19140
|
close() {
|
|
18572
19141
|
if (this.#shutdown.signal.aborted)
|
|
@@ -18581,6 +19150,12 @@ class ClaustrumConsumer {
|
|
|
18581
19150
|
this.#insula = undefined;
|
|
18582
19151
|
this.#roster = undefined;
|
|
18583
19152
|
this.#grantReach = undefined;
|
|
19153
|
+
this.#releaseQuotaWriter();
|
|
19154
|
+
forgetPendingVaultDiscovery(this.#options.rosterPath);
|
|
19155
|
+
}
|
|
19156
|
+
async dispose() {
|
|
19157
|
+
this.close();
|
|
19158
|
+
await this.#releaseQuotaWriter();
|
|
18584
19159
|
}
|
|
18585
19160
|
}
|
|
18586
19161
|
|
|
@@ -18621,16 +19196,16 @@ function nativeCode(value) {
|
|
|
18621
19196
|
class NativeCustodyError extends Error {
|
|
18622
19197
|
code;
|
|
18623
19198
|
constructor(code) {
|
|
18624
|
-
const
|
|
18625
|
-
super(`Native custody refused: ${
|
|
19199
|
+
const safeCode2 = nativeCode(code);
|
|
19200
|
+
super(`Native custody refused: ${safeCode2}`);
|
|
18626
19201
|
this.name = "NativeCustodyError";
|
|
18627
|
-
this.code =
|
|
19202
|
+
this.code = safeCode2;
|
|
18628
19203
|
}
|
|
18629
19204
|
}
|
|
18630
19205
|
function createNativeCustody(options) {
|
|
18631
19206
|
const env = { ...options.env ?? process.env };
|
|
18632
19207
|
const connect = options.connect;
|
|
18633
|
-
const
|
|
19208
|
+
const logger3 = options.logger;
|
|
18634
19209
|
let closed = false;
|
|
18635
19210
|
let revoked = false;
|
|
18636
19211
|
let client;
|
|
@@ -18677,8 +19252,8 @@ function createNativeCustody(options) {
|
|
|
18677
19252
|
let stopped = false;
|
|
18678
19253
|
let inner;
|
|
18679
19254
|
let finish = () => {};
|
|
18680
|
-
const ended = new Promise((
|
|
18681
|
-
finish =
|
|
19255
|
+
const ended = new Promise((resolve9) => {
|
|
19256
|
+
finish = resolve9;
|
|
18682
19257
|
});
|
|
18683
19258
|
const failed = (error) => stopped || closed || error instanceof NativeCustodyError ? { kind: "stopped" } : classifyVaultFailure(error) === "unreachable" ? { kind: "transport_lost", error: new ClaustrumUnreachableError } : { kind: "ended" };
|
|
18684
19259
|
Promise.resolve().then(connection).then((owned) => {
|
|
@@ -18727,8 +19302,8 @@ function createNativeCustody(options) {
|
|
|
18727
19302
|
...options.setTimeout && { setTimeoutImpl: options.setTimeout },
|
|
18728
19303
|
...options.clearTimeout && { clearTimeoutImpl: options.clearTimeout },
|
|
18729
19304
|
logger: {
|
|
18730
|
-
warn: () =>
|
|
18731
|
-
debug: () =>
|
|
19305
|
+
warn: () => logger3?.warn("Native custody inventory record skipped"),
|
|
19306
|
+
debug: () => logger3?.debug("Native custody failure reported")
|
|
18732
19307
|
}
|
|
18733
19308
|
});
|
|
18734
19309
|
async function run(operation, signal) {
|
|
@@ -18852,13 +19427,13 @@ function createNativeCustody(options) {
|
|
|
18852
19427
|
}
|
|
18853
19428
|
|
|
18854
19429
|
// src/native-vault-invalidation.ts
|
|
18855
|
-
import { resolve as
|
|
19430
|
+
import { resolve as resolve9 } from "node:path";
|
|
18856
19431
|
var holders = new Set;
|
|
18857
19432
|
function watchNativeVaultAuthority(holder) {
|
|
18858
19433
|
const held = {
|
|
18859
19434
|
...holder,
|
|
18860
|
-
roster:
|
|
18861
|
-
tokenPath:
|
|
19435
|
+
roster: resolve9(holder.roster),
|
|
19436
|
+
tokenPath: resolve9(holder.tokenPath)
|
|
18862
19437
|
};
|
|
18863
19438
|
holders.add(held);
|
|
18864
19439
|
return () => {
|
|
@@ -18867,12 +19442,12 @@ function watchNativeVaultAuthority(holder) {
|
|
|
18867
19442
|
}
|
|
18868
19443
|
function retainNativeVaultRoster(path2, roster) {
|
|
18869
19444
|
for (const holder of holders)
|
|
18870
|
-
if (holder.roster ===
|
|
19445
|
+
if (holder.roster === resolve9(path2))
|
|
18871
19446
|
holder.retain(roster);
|
|
18872
19447
|
}
|
|
18873
19448
|
function closeNativeVaultAuthority(tokenPath) {
|
|
18874
19449
|
for (const holder of holders)
|
|
18875
|
-
if (holder.tokenPath ===
|
|
19450
|
+
if (holder.tokenPath === resolve9(tokenPath))
|
|
18876
19451
|
holder.close();
|
|
18877
19452
|
}
|
|
18878
19453
|
|
|
@@ -18906,9 +19481,18 @@ var reasons = new Set([
|
|
|
18906
19481
|
"ETIMEDOUT",
|
|
18907
19482
|
"ERR_PRIVATE_FILES_SECURITY"
|
|
18908
19483
|
]);
|
|
19484
|
+
var addonUnavailable = new Set([
|
|
19485
|
+
"ERR_PRIVATE_FILES_UNAVAILABLE",
|
|
19486
|
+
"native-addon-unavailable"
|
|
19487
|
+
]);
|
|
19488
|
+
var privateFilesUnavailableReasons = new Set([
|
|
19489
|
+
"unsupported-filesystem",
|
|
19490
|
+
"native-addon-unavailable"
|
|
19491
|
+
]);
|
|
18909
19492
|
async function logRefusal(host, paths, readStatus) {
|
|
18910
19493
|
let stage = "enrollment";
|
|
18911
19494
|
let reason = "unreadable";
|
|
19495
|
+
let unavailable = false;
|
|
18912
19496
|
try {
|
|
18913
19497
|
await readStatus(paths, `anthropic-auth-${host}`);
|
|
18914
19498
|
} catch (error) {
|
|
@@ -18917,17 +19501,31 @@ async function logRefusal(host, paths, readStatus) {
|
|
|
18917
19501
|
const detail = current;
|
|
18918
19502
|
if (detail.stage && stages.has(detail.stage))
|
|
18919
19503
|
stage = detail.stage;
|
|
18920
|
-
for (const value of [detail.kind, detail.code, detail.reason])
|
|
19504
|
+
for (const value of [detail.kind, detail.code, detail.reason]) {
|
|
18921
19505
|
if (value && reasons.has(value))
|
|
18922
19506
|
reason = value;
|
|
19507
|
+
if (value && addonUnavailable.has(value))
|
|
19508
|
+
unavailable = true;
|
|
19509
|
+
}
|
|
18923
19510
|
current = detail.cause;
|
|
18924
19511
|
}
|
|
18925
19512
|
}
|
|
19513
|
+
if (unavailable)
|
|
19514
|
+
reason = "native-addon-unavailable";
|
|
18926
19515
|
logger.warn("enrollment", "Native enrollment authority refused", {
|
|
18927
19516
|
host,
|
|
18928
19517
|
stage,
|
|
18929
19518
|
reason
|
|
18930
19519
|
});
|
|
19520
|
+
return reason;
|
|
19521
|
+
}
|
|
19522
|
+
var PRIVATE_FILES_UNAVAILABLE_MESSAGE = "Private file support didn't load on this machine (@cortexkit/private-files). Reinstall the plugin; if this persists, report it with your OS and Node version.";
|
|
19523
|
+
|
|
19524
|
+
class NativePrivateFilesUnavailableError extends NativeCustodyError {
|
|
19525
|
+
constructor() {
|
|
19526
|
+
super("invalid-token");
|
|
19527
|
+
this.message = PRIVATE_FILES_UNAVAILABLE_MESSAGE;
|
|
19528
|
+
}
|
|
18931
19529
|
}
|
|
18932
19530
|
async function readNativeEnrollmentMode(host, env = process.env, dependencies = { enrollmentAuthority, readClaustrumEnrollmentStatus }) {
|
|
18933
19531
|
const paths = getHostClaustrumEnrollmentPaths(host, env);
|
|
@@ -18935,7 +19533,9 @@ async function readNativeEnrollmentMode(host, env = process.env, dependencies =
|
|
|
18935
19533
|
if (authority !== "vault")
|
|
18936
19534
|
closeNativeVaultAuthority(getHostClaustrumEnrollmentPaths(host, env).tokenPath);
|
|
18937
19535
|
if (authority === "unreadable") {
|
|
18938
|
-
await logRefusal(host, paths, dependencies.readClaustrumEnrollmentStatus);
|
|
19536
|
+
const reason = await logRefusal(host, paths, dependencies.readClaustrumEnrollmentStatus);
|
|
19537
|
+
if (privateFilesUnavailableReasons.has(reason))
|
|
19538
|
+
throw new NativePrivateFilesUnavailableError;
|
|
18939
19539
|
throw new NativeCustodyError("invalid-token");
|
|
18940
19540
|
}
|
|
18941
19541
|
return authority === "vault" ? "claustrum" : "local";
|
|
@@ -19118,12 +19718,12 @@ async function joinNativePoolWrite(paths, signals, check, onLockEvent) {
|
|
|
19118
19718
|
function pause(ms, signals) {
|
|
19119
19719
|
if (signals.some((signal) => signal.aborted))
|
|
19120
19720
|
return Promise.resolve();
|
|
19121
|
-
return new Promise((
|
|
19721
|
+
return new Promise((resolve10) => {
|
|
19122
19722
|
const wake = () => {
|
|
19123
19723
|
clearTimeout(timer);
|
|
19124
19724
|
for (const signal of signals)
|
|
19125
19725
|
signal.removeEventListener("abort", wake);
|
|
19126
|
-
|
|
19726
|
+
resolve10();
|
|
19127
19727
|
};
|
|
19128
19728
|
const timer = setTimeout(wake, ms);
|
|
19129
19729
|
for (const signal of signals)
|
|
@@ -19379,7 +19979,7 @@ function createNativeRefreshCoordinator(options) {
|
|
|
19379
19979
|
name: spec.name,
|
|
19380
19980
|
timeoutMs: POOL_LOCK_DEFAULTS.timeoutMs
|
|
19381
19981
|
});
|
|
19382
|
-
await new Promise((
|
|
19982
|
+
await new Promise((resolve10) => setTimeout(resolve10, Math.min(POOL_LOCK_DEFAULTS.retryMs, remaining)));
|
|
19383
19983
|
}
|
|
19384
19984
|
}
|
|
19385
19985
|
async function run(job, request) {
|
|
@@ -19949,7 +20549,7 @@ class NativeMigrationSourceError extends Error {
|
|
|
19949
20549
|
}
|
|
19950
20550
|
}
|
|
19951
20551
|
var MAX_SOURCE_BYTES = 4 * 1024 * 1024;
|
|
19952
|
-
function
|
|
20552
|
+
function isRecord10(value) {
|
|
19953
20553
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
19954
20554
|
}
|
|
19955
20555
|
function freezeJson(root) {
|
|
@@ -20029,7 +20629,7 @@ async function readNativeMigrationSource(role, path2, hooks = {}) {
|
|
|
20029
20629
|
} catch {
|
|
20030
20630
|
throw new NativeMigrationSourceError(role, "invalid-source");
|
|
20031
20631
|
}
|
|
20032
|
-
if (!
|
|
20632
|
+
if (!isRecord10(data))
|
|
20033
20633
|
throw new NativeMigrationSourceError(role, "invalid-source");
|
|
20034
20634
|
return sourceSnapshot({
|
|
20035
20635
|
role,
|
|
@@ -20081,7 +20681,7 @@ class NativeAuthorityError extends Error {
|
|
|
20081
20681
|
code;
|
|
20082
20682
|
constructor(code) {
|
|
20083
20683
|
super({
|
|
20084
|
-
"migration-required": "Anthropic account migration is required. Stop OpenCode, LiteCode and Pi, then run npx @cortexkit/opencode-anthropic-auth
|
|
20684
|
+
"migration-required": "Anthropic account migration is required. Stop OpenCode, LiteCode and Pi, then run npx @cortexkit/opencode-anthropic-auth setup",
|
|
20085
20685
|
"migration-incomplete": "Anthropic account migration is incomplete; resume setup",
|
|
20086
20686
|
"invalid-journal": "Anthropic account migration journal is invalid",
|
|
20087
20687
|
"journal-conflict": "Anthropic account migration journal changed"
|
|
@@ -20090,7 +20690,7 @@ class NativeAuthorityError extends Error {
|
|
|
20090
20690
|
this.name = "NativeAuthorityError";
|
|
20091
20691
|
}
|
|
20092
20692
|
}
|
|
20093
|
-
function
|
|
20693
|
+
function isRecord11(value) {
|
|
20094
20694
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
20095
20695
|
}
|
|
20096
20696
|
function captureJournalJson(value) {
|
|
@@ -20126,19 +20726,19 @@ function isCapturedPath(value) {
|
|
|
20126
20726
|
return typeof value === "string" && isAbsolute4(value) && !/\p{Cc}/u.test(value) && !value.endsWith(sep) && normalize(value) === value && (sep !== "\\" || parse3(value).root !== sep) && !value.split(sep).some((part) => part === "." || part === "..");
|
|
20127
20727
|
}
|
|
20128
20728
|
function isSources(value) {
|
|
20129
|
-
return
|
|
20729
|
+
return isRecord11(value) && hasKeys(value, ["config", "state", "hostAuth", "routing"]) && isFileDigest(value.config) && isFileDigest(value.state) && isHostEntry(value.hostAuth) && isFileDigest(value.routing);
|
|
20130
20730
|
}
|
|
20131
20731
|
function isRoutingPaths(value) {
|
|
20132
|
-
return
|
|
20732
|
+
return isRecord11(value) && hasKeys(value, ["source", "destination"]) && isCapturedPath(value.source) && isCapturedPath(value.destination);
|
|
20133
20733
|
}
|
|
20134
20734
|
function isText(value) {
|
|
20135
20735
|
return typeof value === "string" && value.length > 0;
|
|
20136
20736
|
}
|
|
20137
20737
|
function decodeRoster2(value) {
|
|
20138
|
-
if (!
|
|
20738
|
+
if (!isRecord11(value) || !hasKeys(value, ["version", "view", "complete", "rows", "declined"]) || value.version !== 1 || !isText(value.view) || value.complete !== true || !Array.isArray(value.rows) || !Array.isArray(value.declined))
|
|
20139
20739
|
throw new NativeAuthorityError("invalid-journal");
|
|
20140
20740
|
const rows = value.rows.map((row) => {
|
|
20141
|
-
if (!
|
|
20741
|
+
if (!isRecord11(row) || !hasKeys(row, [
|
|
20142
20742
|
"routeId",
|
|
20143
20743
|
"credentialId",
|
|
20144
20744
|
"credentialType",
|
|
@@ -20161,7 +20761,7 @@ function decodeRoster2(value) {
|
|
|
20161
20761
|
};
|
|
20162
20762
|
});
|
|
20163
20763
|
const declined = value.declined.map((entry2) => {
|
|
20164
|
-
if (!
|
|
20764
|
+
if (!isRecord11(entry2) || !isText(entry2.credentialId) || !(hasKeys(entry2, ["credentialId"]) || hasKeys(entry2, ["credentialId", "accountIdentity"]) && isText(entry2.accountIdentity)))
|
|
20165
20765
|
throw new NativeAuthorityError("invalid-journal");
|
|
20166
20766
|
return isText(entry2.accountIdentity) ? {
|
|
20167
20767
|
credentialId: entry2.credentialId,
|
|
@@ -20173,7 +20773,7 @@ function decodeRoster2(value) {
|
|
|
20173
20773
|
return { version: 1, view: value.view, complete: true, rows, declined };
|
|
20174
20774
|
}
|
|
20175
20775
|
function decodeDigestPair(value, keys4, valid) {
|
|
20176
|
-
if (!
|
|
20776
|
+
if (!isRecord11(value) || !hasKeys(value, [...keys4]) || !keys4.every((key) => valid(value[key])))
|
|
20177
20777
|
throw new NativeAuthorityError("invalid-journal");
|
|
20178
20778
|
return Object.fromEntries(keys4.map((key) => [key, value[key]]));
|
|
20179
20779
|
}
|
|
@@ -20181,7 +20781,7 @@ var ACTIVATION_PHASES = ["prepared", "published", "committed"];
|
|
|
20181
20781
|
function decodeActivation(value, phase) {
|
|
20182
20782
|
if (value === null)
|
|
20183
20783
|
return null;
|
|
20184
|
-
if (!
|
|
20784
|
+
if (!isRecord11(value))
|
|
20185
20785
|
throw new NativeAuthorityError("invalid-journal");
|
|
20186
20786
|
if (value.kind === "requested" && hasKeys(value, ["kind"]))
|
|
20187
20787
|
return { kind: "requested" };
|
|
@@ -20195,7 +20795,7 @@ function decodeActivation(value, phase) {
|
|
|
20195
20795
|
"settings",
|
|
20196
20796
|
"runtime",
|
|
20197
20797
|
"hostAuth"
|
|
20198
|
-
]) || !ACTIVATION_PHASES.some((item) => item === value.phase) || !
|
|
20798
|
+
]) || !ACTIVATION_PHASES.some((item) => item === value.phase) || !isRecord11(value.primary) || !hasKeys(value.primary, ["routeId", "credentialId", "accountIdentity"]) || !isText(value.primary.routeId) || !isText(value.primary.credentialId) || !isText(value.primary.accountIdentity) || !Array.isArray(value.removeIds) || !value.removeIds.every(isText))
|
|
20199
20799
|
throw new NativeAuthorityError("invalid-journal");
|
|
20200
20800
|
const primary = {
|
|
20201
20801
|
routeId: value.primary.routeId,
|
|
@@ -20222,7 +20822,7 @@ function decodeActivation(value, phase) {
|
|
|
20222
20822
|
}
|
|
20223
20823
|
function decodeJournal(input, storageId) {
|
|
20224
20824
|
const value = captureJournalJson(input);
|
|
20225
|
-
if (!
|
|
20825
|
+
if (!isRecord11(value) || value.storageId !== storageId)
|
|
20226
20826
|
throw new NativeAuthorityError("invalid-journal");
|
|
20227
20827
|
if (value.version === 5 && value.kind === "empty-init") {
|
|
20228
20828
|
if (!hasKeys(value, ["version", "kind", "storageId", "host", "phase"]) || value.host !== "opencode" || value.phase !== "committed")
|
|
@@ -20398,7 +20998,7 @@ async function beginNativeMigration(paths, input, hooks = {}) {
|
|
|
20398
20998
|
}
|
|
20399
20999
|
async function recordNativeMigrationExpectations(paths, expectations, hooks = {}) {
|
|
20400
21000
|
const captured = captureJournalJson(expectations);
|
|
20401
|
-
if (!
|
|
21001
|
+
if (!isRecord11(captured) || !hasKeys(captured, [
|
|
20402
21002
|
"expectedHostAuth",
|
|
20403
21003
|
"expectedRouting",
|
|
20404
21004
|
"preparedProof"
|
|
@@ -20473,7 +21073,7 @@ function journalLock(hooks) {
|
|
|
20473
21073
|
}
|
|
20474
21074
|
async function recordNativeCustodyActivation(paths, plan, hooks = {}) {
|
|
20475
21075
|
const captured = captureJournalJson(plan);
|
|
20476
|
-
if (!
|
|
21076
|
+
if (!isRecord11(captured) || captured.phase !== "prepared")
|
|
20477
21077
|
throw new NativeAuthorityError("journal-conflict");
|
|
20478
21078
|
const decoded = decodeActivation(captured, "retired");
|
|
20479
21079
|
if (decoded?.kind !== "activation")
|
|
@@ -20819,7 +21419,7 @@ function createNativeUsagePublisher(channel) {
|
|
|
20819
21419
|
return {
|
|
20820
21420
|
observe,
|
|
20821
21421
|
publish(write) {
|
|
20822
|
-
observe(new Promise((
|
|
21422
|
+
observe(new Promise((resolve10) => setTimeout(resolve10, 0)).then(write));
|
|
20823
21423
|
},
|
|
20824
21424
|
async drain() {
|
|
20825
21425
|
while (pending.size)
|
|
@@ -20895,7 +21495,7 @@ class NativeQuotaObservations extends Map {
|
|
|
20895
21495
|
}
|
|
20896
21496
|
|
|
20897
21497
|
// src/native-runtime-registry.ts
|
|
20898
|
-
import { resolve as
|
|
21498
|
+
import { resolve as resolve10 } from "node:path";
|
|
20899
21499
|
var identities = new WeakMap;
|
|
20900
21500
|
var nextIdentity = 0;
|
|
20901
21501
|
function nativeRuntimeOptionIdentity(value) {
|
|
@@ -20924,14 +21524,14 @@ function nativeRuntimeStorageKey(options) {
|
|
|
20924
21524
|
"runtime",
|
|
20925
21525
|
"journal",
|
|
20926
21526
|
"roster"
|
|
20927
|
-
].map((field) =>
|
|
20928
|
-
|
|
20929
|
-
|
|
20930
|
-
|
|
21527
|
+
].map((field) => resolve10(paths[field])),
|
|
21528
|
+
resolve10(enrollment.tokenPath),
|
|
21529
|
+
resolve10(enrollment.statePath),
|
|
21530
|
+
resolve10(connection)
|
|
20931
21531
|
]);
|
|
20932
21532
|
}
|
|
20933
21533
|
function nativeRuntimeConnectionFile(host, env) {
|
|
20934
|
-
return
|
|
21534
|
+
return resolve10(resolveClaustrumConnectionPath(host === "pi" ? env.PI_ANTHROPIC_AUTH_CLAUSTRUM_CONNECTION_FILE : undefined, host === "pi" ? {
|
|
20935
21535
|
...env,
|
|
20936
21536
|
OPENCODE_ANTHROPIC_AUTH_CLAUSTRUM_CONNECTION_FILE: undefined
|
|
20937
21537
|
} : env));
|
|
@@ -20970,9 +21570,9 @@ class NativeRuntimeRegistry {
|
|
|
20970
21570
|
|
|
20971
21571
|
// src/native-vault-paths.ts
|
|
20972
21572
|
import { createHash as createHash15 } from "node:crypto";
|
|
20973
|
-
import { basename as basename5, dirname as dirname11, join as
|
|
21573
|
+
import { basename as basename5, dirname as dirname11, join as join13 } from "node:path";
|
|
20974
21574
|
function sibling(path2, expected, name, suffix) {
|
|
20975
|
-
return basename5(path2) === expected ?
|
|
21575
|
+
return basename5(path2) === expected ? join13(dirname11(path2), name) : path2.replace(/(?:\.json)?$/, `.${suffix}.json`);
|
|
20976
21576
|
}
|
|
20977
21577
|
function nativeVaultPaths(local) {
|
|
20978
21578
|
const config = sibling(local.legacyConfig, "anthropic-auth.json", "anthropic-auth-vault-settings.json", "vault-settings");
|
|
@@ -21185,10 +21785,10 @@ function seedCode(value) {
|
|
|
21185
21785
|
class NativeRosterSeedError extends Error {
|
|
21186
21786
|
code;
|
|
21187
21787
|
constructor(code) {
|
|
21188
|
-
const
|
|
21189
|
-
super(`Native roster seed refused: ${
|
|
21788
|
+
const safeCode2 = seedCode(code);
|
|
21789
|
+
super(`Native roster seed refused: ${safeCode2}`);
|
|
21190
21790
|
this.name = "NativeRosterSeedError";
|
|
21191
|
-
this.code =
|
|
21791
|
+
this.code = safeCode2;
|
|
21192
21792
|
}
|
|
21193
21793
|
}
|
|
21194
21794
|
function guarded(body) {
|
|
@@ -21533,8 +22133,8 @@ function mergeHeaderQuotaSnapshot(existing, incoming) {
|
|
|
21533
22133
|
// src/quota-manager.ts
|
|
21534
22134
|
var nativeSetTimeout = globalThis.setTimeout;
|
|
21535
22135
|
function pauseOnRealTimer(ms) {
|
|
21536
|
-
return new Promise((
|
|
21537
|
-
const id2 = nativeSetTimeout(
|
|
22136
|
+
return new Promise((resolve11) => {
|
|
22137
|
+
const id2 = nativeSetTimeout(resolve11, ms);
|
|
21538
22138
|
if (typeof id2 === "object" && "unref" in id2)
|
|
21539
22139
|
id2.unref();
|
|
21540
22140
|
});
|
|
@@ -22301,7 +22901,8 @@ async function publishNativeVaultRosterSeed(paths, input, options = {}) {
|
|
|
22301
22901
|
}
|
|
22302
22902
|
async function publishNativeVaultRuntimeSeed(paths, state, options = {}) {
|
|
22303
22903
|
const imported = decodeNativeRuntime(captureNativePlainData(state), paths.storageId);
|
|
22304
|
-
|
|
22904
|
+
const assertPinned = async () => {
|
|
22905
|
+
const roster = await readVaultRoster(paths.roster);
|
|
22305
22906
|
for (const [id2, entry2] of Object.entries(imported.accounts)) {
|
|
22306
22907
|
if (entry2.binding.kind !== "custody")
|
|
22307
22908
|
continue;
|
|
@@ -22310,13 +22911,13 @@ async function publishNativeVaultRuntimeSeed(paths, state, options = {}) {
|
|
|
22310
22911
|
if (!row?.accountIdentity || row.accountIdentity !== binding2.accountIdentity || row.credentialId !== binding2.credentialId && !row.aliases?.includes(binding2.credentialId))
|
|
22311
22912
|
throw new NativeRuntimeError("publication-refused");
|
|
22312
22913
|
}
|
|
22313
|
-
|
|
22314
|
-
|
|
22315
|
-
|
|
22316
|
-
|
|
22317
|
-
|
|
22318
|
-
|
|
22319
|
-
|
|
22914
|
+
};
|
|
22915
|
+
await assertPinned();
|
|
22916
|
+
await updateNativeRuntime(paths.runtime, paths.storageId, () => imported, {
|
|
22917
|
+
beforeRename: async () => {
|
|
22918
|
+
await options.assertOwned?.();
|
|
22919
|
+
await assertPinned();
|
|
22920
|
+
}
|
|
22320
22921
|
});
|
|
22321
22922
|
}
|
|
22322
22923
|
var NATIVE_VAULT_CONNECT_TIMEOUT_MS = 2000;
|
|
@@ -22363,11 +22964,6 @@ function createNativeVaultRuntime(options) {
|
|
|
22363
22964
|
onLockEvent: options.onLockEvent
|
|
22364
22965
|
});
|
|
22365
22966
|
const observeLock = nativeLockObserver(options.onLockEvent);
|
|
22366
|
-
const observeRosterLock = () => observeLock?.({
|
|
22367
|
-
type: "acquiring",
|
|
22368
|
-
name: "claustrum-roster-write",
|
|
22369
|
-
path: paths.roster
|
|
22370
|
-
});
|
|
22371
22967
|
let rosterWatch;
|
|
22372
22968
|
let rosterWatching = false;
|
|
22373
22969
|
let rosterView;
|
|
@@ -22584,46 +23180,49 @@ function createNativeVaultRuntime(options) {
|
|
|
22584
23180
|
await requireActive(signal);
|
|
22585
23181
|
if (absentOnly && !await nativeVaultFileAbsent(paths.config))
|
|
22586
23182
|
return;
|
|
22587
|
-
|
|
22588
|
-
await
|
|
22589
|
-
|
|
22590
|
-
|
|
22591
|
-
|
|
22592
|
-
|
|
22593
|
-
|
|
22594
|
-
|
|
22595
|
-
|
|
22596
|
-
|
|
22597
|
-
|
|
22598
|
-
|
|
22599
|
-
|
|
22600
|
-
|
|
22601
|
-
|
|
22602
|
-
|
|
22603
|
-
|
|
22604
|
-
|
|
22605
|
-
|
|
22606
|
-
|
|
22607
|
-
|
|
22608
|
-
|
|
22609
|
-
|
|
22610
|
-
|
|
22611
|
-
return settings;
|
|
22612
|
-
if (primary) {
|
|
22613
|
-
settings.mainAccountId = primary.routeId;
|
|
22614
|
-
settings.claustrum = {
|
|
22615
|
-
primaryAccount: {
|
|
22616
|
-
credentialId: NATIVE_PRIMARY_CREDENTIAL_ID,
|
|
22617
|
-
accountId: primary.accountIdentity
|
|
22618
|
-
}
|
|
22619
|
-
};
|
|
22620
|
-
} else {
|
|
22621
|
-
delete settings.mainAccountId;
|
|
22622
|
-
delete settings.claustrum;
|
|
23183
|
+
const roster = await readVaultRoster(paths.roster);
|
|
23184
|
+
if (absentOnly && !await nativeVaultFileAbsent(paths.config))
|
|
23185
|
+
return;
|
|
23186
|
+
const primaryFor = (roster2) => roster2?.rows.find((row) => (row.credentialId === NATIVE_PRIMARY_CREDENTIAL_ID || row.aliases?.includes(NATIVE_PRIMARY_CREDENTIAL_ID)) && row.credentialType === "oauth" && !row.stale && !row.unclaimed && typeof row.accountIdentity === "string" && row.accountIdentity.length > 0);
|
|
23187
|
+
const primary = primaryFor(roster);
|
|
23188
|
+
const read = await store.readSettings();
|
|
23189
|
+
if (read.status !== "ready")
|
|
23190
|
+
throw new NativeCustodyError("invalid-state");
|
|
23191
|
+
const previous = nativeVaultPrimaryPin(read.settings);
|
|
23192
|
+
if (!absentOnly && (!primary && !previous || primary && previous?.routeId === primary.routeId && previous.credentialId === NATIVE_PRIMARY_CREDENTIAL_ID && previous.accountIdentity === primary.accountIdentity))
|
|
23193
|
+
return;
|
|
23194
|
+
const assertPrimary = async () => {
|
|
23195
|
+
await requireActive(signal);
|
|
23196
|
+
const pinned = primaryFor(await readVaultRoster(paths.roster));
|
|
23197
|
+
if (pinned?.routeId !== primary?.routeId || pinned?.accountIdentity !== primary?.accountIdentity)
|
|
23198
|
+
throw new NativeRuntimeError("publication-refused");
|
|
23199
|
+
};
|
|
23200
|
+
const writer = createNativePoolStore({
|
|
23201
|
+
paths,
|
|
23202
|
+
quota: nativeQuotaCodec,
|
|
23203
|
+
onLockEvent: options.onLockEvent,
|
|
23204
|
+
onStep: async (point) => {
|
|
23205
|
+
if (point === "before-config-write" || point === "before-state-write") {
|
|
23206
|
+
await assertPrimary();
|
|
22623
23207
|
}
|
|
23208
|
+
}
|
|
23209
|
+
});
|
|
23210
|
+
await writer.updateSettings(async (settings) => {
|
|
23211
|
+
if (absentOnly && !await nativeVaultFileAbsent(paths.config))
|
|
22624
23212
|
return settings;
|
|
22625
|
-
|
|
22626
|
-
|
|
23213
|
+
if (primary) {
|
|
23214
|
+
settings.mainAccountId = primary.routeId;
|
|
23215
|
+
settings.claustrum = {
|
|
23216
|
+
primaryAccount: {
|
|
23217
|
+
credentialId: NATIVE_PRIMARY_CREDENTIAL_ID,
|
|
23218
|
+
accountId: primary.accountIdentity
|
|
23219
|
+
}
|
|
23220
|
+
};
|
|
23221
|
+
} else {
|
|
23222
|
+
delete settings.mainAccountId;
|
|
23223
|
+
delete settings.claustrum;
|
|
23224
|
+
}
|
|
23225
|
+
return settings;
|
|
22627
23226
|
});
|
|
22628
23227
|
}
|
|
22629
23228
|
async function rowFor(roster, routeId) {
|
|
@@ -23003,56 +23602,52 @@ function createNativeVaultRuntime(options) {
|
|
|
23003
23602
|
]);
|
|
23004
23603
|
if ((versions.get(key) ?? 0) > receipt.recordVersion)
|
|
23005
23604
|
return false;
|
|
23006
|
-
|
|
23007
|
-
|
|
23008
|
-
|
|
23009
|
-
|
|
23010
|
-
|
|
23011
|
-
|
|
23012
|
-
|
|
23013
|
-
|
|
23014
|
-
const
|
|
23015
|
-
|
|
23016
|
-
|
|
23017
|
-
|
|
23018
|
-
|
|
23019
|
-
|
|
23020
|
-
|
|
23021
|
-
|
|
23022
|
-
|
|
23023
|
-
|
|
23024
|
-
|
|
23025
|
-
|
|
23026
|
-
|
|
23027
|
-
accountIdentity,
|
|
23028
|
-
recordVersion: receipt.recordVersion
|
|
23029
|
-
}
|
|
23030
|
-
});
|
|
23031
|
-
kept = true;
|
|
23032
|
-
return current;
|
|
23033
|
-
}, {
|
|
23034
|
-
onLockEvent: options.onLockEvent,
|
|
23035
|
-
beforeRename: async () => {
|
|
23036
|
-
await requireActive();
|
|
23037
|
-
const pinned = await rowFor(roster, route.logicalId);
|
|
23038
|
-
if (!pinned || pinned.routeId !== route.routeId || pinned.accountIdentity !== receipt.assertedAccountIdentity)
|
|
23039
|
-
throw new NativeRuntimeError("publication-refused");
|
|
23040
|
-
const superseded = (versions.get(key) ?? 0) > receipt.recordVersion;
|
|
23041
|
-
if (superseded && onSuperseded === "refuse")
|
|
23042
|
-
throw new NativeRuntimeError("runtime-conflict");
|
|
23043
|
-
await lease.assertOwned();
|
|
23044
|
-
return superseded ? "skip" : "publish";
|
|
23605
|
+
const row = await rowFor(await readVaultRoster(paths.roster), route.logicalId);
|
|
23606
|
+
if (!row?.accountIdentity || row.routeId !== route.routeId || row.accountIdentity !== receipt.assertedAccountIdentity || row.credentialId !== receipt.credentialId && !row.aliases?.includes(receipt.credentialId))
|
|
23607
|
+
return false;
|
|
23608
|
+
const accountIdentity = row.accountIdentity;
|
|
23609
|
+
let kept = false;
|
|
23610
|
+
try {
|
|
23611
|
+
const outcome = await updateNativeRuntimeOptional(paths.runtime, paths.storageId, (current) => {
|
|
23612
|
+
const old = current.accounts[route.routeId];
|
|
23613
|
+
const binding2 = old?.binding;
|
|
23614
|
+
if (binding2?.kind === "custody" && binding2.credentialId === receipt.credentialId && binding2.accountIdentity === receipt.assertedAccountIdentity && binding2.recordVersion > receipt.recordVersion)
|
|
23615
|
+
throw new NativeRuntimeError("runtime-conflict");
|
|
23616
|
+
const same = binding2?.kind === "custody" && binding2.accountIdentity === receipt.assertedAccountIdentity && (binding2.credentialId === row.credentialId || row.aliases?.includes(binding2.credentialId));
|
|
23617
|
+
current.accounts[route.routeId] = change({
|
|
23618
|
+
...same ? old : {},
|
|
23619
|
+
binding: {
|
|
23620
|
+
kind: "custody",
|
|
23621
|
+
storageId: paths.storageId,
|
|
23622
|
+
routeId: route.routeId,
|
|
23623
|
+
credentialId: receipt.credentialId,
|
|
23624
|
+
accountIdentity,
|
|
23625
|
+
recordVersion: receipt.recordVersion
|
|
23045
23626
|
}
|
|
23046
23627
|
});
|
|
23047
|
-
|
|
23048
|
-
|
|
23049
|
-
}
|
|
23050
|
-
|
|
23051
|
-
|
|
23052
|
-
|
|
23053
|
-
|
|
23054
|
-
|
|
23055
|
-
|
|
23628
|
+
kept = true;
|
|
23629
|
+
return current;
|
|
23630
|
+
}, {
|
|
23631
|
+
onLockEvent: options.onLockEvent,
|
|
23632
|
+
beforeRename: async () => {
|
|
23633
|
+
await requireActive();
|
|
23634
|
+
const pinned = await rowFor(await readVaultRoster(paths.roster), route.logicalId);
|
|
23635
|
+
if (!pinned || pinned.routeId !== route.routeId || pinned.accountIdentity !== receipt.assertedAccountIdentity || pinned.credentialId !== receipt.credentialId && !pinned.aliases?.includes(receipt.credentialId))
|
|
23636
|
+
throw new NativeRuntimeError("publication-refused");
|
|
23637
|
+
const superseded = (versions.get(key) ?? 0) > receipt.recordVersion;
|
|
23638
|
+
if (superseded && onSuperseded === "refuse")
|
|
23639
|
+
throw new NativeRuntimeError("runtime-conflict");
|
|
23640
|
+
return superseded ? "skip" : "publish";
|
|
23641
|
+
}
|
|
23642
|
+
});
|
|
23643
|
+
if (outcome.status === "skipped")
|
|
23644
|
+
return false;
|
|
23645
|
+
} catch (error) {
|
|
23646
|
+
if (error instanceof NativeRuntimeError && error.code === "runtime-conflict")
|
|
23647
|
+
return false;
|
|
23648
|
+
throw error;
|
|
23649
|
+
}
|
|
23650
|
+
return kept;
|
|
23056
23651
|
}
|
|
23057
23652
|
async function fetchReading(routeId, fetchImpl, signal, read, onFailure, dispatch) {
|
|
23058
23653
|
const combined = signalFor(signal);
|
|
@@ -23136,7 +23731,7 @@ function recencyOnly(patch) {
|
|
|
23136
23731
|
return keys4.length === 1 && keys4[0] === "lastUsed" && typeof patch.lastUsed === "number";
|
|
23137
23732
|
}
|
|
23138
23733
|
function waitFor(pending, signal) {
|
|
23139
|
-
return new Promise((
|
|
23734
|
+
return new Promise((resolve11, reject) => {
|
|
23140
23735
|
const abort = () => {
|
|
23141
23736
|
cleanup2();
|
|
23142
23737
|
reject(signal.reason);
|
|
@@ -23145,7 +23740,7 @@ function waitFor(pending, signal) {
|
|
|
23145
23740
|
signal.addEventListener("abort", abort, { once: true });
|
|
23146
23741
|
pending.then((value) => {
|
|
23147
23742
|
cleanup2();
|
|
23148
|
-
signal.aborted ? reject(signal.reason) :
|
|
23743
|
+
signal.aborted ? reject(signal.reason) : resolve11(value);
|
|
23149
23744
|
}, (error) => {
|
|
23150
23745
|
cleanup2();
|
|
23151
23746
|
reject(error);
|
|
@@ -23219,12 +23814,12 @@ function leaseNativeVaultRuntime(use, close) {
|
|
|
23219
23814
|
// src/pool-paths.ts
|
|
23220
23815
|
import { createHash as createHash17 } from "node:crypto";
|
|
23221
23816
|
import { realpath as realpath3 } from "node:fs/promises";
|
|
23222
|
-
import { basename as basename7, dirname as dirname13, join as
|
|
23817
|
+
import { basename as basename7, dirname as dirname13, join as join15, resolve as resolve11 } from "node:path";
|
|
23223
23818
|
|
|
23224
23819
|
// src/sticky-routing.ts
|
|
23225
23820
|
import { createHash as createHash16, randomUUID as randomUUID14 } from "node:crypto";
|
|
23226
23821
|
import { mkdir as mkdir10, readFile as readFile9, rename as rename12, rm as rm7, stat as stat7, writeFile as writeFile4 } from "node:fs/promises";
|
|
23227
|
-
import { basename as basename6, dirname as dirname12, join as
|
|
23822
|
+
import { basename as basename6, dirname as dirname12, join as join14 } from "node:path";
|
|
23228
23823
|
var STICKY_ROUTING_MAIN_ACCOUNT_ID = "main";
|
|
23229
23824
|
var STICKY_ROUTING_SHORT_RESET_GRACE_MS = 15 * 60000;
|
|
23230
23825
|
var STICKY_ROUTING_ASSIGNMENT_TTL_MS = 7 * 24 * 60 * 60000;
|
|
@@ -23274,14 +23869,14 @@ function createStickyNoRouteResponse(input) {
|
|
|
23274
23869
|
}
|
|
23275
23870
|
});
|
|
23276
23871
|
}
|
|
23277
|
-
function
|
|
23872
|
+
function isRecord12(value) {
|
|
23278
23873
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
23279
23874
|
}
|
|
23280
23875
|
function finiteNumber(value) {
|
|
23281
23876
|
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
23282
23877
|
}
|
|
23283
23878
|
function normalizeAssignment(value) {
|
|
23284
|
-
if (!
|
|
23879
|
+
if (!isRecord12(value))
|
|
23285
23880
|
return;
|
|
23286
23881
|
if (typeof value.accountId !== "string" || !["fable", "opus", "general"].includes(String(value.family))) {
|
|
23287
23882
|
return;
|
|
@@ -23310,7 +23905,7 @@ function normalizeAssignment(value) {
|
|
|
23310
23905
|
};
|
|
23311
23906
|
}
|
|
23312
23907
|
function normalizeState(value) {
|
|
23313
|
-
if (!
|
|
23908
|
+
if (!isRecord12(value) || value.version !== 1 || !isRecord12(value.assignments)) {
|
|
23314
23909
|
return;
|
|
23315
23910
|
}
|
|
23316
23911
|
const assignments = {};
|
|
@@ -23328,7 +23923,7 @@ function normalizeState(value) {
|
|
|
23328
23923
|
}
|
|
23329
23924
|
function migrateStickyRoutingState(source2, rowIdMap) {
|
|
23330
23925
|
try {
|
|
23331
|
-
if (!
|
|
23926
|
+
if (!isRecord12(source2) || !isRecord12(source2.assignments))
|
|
23332
23927
|
throw new Error;
|
|
23333
23928
|
const entries = Object.entries(source2.assignments);
|
|
23334
23929
|
const state = normalizeState({
|
|
@@ -23346,10 +23941,10 @@ function migrateStickyRoutingState(source2, rowIdMap) {
|
|
|
23346
23941
|
const assignments = Object.create(null);
|
|
23347
23942
|
for (const [index, [key, original]] of entries.entries()) {
|
|
23348
23943
|
const assignment = state.assignments[String(index)];
|
|
23349
|
-
if (!
|
|
23944
|
+
if (!isRecord12(original) || !assignment)
|
|
23350
23945
|
throw new Error;
|
|
23351
|
-
const
|
|
23352
|
-
if (Object.keys(original).length !==
|
|
23946
|
+
const fields2 = Object.keys(assignment).filter((field) => field !== "affinityModelId" || Object.hasOwn(original, "affinityModelId"));
|
|
23947
|
+
if (Object.keys(original).length !== fields2.length || fields2.some((field) => !Object.hasOwn(original, field) || !Object.is(original[field], Reflect.get(assignment, field)))) {
|
|
23353
23948
|
throw new Error;
|
|
23354
23949
|
}
|
|
23355
23950
|
const accountId = rowIdMap.get(assignment.accountId);
|
|
@@ -23474,7 +24069,7 @@ function decideStickyQuotaFailure(input) {
|
|
|
23474
24069
|
function getStickyRoutingStatePath(accountStoragePath) {
|
|
23475
24070
|
const name = basename6(accountStoragePath);
|
|
23476
24071
|
const stem = name.endsWith(".json") ? name.slice(0, -5) : name;
|
|
23477
|
-
return
|
|
24072
|
+
return join14(dirname12(accountStoragePath), `${stem}-routing-state.json`);
|
|
23478
24073
|
}
|
|
23479
24074
|
function stickyRetryAfterWithJitter(sessionId, retryAfterSeconds) {
|
|
23480
24075
|
const hash2 = createHash16("sha256").update(sessionId).digest().readUInt32BE(0);
|
|
@@ -23575,7 +24170,7 @@ class StickySessionRouter {
|
|
|
23575
24170
|
if (!wait || performance.now() >= deadline) {
|
|
23576
24171
|
throw new Error("Timed out acquiring sticky routing state lock");
|
|
23577
24172
|
}
|
|
23578
|
-
await new Promise((
|
|
24173
|
+
await new Promise((resolve11) => setTimeout(resolve11, STICKY_ROUTING_LOCK_POLL_MS));
|
|
23579
24174
|
}
|
|
23580
24175
|
}
|
|
23581
24176
|
recoverLocalPins() {
|
|
@@ -23690,7 +24285,7 @@ class StickySessionRouter {
|
|
|
23690
24285
|
const source2 = await readNativeVaultLegacyJson(seed.legacyConfig);
|
|
23691
24286
|
const routes = nativeVaultLegacyRoutes(source2, roster);
|
|
23692
24287
|
const legacy = await readNativeVaultLegacyJson(getStickyRoutingStatePath(seed.legacyConfig));
|
|
23693
|
-
if (
|
|
24288
|
+
if (isRecord12(legacy) && legacy.version === 1 && isRecord12(legacy.assignments)) {
|
|
23694
24289
|
for (const [key, raw] of Object.entries(legacy.assignments)) {
|
|
23695
24290
|
if (!/^[0-9a-f]{64}$/.test(key) || Object.hasOwn(state.assignments, key))
|
|
23696
24291
|
continue;
|
|
@@ -23941,7 +24536,7 @@ function resolveLocalRoutingDestination(host, paths, env) {
|
|
|
23941
24536
|
return (host === "opencode" ? env.OPENCODE_ANTHROPIC_AUTH_ROUTING_STATE_FILE : env.PI_ANTHROPIC_AUTH_ROUTING_STATE_FILE) || getStickyRoutingStatePath(paths.config);
|
|
23942
24537
|
}
|
|
23943
24538
|
async function canonicalPath(path2) {
|
|
23944
|
-
const absolute =
|
|
24539
|
+
const absolute = resolve11(path2);
|
|
23945
24540
|
try {
|
|
23946
24541
|
return await realpath3(absolute);
|
|
23947
24542
|
} catch (error) {
|
|
@@ -23952,10 +24547,10 @@ async function canonicalPath(path2) {
|
|
|
23952
24547
|
const parent = dirname13(absolute);
|
|
23953
24548
|
if (parent === absolute)
|
|
23954
24549
|
return absolute;
|
|
23955
|
-
return
|
|
24550
|
+
return join15(await canonicalPath(parent), basename7(absolute));
|
|
23956
24551
|
}
|
|
23957
24552
|
function sibling2(path2, legacyName, name, suffix) {
|
|
23958
|
-
return basename7(path2) === legacyName ?
|
|
24553
|
+
return basename7(path2) === legacyName ? join15(dirname13(path2), name) : `${path2}.${suffix}.json`;
|
|
23959
24554
|
}
|
|
23960
24555
|
async function resolveNativePoolPaths(legacyConfig = getAccountStoragePath(), legacyState = getAccountStatePath(legacyConfig)) {
|
|
23961
24556
|
const [sourceConfig, sourceState] = await Promise.all([
|
|
@@ -24532,7 +25127,7 @@ class PersistentRelaySession {
|
|
|
24532
25127
|
return;
|
|
24533
25128
|
if (this.connecting)
|
|
24534
25129
|
return await this.connecting;
|
|
24535
|
-
this.connecting = new Promise((
|
|
25130
|
+
this.connecting = new Promise((resolve12, reject) => {
|
|
24536
25131
|
const url = toWebSocketUrl(this.config.url, this.config.token);
|
|
24537
25132
|
const parsed = new URL(url);
|
|
24538
25133
|
parsed.searchParams.set("affinity", this.affinity);
|
|
@@ -24554,7 +25149,7 @@ class PersistentRelaySession {
|
|
|
24554
25149
|
if (message.type === "ready") {
|
|
24555
25150
|
this.timers.clearTimeout(timeout);
|
|
24556
25151
|
this.serverState = message.state;
|
|
24557
|
-
|
|
25152
|
+
resolve12();
|
|
24558
25153
|
return;
|
|
24559
25154
|
}
|
|
24560
25155
|
this.handleMessage(message);
|
|
@@ -24606,15 +25201,15 @@ class PersistentRelaySession {
|
|
|
24606
25201
|
const sentAt = perfNowMs();
|
|
24607
25202
|
let resolveDone;
|
|
24608
25203
|
let rejectDone;
|
|
24609
|
-
const done = new Promise((
|
|
24610
|
-
resolveDone =
|
|
25204
|
+
const done = new Promise((resolve12, reject) => {
|
|
25205
|
+
resolveDone = resolve12;
|
|
24611
25206
|
rejectDone = reject;
|
|
24612
25207
|
});
|
|
24613
|
-
const response = new Promise((
|
|
25208
|
+
const response = new Promise((resolve12, reject) => {
|
|
24614
25209
|
const pending = {
|
|
24615
25210
|
payload,
|
|
24616
25211
|
bodyText,
|
|
24617
|
-
resolve:
|
|
25212
|
+
resolve: resolve12,
|
|
24618
25213
|
reject,
|
|
24619
25214
|
streamDone: false,
|
|
24620
25215
|
accepted: false,
|
|
@@ -25938,7 +26533,7 @@ function createNativeAccountRuntime(options) {
|
|
|
25938
26533
|
const { mode, paths: paths2, store: store2 } = await selectedStorage();
|
|
25939
26534
|
for (let attempt = 0;attempt < 4; attempt++) {
|
|
25940
26535
|
if (attempt)
|
|
25941
|
-
await new Promise((
|
|
26536
|
+
await new Promise((resolve12) => setTimeout(resolve12, 10));
|
|
25942
26537
|
const settings = await store2.readSettings();
|
|
25943
26538
|
if (settings.status !== "ready")
|
|
25944
26539
|
throw new NativeRuntimeError("publication-refused");
|
|
@@ -26648,7 +27243,7 @@ function relayGeneration(input) {
|
|
|
26648
27243
|
// src/native-host-auth-write.ts
|
|
26649
27244
|
import { randomUUID as randomUUID16 } from "node:crypto";
|
|
26650
27245
|
import { lstat as lstat7, open as open9, rename as rename13, unlink as unlink6 } from "node:fs/promises";
|
|
26651
|
-
import { dirname as dirname14, isAbsolute as isAbsolute5, join as
|
|
27246
|
+
import { dirname as dirname14, isAbsolute as isAbsolute5, join as join16 } from "node:path";
|
|
26652
27247
|
class NativeHostAuthWriteError extends Error {
|
|
26653
27248
|
code;
|
|
26654
27249
|
effect;
|
|
@@ -26709,7 +27304,7 @@ async function writeNativeHostAuth(input, hooks = {}) {
|
|
|
26709
27304
|
const removingFile = host === "pi" && Object.keys(next).length === 0;
|
|
26710
27305
|
const outcome = Object.freeze(host === "pi" ? { status: "removed", file: removingFile ? "unlinked" : "replaced" } : { status: snapshot.data === undefined ? "created" : "replaced" });
|
|
26711
27306
|
if (!removingFile) {
|
|
26712
|
-
stage =
|
|
27307
|
+
stage = join16(dirname14(authPath), `.native-host-auth-write.${randomUUID16()}.tmp`);
|
|
26713
27308
|
const bytes = `${JSON.stringify(next, null, 2)}
|
|
26714
27309
|
`;
|
|
26715
27310
|
const nativeCreated = await createWindowsOwnerOnly(stage, bytes);
|
|
@@ -27584,7 +28179,7 @@ class NativeCustodyActivationError extends Error {
|
|
|
27584
28179
|
function refuse4(code) {
|
|
27585
28180
|
throw new NativeCustodyActivationError(code);
|
|
27586
28181
|
}
|
|
27587
|
-
function
|
|
28182
|
+
function isRecord13(value) {
|
|
27588
28183
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
27589
28184
|
}
|
|
27590
28185
|
function sameJson(left, right) {
|
|
@@ -27669,7 +28264,7 @@ var ACCOUNT_RUNTIME_FIELDS = [
|
|
|
27669
28264
|
"quotaErrorGeneration"
|
|
27670
28265
|
];
|
|
27671
28266
|
function vaultSettings(settings, primary) {
|
|
27672
|
-
const custody =
|
|
28267
|
+
const custody = isRecord13(settings.claustrum) ? settings.claustrum : {};
|
|
27673
28268
|
return {
|
|
27674
28269
|
...settings,
|
|
27675
28270
|
claustrum: {
|
|
@@ -27779,7 +28374,7 @@ async function preparePlan(options, journal, store) {
|
|
|
27779
28374
|
const main = pool.settings.mainAccountId;
|
|
27780
28375
|
if (typeof main !== "string" || !main)
|
|
27781
28376
|
refuse4("invalid-state");
|
|
27782
|
-
const custody =
|
|
28377
|
+
const custody = isRecord13(pool.settings.claustrum) ? pool.settings.claustrum : {};
|
|
27783
28378
|
const host = await readHostEntry(options.host, journal.hostAuthPath);
|
|
27784
28379
|
const hostAuth = {
|
|
27785
28380
|
source: host.digest,
|
|
@@ -27810,7 +28405,7 @@ async function preparePlan(options, journal, store) {
|
|
|
27810
28405
|
let roster;
|
|
27811
28406
|
let targetSettings;
|
|
27812
28407
|
if (custody.mode === "claustrum") {
|
|
27813
|
-
const pin =
|
|
28408
|
+
const pin = isRecord13(custody.primaryAccount) ? custody.primaryAccount : {};
|
|
27814
28409
|
if (oauth.length > 0 || pin.credentialId !== primary.credentialId || pin.accountId !== primary.accountIdentity)
|
|
27815
28410
|
refuse4("primary-mismatch");
|
|
27816
28411
|
if (!existing)
|
|
@@ -27861,7 +28456,7 @@ async function preparePlan(options, journal, store) {
|
|
|
27861
28456
|
} catch (error) {
|
|
27862
28457
|
if (error instanceof NativeCustodyActivationError)
|
|
27863
28458
|
throw error;
|
|
27864
|
-
return refuse4(
|
|
28459
|
+
return refuse4(isRecord13(error) && error.code === "unenrolled-local-row" ? "unenrolled-local-row" : "roster-conflict");
|
|
27865
28460
|
}
|
|
27866
28461
|
roster = existing ?? rosterProjection(seed);
|
|
27867
28462
|
targetSettings = vaultSettings(pool.settings, primary);
|
|
@@ -28013,7 +28608,7 @@ async function runNativeCustodyActivation(options, hooks = {}) {
|
|
|
28013
28608
|
if (settings.status !== "ready")
|
|
28014
28609
|
refuse4("invalid-state");
|
|
28015
28610
|
const custody = settings.settings.claustrum;
|
|
28016
|
-
if (
|
|
28611
|
+
if (isRecord13(custody) && custody.mode === "claustrum")
|
|
28017
28612
|
return { status: "already-vault", journal };
|
|
28018
28613
|
}
|
|
28019
28614
|
if (journal.activation?.kind === "activation" && journal.activation.phase === "committed")
|
|
@@ -28234,8 +28829,8 @@ async function runNativeCustodyActivation(options, hooks = {}) {
|
|
|
28234
28829
|
}
|
|
28235
28830
|
async function commitMode(paths, routingPath, plan, context) {
|
|
28236
28831
|
let openGate = () => {};
|
|
28237
|
-
const gate = new Promise((
|
|
28238
|
-
openGate =
|
|
28832
|
+
const gate = new Promise((resolve12) => {
|
|
28833
|
+
openGate = resolve12;
|
|
28239
28834
|
});
|
|
28240
28835
|
let leases;
|
|
28241
28836
|
let scope;
|
|
@@ -28864,7 +29459,7 @@ function readPlain(value, allowed) {
|
|
|
28864
29459
|
const prototype = Object.getPrototypeOf(value);
|
|
28865
29460
|
if (prototype !== Object.prototype && prototype !== null)
|
|
28866
29461
|
return "malformed";
|
|
28867
|
-
const
|
|
29462
|
+
const fields2 = new Map;
|
|
28868
29463
|
let unknownKey = false;
|
|
28869
29464
|
for (const key of Reflect.ownKeys(value)) {
|
|
28870
29465
|
if (typeof key !== "string")
|
|
@@ -28875,9 +29470,9 @@ function readPlain(value, allowed) {
|
|
|
28875
29470
|
if (!allowed.includes(key))
|
|
28876
29471
|
unknownKey = true;
|
|
28877
29472
|
else
|
|
28878
|
-
|
|
29473
|
+
fields2.set(key, descriptor.value);
|
|
28879
29474
|
}
|
|
28880
|
-
return unknownKey ? "unknown-key" :
|
|
29475
|
+
return unknownKey ? "unknown-key" : fields2;
|
|
28881
29476
|
}
|
|
28882
29477
|
function readArray(value) {
|
|
28883
29478
|
if (value === null || typeof value !== "object")
|
|
@@ -28931,13 +29526,13 @@ function readKillswitchEntries(value) {
|
|
|
28931
29526
|
return;
|
|
28932
29527
|
const entries = [];
|
|
28933
29528
|
for (const item of items2) {
|
|
28934
|
-
const
|
|
28935
|
-
if (!(
|
|
29529
|
+
const fields2 = readPlain(item, ENTRY_KEYS);
|
|
29530
|
+
if (!(fields2 instanceof Map))
|
|
28936
29531
|
return;
|
|
28937
|
-
const account =
|
|
28938
|
-
const fh =
|
|
28939
|
-
const sd =
|
|
28940
|
-
const scoped =
|
|
29532
|
+
const account = fields2.get("account");
|
|
29533
|
+
const fh = fields2.get("fh");
|
|
29534
|
+
const sd = fields2.get("sd");
|
|
29535
|
+
const scoped = fields2.get("scoped");
|
|
28941
29536
|
if (!isKillswitchAccount(account))
|
|
28942
29537
|
return;
|
|
28943
29538
|
if (!isDigitInteger(fh) || !isDigitInteger(sd))
|
|
@@ -29021,14 +29616,14 @@ var CONTEXT_KEYS = [
|
|
|
29021
29616
|
"signal"
|
|
29022
29617
|
];
|
|
29023
29618
|
function readContext(value) {
|
|
29024
|
-
const
|
|
29025
|
-
if (!(
|
|
29619
|
+
const fields2 = readPlain(value, CONTEXT_KEYS);
|
|
29620
|
+
if (!(fields2 instanceof Map))
|
|
29026
29621
|
return;
|
|
29027
|
-
const interactive =
|
|
29028
|
-
const custodyMode =
|
|
29029
|
-
const confirmed =
|
|
29030
|
-
const sessionId =
|
|
29031
|
-
const rawSignal =
|
|
29622
|
+
const interactive = fields2.get("interactive");
|
|
29623
|
+
const custodyMode = fields2.get("custodyMode");
|
|
29624
|
+
const confirmed = fields2.get("confirmed");
|
|
29625
|
+
const sessionId = fields2.get("sessionId");
|
|
29626
|
+
const rawSignal = fields2.get("signal");
|
|
29032
29627
|
if (typeof interactive !== "boolean")
|
|
29033
29628
|
return;
|
|
29034
29629
|
if (custodyMode !== "local" && custodyMode !== "claustrum")
|
|
@@ -29128,9 +29723,9 @@ var DISCONNECT_RESULTS = new Set([
|
|
|
29128
29723
|
"conflict"
|
|
29129
29724
|
]);
|
|
29130
29725
|
function readOutcome(action, outcome) {
|
|
29131
|
-
const
|
|
29132
|
-
const ok =
|
|
29133
|
-
const text5 =
|
|
29726
|
+
const fields2 = readPlain(outcome, ["ok", "text"]);
|
|
29727
|
+
const ok = fields2 instanceof Map ? fields2.get("ok") : undefined;
|
|
29728
|
+
const text5 = fields2 instanceof Map ? fields2.get("text") : undefined;
|
|
29134
29729
|
if (typeof ok !== "boolean" || typeof text5 !== "string")
|
|
29135
29730
|
return Object.freeze({ status: "failed", action, code: "invalid-outcome" });
|
|
29136
29731
|
return Object.freeze({ status: "executed", action, ok, text: text5 });
|
|
@@ -29173,12 +29768,12 @@ function disconnectFailureCode(error) {
|
|
|
29173
29768
|
return "execution-failed";
|
|
29174
29769
|
}
|
|
29175
29770
|
function createNativeMenuExecutor(options) {
|
|
29176
|
-
const
|
|
29177
|
-
if (!(
|
|
29771
|
+
const fields2 = readPlain(options, ["host", "dispatch", "disconnectVault"]);
|
|
29772
|
+
if (!(fields2 instanceof Map))
|
|
29178
29773
|
throw new TypeError("Native menu executor options are invalid");
|
|
29179
|
-
const host =
|
|
29180
|
-
const dispatch =
|
|
29181
|
-
const disconnectVault =
|
|
29774
|
+
const host = fields2.get("host");
|
|
29775
|
+
const dispatch = fields2.get("dispatch");
|
|
29776
|
+
const disconnectVault = fields2.get("disconnectVault");
|
|
29182
29777
|
if (!HOSTS2.has(host))
|
|
29183
29778
|
throw invalidOption2("host");
|
|
29184
29779
|
if (typeof dispatch !== "function" || utilTypes7.isProxy(dispatch))
|
|
@@ -29634,8 +30229,8 @@ function showSignInLink(text5, scrub) {
|
|
|
29634
30229
|
const links = new Set((text5.match(/https:\/\/\S+/g) ?? []).filter(isSignInLink));
|
|
29635
30230
|
const [link2] = links;
|
|
29636
30231
|
if (links.size !== 1 || link2 === undefined)
|
|
29637
|
-
return scrub(text5);
|
|
29638
|
-
return text5.split(link2).map(scrub).join(link2);
|
|
30232
|
+
return { text: scrub(text5) };
|
|
30233
|
+
return { text: text5.split(link2).map(scrub).join(link2), link: link2 };
|
|
29639
30234
|
}
|
|
29640
30235
|
var DISCONNECT_OUTCOMES = {
|
|
29641
30236
|
disconnected: {
|
|
@@ -29834,12 +30429,16 @@ function createNativeUi(options) {
|
|
|
29834
30429
|
safe = safe.split(value).join("[REDACTED]");
|
|
29835
30430
|
return redact2(safe);
|
|
29836
30431
|
};
|
|
29837
|
-
const finish = async (result2, signInLink = false) =>
|
|
29838
|
-
|
|
29839
|
-
|
|
29840
|
-
|
|
29841
|
-
|
|
29842
|
-
|
|
30432
|
+
const finish = async (result2, signInLink = false) => {
|
|
30433
|
+
const shown = signInLink ? showSignInLink(result2.text, scrub) : { text: scrub(result2.text) };
|
|
30434
|
+
return {
|
|
30435
|
+
command: "claude",
|
|
30436
|
+
...result2,
|
|
30437
|
+
text: shown.text,
|
|
30438
|
+
...shown.link !== undefined ? { authorizationUrl: shown.link } : {},
|
|
30439
|
+
menu: await model(invocation, scrub, readable)
|
|
30440
|
+
};
|
|
30441
|
+
};
|
|
29843
30442
|
if (request?.command !== "claude" || !action || request.itemId !== undefined || request.sessionId !== undefined && request.sessionId !== invocation.sessionId) {
|
|
29844
30443
|
return finish({
|
|
29845
30444
|
ok: false,
|
|
@@ -29933,11 +30532,11 @@ async function refreshForRequest(runtime2, ready) {
|
|
|
29933
30532
|
break;
|
|
29934
30533
|
if (combined.aborted)
|
|
29935
30534
|
break;
|
|
29936
|
-
await new Promise((
|
|
30535
|
+
await new Promise((resolve12) => {
|
|
29937
30536
|
const finish = () => {
|
|
29938
30537
|
clearTimeout(pause2);
|
|
29939
30538
|
combined.removeEventListener("abort", finish);
|
|
29940
|
-
|
|
30539
|
+
resolve12();
|
|
29941
30540
|
};
|
|
29942
30541
|
const pause2 = setTimeout(finish, 25);
|
|
29943
30542
|
combined.addEventListener("abort", finish, { once: true });
|
|
@@ -29953,16 +30552,16 @@ async function refreshForRequest(runtime2, ready) {
|
|
|
29953
30552
|
function waitForRequest(pending, signal) {
|
|
29954
30553
|
if (!signal)
|
|
29955
30554
|
return pending;
|
|
29956
|
-
return new Promise((
|
|
30555
|
+
return new Promise((resolve12, reject) => {
|
|
29957
30556
|
const abort = () => reject(signal.reason);
|
|
29958
30557
|
signal.addEventListener("abort", abort, { once: true });
|
|
29959
|
-
pending.then(
|
|
30558
|
+
pending.then(resolve12, reject).finally(() => signal.removeEventListener("abort", abort));
|
|
29960
30559
|
if (signal.aborted)
|
|
29961
30560
|
abort();
|
|
29962
30561
|
});
|
|
29963
30562
|
}
|
|
29964
30563
|
// src/native-vault-connection.ts
|
|
29965
|
-
import { dirname as dirname17, join as
|
|
30564
|
+
import { dirname as dirname17, join as join17, resolve as resolve13 } from "node:path";
|
|
29966
30565
|
// ../../node_modules/@cortexkit/common-auth/dist/opencode2/integration.js
|
|
29967
30566
|
var PLACEHOLDER_PREFIX = "common-auth-placeholder";
|
|
29968
30567
|
var PLACEHOLDER_LIFETIME_MS = 365 * 24 * 60 * 60 * 1000;
|
|
@@ -29973,7 +30572,7 @@ function placeholderSecret(integrationID) {
|
|
|
29973
30572
|
import { createHash as createHash20 } from "node:crypto";
|
|
29974
30573
|
import { constants as constants4 } from "node:fs";
|
|
29975
30574
|
import { lstat as lstat9, mkdir as mkdir13, open as open10, unlink as unlink8 } from "node:fs/promises";
|
|
29976
|
-
import { dirname as dirname16, resolve as
|
|
30575
|
+
import { dirname as dirname16, resolve as resolve12 } from "node:path";
|
|
29977
30576
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
29978
30577
|
|
|
29979
30578
|
// ../../node_modules/@cortexkit/common-auth/dist/pi-slot/lock.js
|
|
@@ -30066,7 +30665,7 @@ async function acquirePiLock(authPath, onCompromised, onRenew) {
|
|
|
30066
30665
|
if (!released && lastUpdate + RENEWAL_STALE < Date.now())
|
|
30067
30666
|
compromise();
|
|
30068
30667
|
}
|
|
30069
|
-
function
|
|
30668
|
+
function schedule2(delay3 = UPDATE) {
|
|
30070
30669
|
if (released)
|
|
30071
30670
|
return;
|
|
30072
30671
|
timer = setTimeout(() => {
|
|
@@ -30080,7 +30679,7 @@ async function acquirePiLock(authPath, onCompromised, onRenew) {
|
|
|
30080
30679
|
if (errorCode2(error) === "ENOENT" || lastUpdate + RENEWAL_STALE < Date.now())
|
|
30081
30680
|
compromise();
|
|
30082
30681
|
else
|
|
30083
|
-
|
|
30682
|
+
schedule2(1000);
|
|
30084
30683
|
}
|
|
30085
30684
|
async function update() {
|
|
30086
30685
|
assertFresh();
|
|
@@ -30113,14 +30712,14 @@ async function acquirePiLock(authPath, onCompromised, onRenew) {
|
|
|
30113
30712
|
mtime = next.getTime();
|
|
30114
30713
|
lastUpdate = Date.now();
|
|
30115
30714
|
active.set(path2, { ...identity2, mtime, renewedAt: lastUpdate });
|
|
30116
|
-
|
|
30715
|
+
schedule2();
|
|
30117
30716
|
}
|
|
30118
30717
|
onRenew?.(async () => {
|
|
30119
30718
|
if (timer)
|
|
30120
30719
|
clearTimeout(timer);
|
|
30121
30720
|
await update();
|
|
30122
30721
|
});
|
|
30123
|
-
|
|
30722
|
+
schedule2();
|
|
30124
30723
|
return {
|
|
30125
30724
|
assertFresh,
|
|
30126
30725
|
async release() {
|
|
@@ -30361,8 +30960,8 @@ function createPiSlot(options, onStep, hooks) {
|
|
|
30361
30960
|
if (!provider || !options.authPath || !options.stashPath || !placeholderKey || placeholderKey.startsWith("!") || placeholderKey.includes("$") || !Number.isFinite(timeout) || timeout < 0) {
|
|
30362
30961
|
throw new PiSlotError("invalid-options");
|
|
30363
30962
|
}
|
|
30364
|
-
const authPath =
|
|
30365
|
-
const stashPath =
|
|
30963
|
+
const authPath = resolve12(options.authPath);
|
|
30964
|
+
const stashPath = resolve12(options.stashPath);
|
|
30366
30965
|
if (authPath === stashPath || stashPath === `${authPath}.lock`) {
|
|
30367
30966
|
throw new PiSlotError("invalid-options");
|
|
30368
30967
|
}
|
|
@@ -30500,8 +31099,8 @@ function createPiSlot(options, onStep, hooks) {
|
|
|
30500
31099
|
// src/native-vault-connection.ts
|
|
30501
31100
|
function nativePiAuthSlotPaths(options) {
|
|
30502
31101
|
return {
|
|
30503
|
-
authPath:
|
|
30504
|
-
stashPath:
|
|
31102
|
+
authPath: resolve13(options.authPath),
|
|
31103
|
+
stashPath: join17(dirname17(getHostClaustrumEnrollmentPaths("pi", options.env).tokenPath), "pi-auth-slot", "anthropic.json"),
|
|
30505
31104
|
provider: "anthropic",
|
|
30506
31105
|
placeholderKey: placeholderSecret("anthropic")
|
|
30507
31106
|
};
|
|
@@ -30522,8 +31121,8 @@ async function disconnectNativeVaultForHost(options) {
|
|
|
30522
31121
|
import { createHash as createHash21 } from "node:crypto";
|
|
30523
31122
|
import { realpathSync as realpathSync2 } from "node:fs";
|
|
30524
31123
|
import { mkdir as mkdir14, readdir as readdir3, rm as rm8, stat as stat9, writeFile as writeFile5 } from "node:fs/promises";
|
|
30525
|
-
import { tmpdir as
|
|
30526
|
-
import { join as
|
|
31124
|
+
import { tmpdir as tmpdir7 } from "node:os";
|
|
31125
|
+
import { join as join18, resolve as resolve14 } from "node:path";
|
|
30527
31126
|
var CLAUDE_PRIME_COMMAND_NAME = "claude-prime";
|
|
30528
31127
|
var PRIME_TICK_MS = 60000;
|
|
30529
31128
|
var PRIME_DUE_OFFSET_MS = 60000;
|
|
@@ -30711,10 +31310,10 @@ function buildPrimeRequestBody() {
|
|
|
30711
31310
|
return JSON.parse(JSON.stringify(PRIME_REQUEST_BODY));
|
|
30712
31311
|
}
|
|
30713
31312
|
function defaultMarkerDir() {
|
|
30714
|
-
return
|
|
31313
|
+
return join18(tmpdir7(), "opencode-anthropic-auth", "prime");
|
|
30715
31314
|
}
|
|
30716
31315
|
function primeStorageFingerprint(storagePath) {
|
|
30717
|
-
const absolutePath =
|
|
31316
|
+
const absolutePath = resolve14(storagePath);
|
|
30718
31317
|
let canonicalPath2;
|
|
30719
31318
|
try {
|
|
30720
31319
|
canonicalPath2 = realpathSync2(absolutePath);
|
|
@@ -30726,19 +31325,19 @@ function primeStorageFingerprint(storagePath) {
|
|
|
30726
31325
|
return createHash21("sha256").update(canonicalPath2).digest("hex").slice(0, 12);
|
|
30727
31326
|
}
|
|
30728
31327
|
function primeMarkerNamespaceDir(markerDir, storagePath) {
|
|
30729
|
-
return
|
|
31328
|
+
return join18(markerDir, primeStorageFingerprint(storagePath));
|
|
30730
31329
|
}
|
|
30731
31330
|
function primeAccountMarkerDir(markerDir, storagePath, accountFingerprint) {
|
|
30732
31331
|
if (!/^[a-f0-9]{12,}$/i.test(accountFingerprint)) {
|
|
30733
31332
|
throw new Error("Prime account fingerprint must be a hexadecimal digest");
|
|
30734
31333
|
}
|
|
30735
|
-
return
|
|
31334
|
+
return join18(primeMarkerNamespaceDir(markerDir, storagePath), accountFingerprint.toLowerCase().slice(0, 12));
|
|
30736
31335
|
}
|
|
30737
31336
|
function primeMarkerPath(markerDir, accountId2, resetsAtEpochMs) {
|
|
30738
|
-
return
|
|
31337
|
+
return join18(markerDir, `${encodeURIComponent(accountId2)}-${resetsAtEpochMs}`);
|
|
30739
31338
|
}
|
|
30740
31339
|
function primeBootstrapMarkerPath(markerDir, accountId2) {
|
|
30741
|
-
return
|
|
31340
|
+
return join18(markerDir, `${encodeURIComponent(accountId2)}-bootstrap`);
|
|
30742
31341
|
}
|
|
30743
31342
|
function primeAccountLabel(id2, fallback) {
|
|
30744
31343
|
if (id2 === "main")
|
|
@@ -31162,7 +31761,7 @@ class PrimeManager {
|
|
|
31162
31761
|
let swept = 0;
|
|
31163
31762
|
for (const entry2 of entries) {
|
|
31164
31763
|
try {
|
|
31165
|
-
const path2 =
|
|
31764
|
+
const path2 = join18(dir, entry2);
|
|
31166
31765
|
const s = await stat9(path2);
|
|
31167
31766
|
if (s.isDirectory()) {
|
|
31168
31767
|
swept += await this.sweepMarkerDirectory(path2, now);
|
|
@@ -31196,12 +31795,12 @@ import {
|
|
|
31196
31795
|
stat as stat10,
|
|
31197
31796
|
writeFile as writeFile6
|
|
31198
31797
|
} from "node:fs/promises";
|
|
31199
|
-
import { tmpdir as
|
|
31200
|
-
import { join as
|
|
31798
|
+
import { tmpdir as tmpdir8 } from "node:os";
|
|
31799
|
+
import { join as join19 } from "node:path";
|
|
31201
31800
|
var QUOTA_HEADER_FEED_SCHEMA_VERSION = 3;
|
|
31202
31801
|
var QUOTA_HEADER_FEED_LEASE_MS = 180000;
|
|
31203
31802
|
function getDefaultQuotaHeaderFeedDirectory() {
|
|
31204
|
-
return process.env.OPENCODE_ANTHROPIC_AUTH_QUOTA_FEED_DIR ??
|
|
31803
|
+
return process.env.OPENCODE_ANTHROPIC_AUTH_QUOTA_FEED_DIR ?? join19(tmpdir8(), "opencode-anthropic-auth", "quota-header-feed");
|
|
31205
31804
|
}
|
|
31206
31805
|
function configuredAnthropicOAuthAccountCount(input) {
|
|
31207
31806
|
const fallbackCount = input.storage?.accounts.filter(isOAuthAccount).length ?? 0;
|
|
@@ -31360,7 +31959,7 @@ class QuotaHeaderFeedRegistry {
|
|
|
31360
31959
|
constructor(options = {}) {
|
|
31361
31960
|
this.options = options;
|
|
31362
31961
|
const instanceId = options.instanceId ?? `${process.pid}-${randomUUID17()}`;
|
|
31363
|
-
this.filePath =
|
|
31962
|
+
this.filePath = join19(options.directory ?? getDefaultQuotaHeaderFeedDirectory(), `${instanceId}.json`);
|
|
31364
31963
|
}
|
|
31365
31964
|
publish(entry2) {
|
|
31366
31965
|
const { accountKey, quota: quota2 } = entry2;
|
|
@@ -31421,7 +32020,7 @@ class QuotaHeaderFeedRegistry {
|
|
|
31421
32020
|
return;
|
|
31422
32021
|
}
|
|
31423
32022
|
await Promise.all(names2.filter((name) => /^\d+-[0-9a-f-]+\.json$/i.test(name)).map(async (name) => {
|
|
31424
|
-
const path2 =
|
|
32023
|
+
const path2 = join19(directory, name);
|
|
31425
32024
|
if (path2 === this.filePath)
|
|
31426
32025
|
return;
|
|
31427
32026
|
try {
|
|
@@ -31450,7 +32049,7 @@ class QuotaHeaderFeedRegistry {
|
|
|
31450
32049
|
const newest = new Map;
|
|
31451
32050
|
await Promise.all(names2.map(async (name) => {
|
|
31452
32051
|
try {
|
|
31453
|
-
const record9 = JSON.parse(await readFile10(
|
|
32052
|
+
const record9 = JSON.parse(await readFile10(join19(directory, name), "utf8"));
|
|
31454
32053
|
if (record9.version !== QUOTA_HEADER_FEED_SCHEMA_VERSION || !record9.entries || typeof record9.entries !== "object")
|
|
31455
32054
|
return;
|
|
31456
32055
|
for (const [accountKey, candidate] of Object.entries(record9.entries)) {
|
|
@@ -31631,7 +32230,7 @@ function buildClaudeQuotaSummary(input) {
|
|
|
31631
32230
|
}
|
|
31632
32231
|
// src/request-gzip.ts
|
|
31633
32232
|
import { mkdir as mkdir16, readFile as readFile11, rename as rename15, rm as rm10, writeFile as writeFile7 } from "node:fs/promises";
|
|
31634
|
-
import { basename as basename8, dirname as dirname18, join as
|
|
32233
|
+
import { basename as basename8, dirname as dirname18, join as join20 } from "node:path";
|
|
31635
32234
|
import { promisify } from "node:util";
|
|
31636
32235
|
import { gzip } from "node:zlib";
|
|
31637
32236
|
var gzipAsync = promisify(gzip);
|
|
@@ -31777,7 +32376,7 @@ function getRequestGzipLatch(path2) {
|
|
|
31777
32376
|
function getRequestGzipLatchPath(accountStoragePath) {
|
|
31778
32377
|
const name = basename8(accountStoragePath);
|
|
31779
32378
|
const stem = name.endsWith(".json") ? name.slice(0, -5) : name;
|
|
31780
|
-
return
|
|
32379
|
+
return join20(dirname18(accountStoragePath), `${stem}-request-gzip.json`);
|
|
31781
32380
|
}
|
|
31782
32381
|
async function decideRequestGzip(options) {
|
|
31783
32382
|
if (!CLAUDE_CODE_GZIPS_REQUEST_BODIES)
|
|
@@ -31922,7 +32521,7 @@ var REPORTED_BLOCK_TYPES = new Set([
|
|
|
31922
32521
|
"document"
|
|
31923
32522
|
]);
|
|
31924
32523
|
var EMPTY_TEXT_BLOCK_KEYS = new Set(["type", "text", "cache_control"]);
|
|
31925
|
-
function
|
|
32524
|
+
function isRecord14(value) {
|
|
31926
32525
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
31927
32526
|
}
|
|
31928
32527
|
function isProvablyEmptyContent(content) {
|
|
@@ -31930,14 +32529,14 @@ function isProvablyEmptyContent(content) {
|
|
|
31930
32529
|
return content.trim() === "";
|
|
31931
32530
|
if (!Array.isArray(content))
|
|
31932
32531
|
return false;
|
|
31933
|
-
return content.every((block) =>
|
|
32532
|
+
return content.every((block) => isRecord14(block) && block.type === "text" && typeof block.text === "string" && block.text.trim() === "" && Object.keys(block).every((key) => EMPTY_TEXT_BLOCK_KEYS.has(key)));
|
|
31934
32533
|
}
|
|
31935
32534
|
function describeContent(content) {
|
|
31936
32535
|
if (Array.isArray(content)) {
|
|
31937
32536
|
return {
|
|
31938
32537
|
contentShape: "array",
|
|
31939
32538
|
contentBlockCount: content.length,
|
|
31940
|
-
contentBlockTypes: content.map((block) =>
|
|
32539
|
+
contentBlockTypes: content.map((block) => isRecord14(block) && typeof block.type === "string" && REPORTED_BLOCK_TYPES.has(block.type) ? block.type : "other")
|
|
31941
32540
|
};
|
|
31942
32541
|
}
|
|
31943
32542
|
if (typeof content === "string")
|
|
@@ -31950,7 +32549,7 @@ function assertNoMeaningfulTrailingAssistant(messages) {
|
|
|
31950
32549
|
let end = messages.length;
|
|
31951
32550
|
while (end > 0) {
|
|
31952
32551
|
const last = messages[end - 1];
|
|
31953
|
-
if (!
|
|
32552
|
+
if (!isRecord14(last) || last.role !== "assistant")
|
|
31954
32553
|
break;
|
|
31955
32554
|
if (!isProvablyEmptyContent(last.content)) {
|
|
31956
32555
|
throw new TrailingAssistantHistoryError({
|
|
@@ -32093,11 +32692,11 @@ function executeLaneStartCommand(input) {
|
|
|
32093
32692
|
}
|
|
32094
32693
|
// src/thinking-binding.ts
|
|
32095
32694
|
var THINKING_BINDING_CONTROLS_BETA = "thinking-binding-controls-2026-08-01";
|
|
32096
|
-
function
|
|
32695
|
+
function isRecord15(value) {
|
|
32097
32696
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
32098
32697
|
}
|
|
32099
32698
|
function isReplayableThinkingBlock(block) {
|
|
32100
|
-
if (!
|
|
32699
|
+
if (!isRecord15(block))
|
|
32101
32700
|
return false;
|
|
32102
32701
|
if (block.type === "thinking") {
|
|
32103
32702
|
return typeof block.signature === "string" && block.signature.length > 0;
|
|
@@ -32115,7 +32714,7 @@ function hasReplayableThinkingBlocks(body) {
|
|
|
32115
32714
|
if (!Array.isArray(body.messages))
|
|
32116
32715
|
return false;
|
|
32117
32716
|
return body.messages.some((message) => {
|
|
32118
|
-
if (!
|
|
32717
|
+
if (!isRecord15(message) || message.role !== "assistant")
|
|
32119
32718
|
return false;
|
|
32120
32719
|
return Array.isArray(message.content) && message.content.some(isReplayableThinkingBlock);
|
|
32121
32720
|
});
|
|
@@ -32123,11 +32722,11 @@ function hasReplayableThinkingBlocks(body) {
|
|
|
32123
32722
|
function applyThinkingBindingControls(body, behavior = "account-default") {
|
|
32124
32723
|
if (behavior === "account-default")
|
|
32125
32724
|
return false;
|
|
32126
|
-
if (!
|
|
32725
|
+
if (!resolveClaudeModelCapabilities(body.model)?.thinkingBindingControls)
|
|
32127
32726
|
return false;
|
|
32128
32727
|
if (!hasReplayableThinkingBlocks(body))
|
|
32129
32728
|
return false;
|
|
32130
|
-
if (!
|
|
32729
|
+
if (!isRecord15(body.thinking) || body.thinking.type !== "adaptive")
|
|
32131
32730
|
return false;
|
|
32132
32731
|
body.thinking.block_binding = {
|
|
32133
32732
|
prefix_mismatch_behavior: behavior
|
|
@@ -32135,13 +32734,68 @@ function applyThinkingBindingControls(body, behavior = "account-default") {
|
|
|
32135
32734
|
return true;
|
|
32136
32735
|
}
|
|
32137
32736
|
function hasThinkingBindingControls(body) {
|
|
32138
|
-
if (!
|
|
32737
|
+
if (!isRecord15(body.thinking))
|
|
32139
32738
|
return false;
|
|
32140
|
-
if (!
|
|
32739
|
+
if (!isRecord15(body.thinking.block_binding))
|
|
32141
32740
|
return false;
|
|
32142
32741
|
const behavior = body.thinking.block_binding.prefix_mismatch_behavior;
|
|
32143
32742
|
return behavior === "error" || behavior === "drop_block";
|
|
32144
32743
|
}
|
|
32744
|
+
// src/turn-end-note.ts
|
|
32745
|
+
var TURN_END_NOTE_MIN_VISIBLE_CHARACTERS = 350;
|
|
32746
|
+
var TURN_END_NOTE_CONTENT = "Your reply above has already reached the user. The tool call after it was housekeeping and changed nothing they need to know. Do not repeat, summarize or rewrite that reply. If no new work remains, end the turn without restating anything.";
|
|
32747
|
+
var DEFAULT_TOOLS = ["board", "ctx_reduce"];
|
|
32748
|
+
function isRecord16(value) {
|
|
32749
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
32750
|
+
}
|
|
32751
|
+
function supportsTurnEndNote(model) {
|
|
32752
|
+
return resolveClaudeModelCapabilities(model)?.turnEndNote === true;
|
|
32753
|
+
}
|
|
32754
|
+
function applyTurnEndNotes(body, options = {}) {
|
|
32755
|
+
if (!supportsTurnEndNote(body.model) || !Array.isArray(body.messages))
|
|
32756
|
+
return 0;
|
|
32757
|
+
const allowed = new Set((options.tools ?? DEFAULT_TOOLS).map((name) => options.mapToolName?.(name) ?? name));
|
|
32758
|
+
if (!allowed.size)
|
|
32759
|
+
return 0;
|
|
32760
|
+
const messages = body.messages;
|
|
32761
|
+
const rewritten = [];
|
|
32762
|
+
let inserted = 0;
|
|
32763
|
+
for (let index = 0;index < messages.length; index++) {
|
|
32764
|
+
const results = messages[index];
|
|
32765
|
+
rewritten.push(results);
|
|
32766
|
+
let preceding = index - 1;
|
|
32767
|
+
while (preceding >= 0) {
|
|
32768
|
+
const control = messages[preceding];
|
|
32769
|
+
if (!isRecord16(control) || control.role !== "system" || !Array.isArray(control.content) || control.content.length !== 0 || !isRecord16(control.output_config))
|
|
32770
|
+
break;
|
|
32771
|
+
preceding--;
|
|
32772
|
+
}
|
|
32773
|
+
const assistant = messages[preceding];
|
|
32774
|
+
if (!isRecord16(assistant) || assistant.role !== "assistant" || !Array.isArray(assistant.content) || !isRecord16(results) || results.role !== "user" || !Array.isArray(results.content))
|
|
32775
|
+
continue;
|
|
32776
|
+
const visible = options.visibleText ? options.visibleText(assistant) : assistant.content.filter((block) => isRecord16(block) && block.type === "text" && typeof block.text === "string" && block.text.trim().length > 0).map((block) => block.text).join("");
|
|
32777
|
+
if (visible.length < TURN_END_NOTE_MIN_VISIBLE_CHARACTERS)
|
|
32778
|
+
continue;
|
|
32779
|
+
const calls = assistant.content.filter((block) => isRecord16(block) && block.type === "tool_use");
|
|
32780
|
+
if (!calls.length || !calls.every((call) => allowed.has(call.name)))
|
|
32781
|
+
continue;
|
|
32782
|
+
const resultIds = new Set(results.content.filter((block) => isRecord16(block) && block.type === "tool_result").map((block) => block.tool_use_id));
|
|
32783
|
+
if (!calls.every((call) => typeof call.id === "string" && resultIds.has(call.id)))
|
|
32784
|
+
continue;
|
|
32785
|
+
const next = messages[index + 1];
|
|
32786
|
+
if (isRecord16(next) && next.role === "user")
|
|
32787
|
+
continue;
|
|
32788
|
+
rewritten.push({
|
|
32789
|
+
role: "system",
|
|
32790
|
+
clear_at: "next_user_message",
|
|
32791
|
+
content: TURN_END_NOTE_CONTENT
|
|
32792
|
+
});
|
|
32793
|
+
inserted++;
|
|
32794
|
+
}
|
|
32795
|
+
if (inserted)
|
|
32796
|
+
body.messages = rewritten;
|
|
32797
|
+
return inserted;
|
|
32798
|
+
}
|
|
32145
32799
|
export {
|
|
32146
32800
|
writeNativeHostAuth,
|
|
32147
32801
|
writeDumpFile,
|
|
@@ -32183,6 +32837,7 @@ export {
|
|
|
32183
32837
|
resolveNativePoolPaths,
|
|
32184
32838
|
resolveLocalRoutingDestination,
|
|
32185
32839
|
resolveClaustrumConnectionPath,
|
|
32840
|
+
resolveClaudeModelCapabilities,
|
|
32186
32841
|
resolveClaudeCodeIdentity,
|
|
32187
32842
|
resolveClaudeCodeAccountIdentity,
|
|
32188
32843
|
resetFastModeState,
|
|
@@ -32227,6 +32882,7 @@ export {
|
|
|
32227
32882
|
primeEligibilityReasonLabel,
|
|
32228
32883
|
primeAccountMarkerDir,
|
|
32229
32884
|
prepareNativeMigration,
|
|
32885
|
+
pinsEffortOnEveryRequest,
|
|
32230
32886
|
parseSseFrame,
|
|
32231
32887
|
parseRoutingCommandAction,
|
|
32232
32888
|
parseRetryAfterHeader,
|
|
@@ -32352,6 +33008,8 @@ export {
|
|
|
32352
33008
|
getDefaultCacheKeepRegistryDirectory,
|
|
32353
33009
|
getClaustrumMode,
|
|
32354
33010
|
getClaustrumEnrollmentPaths2 as getClaustrumEnrollmentPaths,
|
|
33011
|
+
getClaudeModelCatalogue,
|
|
33012
|
+
getClaudeModelCapabilities,
|
|
32355
33013
|
getClaudeFableMythos5ReleaseDate,
|
|
32356
33014
|
getClaudeCodeIdentityForVerifiedAccount,
|
|
32357
33015
|
getClaudeCodeIdentity,
|
|
@@ -32496,6 +33154,7 @@ export {
|
|
|
32496
33154
|
PrimeManager,
|
|
32497
33155
|
PROFILE_TTL_MS,
|
|
32498
33156
|
PRODUCTION_CLAUSTRUM_CONNECTION_FILE_NAME,
|
|
33157
|
+
PRIVATE_FILES_UNAVAILABLE_MESSAGE,
|
|
32499
33158
|
PRIME_TICK_MS,
|
|
32500
33159
|
PRIME_REQUEST_BODY,
|
|
32501
33160
|
PRIME_POST_FIRE_REFRESH_MS,
|
|
@@ -32511,6 +33170,7 @@ export {
|
|
|
32511
33170
|
NativeTransientAccountError,
|
|
32512
33171
|
NativeRuntimeError,
|
|
32513
33172
|
NativeQuotaObservations,
|
|
33173
|
+
NativePrivateFilesUnavailableError,
|
|
32514
33174
|
PiSlotError as NativePiAuthSlotError,
|
|
32515
33175
|
NativeMigrationError,
|
|
32516
33176
|
NativeHostAuthError,
|
|
@@ -32563,6 +33223,7 @@ export {
|
|
|
32563
33223
|
CLAUDE_OPUS_5_5_ADAPTIVE_THINKING,
|
|
32564
33224
|
CLAUDE_MYTHOS_5_MODEL_ID,
|
|
32565
33225
|
CLAUDE_MYTHOS_5_1_MODEL_ID,
|
|
33226
|
+
CLAUDE_MODEL_CAPABILITIES,
|
|
32566
33227
|
CLAUDE_LOGGING_COMMAND_NAME,
|
|
32567
33228
|
CLAUDE_HAIKU_5_5_RELEASE_DATE,
|
|
32568
33229
|
CLAUDE_HAIKU_5_5_PRICING,
|
|
@@ -32597,6 +33258,7 @@ export {
|
|
|
32597
33258
|
CLAUDE_CODE_GZIPS_REQUEST_BODIES,
|
|
32598
33259
|
CLAUDE_CODE_FULL_AGENT_BETAS,
|
|
32599
33260
|
CLAUDE_CODE_ENTRYPOINT,
|
|
33261
|
+
CLAUDE_CODE_DEFAULT_BETAS,
|
|
32600
33262
|
CLAUDE_CACHE_KEEP_COMMAND_NAME,
|
|
32601
33263
|
CLAUDE_ACCOUNT_COMMAND_NAME,
|
|
32602
33264
|
CCH_SALT,
|