codexuse-cli 6.0.1 → 6.0.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/README.md +1 -1
- package/dist/index.js +1106 -429
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2026,7 +2026,7 @@ var require_toml = __commonJS({
|
|
|
2026
2026
|
});
|
|
2027
2027
|
|
|
2028
2028
|
// src/commands/accountPool.ts
|
|
2029
|
-
var
|
|
2029
|
+
var import_node_crypto13 = require("crypto");
|
|
2030
2030
|
var import_node_path13 = __toESM(require("path"));
|
|
2031
2031
|
|
|
2032
2032
|
// ../../packages/contracts/src/settings/types.ts
|
|
@@ -2078,8 +2078,8 @@ function migrateLegacyAccountPoolExposedReasoningDefaults(efforts) {
|
|
|
2078
2078
|
|
|
2079
2079
|
// ../../packages/runtime-app-state/src/app/state.ts
|
|
2080
2080
|
var import_node_async_hooks = require("async_hooks");
|
|
2081
|
-
var
|
|
2082
|
-
var
|
|
2081
|
+
var import_node_crypto2 = require("crypto");
|
|
2082
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
2083
2083
|
var import_node_os = __toESM(require("os"), 1);
|
|
2084
2084
|
|
|
2085
2085
|
// ../../packages/contracts/src/settings/auto-roll.ts
|
|
@@ -2211,16 +2211,98 @@ function normalizeAutoRollSettings(raw) {
|
|
|
2211
2211
|
}
|
|
2212
2212
|
|
|
2213
2213
|
// ../../packages/runtime-app-state/src/storage/documents.ts
|
|
2214
|
+
var import_node_fs2 = require("fs");
|
|
2215
|
+
var import_node_fs3 = require("fs");
|
|
2216
|
+
var import_node_crypto = require("crypto");
|
|
2217
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
2218
|
+
|
|
2219
|
+
// ../../packages/runtime-app-state/src/storage/fileLock.ts
|
|
2214
2220
|
var import_node_fs = require("fs");
|
|
2215
2221
|
var import_node_path = __toESM(require("path"), 1);
|
|
2222
|
+
function isSqliteBusyError(error) {
|
|
2223
|
+
if (!error || typeof error !== "object") {
|
|
2224
|
+
return false;
|
|
2225
|
+
}
|
|
2226
|
+
const value3 = error;
|
|
2227
|
+
if (value3.cause && value3.cause !== error && isSqliteBusyError(value3.cause)) {
|
|
2228
|
+
return true;
|
|
2229
|
+
}
|
|
2230
|
+
if (value3.error && value3.error !== error && isSqliteBusyError(value3.error)) {
|
|
2231
|
+
return true;
|
|
2232
|
+
}
|
|
2233
|
+
const message = typeof value3.message === "string" ? value3.message.toLowerCase() : String(error).toLowerCase();
|
|
2234
|
+
return value3.code === "SQLITE_BUSY" || value3.errno === 5 || message.includes("sqlite_busy") || message.includes("database is locked");
|
|
2235
|
+
}
|
|
2236
|
+
async function openLockDatabase(databasePath) {
|
|
2237
|
+
await import_node_fs.promises.mkdir(import_node_path.default.dirname(databasePath), { recursive: true, mode: 448 });
|
|
2238
|
+
const sqlite = process.versions.bun ? await Function("return import('bun:sqlite')")() : await Function("return import('node:sqlite')")();
|
|
2239
|
+
const database = process.versions.bun ? new sqlite.Database(databasePath) : new sqlite.DatabaseSync(databasePath);
|
|
2240
|
+
try {
|
|
2241
|
+
if (process.platform !== "win32") {
|
|
2242
|
+
await import_node_fs.promises.chmod(databasePath, 384);
|
|
2243
|
+
}
|
|
2244
|
+
return {
|
|
2245
|
+
exec: database.exec.bind(database),
|
|
2246
|
+
close: database.close.bind(database)
|
|
2247
|
+
};
|
|
2248
|
+
} catch (error) {
|
|
2249
|
+
database.close();
|
|
2250
|
+
throw error;
|
|
2251
|
+
}
|
|
2252
|
+
}
|
|
2253
|
+
async function acquireCrossProcessFileLockTransaction(filePath, mode) {
|
|
2254
|
+
const databasePath = `${import_node_path.default.resolve(filePath)}.codexuse-lock.sqlite`;
|
|
2255
|
+
let database = null;
|
|
2256
|
+
try {
|
|
2257
|
+
database = await openLockDatabase(databasePath);
|
|
2258
|
+
database.exec(`PRAGMA busy_timeout = ${mode === "write" ? 1e3 : 0};`);
|
|
2259
|
+
database.exec("CREATE TABLE IF NOT EXISTS codexuse_file_lock (id INTEGER PRIMARY KEY);");
|
|
2260
|
+
if (mode === "write") {
|
|
2261
|
+
database.exec("BEGIN EXCLUSIVE;");
|
|
2262
|
+
} else {
|
|
2263
|
+
database.exec("BEGIN;");
|
|
2264
|
+
database.exec("SELECT COUNT(*) FROM codexuse_file_lock;");
|
|
2265
|
+
}
|
|
2266
|
+
} catch (error) {
|
|
2267
|
+
database?.close();
|
|
2268
|
+
if (isSqliteBusyError(error)) {
|
|
2269
|
+
return null;
|
|
2270
|
+
}
|
|
2271
|
+
throw error;
|
|
2272
|
+
}
|
|
2273
|
+
const acquiredDatabase = database;
|
|
2274
|
+
let released = false;
|
|
2275
|
+
return async () => {
|
|
2276
|
+
if (released) {
|
|
2277
|
+
return;
|
|
2278
|
+
}
|
|
2279
|
+
released = true;
|
|
2280
|
+
try {
|
|
2281
|
+
acquiredDatabase.exec("ROLLBACK;");
|
|
2282
|
+
} finally {
|
|
2283
|
+
acquiredDatabase.close();
|
|
2284
|
+
}
|
|
2285
|
+
};
|
|
2286
|
+
}
|
|
2287
|
+
async function acquireCrossProcessFileLock(filePath) {
|
|
2288
|
+
return acquireCrossProcessFileLockTransaction(filePath, "write");
|
|
2289
|
+
}
|
|
2290
|
+
async function acquireCrossProcessFileReadLock(filePath) {
|
|
2291
|
+
return acquireCrossProcessFileLockTransaction(filePath, "read");
|
|
2292
|
+
}
|
|
2293
|
+
|
|
2294
|
+
// ../../packages/runtime-app-state/src/storage/documents.ts
|
|
2216
2295
|
var APP_STORAGE_TABLE = "app_storage_documents";
|
|
2217
2296
|
var APP_STORAGE_DB_DIR = "app-state";
|
|
2218
2297
|
var APP_STORAGE_DB_NAME = "state.sqlite";
|
|
2298
|
+
var APP_STORAGE_QUARANTINE_DIR = "quarantine";
|
|
2299
|
+
var APP_STORAGE_RECOVERY_LOG_LIMIT = 50;
|
|
2300
|
+
var APP_STORAGE_QUARANTINE_LIMIT = 3;
|
|
2219
2301
|
var SQLITE_BUSY_TIMEOUT_MS = 5e3;
|
|
2220
2302
|
var SQLITE_BUSY_MAX_ATTEMPTS = 3;
|
|
2221
2303
|
var SQLITE_BUSY_RETRY_DELAY_MS = 100;
|
|
2222
2304
|
var writeQueueByDbPath = /* @__PURE__ */ new Map();
|
|
2223
|
-
var
|
|
2305
|
+
var databaseRecoveryByDbPath = /* @__PURE__ */ new Map();
|
|
2224
2306
|
var AppStorageCorruptionError = class extends Error {
|
|
2225
2307
|
constructor(message, options) {
|
|
2226
2308
|
super(message);
|
|
@@ -2232,6 +2314,13 @@ var AppStorageCorruptionError = class extends Error {
|
|
|
2232
2314
|
}
|
|
2233
2315
|
}
|
|
2234
2316
|
};
|
|
2317
|
+
var recoveryLog = [];
|
|
2318
|
+
function recordRecovery(event) {
|
|
2319
|
+
recoveryLog.push(event);
|
|
2320
|
+
if (recoveryLog.length > APP_STORAGE_RECOVERY_LOG_LIMIT) {
|
|
2321
|
+
recoveryLog.splice(0, recoveryLog.length - APP_STORAGE_RECOVERY_LOG_LIMIT);
|
|
2322
|
+
}
|
|
2323
|
+
}
|
|
2235
2324
|
function isRecord(value3) {
|
|
2236
2325
|
return Boolean(value3) && typeof value3 === "object" && !Array.isArray(value3);
|
|
2237
2326
|
}
|
|
@@ -2251,53 +2340,239 @@ function safeParseJson(raw) {
|
|
|
2251
2340
|
return null;
|
|
2252
2341
|
}
|
|
2253
2342
|
}
|
|
2254
|
-
function
|
|
2255
|
-
|
|
2256
|
-
return null;
|
|
2257
|
-
}
|
|
2258
|
-
try {
|
|
2259
|
-
return JSON.parse(raw);
|
|
2260
|
-
} catch (error) {
|
|
2261
|
-
throw new AppStorageCorruptionError(
|
|
2262
|
-
`App storage document ${options.namespace} contains invalid JSON.`,
|
|
2263
|
-
{
|
|
2264
|
-
dbPath: options.dbPath,
|
|
2265
|
-
namespace: options.namespace,
|
|
2266
|
-
cause: error
|
|
2267
|
-
}
|
|
2268
|
-
);
|
|
2269
|
-
}
|
|
2343
|
+
function describeError(error) {
|
|
2344
|
+
return error instanceof Error ? error.message : String(error);
|
|
2270
2345
|
}
|
|
2271
2346
|
function sleep(ms) {
|
|
2272
2347
|
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
2273
2348
|
}
|
|
2274
|
-
function
|
|
2349
|
+
function matchesErrorChain(error, predicate) {
|
|
2275
2350
|
if (!error || typeof error !== "object") {
|
|
2276
2351
|
return false;
|
|
2277
2352
|
}
|
|
2278
|
-
const
|
|
2279
|
-
if (
|
|
2353
|
+
const candidate = error;
|
|
2354
|
+
if (predicate(candidate)) {
|
|
2280
2355
|
return true;
|
|
2281
2356
|
}
|
|
2282
|
-
|
|
2283
|
-
|
|
2357
|
+
for (const key of ["cause", "error"]) {
|
|
2358
|
+
const nested = candidate[key];
|
|
2359
|
+
if (nested && nested !== error && matchesErrorChain(nested, predicate)) {
|
|
2360
|
+
return true;
|
|
2361
|
+
}
|
|
2284
2362
|
}
|
|
2285
|
-
|
|
2286
|
-
|
|
2363
|
+
return false;
|
|
2364
|
+
}
|
|
2365
|
+
function isSqliteBusyError2(error) {
|
|
2366
|
+
return matchesErrorChain(error, (candidate) => {
|
|
2367
|
+
const message = typeof candidate.message === "string" ? candidate.message.toLowerCase() : "";
|
|
2368
|
+
return candidate.code === "SQLITE_BUSY" || candidate.errno === 5 || message.includes("sqlite_busy") || message.includes("database is locked");
|
|
2369
|
+
});
|
|
2287
2370
|
}
|
|
2288
2371
|
function isSqliteCorruptionError(error) {
|
|
2289
|
-
|
|
2290
|
-
|
|
2372
|
+
return matchesErrorChain(error, (candidate) => {
|
|
2373
|
+
const message = typeof candidate.message === "string" ? candidate.message.toLowerCase() : "";
|
|
2374
|
+
return candidate.code === "SQLITE_CORRUPT" || candidate.code === "SQLITE_NOTADB" || candidate.errno === 11 || candidate.errno === 26 || message.includes("database disk image is malformed") || message.includes("file is not a database") || message.includes("database corruption") || message.includes("sqlite_corrupt") || message.includes("sqlite_notadb");
|
|
2375
|
+
});
|
|
2376
|
+
}
|
|
2377
|
+
function isSqliteCantOpenError(error) {
|
|
2378
|
+
return matchesErrorChain(error, (candidate) => {
|
|
2379
|
+
const message = typeof candidate.message === "string" ? candidate.message.toLowerCase() : "";
|
|
2380
|
+
return candidate.code === "SQLITE_CANTOPEN" || message.includes("unable to open database file");
|
|
2381
|
+
});
|
|
2382
|
+
}
|
|
2383
|
+
var STORAGE_UNAVAILABLE_CODES = /* @__PURE__ */ new Set([
|
|
2384
|
+
"EACCES",
|
|
2385
|
+
"EPERM",
|
|
2386
|
+
"EROFS",
|
|
2387
|
+
"ENOSPC",
|
|
2388
|
+
"ENOTDIR",
|
|
2389
|
+
"ENAMETOOLONG",
|
|
2390
|
+
"ENOENT",
|
|
2391
|
+
"ELOOP",
|
|
2392
|
+
"EIO",
|
|
2393
|
+
"EMFILE",
|
|
2394
|
+
"ENFILE"
|
|
2395
|
+
]);
|
|
2396
|
+
function isStorageUnavailableError(error) {
|
|
2397
|
+
return matchesErrorChain(error, (candidate) => {
|
|
2398
|
+
const message = typeof candidate.message === "string" ? candidate.message.toLowerCase() : "";
|
|
2399
|
+
return typeof candidate.code === "string" && (STORAGE_UNAVAILABLE_CODES.has(candidate.code) || candidate.code === "SQLITE_READONLY" || candidate.code === "SQLITE_CANTOPEN") || candidate.errno === 8 || message.includes("attempt to write a readonly database") || message.includes("unable to open database file");
|
|
2400
|
+
});
|
|
2401
|
+
}
|
|
2402
|
+
function isAppStorageCorruptionError(error) {
|
|
2403
|
+
return error instanceof AppStorageCorruptionError || isSqliteCorruptionError(error);
|
|
2404
|
+
}
|
|
2405
|
+
function classifyAppStorageFailure(error) {
|
|
2406
|
+
if (isAppStorageCorruptionError(error)) {
|
|
2407
|
+
return "corrupt";
|
|
2291
2408
|
}
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
return true;
|
|
2409
|
+
if (isSqliteBusyError2(error)) {
|
|
2410
|
+
return "busy";
|
|
2295
2411
|
}
|
|
2296
|
-
if (
|
|
2297
|
-
return
|
|
2412
|
+
if (isStorageUnavailableError(error)) {
|
|
2413
|
+
return "unavailable";
|
|
2414
|
+
}
|
|
2415
|
+
return "unknown";
|
|
2416
|
+
}
|
|
2417
|
+
function quarantineDirFor(dbPath) {
|
|
2418
|
+
return import_node_path2.default.join(import_node_path2.default.dirname(dbPath), APP_STORAGE_QUARANTINE_DIR);
|
|
2419
|
+
}
|
|
2420
|
+
function safeFileNamePart(value3) {
|
|
2421
|
+
const cleaned = value3.replace(/[^A-Za-z0-9._-]+/g, "_").slice(0, 80);
|
|
2422
|
+
return cleaned.length > 0 ? cleaned : "unknown";
|
|
2423
|
+
}
|
|
2424
|
+
function quarantineKey(scope2, value3) {
|
|
2425
|
+
const digest = (0, import_node_crypto.createHash)("sha256").update(value3).digest("hex").slice(0, 10);
|
|
2426
|
+
return `${scope2}-${safeFileNamePart(value3)}-${digest}`;
|
|
2427
|
+
}
|
|
2428
|
+
function uniqueQuarantinePath(dir, key, extension) {
|
|
2429
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
2430
|
+
return import_node_path2.default.join(dir, `${key}-${stamp}-${(0, import_node_crypto.randomUUID)()}${extension}`);
|
|
2431
|
+
}
|
|
2432
|
+
async function pruneQuarantineCopies(input) {
|
|
2433
|
+
try {
|
|
2434
|
+
const prefix = `${input.key}-`;
|
|
2435
|
+
const names = (await import_node_fs3.promises.readdir(input.dir)).filter((name) => {
|
|
2436
|
+
if (name.startsWith(prefix) && name.endsWith(input.extension)) {
|
|
2437
|
+
return true;
|
|
2438
|
+
}
|
|
2439
|
+
if (!input.legacyPrefix || !name.startsWith(input.legacyPrefix)) {
|
|
2440
|
+
return false;
|
|
2441
|
+
}
|
|
2442
|
+
return input.databaseSidecars ? !name.endsWith("-wal") && !name.endsWith("-shm") : name.endsWith(input.extension);
|
|
2443
|
+
});
|
|
2444
|
+
const copies = await Promise.all(names.map(async (name) => ({
|
|
2445
|
+
name,
|
|
2446
|
+
modifiedAt: (await import_node_fs3.promises.stat(import_node_path2.default.join(input.dir, name))).mtimeMs
|
|
2447
|
+
})));
|
|
2448
|
+
copies.sort(
|
|
2449
|
+
(left, right) => right.modifiedAt - left.modifiedAt || right.name.localeCompare(left.name)
|
|
2450
|
+
);
|
|
2451
|
+
for (const { name } of copies.slice(APP_STORAGE_QUARANTINE_LIMIT)) {
|
|
2452
|
+
const candidate = import_node_path2.default.join(input.dir, name);
|
|
2453
|
+
await import_node_fs3.promises.rm(candidate, { force: true });
|
|
2454
|
+
if (input.databaseSidecars) {
|
|
2455
|
+
await Promise.all([
|
|
2456
|
+
import_node_fs3.promises.rm(`${candidate}-wal`, { force: true }),
|
|
2457
|
+
import_node_fs3.promises.rm(`${candidate}-shm`, { force: true })
|
|
2458
|
+
]);
|
|
2459
|
+
}
|
|
2460
|
+
}
|
|
2461
|
+
} catch {
|
|
2462
|
+
}
|
|
2463
|
+
}
|
|
2464
|
+
function stageDamagedDocumentRecovery(input) {
|
|
2465
|
+
let backupPath = null;
|
|
2466
|
+
const key = quarantineKey("document", input.namespace);
|
|
2467
|
+
try {
|
|
2468
|
+
const dir = quarantineDirFor(input.dbPath);
|
|
2469
|
+
(0, import_node_fs2.mkdirSync)(dir, { recursive: true, mode: 448 });
|
|
2470
|
+
if (process.platform !== "win32") {
|
|
2471
|
+
(0, import_node_fs2.chmodSync)(dir, 448);
|
|
2472
|
+
}
|
|
2473
|
+
const candidate = uniqueQuarantinePath(dir, key, ".json");
|
|
2474
|
+
(0, import_node_fs2.writeFileSync)(candidate, input.raw ?? "", { flag: "wx", mode: 384 });
|
|
2475
|
+
backupPath = candidate;
|
|
2476
|
+
} catch {
|
|
2477
|
+
}
|
|
2478
|
+
try {
|
|
2479
|
+
withStatement(
|
|
2480
|
+
input.db,
|
|
2481
|
+
`DELETE FROM ${APP_STORAGE_TABLE} WHERE namespace = ?`,
|
|
2482
|
+
(statement) => statement.run(input.namespace)
|
|
2483
|
+
);
|
|
2484
|
+
} catch (error) {
|
|
2485
|
+
if (backupPath) {
|
|
2486
|
+
try {
|
|
2487
|
+
(0, import_node_fs2.rmSync)(backupPath, { force: true });
|
|
2488
|
+
} catch {
|
|
2489
|
+
}
|
|
2490
|
+
}
|
|
2491
|
+
throw error;
|
|
2492
|
+
}
|
|
2493
|
+
return {
|
|
2494
|
+
event: {
|
|
2495
|
+
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2496
|
+
scope: "document",
|
|
2497
|
+
dbPath: input.dbPath,
|
|
2498
|
+
namespace: input.namespace,
|
|
2499
|
+
backupPath,
|
|
2500
|
+
reason: input.reason
|
|
2501
|
+
},
|
|
2502
|
+
quarantineKey: key
|
|
2503
|
+
};
|
|
2504
|
+
}
|
|
2505
|
+
function discardStagedDocumentRecovery(recovery) {
|
|
2506
|
+
if (!recovery?.event.backupPath) {
|
|
2507
|
+
return;
|
|
2508
|
+
}
|
|
2509
|
+
try {
|
|
2510
|
+
(0, import_node_fs2.rmSync)(recovery.event.backupPath, { force: true });
|
|
2511
|
+
} catch {
|
|
2512
|
+
}
|
|
2513
|
+
}
|
|
2514
|
+
async function finalizeDocumentRecovery(recovery) {
|
|
2515
|
+
if (!recovery) {
|
|
2516
|
+
return;
|
|
2517
|
+
}
|
|
2518
|
+
recordRecovery(recovery.event);
|
|
2519
|
+
await pruneQuarantineCopies({
|
|
2520
|
+
dir: quarantineDirFor(recovery.event.dbPath),
|
|
2521
|
+
key: recovery.quarantineKey,
|
|
2522
|
+
extension: ".json",
|
|
2523
|
+
legacyPrefix: `${safeFileNamePart(recovery.event.namespace ?? "unknown")}-`
|
|
2524
|
+
});
|
|
2525
|
+
}
|
|
2526
|
+
async function copyDatabaseToQuarantine(dbPath) {
|
|
2527
|
+
const dir = quarantineDirFor(dbPath);
|
|
2528
|
+
await import_node_fs3.promises.mkdir(dir, { recursive: true, mode: 448 });
|
|
2529
|
+
if (process.platform !== "win32") {
|
|
2530
|
+
await import_node_fs3.promises.chmod(dir, 448);
|
|
2531
|
+
}
|
|
2532
|
+
const key = quarantineKey("database", import_node_path2.default.basename(dbPath));
|
|
2533
|
+
const target = uniqueQuarantinePath(dir, key, ".sqlite");
|
|
2534
|
+
const copiedSuffixes = [];
|
|
2535
|
+
try {
|
|
2536
|
+
await import_node_fs3.promises.copyFile(dbPath, target);
|
|
2537
|
+
copiedSuffixes.push("");
|
|
2538
|
+
if (process.platform !== "win32") {
|
|
2539
|
+
await import_node_fs3.promises.chmod(target, 384);
|
|
2540
|
+
}
|
|
2541
|
+
for (const suffix of ["-wal", "-shm"]) {
|
|
2542
|
+
try {
|
|
2543
|
+
await import_node_fs3.promises.copyFile(`${dbPath}${suffix}`, `${target}${suffix}`);
|
|
2544
|
+
copiedSuffixes.push(suffix);
|
|
2545
|
+
if (process.platform !== "win32") {
|
|
2546
|
+
await import_node_fs3.promises.chmod(`${target}${suffix}`, 384);
|
|
2547
|
+
}
|
|
2548
|
+
} catch (error) {
|
|
2549
|
+
if (error.code !== "ENOENT") {
|
|
2550
|
+
throw error;
|
|
2551
|
+
}
|
|
2552
|
+
}
|
|
2553
|
+
}
|
|
2554
|
+
} catch (error) {
|
|
2555
|
+
for (const copiedSuffix of copiedSuffixes) {
|
|
2556
|
+
await import_node_fs3.promises.rm(`${target}${copiedSuffix}`, { force: true }).catch(() => void 0);
|
|
2557
|
+
}
|
|
2558
|
+
throw error;
|
|
2559
|
+
}
|
|
2560
|
+
return { backupPath: target, quarantineKey: key };
|
|
2561
|
+
}
|
|
2562
|
+
async function installReplacementDatabase(dbPath, replacementPath) {
|
|
2563
|
+
for (const suffix of ["-wal", "-shm"]) {
|
|
2564
|
+
await import_node_fs3.promises.rm(`${dbPath}${suffix}`, { force: true });
|
|
2565
|
+
}
|
|
2566
|
+
try {
|
|
2567
|
+
await import_node_fs3.promises.rename(replacementPath, dbPath);
|
|
2568
|
+
} catch (error) {
|
|
2569
|
+
const code = error.code;
|
|
2570
|
+
if (code !== "EEXIST" && code !== "EPERM") {
|
|
2571
|
+
throw error;
|
|
2572
|
+
}
|
|
2573
|
+
await import_node_fs3.promises.copyFile(replacementPath, dbPath);
|
|
2574
|
+
await import_node_fs3.promises.rm(replacementPath, { force: true }).catch(() => void 0);
|
|
2298
2575
|
}
|
|
2299
|
-
const message = typeof sqliteError.message === "string" ? sqliteError.message.toLowerCase() : "";
|
|
2300
|
-
return sqliteError.code === "SQLITE_CORRUPT" || sqliteError.code === "SQLITE_NOTADB" || sqliteError.errno === 11 || sqliteError.errno === 26 || message.includes("database disk image is malformed") || message.includes("file is not a database") || message.includes("database corruption") || message.includes("sqlite_corrupt") || message.includes("sqlite_notadb");
|
|
2301
2576
|
}
|
|
2302
2577
|
function beginImmediate(db) {
|
|
2303
2578
|
db.exec("BEGIN IMMEDIATE");
|
|
@@ -2311,7 +2586,7 @@ function rollback(db) {
|
|
|
2311
2586
|
} catch {
|
|
2312
2587
|
}
|
|
2313
2588
|
}
|
|
2314
|
-
function
|
|
2589
|
+
function withStatement(db, sql, task) {
|
|
2315
2590
|
const statement = db.prepare(sql);
|
|
2316
2591
|
try {
|
|
2317
2592
|
return task(statement);
|
|
@@ -2341,10 +2616,11 @@ function applyConnectionPragmas(db) {
|
|
|
2341
2616
|
db.exec("PRAGMA journal_mode = WAL;");
|
|
2342
2617
|
db.exec("PRAGMA foreign_keys = ON;");
|
|
2343
2618
|
}
|
|
2344
|
-
function
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2619
|
+
function applyReadConnectionPragmas(db) {
|
|
2620
|
+
db.exec(`PRAGMA busy_timeout = ${SQLITE_BUSY_TIMEOUT_MS};`);
|
|
2621
|
+
db.exec("PRAGMA foreign_keys = ON;");
|
|
2622
|
+
}
|
|
2623
|
+
function ensureSchema(db) {
|
|
2348
2624
|
db.exec(`
|
|
2349
2625
|
CREATE TABLE IF NOT EXISTS ${APP_STORAGE_TABLE} (
|
|
2350
2626
|
namespace TEXT PRIMARY KEY,
|
|
@@ -2352,76 +2628,387 @@ function ensureSchema(db, dbPath) {
|
|
|
2352
2628
|
updated_at TEXT NOT NULL
|
|
2353
2629
|
)
|
|
2354
2630
|
`);
|
|
2355
|
-
initializedDbPaths.add(dbPath);
|
|
2356
2631
|
}
|
|
2357
2632
|
async function openDatabase(dbPath) {
|
|
2358
|
-
const dbDir =
|
|
2359
|
-
await
|
|
2633
|
+
const dbDir = import_node_path2.default.dirname(dbPath);
|
|
2634
|
+
await import_node_fs3.promises.mkdir(dbDir, { recursive: true, mode: 448 });
|
|
2360
2635
|
if (process.platform !== "win32") {
|
|
2361
|
-
await
|
|
2636
|
+
await import_node_fs3.promises.chmod(dbDir, 448);
|
|
2362
2637
|
}
|
|
2363
2638
|
if (process.versions.bun !== void 0) {
|
|
2364
2639
|
const sqlite2 = await Function("return import('bun:sqlite')")();
|
|
2365
2640
|
const database2 = new sqlite2.Database(dbPath);
|
|
2366
|
-
|
|
2641
|
+
try {
|
|
2642
|
+
if (process.platform !== "win32") {
|
|
2643
|
+
await import_node_fs3.promises.chmod(dbPath, 384);
|
|
2644
|
+
}
|
|
2645
|
+
return {
|
|
2646
|
+
exec: database2.exec.bind(database2),
|
|
2647
|
+
prepare: database2.prepare.bind(database2),
|
|
2648
|
+
close: database2.close.bind(database2)
|
|
2649
|
+
};
|
|
2650
|
+
} catch (error) {
|
|
2651
|
+
database2.close();
|
|
2652
|
+
throw error;
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
const sqlite = await Function("return import('node:sqlite')")();
|
|
2656
|
+
const database = new sqlite.DatabaseSync(dbPath);
|
|
2657
|
+
try {
|
|
2658
|
+
if (process.platform !== "win32") {
|
|
2659
|
+
await import_node_fs3.promises.chmod(dbPath, 384);
|
|
2660
|
+
}
|
|
2661
|
+
return {
|
|
2662
|
+
exec: database.exec.bind(database),
|
|
2663
|
+
prepare: database.prepare.bind(database),
|
|
2664
|
+
close: database.close.bind(database)
|
|
2665
|
+
};
|
|
2666
|
+
} catch (error) {
|
|
2667
|
+
database.close();
|
|
2668
|
+
throw error;
|
|
2669
|
+
}
|
|
2670
|
+
}
|
|
2671
|
+
async function openReadOnlyDatabase(dbPath) {
|
|
2672
|
+
if (process.versions.bun !== void 0) {
|
|
2673
|
+
const sqlite2 = await Function("return import('bun:sqlite')")();
|
|
2674
|
+
const database2 = new sqlite2.Database(dbPath, { readonly: true });
|
|
2675
|
+
return {
|
|
2367
2676
|
exec: database2.exec.bind(database2),
|
|
2368
2677
|
prepare: database2.prepare.bind(database2),
|
|
2369
2678
|
close: database2.close.bind(database2)
|
|
2370
2679
|
};
|
|
2371
|
-
if (process.platform !== "win32") {
|
|
2372
|
-
await import_node_fs.promises.chmod(dbPath, 384);
|
|
2373
|
-
}
|
|
2374
|
-
return result3;
|
|
2375
2680
|
}
|
|
2376
2681
|
const sqlite = await Function("return import('node:sqlite')")();
|
|
2377
|
-
const database = new sqlite.DatabaseSync(dbPath);
|
|
2378
|
-
|
|
2682
|
+
const database = new sqlite.DatabaseSync(dbPath, { readOnly: true });
|
|
2683
|
+
return {
|
|
2379
2684
|
exec: database.exec.bind(database),
|
|
2380
2685
|
prepare: database.prepare.bind(database),
|
|
2381
2686
|
close: database.close.bind(database)
|
|
2382
2687
|
};
|
|
2383
|
-
|
|
2384
|
-
|
|
2688
|
+
}
|
|
2689
|
+
function sqliteBusyError(message) {
|
|
2690
|
+
return Object.assign(new Error(message), { code: "SQLITE_BUSY" });
|
|
2691
|
+
}
|
|
2692
|
+
function isMissingStorageTableError(error) {
|
|
2693
|
+
return matchesErrorChain(error, (candidate) => {
|
|
2694
|
+
const message = typeof candidate.message === "string" ? candidate.message.toLowerCase() : "";
|
|
2695
|
+
return message.includes(`no such table: ${APP_STORAGE_TABLE}`);
|
|
2696
|
+
});
|
|
2697
|
+
}
|
|
2698
|
+
async function acquireDatabaseFileLock(dbPath, mode) {
|
|
2699
|
+
const acquire = mode === "read" ? acquireCrossProcessFileReadLock : acquireCrossProcessFileLock;
|
|
2700
|
+
for (let attempt = 1; attempt <= SQLITE_BUSY_MAX_ATTEMPTS; attempt += 1) {
|
|
2701
|
+
const release = await acquire(dbPath);
|
|
2702
|
+
if (release) {
|
|
2703
|
+
return release;
|
|
2704
|
+
}
|
|
2705
|
+
if (attempt < SQLITE_BUSY_MAX_ATTEMPTS) {
|
|
2706
|
+
await sleep(SQLITE_BUSY_RETRY_DELAY_MS * attempt);
|
|
2707
|
+
}
|
|
2385
2708
|
}
|
|
2386
|
-
|
|
2709
|
+
throw sqliteBusyError(`App storage ${mode} lock is busy.`);
|
|
2387
2710
|
}
|
|
2388
|
-
function
|
|
2389
|
-
|
|
2711
|
+
async function probeDatabaseHealth(dbPath) {
|
|
2712
|
+
if (!(0, import_node_fs2.existsSync)(dbPath)) {
|
|
2713
|
+
return "healthy";
|
|
2714
|
+
}
|
|
2715
|
+
let db = null;
|
|
2716
|
+
try {
|
|
2717
|
+
db = await openReadOnlyDatabase(dbPath);
|
|
2718
|
+
applyReadConnectionPragmas(db);
|
|
2719
|
+
const row = withStatement(
|
|
2720
|
+
db,
|
|
2721
|
+
"PRAGMA quick_check(1)",
|
|
2722
|
+
(statement) => statement.get()
|
|
2723
|
+
);
|
|
2724
|
+
return isRecord(row) && Object.values(row).some((value3) => value3 === "ok") ? "healthy" : "corrupt";
|
|
2725
|
+
} catch (error) {
|
|
2726
|
+
if (isAppStorageCorruptionError(error)) {
|
|
2727
|
+
return "corrupt";
|
|
2728
|
+
}
|
|
2729
|
+
throw error;
|
|
2730
|
+
} finally {
|
|
2731
|
+
db?.close();
|
|
2732
|
+
}
|
|
2733
|
+
}
|
|
2734
|
+
async function readSalvageableDocuments(dbPath) {
|
|
2735
|
+
let db = null;
|
|
2736
|
+
try {
|
|
2737
|
+
db = await openReadOnlyDatabase(dbPath);
|
|
2738
|
+
applyReadConnectionPragmas(db);
|
|
2739
|
+
const rows = withStatement(
|
|
2740
|
+
db,
|
|
2741
|
+
`
|
|
2742
|
+
SELECT
|
|
2743
|
+
namespace,
|
|
2744
|
+
value_json AS valueJson,
|
|
2745
|
+
updated_at AS updatedAt
|
|
2746
|
+
FROM ${APP_STORAGE_TABLE}
|
|
2747
|
+
`,
|
|
2748
|
+
(statement) => statement.all()
|
|
2749
|
+
);
|
|
2750
|
+
return rows.flatMap((row) => {
|
|
2751
|
+
if (!isRecord(row) || typeof row.namespace !== "string" || typeof row.valueJson !== "string" || typeof row.updatedAt !== "string") {
|
|
2752
|
+
return [];
|
|
2753
|
+
}
|
|
2754
|
+
return [{
|
|
2755
|
+
namespace: row.namespace,
|
|
2756
|
+
valueJson: row.valueJson,
|
|
2757
|
+
updatedAt: row.updatedAt
|
|
2758
|
+
}];
|
|
2759
|
+
});
|
|
2760
|
+
} catch (error) {
|
|
2761
|
+
if (isAppStorageCorruptionError(error) || isMissingStorageTableError(error)) {
|
|
2762
|
+
return [];
|
|
2763
|
+
}
|
|
2764
|
+
throw error;
|
|
2765
|
+
} finally {
|
|
2766
|
+
db?.close();
|
|
2767
|
+
}
|
|
2768
|
+
}
|
|
2769
|
+
async function buildReplacementDatabase(dbPath, rows) {
|
|
2770
|
+
const replacementPath = `${dbPath}.recovery-${(0, import_node_crypto.randomUUID)()}.sqlite`;
|
|
2771
|
+
try {
|
|
2772
|
+
const db = await openDatabase(replacementPath);
|
|
2773
|
+
try {
|
|
2774
|
+
db.exec(`PRAGMA busy_timeout = ${SQLITE_BUSY_TIMEOUT_MS};`);
|
|
2775
|
+
db.exec("PRAGMA journal_mode = DELETE;");
|
|
2776
|
+
db.exec("PRAGMA foreign_keys = ON;");
|
|
2777
|
+
ensureSchema(db);
|
|
2778
|
+
beginImmediate(db);
|
|
2779
|
+
try {
|
|
2780
|
+
for (const row of rows) {
|
|
2781
|
+
withStatement(
|
|
2782
|
+
db,
|
|
2783
|
+
`
|
|
2784
|
+
INSERT INTO ${APP_STORAGE_TABLE} (namespace, value_json, updated_at)
|
|
2785
|
+
VALUES (?, ?, ?)
|
|
2786
|
+
`,
|
|
2787
|
+
(statement) => statement.run(row.namespace, row.valueJson, row.updatedAt)
|
|
2788
|
+
);
|
|
2789
|
+
}
|
|
2790
|
+
commit(db);
|
|
2791
|
+
} catch (error) {
|
|
2792
|
+
rollback(db);
|
|
2793
|
+
throw error;
|
|
2794
|
+
}
|
|
2795
|
+
} finally {
|
|
2796
|
+
db.close();
|
|
2797
|
+
}
|
|
2798
|
+
return replacementPath;
|
|
2799
|
+
} catch (error) {
|
|
2800
|
+
await import_node_fs3.promises.rm(replacementPath, { force: true });
|
|
2801
|
+
throw error;
|
|
2802
|
+
}
|
|
2803
|
+
}
|
|
2804
|
+
async function restoreQuarantinedDatabase(dbPath, backupPath) {
|
|
2805
|
+
for (const suffix of ["", "-wal", "-shm"]) {
|
|
2806
|
+
if (!(0, import_node_fs2.existsSync)(`${backupPath}${suffix}`) || (0, import_node_fs2.existsSync)(`${dbPath}${suffix}`)) {
|
|
2807
|
+
continue;
|
|
2808
|
+
}
|
|
2809
|
+
try {
|
|
2810
|
+
await import_node_fs3.promises.rename(`${backupPath}${suffix}`, `${dbPath}${suffix}`);
|
|
2811
|
+
} catch {
|
|
2812
|
+
}
|
|
2813
|
+
}
|
|
2814
|
+
}
|
|
2815
|
+
async function performDatabaseRecovery(dbPath, reason) {
|
|
2816
|
+
const release = await acquireDatabaseFileLock(dbPath, "write");
|
|
2817
|
+
try {
|
|
2818
|
+
if (await probeDatabaseHealth(dbPath) === "healthy") {
|
|
2819
|
+
return;
|
|
2820
|
+
}
|
|
2821
|
+
const salvagedRows = await readSalvageableDocuments(dbPath);
|
|
2822
|
+
const replacementPath = await buildReplacementDatabase(dbPath, salvagedRows);
|
|
2823
|
+
let backup = null;
|
|
2824
|
+
try {
|
|
2825
|
+
backup = await copyDatabaseToQuarantine(dbPath);
|
|
2826
|
+
await installReplacementDatabase(dbPath, replacementPath);
|
|
2827
|
+
} catch (error) {
|
|
2828
|
+
await import_node_fs3.promises.rm(replacementPath, { force: true });
|
|
2829
|
+
if (backup) {
|
|
2830
|
+
await restoreQuarantinedDatabase(dbPath, backup.backupPath);
|
|
2831
|
+
}
|
|
2832
|
+
throw error;
|
|
2833
|
+
}
|
|
2834
|
+
recordRecovery({
|
|
2835
|
+
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2836
|
+
scope: "database",
|
|
2837
|
+
dbPath,
|
|
2838
|
+
namespace: null,
|
|
2839
|
+
backupPath: backup.backupPath,
|
|
2840
|
+
reason: `${reason} Salvaged ${salvagedRows.length} document(s).`
|
|
2841
|
+
});
|
|
2842
|
+
await pruneQuarantineCopies({
|
|
2843
|
+
dir: quarantineDirFor(dbPath),
|
|
2844
|
+
key: backup.quarantineKey,
|
|
2845
|
+
extension: ".sqlite",
|
|
2846
|
+
databaseSidecars: true,
|
|
2847
|
+
legacyPrefix: `${safeFileNamePart(import_node_path2.default.basename(dbPath))}-`
|
|
2848
|
+
});
|
|
2849
|
+
} finally {
|
|
2850
|
+
await release();
|
|
2851
|
+
}
|
|
2852
|
+
}
|
|
2853
|
+
async function recoverCorruptDatabase(dbPath, reason) {
|
|
2854
|
+
const activeRecovery = databaseRecoveryByDbPath.get(dbPath);
|
|
2855
|
+
if (activeRecovery) {
|
|
2856
|
+
return activeRecovery;
|
|
2857
|
+
}
|
|
2858
|
+
const recovery = performDatabaseRecovery(dbPath, reason);
|
|
2859
|
+
databaseRecoveryByDbPath.set(dbPath, recovery);
|
|
2860
|
+
try {
|
|
2861
|
+
await recovery;
|
|
2862
|
+
} finally {
|
|
2863
|
+
if (databaseRecoveryByDbPath.get(dbPath) === recovery) {
|
|
2864
|
+
databaseRecoveryByDbPath.delete(dbPath);
|
|
2865
|
+
}
|
|
2866
|
+
}
|
|
2390
2867
|
}
|
|
2391
2868
|
async function withDatabase(dbPath, task) {
|
|
2392
|
-
|
|
2869
|
+
let busyAttempts = 0;
|
|
2870
|
+
let databaseRecovered = false;
|
|
2871
|
+
for (; ; ) {
|
|
2393
2872
|
let db = null;
|
|
2873
|
+
let releaseFileLock = null;
|
|
2874
|
+
let corruption = null;
|
|
2394
2875
|
try {
|
|
2876
|
+
releaseFileLock = await acquireDatabaseFileLock(dbPath, "read");
|
|
2395
2877
|
db = await openDatabase(dbPath);
|
|
2396
2878
|
applyConnectionPragmas(db);
|
|
2397
|
-
ensureSchema(db
|
|
2879
|
+
ensureSchema(db);
|
|
2398
2880
|
return task(db);
|
|
2399
2881
|
} catch (error) {
|
|
2400
|
-
if (error
|
|
2882
|
+
if (isAppStorageCorruptionError(error)) {
|
|
2883
|
+
if (databaseRecovered) {
|
|
2884
|
+
throw error instanceof AppStorageCorruptionError ? error : new AppStorageCorruptionError("App storage database is corrupt.", {
|
|
2885
|
+
dbPath,
|
|
2886
|
+
cause: error
|
|
2887
|
+
});
|
|
2888
|
+
}
|
|
2889
|
+
databaseRecovered = true;
|
|
2890
|
+
corruption = error;
|
|
2891
|
+
} else if (!isSqliteBusyError2(error)) {
|
|
2401
2892
|
throw error;
|
|
2893
|
+
} else {
|
|
2894
|
+
busyAttempts += 1;
|
|
2895
|
+
if (busyAttempts >= SQLITE_BUSY_MAX_ATTEMPTS) {
|
|
2896
|
+
throw error;
|
|
2897
|
+
}
|
|
2402
2898
|
}
|
|
2403
|
-
|
|
2899
|
+
} finally {
|
|
2900
|
+
db?.close();
|
|
2901
|
+
await releaseFileLock?.();
|
|
2902
|
+
}
|
|
2903
|
+
if (corruption) {
|
|
2904
|
+
try {
|
|
2905
|
+
await recoverCorruptDatabase(dbPath, describeError(corruption));
|
|
2906
|
+
} catch (error) {
|
|
2907
|
+
if (isSqliteBusyError2(error) || isStorageUnavailableError(error)) {
|
|
2908
|
+
throw error;
|
|
2909
|
+
}
|
|
2404
2910
|
throw new AppStorageCorruptionError(
|
|
2405
|
-
"App storage database is corrupt.",
|
|
2911
|
+
"App storage database is corrupt and could not be moved aside.",
|
|
2406
2912
|
{ dbPath, cause: error }
|
|
2407
2913
|
);
|
|
2408
2914
|
}
|
|
2409
|
-
|
|
2915
|
+
continue;
|
|
2916
|
+
}
|
|
2917
|
+
await sleep(SQLITE_BUSY_RETRY_DELAY_MS * busyAttempts);
|
|
2918
|
+
}
|
|
2919
|
+
}
|
|
2920
|
+
async function withReadOnlyDatabase(dbPath, task) {
|
|
2921
|
+
let busyAttempts = 0;
|
|
2922
|
+
let databaseRecovered = false;
|
|
2923
|
+
for (; ; ) {
|
|
2924
|
+
let db = null;
|
|
2925
|
+
let releaseFileLock = null;
|
|
2926
|
+
let corruption = null;
|
|
2927
|
+
let requiresReadWriteFallback = false;
|
|
2928
|
+
try {
|
|
2929
|
+
try {
|
|
2930
|
+
releaseFileLock = await acquireDatabaseFileLock(dbPath, "read");
|
|
2931
|
+
} catch (error) {
|
|
2932
|
+
if (!isStorageUnavailableError(error)) {
|
|
2933
|
+
throw error;
|
|
2934
|
+
}
|
|
2935
|
+
}
|
|
2936
|
+
db = await openReadOnlyDatabase(dbPath);
|
|
2937
|
+
applyReadConnectionPragmas(db);
|
|
2938
|
+
return task(db);
|
|
2939
|
+
} catch (error) {
|
|
2940
|
+
if (isMissingStorageTableError(error) || isSqliteCantOpenError(error)) {
|
|
2941
|
+
requiresReadWriteFallback = true;
|
|
2942
|
+
} else if (isAppStorageCorruptionError(error)) {
|
|
2943
|
+
if (databaseRecovered) {
|
|
2944
|
+
throw error;
|
|
2945
|
+
}
|
|
2946
|
+
databaseRecovered = true;
|
|
2947
|
+
corruption = error;
|
|
2948
|
+
} else if (!isSqliteBusyError2(error)) {
|
|
2410
2949
|
throw error;
|
|
2950
|
+
} else {
|
|
2951
|
+
busyAttempts += 1;
|
|
2952
|
+
if (busyAttempts >= SQLITE_BUSY_MAX_ATTEMPTS) {
|
|
2953
|
+
throw error;
|
|
2954
|
+
}
|
|
2411
2955
|
}
|
|
2412
2956
|
} finally {
|
|
2413
2957
|
db?.close();
|
|
2958
|
+
await releaseFileLock?.();
|
|
2959
|
+
}
|
|
2960
|
+
if (requiresReadWriteFallback) {
|
|
2961
|
+
return withDatabase(dbPath, task);
|
|
2962
|
+
}
|
|
2963
|
+
if (corruption) {
|
|
2964
|
+
await recoverCorruptDatabase(dbPath, describeError(corruption));
|
|
2965
|
+
continue;
|
|
2414
2966
|
}
|
|
2415
|
-
await sleep(SQLITE_BUSY_RETRY_DELAY_MS *
|
|
2967
|
+
await sleep(SQLITE_BUSY_RETRY_DELAY_MS * busyAttempts);
|
|
2416
2968
|
}
|
|
2417
|
-
|
|
2969
|
+
}
|
|
2970
|
+
async function withReadableDatabase(dbPath, task) {
|
|
2971
|
+
return (0, import_node_fs2.existsSync)(dbPath) ? withReadOnlyDatabase(dbPath, task) : withDatabase(dbPath, task);
|
|
2418
2972
|
}
|
|
2419
2973
|
function resolveAppStorageDbPath(userDataDir) {
|
|
2420
|
-
return
|
|
2974
|
+
return import_node_path2.default.join(userDataDir, APP_STORAGE_DB_DIR, APP_STORAGE_DB_NAME);
|
|
2975
|
+
}
|
|
2976
|
+
function readStrictDocumentRow(input) {
|
|
2977
|
+
const row = withStatement(
|
|
2978
|
+
input.db,
|
|
2979
|
+
`SELECT value_json AS valueJson FROM ${APP_STORAGE_TABLE} WHERE namespace = ?`,
|
|
2980
|
+
(statement) => statement.get(input.namespace)
|
|
2981
|
+
);
|
|
2982
|
+
if (!isRecord(row)) {
|
|
2983
|
+
return { kind: "absent" };
|
|
2984
|
+
}
|
|
2985
|
+
const raw = typeof row.valueJson === "string" ? row.valueJson : null;
|
|
2986
|
+
if (raw === null || raw.trim().length === 0) {
|
|
2987
|
+
return { kind: "damaged", raw, reason: "Stored document is empty." };
|
|
2988
|
+
}
|
|
2989
|
+
let parsed;
|
|
2990
|
+
try {
|
|
2991
|
+
parsed = JSON.parse(raw);
|
|
2992
|
+
} catch (error) {
|
|
2993
|
+
return {
|
|
2994
|
+
kind: "damaged",
|
|
2995
|
+
raw,
|
|
2996
|
+
reason: `Stored document is not valid JSON: ${describeError(error)}`
|
|
2997
|
+
};
|
|
2998
|
+
}
|
|
2999
|
+
try {
|
|
3000
|
+
return { kind: "value", value: input.normalize(parsed) };
|
|
3001
|
+
} catch (error) {
|
|
3002
|
+
return {
|
|
3003
|
+
kind: "damaged",
|
|
3004
|
+
raw,
|
|
3005
|
+
reason: `Stored document failed validation: ${describeError(error)}`
|
|
3006
|
+
};
|
|
3007
|
+
}
|
|
2421
3008
|
}
|
|
2422
3009
|
async function readDocument(dbPath, namespace, normalize3) {
|
|
2423
|
-
return
|
|
2424
|
-
const row =
|
|
3010
|
+
return withReadableDatabase(dbPath, (db) => {
|
|
3011
|
+
const row = withStatement(
|
|
2425
3012
|
db,
|
|
2426
3013
|
`SELECT value_json AS valueJson FROM ${APP_STORAGE_TABLE} WHERE namespace = ?`,
|
|
2427
3014
|
(statement) => statement.get(namespace)
|
|
@@ -2434,38 +3021,46 @@ async function readDocument(dbPath, namespace, normalize3) {
|
|
|
2434
3021
|
});
|
|
2435
3022
|
}
|
|
2436
3023
|
async function readDocumentStrict(dbPath, namespace, normalize3) {
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
{
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
3024
|
+
const initialRead = await withReadableDatabase(
|
|
3025
|
+
dbPath,
|
|
3026
|
+
(db) => readStrictDocumentRow({ db, namespace, normalize: normalize3 })
|
|
3027
|
+
);
|
|
3028
|
+
if (initialRead.kind === "value") {
|
|
3029
|
+
return initialRead.value;
|
|
3030
|
+
}
|
|
3031
|
+
if (initialRead.kind === "absent") {
|
|
3032
|
+
return null;
|
|
3033
|
+
}
|
|
3034
|
+
const recovered = await withWriteQueue(
|
|
3035
|
+
dbPath,
|
|
3036
|
+
async () => withDatabase(dbPath, (db) => {
|
|
3037
|
+
let stagedRecovery = null;
|
|
3038
|
+
beginImmediate(db);
|
|
3039
|
+
try {
|
|
3040
|
+
const read = readStrictDocumentRow({ db, namespace, normalize: normalize3 });
|
|
3041
|
+
let value3 = null;
|
|
3042
|
+
if (read.kind === "value") {
|
|
3043
|
+
value3 = read.value;
|
|
3044
|
+
} else if (read.kind === "damaged") {
|
|
3045
|
+
stagedRecovery = stageDamagedDocumentRecovery({
|
|
3046
|
+
db,
|
|
3047
|
+
dbPath,
|
|
3048
|
+
namespace,
|
|
3049
|
+
raw: read.raw,
|
|
3050
|
+
reason: read.reason
|
|
3051
|
+
});
|
|
2465
3052
|
}
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
3053
|
+
commit(db);
|
|
3054
|
+
return { value: value3, stagedRecovery };
|
|
3055
|
+
} catch (error) {
|
|
3056
|
+
rollback(db);
|
|
3057
|
+
discardStagedDocumentRecovery(stagedRecovery);
|
|
3058
|
+
throw error;
|
|
3059
|
+
}
|
|
3060
|
+
})
|
|
3061
|
+
);
|
|
3062
|
+
await finalizeDocumentRecovery(recovered.stagedRecovery);
|
|
3063
|
+
return recovered.value;
|
|
2469
3064
|
}
|
|
2470
3065
|
async function writeDocument(dbPath, namespace, value3, options = {}) {
|
|
2471
3066
|
return withWriteQueue(
|
|
@@ -2474,7 +3069,7 @@ async function writeDocument(dbPath, namespace, value3, options = {}) {
|
|
|
2474
3069
|
const normalizedValue = options.cloneValue === false ? value3 : clone(value3);
|
|
2475
3070
|
beginImmediate(db);
|
|
2476
3071
|
try {
|
|
2477
|
-
|
|
3072
|
+
withStatement(
|
|
2478
3073
|
db,
|
|
2479
3074
|
`
|
|
2480
3075
|
INSERT INTO ${APP_STORAGE_TABLE} (namespace, value_json, updated_at)
|
|
@@ -2496,36 +3091,42 @@ async function writeDocument(dbPath, namespace, value3, options = {}) {
|
|
|
2496
3091
|
);
|
|
2497
3092
|
}
|
|
2498
3093
|
async function updateDocument(input) {
|
|
2499
|
-
|
|
3094
|
+
const updated = await withWriteQueue(
|
|
2500
3095
|
input.dbPath,
|
|
2501
3096
|
async () => withDatabase(input.dbPath, (db) => {
|
|
3097
|
+
let stagedRecovery = null;
|
|
2502
3098
|
beginImmediate(db);
|
|
2503
3099
|
try {
|
|
2504
|
-
const row = useStatement(
|
|
2505
|
-
db,
|
|
2506
|
-
`SELECT value_json AS valueJson FROM ${APP_STORAGE_TABLE} WHERE namespace = ?`,
|
|
2507
|
-
(statement) => statement.get(input.namespace)
|
|
2508
|
-
);
|
|
2509
3100
|
let current;
|
|
2510
|
-
if (
|
|
2511
|
-
const
|
|
2512
|
-
|
|
2513
|
-
namespace: input.namespace
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
3101
|
+
if (input.strictExisting) {
|
|
3102
|
+
const read = readStrictDocumentRow({
|
|
3103
|
+
db,
|
|
3104
|
+
namespace: input.namespace,
|
|
3105
|
+
normalize: input.normalize
|
|
3106
|
+
});
|
|
3107
|
+
if (read.kind === "damaged") {
|
|
3108
|
+
stagedRecovery = stageDamagedDocumentRecovery({
|
|
3109
|
+
db,
|
|
3110
|
+
dbPath: input.dbPath,
|
|
3111
|
+
namespace: input.namespace,
|
|
3112
|
+
raw: read.raw,
|
|
3113
|
+
reason: read.reason
|
|
3114
|
+
});
|
|
2520
3115
|
}
|
|
2521
|
-
current =
|
|
3116
|
+
current = read.kind === "value" ? read.value : input.fallback();
|
|
2522
3117
|
} else {
|
|
2523
|
-
|
|
3118
|
+
const row = withStatement(
|
|
3119
|
+
db,
|
|
3120
|
+
`SELECT value_json AS valueJson FROM ${APP_STORAGE_TABLE} WHERE namespace = ?`,
|
|
3121
|
+
(statement) => statement.get(input.namespace)
|
|
3122
|
+
);
|
|
3123
|
+
const parsed = isRecord(row) ? safeParseJson(row.valueJson) : null;
|
|
3124
|
+
current = input.normalize(parsed ?? input.fallback());
|
|
2524
3125
|
}
|
|
2525
3126
|
const transformInput = input.cloneBeforeTransform === false ? current : clone(current);
|
|
2526
3127
|
const transformed = input.transform(transformInput);
|
|
2527
3128
|
const next = input.normalizeResult === false ? transformed : input.normalize(transformed);
|
|
2528
|
-
|
|
3129
|
+
withStatement(
|
|
2529
3130
|
db,
|
|
2530
3131
|
`
|
|
2531
3132
|
INSERT INTO ${APP_STORAGE_TABLE} (namespace, value_json, updated_at)
|
|
@@ -2538,13 +3139,19 @@ async function updateDocument(input) {
|
|
|
2538
3139
|
(statement) => statement.run(input.namespace, JSON.stringify(next), (/* @__PURE__ */ new Date()).toISOString())
|
|
2539
3140
|
);
|
|
2540
3141
|
commit(db);
|
|
2541
|
-
return
|
|
3142
|
+
return {
|
|
3143
|
+
value: input.cloneResult === false ? next : clone(next),
|
|
3144
|
+
stagedRecovery
|
|
3145
|
+
};
|
|
2542
3146
|
} catch (error) {
|
|
2543
3147
|
rollback(db);
|
|
3148
|
+
discardStagedDocumentRecovery(stagedRecovery);
|
|
2544
3149
|
throw error;
|
|
2545
3150
|
}
|
|
2546
3151
|
})
|
|
2547
3152
|
);
|
|
3153
|
+
await finalizeDocumentRecovery(updated.stagedRecovery);
|
|
3154
|
+
return updated.value;
|
|
2548
3155
|
}
|
|
2549
3156
|
async function deleteDocument(dbPath, namespace) {
|
|
2550
3157
|
await withWriteQueue(
|
|
@@ -2552,7 +3159,7 @@ async function deleteDocument(dbPath, namespace) {
|
|
|
2552
3159
|
async () => withDatabase(dbPath, (db) => {
|
|
2553
3160
|
beginImmediate(db);
|
|
2554
3161
|
try {
|
|
2555
|
-
|
|
3162
|
+
withStatement(
|
|
2556
3163
|
db,
|
|
2557
3164
|
`DELETE FROM ${APP_STORAGE_TABLE} WHERE namespace = ?`,
|
|
2558
3165
|
(statement) => statement.run(namespace)
|
|
@@ -2569,8 +3176,15 @@ async function deleteDocument(dbPath, namespace) {
|
|
|
2569
3176
|
// ../../packages/runtime-app-state/src/app/state.ts
|
|
2570
3177
|
var APP_STATE_DOCUMENT = "desktop.app-state";
|
|
2571
3178
|
var APP_NAME = "codexuse-desktop";
|
|
3179
|
+
var PERSISTENCE_RETRY_COOLDOWN_MS = 5e3;
|
|
3180
|
+
var PERSISTENCE_READ_DEADLINE_MS = 8e3;
|
|
3181
|
+
var READ_TOO_SLOW = /* @__PURE__ */ Symbol("app-state-read-too-slow");
|
|
2572
3182
|
var configuredUserDataDir = null;
|
|
2573
3183
|
var appStateCache = null;
|
|
3184
|
+
var ephemeralAppState = null;
|
|
3185
|
+
var persistenceFailure = null;
|
|
3186
|
+
var pendingRendererUiPatch = null;
|
|
3187
|
+
var nextPersistenceRetryAt = 0;
|
|
2574
3188
|
var writeLock = Promise.resolve();
|
|
2575
3189
|
var writeLockContext = new import_node_async_hooks.AsyncLocalStorage();
|
|
2576
3190
|
function isRecord2(value3) {
|
|
@@ -2601,7 +3215,7 @@ function resolveDefaultUserDataDir() {
|
|
|
2601
3215
|
if (!home) {
|
|
2602
3216
|
throw new Error("Unable to resolve home directory for app state.");
|
|
2603
3217
|
}
|
|
2604
|
-
return
|
|
3218
|
+
return import_node_path3.default.join(home, "Library", "Application Support", APP_NAME);
|
|
2605
3219
|
}
|
|
2606
3220
|
function getUserDataDir() {
|
|
2607
3221
|
return configuredUserDataDir ?? resolveDefaultUserDataDir();
|
|
@@ -2638,7 +3252,7 @@ function createDefaultAppState() {
|
|
|
2638
3252
|
desktopLlmEnabled: false,
|
|
2639
3253
|
desktopLlmRegistry: {
|
|
2640
3254
|
version: 3,
|
|
2641
|
-
revision: (0,
|
|
3255
|
+
revision: (0, import_node_crypto2.createHash)("sha256").update("empty").digest("hex"),
|
|
2642
3256
|
providers: [],
|
|
2643
3257
|
routes: [],
|
|
2644
3258
|
externalProfiles: []
|
|
@@ -2933,7 +3547,7 @@ function normalizeOfficialCodexRelayProfile(value3) {
|
|
|
2933
3547
|
}
|
|
2934
3548
|
function migrateDesktopLlmRegistry(profiles) {
|
|
2935
3549
|
const entries3 = Object.values(profiles).filter((profile) => Boolean(profile.model)).sort((left, right) => left.id.localeCompare(right.id));
|
|
2936
|
-
const revision = (0,
|
|
3550
|
+
const revision = (0, import_node_crypto2.createHash)("sha256").update(
|
|
2937
3551
|
JSON.stringify(
|
|
2938
3552
|
entries3.map((profile) => [
|
|
2939
3553
|
profile.id,
|
|
@@ -3257,7 +3871,7 @@ function normalizeDesktopLlmRegistry(value3, profiles) {
|
|
|
3257
3871
|
externalProfiles.sort((left, right) => left.updatedAt.localeCompare(right.updatedAt)).map((profile) => [profile.id, profile])
|
|
3258
3872
|
).values()
|
|
3259
3873
|
).sort((left, right) => left.id.localeCompare(right.id));
|
|
3260
|
-
const revision = (0,
|
|
3874
|
+
const revision = (0, import_node_crypto2.createHash)("sha256").update(
|
|
3261
3875
|
JSON.stringify({
|
|
3262
3876
|
providers: providers.map((provider) => ({
|
|
3263
3877
|
id: provider.id,
|
|
@@ -3898,10 +4512,10 @@ function normalizeAppState(raw) {
|
|
|
3898
4512
|
([rootPath, profileName]) => {
|
|
3899
4513
|
const normalizedRoot = asString(rootPath);
|
|
3900
4514
|
const normalizedProfile = asString(profileName);
|
|
3901
|
-
if (!normalizedRoot || !
|
|
4515
|
+
if (!normalizedRoot || !import_node_path3.default.isAbsolute(normalizedRoot) || !normalizedProfile) {
|
|
3902
4516
|
return [];
|
|
3903
4517
|
}
|
|
3904
|
-
return [[
|
|
4518
|
+
return [[import_node_path3.default.normalize(normalizedRoot), normalizedProfile]];
|
|
3905
4519
|
}
|
|
3906
4520
|
)
|
|
3907
4521
|
);
|
|
@@ -3942,22 +4556,85 @@ async function readAppStateFromStorage() {
|
|
|
3942
4556
|
normalizeAppState
|
|
3943
4557
|
);
|
|
3944
4558
|
}
|
|
3945
|
-
async function
|
|
3946
|
-
|
|
3947
|
-
return
|
|
4559
|
+
async function readStoredAppStateOrNull() {
|
|
4560
|
+
try {
|
|
4561
|
+
return await readStoredAppStateForInit();
|
|
4562
|
+
} catch (error) {
|
|
4563
|
+
persistenceFailure = {
|
|
4564
|
+
kind: classifyAppStorageFailure(error),
|
|
4565
|
+
message: error instanceof Error ? error.message : String(error)
|
|
4566
|
+
};
|
|
4567
|
+
nextPersistenceRetryAt = Date.now() + PERSISTENCE_RETRY_COOLDOWN_MS;
|
|
4568
|
+
return null;
|
|
3948
4569
|
}
|
|
3949
|
-
|
|
4570
|
+
}
|
|
4571
|
+
async function readStoredAppStateForInit() {
|
|
4572
|
+
const stored = await readAppStateFromStorage();
|
|
4573
|
+
if (stored && !pendingRendererUiPatch) {
|
|
4574
|
+
return stored;
|
|
4575
|
+
}
|
|
4576
|
+
const pendingUiPatch = pendingRendererUiPatch;
|
|
4577
|
+
const initialized = await updateDocument({
|
|
3950
4578
|
dbPath: resolveStorageDbPath(),
|
|
3951
4579
|
namespace: APP_STATE_DOCUMENT,
|
|
3952
4580
|
normalize: normalizeAppState,
|
|
3953
4581
|
fallback: () => normalizeAppState(null),
|
|
3954
|
-
transform: (current) => current,
|
|
4582
|
+
transform: (current) => pendingUiPatch ? deepMerge(current, { ui: pendingUiPatch }) : current,
|
|
3955
4583
|
cloneBeforeTransform: false,
|
|
3956
4584
|
cloneResult: false,
|
|
3957
4585
|
strictExisting: true
|
|
3958
4586
|
});
|
|
3959
|
-
|
|
3960
|
-
|
|
4587
|
+
if (pendingRendererUiPatch === pendingUiPatch) {
|
|
4588
|
+
pendingRendererUiPatch = null;
|
|
4589
|
+
}
|
|
4590
|
+
return initialized;
|
|
4591
|
+
}
|
|
4592
|
+
function degradeToMemory(kind, message) {
|
|
4593
|
+
persistenceFailure = { kind, message };
|
|
4594
|
+
nextPersistenceRetryAt = Date.now() + PERSISTENCE_RETRY_COOLDOWN_MS;
|
|
4595
|
+
if (appStateCache) {
|
|
4596
|
+
return appStateCache;
|
|
4597
|
+
}
|
|
4598
|
+
ephemeralAppState = ephemeralAppState ?? freezeDeep(normalizeAppState(null));
|
|
4599
|
+
return ephemeralAppState;
|
|
4600
|
+
}
|
|
4601
|
+
async function ensureInitialized() {
|
|
4602
|
+
if (appStateCache && !persistenceFailure) {
|
|
4603
|
+
return appStateCache;
|
|
4604
|
+
}
|
|
4605
|
+
const memoryState = appStateCache ?? ephemeralAppState;
|
|
4606
|
+
if (memoryState && Date.now() < nextPersistenceRetryAt) {
|
|
4607
|
+
return memoryState;
|
|
4608
|
+
}
|
|
4609
|
+
const attempt = readStoredAppStateForInit();
|
|
4610
|
+
attempt.catch(() => void 0);
|
|
4611
|
+
let deadlineTimer;
|
|
4612
|
+
const deadline = new Promise((resolve2) => {
|
|
4613
|
+
deadlineTimer = setTimeout(
|
|
4614
|
+
() => resolve2(READ_TOO_SLOW),
|
|
4615
|
+
PERSISTENCE_READ_DEADLINE_MS
|
|
4616
|
+
);
|
|
4617
|
+
});
|
|
4618
|
+
try {
|
|
4619
|
+
const outcome = await Promise.race([attempt, deadline]);
|
|
4620
|
+
if (outcome === READ_TOO_SLOW) {
|
|
4621
|
+
return degradeToMemory(
|
|
4622
|
+
"busy",
|
|
4623
|
+
`Saved app state did not load within ${PERSISTENCE_READ_DEADLINE_MS}ms.`
|
|
4624
|
+
);
|
|
4625
|
+
}
|
|
4626
|
+
appStateCache = freezeDeep(outcome);
|
|
4627
|
+
ephemeralAppState = null;
|
|
4628
|
+
persistenceFailure = null;
|
|
4629
|
+
return appStateCache;
|
|
4630
|
+
} catch (error) {
|
|
4631
|
+
return degradeToMemory(
|
|
4632
|
+
classifyAppStorageFailure(error),
|
|
4633
|
+
error instanceof Error ? error.message : String(error)
|
|
4634
|
+
);
|
|
4635
|
+
} finally {
|
|
4636
|
+
clearTimeout(deadlineTimer);
|
|
4637
|
+
}
|
|
3961
4638
|
}
|
|
3962
4639
|
async function withWriteLock(task) {
|
|
3963
4640
|
if (writeLockContext.getStore()) {
|
|
@@ -3981,7 +4658,10 @@ async function initializeAppState(userDataDir) {
|
|
|
3981
4658
|
if (configuredUserDataDir !== userDataDir) {
|
|
3982
4659
|
configuredUserDataDir = userDataDir;
|
|
3983
4660
|
appStateCache = null;
|
|
3984
|
-
|
|
4661
|
+
ephemeralAppState = null;
|
|
4662
|
+
persistenceFailure = null;
|
|
4663
|
+
pendingRendererUiPatch = null;
|
|
4664
|
+
nextPersistenceRetryAt = 0;
|
|
3985
4665
|
}
|
|
3986
4666
|
const state = await ensureInitialized();
|
|
3987
4667
|
return state;
|
|
@@ -3992,8 +4672,13 @@ async function getAppState() {
|
|
|
3992
4672
|
}
|
|
3993
4673
|
async function refreshAppStateCache() {
|
|
3994
4674
|
return withWriteLock(async () => {
|
|
3995
|
-
const
|
|
3996
|
-
|
|
4675
|
+
const stored = await readStoredAppStateOrNull();
|
|
4676
|
+
if (!stored) {
|
|
4677
|
+
return ensureInitialized();
|
|
4678
|
+
}
|
|
4679
|
+
appStateCache = freezeDeep(stored);
|
|
4680
|
+
ephemeralAppState = null;
|
|
4681
|
+
persistenceFailure = null;
|
|
3997
4682
|
return appStateCache;
|
|
3998
4683
|
});
|
|
3999
4684
|
}
|
|
@@ -4001,24 +4686,40 @@ async function updateAppState(transform3, options = {}) {
|
|
|
4001
4686
|
const mode = options.mode ?? "patch";
|
|
4002
4687
|
return withWriteLock(async () => {
|
|
4003
4688
|
const shouldNormalize = options.normalize !== false;
|
|
4004
|
-
const
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4689
|
+
const pendingUiPatch = pendingRendererUiPatch;
|
|
4690
|
+
try {
|
|
4691
|
+
const stored = await updateDocument({
|
|
4692
|
+
dbPath: resolveStorageDbPath(),
|
|
4693
|
+
namespace: APP_STATE_DOCUMENT,
|
|
4694
|
+
normalize: normalizeAppState,
|
|
4695
|
+
fallback: () => normalizeAppState(null),
|
|
4696
|
+
cloneBeforeTransform: false,
|
|
4697
|
+
normalizeResult: shouldNormalize,
|
|
4698
|
+
cloneResult: false,
|
|
4699
|
+
strictExisting: true,
|
|
4700
|
+
transform: (current) => {
|
|
4701
|
+
const transformed = transform3(
|
|
4702
|
+
options.cloneCurrent === false ? current : clone2(current)
|
|
4703
|
+
);
|
|
4704
|
+
const next = mode === "replace" ? transformed : deepMerge(current, transformed);
|
|
4705
|
+
return pendingUiPatch ? deepMerge(next, { ui: pendingUiPatch }) : next;
|
|
4706
|
+
}
|
|
4707
|
+
});
|
|
4708
|
+
if (pendingRendererUiPatch === pendingUiPatch) {
|
|
4709
|
+
pendingRendererUiPatch = null;
|
|
4018
4710
|
}
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4711
|
+
appStateCache = freezeDeep(stored);
|
|
4712
|
+
ephemeralAppState = null;
|
|
4713
|
+
persistenceFailure = null;
|
|
4714
|
+
return appStateCache;
|
|
4715
|
+
} catch (error) {
|
|
4716
|
+
persistenceFailure = {
|
|
4717
|
+
kind: classifyAppStorageFailure(error),
|
|
4718
|
+
message: error instanceof Error ? error.message : String(error)
|
|
4719
|
+
};
|
|
4720
|
+
nextPersistenceRetryAt = Date.now() + PERSISTENCE_RETRY_COOLDOWN_MS;
|
|
4721
|
+
throw error;
|
|
4722
|
+
}
|
|
4022
4723
|
});
|
|
4023
4724
|
}
|
|
4024
4725
|
async function patchAppState(patch) {
|
|
@@ -4131,7 +4832,7 @@ async function updateAppSettings(transform3, onUpdated) {
|
|
|
4131
4832
|
}
|
|
4132
4833
|
|
|
4133
4834
|
// ../../packages/runtime-profiles/src/license/service.ts
|
|
4134
|
-
var
|
|
4835
|
+
var import_node_crypto7 = __toESM(require("crypto"), 1);
|
|
4135
4836
|
|
|
4136
4837
|
// ../../packages/runtime-codex/src/codex/settings.ts
|
|
4137
4838
|
function asString2(value3) {
|
|
@@ -4370,10 +5071,10 @@ async function writeCodexSettingsJsonRaw(payload) {
|
|
|
4370
5071
|
}
|
|
4371
5072
|
|
|
4372
5073
|
// ../../packages/runtime-profiles/src/license/secret.ts
|
|
4373
|
-
var
|
|
5074
|
+
var import_node_crypto3 = __toESM(require("crypto"), 1);
|
|
4374
5075
|
var LICENSE_SECRET_DOCUMENT = "desktop.license-secret";
|
|
4375
5076
|
async function generateSecret() {
|
|
4376
|
-
return
|
|
5077
|
+
return import_node_crypto3.default.randomBytes(32).toString("hex");
|
|
4377
5078
|
}
|
|
4378
5079
|
function normalizeSecret(value3) {
|
|
4379
5080
|
return typeof value3 === "string" ? value3.trim() : "";
|
|
@@ -4434,10 +5135,10 @@ function buildCheckoutUrl(offer2, options) {
|
|
|
4434
5135
|
}
|
|
4435
5136
|
|
|
4436
5137
|
// ../../packages/runtime-profiles/src/license/trial.ts
|
|
4437
|
-
var
|
|
5138
|
+
var import_node_crypto6 = __toESM(require("crypto"), 1);
|
|
4438
5139
|
|
|
4439
5140
|
// ../../packages/runtime-profiles/src/license/device-id.ts
|
|
4440
|
-
var
|
|
5141
|
+
var import_node_crypto4 = __toESM(require("crypto"), 1);
|
|
4441
5142
|
var import_promises = require("fs/promises");
|
|
4442
5143
|
var import_node_child_process = require("child_process");
|
|
4443
5144
|
var import_node_util = require("util");
|
|
@@ -4480,7 +5181,7 @@ async function readLinuxMachineId() {
|
|
|
4480
5181
|
return null;
|
|
4481
5182
|
}
|
|
4482
5183
|
function hashDeviceComponent(value3) {
|
|
4483
|
-
return
|
|
5184
|
+
return import_node_crypto4.default.createHash("sha256").update(`codexuse-device:${value3}`).digest("hex");
|
|
4484
5185
|
}
|
|
4485
5186
|
async function getDeviceId() {
|
|
4486
5187
|
if (memoizedDeviceId) {
|
|
@@ -4501,7 +5202,7 @@ async function getDeviceId() {
|
|
|
4501
5202
|
memoizedDeviceId = cached2;
|
|
4502
5203
|
return cached2;
|
|
4503
5204
|
}
|
|
4504
|
-
const seed =
|
|
5205
|
+
const seed = import_node_crypto4.default.randomBytes(32).toString("hex");
|
|
4505
5206
|
const deviceId = hashDeviceComponent(seed);
|
|
4506
5207
|
await writeDocument(dbPath, DEVICE_ID_DOCUMENT, deviceId);
|
|
4507
5208
|
memoizedDeviceId = deviceId;
|
|
@@ -4512,7 +5213,7 @@ function hashEmail(email) {
|
|
|
4512
5213
|
if (!normalized) {
|
|
4513
5214
|
return null;
|
|
4514
5215
|
}
|
|
4515
|
-
return
|
|
5216
|
+
return import_node_crypto4.default.createHash("sha256").update(`codexuse-email:${normalized}`).digest("hex");
|
|
4516
5217
|
}
|
|
4517
5218
|
|
|
4518
5219
|
// ../../packages/runtime-profiles/src/license/trial-client.ts
|
|
@@ -4567,17 +5268,17 @@ async function registerTrialWithServer(input) {
|
|
|
4567
5268
|
}
|
|
4568
5269
|
|
|
4569
5270
|
// ../../packages/runtime-profiles/src/license/trial-token-store.ts
|
|
4570
|
-
var
|
|
5271
|
+
var import_node_crypto5 = require("crypto");
|
|
4571
5272
|
var import_node_child_process2 = require("child_process");
|
|
4572
5273
|
var KEYCHAIN_SERVICE = "CODEXUSE_TRIAL_TOKEN";
|
|
4573
5274
|
var KEYCHAIN_ACCOUNT_PREFIX = "device-sha256:";
|
|
4574
5275
|
var FALLBACK_DOCUMENT_PREFIX = "desktop.trial-token.";
|
|
4575
5276
|
function keychainAccountForDevice(deviceId) {
|
|
4576
|
-
const digest = (0,
|
|
5277
|
+
const digest = (0, import_node_crypto5.createHash)("sha256").update(deviceId).digest("hex");
|
|
4577
5278
|
return KEYCHAIN_ACCOUNT_PREFIX + digest;
|
|
4578
5279
|
}
|
|
4579
5280
|
function fallbackDocumentForDevice(deviceId) {
|
|
4580
|
-
const digest = (0,
|
|
5281
|
+
const digest = (0, import_node_crypto5.createHash)("sha256").update(deviceId).digest("hex");
|
|
4581
5282
|
return FALLBACK_DOCUMENT_PREFIX + digest;
|
|
4582
5283
|
}
|
|
4583
5284
|
function normalizeToken(value3) {
|
|
@@ -4681,7 +5382,7 @@ function trialSignaturePayload(trial) {
|
|
|
4681
5382
|
});
|
|
4682
5383
|
}
|
|
4683
5384
|
function signTrial(trial, secret) {
|
|
4684
|
-
return
|
|
5385
|
+
return import_node_crypto6.default.createHmac("sha256", secret).update(trialSignaturePayload(trial)).digest("hex");
|
|
4685
5386
|
}
|
|
4686
5387
|
function withTrialSignature(trial, secret) {
|
|
4687
5388
|
return { ...trial, signature: signTrial(trial, secret) };
|
|
@@ -4995,7 +5696,7 @@ function licenseSignaturePayload(license) {
|
|
|
4995
5696
|
return JSON.stringify(payload);
|
|
4996
5697
|
}
|
|
4997
5698
|
function signLicense(license, secret) {
|
|
4998
|
-
return
|
|
5699
|
+
return import_node_crypto7.default.createHmac("sha256", secret).update(licenseSignaturePayload(license)).digest("hex");
|
|
4999
5700
|
}
|
|
5000
5701
|
function withSignature(license, secret) {
|
|
5001
5702
|
return {
|
|
@@ -5175,7 +5876,19 @@ var LicenseService = class {
|
|
|
5175
5876
|
this.verificationPromise = null;
|
|
5176
5877
|
}
|
|
5177
5878
|
async getCachedStatus() {
|
|
5178
|
-
|
|
5879
|
+
try {
|
|
5880
|
+
return await this.getStatus({ allowStale: true, refreshInBackground: true });
|
|
5881
|
+
} catch (error) {
|
|
5882
|
+
const message = error instanceof Error ? error.message : "License status could not be loaded.";
|
|
5883
|
+
console.warn("Cached license status unavailable:", error);
|
|
5884
|
+
return toLicenseStatus(null, {
|
|
5885
|
+
state: "error",
|
|
5886
|
+
profileLimit: null,
|
|
5887
|
+
profilesRemaining: null,
|
|
5888
|
+
message: "License status is temporarily unavailable.",
|
|
5889
|
+
error: message
|
|
5890
|
+
});
|
|
5891
|
+
}
|
|
5179
5892
|
}
|
|
5180
5893
|
async getStatus(options = {}) {
|
|
5181
5894
|
const forceRefresh = Boolean(options.forceRefresh);
|
|
@@ -5291,7 +6004,7 @@ var LicenseService = class {
|
|
|
5291
6004
|
throw new Error("License key is required.");
|
|
5292
6005
|
}
|
|
5293
6006
|
const secret = await getLicenseSecret();
|
|
5294
|
-
const digest =
|
|
6007
|
+
const digest = import_node_crypto7.default.createHash("sha256").update(trimmed).digest("hex");
|
|
5295
6008
|
const result2 = await requestGumroadVerify(trimmed, "activation");
|
|
5296
6009
|
ensureWithinUseLimit(result2);
|
|
5297
6010
|
const normalized = normalizeVerificationResult(result2, "activation");
|
|
@@ -5354,7 +6067,7 @@ function shouldEnforceProfileLimit(status) {
|
|
|
5354
6067
|
}
|
|
5355
6068
|
|
|
5356
6069
|
// ../../packages/runtime-profiles/src/profiles/profile-manager.ts
|
|
5357
|
-
var
|
|
6070
|
+
var import_node_crypto12 = require("crypto");
|
|
5358
6071
|
var import_fs = require("fs");
|
|
5359
6072
|
var import_node_os5 = __toESM(require("os"), 1);
|
|
5360
6073
|
var import_path = __toESM(require("path"), 1);
|
|
@@ -5413,29 +6126,29 @@ function resolveProfileIdentityKeyFromProfile(profile) {
|
|
|
5413
6126
|
|
|
5414
6127
|
// ../../packages/runtime-codex/src/codex/rpc.ts
|
|
5415
6128
|
var import_node_child_process5 = require("child_process");
|
|
5416
|
-
var
|
|
6129
|
+
var import_node_crypto9 = require("crypto");
|
|
5417
6130
|
var import_node_readline = __toESM(require("readline"), 1);
|
|
5418
|
-
var
|
|
6131
|
+
var import_node_fs6 = require("fs");
|
|
5419
6132
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
5420
6133
|
var import_node_path9 = __toESM(require("path"), 1);
|
|
5421
6134
|
|
|
5422
6135
|
// ../../packages/runtime-codex/src/codex/cli.ts
|
|
5423
|
-
var
|
|
5424
|
-
var
|
|
6136
|
+
var import_node_fs4 = require("fs");
|
|
6137
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
5425
6138
|
var STABLE_CHANNEL = "stable";
|
|
5426
6139
|
var ENV_HINTS = ["CODEX_BINARY", "CODEX_CLI_PATH", "CODEX_PATH"];
|
|
5427
6140
|
var cachedStatus = null;
|
|
5428
6141
|
function getPathHintEntries() {
|
|
5429
6142
|
const homeDir = process.env.HOME ?? "";
|
|
5430
6143
|
const homeEntries = homeDir ? [
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
6144
|
+
import_node_path4.default.join(homeDir, ".local", "bin"),
|
|
6145
|
+
import_node_path4.default.join(homeDir, ".fnm", "aliases", "default", "bin"),
|
|
6146
|
+
import_node_path4.default.join(homeDir, ".fnm", "current", "bin"),
|
|
6147
|
+
import_node_path4.default.join(homeDir, ".volta", "bin"),
|
|
6148
|
+
import_node_path4.default.join(homeDir, ".asdf", "shims"),
|
|
6149
|
+
import_node_path4.default.join(homeDir, ".bun", "bin")
|
|
5437
6150
|
] : [];
|
|
5438
|
-
const configuredHints = (process.env.CODEX_PATH_HINTS ?? "").split(
|
|
6151
|
+
const configuredHints = (process.env.CODEX_PATH_HINTS ?? "").split(import_node_path4.default.delimiter).map((entry) => entry.trim()).filter(Boolean);
|
|
5439
6152
|
return [
|
|
5440
6153
|
"/opt/homebrew/bin",
|
|
5441
6154
|
"/usr/local/bin",
|
|
@@ -5447,9 +6160,9 @@ function fileExists(candidate) {
|
|
|
5447
6160
|
if (!candidate) {
|
|
5448
6161
|
return null;
|
|
5449
6162
|
}
|
|
5450
|
-
const normalized =
|
|
6163
|
+
const normalized = import_node_path4.default.resolve(candidate);
|
|
5451
6164
|
try {
|
|
5452
|
-
const stats = (0,
|
|
6165
|
+
const stats = (0, import_node_fs4.statSync)(normalized);
|
|
5453
6166
|
if (stats.isFile()) {
|
|
5454
6167
|
return normalized;
|
|
5455
6168
|
}
|
|
@@ -5476,12 +6189,12 @@ function resolveCodexFromPath() {
|
|
|
5476
6189
|
new Set(
|
|
5477
6190
|
[
|
|
5478
6191
|
...getPathHintEntries(),
|
|
5479
|
-
...pathValue.split(
|
|
6192
|
+
...pathValue.split(import_node_path4.default.delimiter).map((entry) => entry.trim()).filter(Boolean)
|
|
5480
6193
|
].filter(Boolean)
|
|
5481
6194
|
)
|
|
5482
6195
|
);
|
|
5483
6196
|
for (const entry of entries3) {
|
|
5484
|
-
const candidate = fileExists(
|
|
6197
|
+
const candidate = fileExists(import_node_path4.default.join(entry, "codex"));
|
|
5485
6198
|
if (candidate) {
|
|
5486
6199
|
return candidate;
|
|
5487
6200
|
}
|
|
@@ -5545,7 +6258,7 @@ async function requireCodexCli() {
|
|
|
5545
6258
|
|
|
5546
6259
|
// ../../packages/runtime-codex/src/codex/command.ts
|
|
5547
6260
|
var import_node_child_process3 = require("child_process");
|
|
5548
|
-
var
|
|
6261
|
+
var import_node_path5 = __toESM(require("path"), 1);
|
|
5549
6262
|
var cachedNodeRuntime = null;
|
|
5550
6263
|
function isJavaScriptEntrypoint(binaryPath) {
|
|
5551
6264
|
const normalized = binaryPath.trim().toLowerCase();
|
|
@@ -5561,19 +6274,19 @@ function resolveNodeRuntime(env) {
|
|
|
5561
6274
|
}
|
|
5562
6275
|
const runtimeEnv = { ...process.env, ...env };
|
|
5563
6276
|
const homeDir = runtimeEnv.HOME ?? "";
|
|
5564
|
-
const pathHints = (runtimeEnv.CODEX_PATH_HINTS ?? process.env.CODEX_PATH_HINTS ?? "").split(
|
|
6277
|
+
const pathHints = (runtimeEnv.CODEX_PATH_HINTS ?? process.env.CODEX_PATH_HINTS ?? "").split(import_node_path5.default.delimiter).map((entry) => entry.trim()).filter(Boolean);
|
|
5565
6278
|
const extraPathEntries = [
|
|
5566
6279
|
"/usr/local/bin",
|
|
5567
6280
|
"/opt/homebrew/bin",
|
|
5568
|
-
|
|
5569
|
-
|
|
5570
|
-
|
|
6281
|
+
import_node_path5.default.join(homeDir, ".local", "bin"),
|
|
6282
|
+
import_node_path5.default.join(homeDir, ".fnm", "aliases", "default", "bin"),
|
|
6283
|
+
import_node_path5.default.join(homeDir, ".fnm", "current", "bin"),
|
|
5571
6284
|
...pathHints
|
|
5572
6285
|
].filter(Boolean);
|
|
5573
6286
|
const currentPath = runtimeEnv.PATH ?? "";
|
|
5574
6287
|
runtimeEnv.PATH = Array.from(
|
|
5575
|
-
/* @__PURE__ */ new Set([...extraPathEntries, ...currentPath.split(
|
|
5576
|
-
).join(
|
|
6288
|
+
/* @__PURE__ */ new Set([...extraPathEntries, ...currentPath.split(import_node_path5.default.delimiter).filter(Boolean)])
|
|
6289
|
+
).join(import_node_path5.default.delimiter);
|
|
5577
6290
|
const candidates = Array.from(
|
|
5578
6291
|
new Set(
|
|
5579
6292
|
[
|
|
@@ -5612,11 +6325,11 @@ function buildCodexCommand(binaryPath, args2, env) {
|
|
|
5612
6325
|
}
|
|
5613
6326
|
|
|
5614
6327
|
// ../../packages/runtime-codex/src/codex/home.ts
|
|
5615
|
-
var
|
|
5616
|
-
var
|
|
6328
|
+
var import_node_crypto8 = require("crypto");
|
|
6329
|
+
var import_node_fs5 = require("fs");
|
|
5617
6330
|
var import_promises2 = require("fs/promises");
|
|
5618
6331
|
var import_node_os2 = __toESM(require("os"), 1);
|
|
5619
|
-
var
|
|
6332
|
+
var import_node_path6 = __toESM(require("path"), 1);
|
|
5620
6333
|
function resolveHomeDir() {
|
|
5621
6334
|
return process.env.HOME || import_node_os2.default.homedir();
|
|
5622
6335
|
}
|
|
@@ -5625,7 +6338,7 @@ function expandHomePrefix(input, homeDir) {
|
|
|
5625
6338
|
return homeDir;
|
|
5626
6339
|
}
|
|
5627
6340
|
if (input.startsWith("~/") || input.startsWith("~\\")) {
|
|
5628
|
-
return
|
|
6341
|
+
return import_node_path6.default.join(homeDir, input.slice(2));
|
|
5629
6342
|
}
|
|
5630
6343
|
return input;
|
|
5631
6344
|
}
|
|
@@ -5641,25 +6354,25 @@ function normalizeCodexHomePath(input) {
|
|
|
5641
6354
|
if (!configured) {
|
|
5642
6355
|
return null;
|
|
5643
6356
|
}
|
|
5644
|
-
return
|
|
6357
|
+
return import_node_path6.default.resolve(expandHomePrefix(configured, resolveHomeDir()));
|
|
5645
6358
|
}
|
|
5646
6359
|
function resolveDefaultCodexHomeDir() {
|
|
5647
|
-
return normalizeCodexHomePath(process.env.CODEX_HOME) ??
|
|
6360
|
+
return normalizeCodexHomePath(process.env.CODEX_HOME) ?? import_node_path6.default.join(resolveHomeDir(), ".codex");
|
|
5648
6361
|
}
|
|
5649
6362
|
function resolveCodexSqliteHomeDir(codexHomePath) {
|
|
5650
6363
|
return normalizeCodexHomePath(process.env.CODEX_SQLITE_HOME) ?? resolveCodexHomeDir({ codexHomePath });
|
|
5651
6364
|
}
|
|
5652
6365
|
function resolveCurrentProfileCodexHomeDir(profileHomeId) {
|
|
5653
|
-
return
|
|
6366
|
+
return import_node_path6.default.join(
|
|
5654
6367
|
resolveProfileCodexHomesRoot(),
|
|
5655
|
-
(0,
|
|
6368
|
+
(0, import_node_crypto8.createHash)("sha256").update(profileHomeId).digest("hex").slice(0, 20)
|
|
5656
6369
|
);
|
|
5657
6370
|
}
|
|
5658
6371
|
function resolveProfileCodexHomeDir(profileHomeId) {
|
|
5659
6372
|
const current = resolveCurrentProfileCodexHomeDir(profileHomeId);
|
|
5660
|
-
const legacy =
|
|
5661
|
-
const currentExists = (0,
|
|
5662
|
-
const legacyExists = (0,
|
|
6373
|
+
const legacy = import_node_path6.default.join(resolveLegacyProfileCodexHomesRoot(), profileHomeId);
|
|
6374
|
+
const currentExists = (0, import_node_fs5.existsSync)(current);
|
|
6375
|
+
const legacyExists = (0, import_node_fs5.existsSync)(legacy);
|
|
5663
6376
|
if (currentExists && legacyExists) {
|
|
5664
6377
|
return current;
|
|
5665
6378
|
}
|
|
@@ -5667,15 +6380,15 @@ function resolveProfileCodexHomeDir(profileHomeId) {
|
|
|
5667
6380
|
}
|
|
5668
6381
|
function findProfileCodexHomeLocationConflict(profileHomeId) {
|
|
5669
6382
|
const current = resolveCurrentProfileCodexHomeDir(profileHomeId);
|
|
5670
|
-
const legacy =
|
|
5671
|
-
return (0,
|
|
6383
|
+
const legacy = import_node_path6.default.join(resolveLegacyProfileCodexHomesRoot(), profileHomeId);
|
|
6384
|
+
return (0, import_node_fs5.existsSync)(current) && (0, import_node_fs5.existsSync)(legacy) ? { current, legacy } : null;
|
|
5672
6385
|
}
|
|
5673
6386
|
function resolveProfileCodexHomesRoot() {
|
|
5674
|
-
return
|
|
6387
|
+
return import_node_path6.default.join(resolveHomeDir(), ".codexuse", "p");
|
|
5675
6388
|
}
|
|
5676
6389
|
async function ensureProfileCodexHomesRoot() {
|
|
5677
6390
|
const root = resolveProfileCodexHomesRoot();
|
|
5678
|
-
const parent =
|
|
6391
|
+
const parent = import_node_path6.default.dirname(root);
|
|
5679
6392
|
await (0, import_promises2.mkdir)(parent, { recursive: true, mode: 448 });
|
|
5680
6393
|
await (0, import_promises2.mkdir)(root, { recursive: true, mode: 448 });
|
|
5681
6394
|
if (process.platform !== "win32") {
|
|
@@ -5685,13 +6398,13 @@ async function ensureProfileCodexHomesRoot() {
|
|
|
5685
6398
|
return root;
|
|
5686
6399
|
}
|
|
5687
6400
|
function resolveLegacyProfileCodexHomesRoot() {
|
|
5688
|
-
return
|
|
6401
|
+
return import_node_path6.default.join(getUserDataDir(), "profile-homes");
|
|
5689
6402
|
}
|
|
5690
6403
|
async function migrateProfileCodexHomeDir(profileHomeId) {
|
|
5691
|
-
const legacy =
|
|
6404
|
+
const legacy = import_node_path6.default.join(resolveLegacyProfileCodexHomesRoot(), profileHomeId);
|
|
5692
6405
|
const current = resolveCurrentProfileCodexHomeDir(profileHomeId);
|
|
5693
|
-
const currentExists = (0,
|
|
5694
|
-
const legacyExists = (0,
|
|
6406
|
+
const currentExists = (0, import_node_fs5.existsSync)(current);
|
|
6407
|
+
const legacyExists = (0, import_node_fs5.existsSync)(legacy);
|
|
5695
6408
|
if (currentExists && legacyExists) {
|
|
5696
6409
|
return current;
|
|
5697
6410
|
}
|
|
@@ -5767,7 +6480,7 @@ var import_toml = __toESM(require_toml(), 1);
|
|
|
5767
6480
|
// ../../packages/runtime-codex/src/codex/config-metadata.ts
|
|
5768
6481
|
var import_node_child_process4 = require("child_process");
|
|
5769
6482
|
var import_promises3 = require("fs/promises");
|
|
5770
|
-
var
|
|
6483
|
+
var import_node_path7 = __toESM(require("path"), 1);
|
|
5771
6484
|
var CONFIG_SCHEMA_URL = "https://raw.githubusercontent.com/openai/codex/main/codex-rs/core/config.schema.json";
|
|
5772
6485
|
var METADATA_CACHE_TTL_MS = 6e4;
|
|
5773
6486
|
var FALLBACK_SCHEMA_TOP_LEVEL_KEYS = [
|
|
@@ -5953,8 +6666,8 @@ function parseSchemaKeys(schemaRaw) {
|
|
|
5953
6666
|
async function readSchemaFromLocal() {
|
|
5954
6667
|
const candidates = [
|
|
5955
6668
|
process.env.CODEX_CONFIG_SCHEMA_PATH,
|
|
5956
|
-
|
|
5957
|
-
|
|
6669
|
+
import_node_path7.default.join(process.cwd(), "codex-rs", "core", "config.schema.json"),
|
|
6670
|
+
import_node_path7.default.join(process.cwd(), "node_modules", "@openai", "codex", "codex-rs", "core", "config.schema.json")
|
|
5958
6671
|
].filter((candidate) => Boolean(candidate));
|
|
5959
6672
|
for (const candidate of candidates) {
|
|
5960
6673
|
try {
|
|
@@ -6059,7 +6772,7 @@ async function getCodexConfigMetadata(forceRefresh = false) {
|
|
|
6059
6772
|
|
|
6060
6773
|
// ../../packages/runtime-codex/src/codex/config-io.ts
|
|
6061
6774
|
var import_promises4 = require("fs/promises");
|
|
6062
|
-
var
|
|
6775
|
+
var import_node_path8 = __toESM(require("path"), 1);
|
|
6063
6776
|
|
|
6064
6777
|
// ../../packages/runtime-codex/src/codex/config-presets.ts
|
|
6065
6778
|
var DEFAULT_CONFIG_TEMPLATE = [
|
|
@@ -6102,10 +6815,10 @@ var YOLO_PRESET = {
|
|
|
6102
6815
|
|
|
6103
6816
|
// ../../packages/runtime-codex/src/codex/config-io.ts
|
|
6104
6817
|
function getConfigPath(options) {
|
|
6105
|
-
return
|
|
6818
|
+
return import_node_path8.default.join(resolveCodexHomeDir(options), "config.toml");
|
|
6106
6819
|
}
|
|
6107
6820
|
async function ensureConfigDirExists(filePath) {
|
|
6108
|
-
const dir =
|
|
6821
|
+
const dir = import_node_path8.default.dirname(filePath);
|
|
6109
6822
|
await (0, import_promises4.mkdir)(dir, { recursive: true });
|
|
6110
6823
|
}
|
|
6111
6824
|
function normalizeLineEndings(content) {
|
|
@@ -6663,82 +7376,6 @@ async function saveCodexConfigContent(content, options) {
|
|
|
6663
7376
|
return buildSnapshot(normalized, true, options);
|
|
6664
7377
|
}
|
|
6665
7378
|
|
|
6666
|
-
// ../../packages/runtime-app-state/src/storage/fileLock.ts
|
|
6667
|
-
var import_node_fs4 = require("fs");
|
|
6668
|
-
var import_node_path8 = __toESM(require("path"), 1);
|
|
6669
|
-
function isSqliteBusyError2(error) {
|
|
6670
|
-
if (!error || typeof error !== "object") {
|
|
6671
|
-
return false;
|
|
6672
|
-
}
|
|
6673
|
-
const value3 = error;
|
|
6674
|
-
if (value3.cause && value3.cause !== error && isSqliteBusyError2(value3.cause)) {
|
|
6675
|
-
return true;
|
|
6676
|
-
}
|
|
6677
|
-
if (value3.error && value3.error !== error && isSqliteBusyError2(value3.error)) {
|
|
6678
|
-
return true;
|
|
6679
|
-
}
|
|
6680
|
-
const message = typeof value3.message === "string" ? value3.message.toLowerCase() : String(error).toLowerCase();
|
|
6681
|
-
return value3.code === "SQLITE_BUSY" || value3.errno === 5 || message.includes("sqlite_busy") || message.includes("database is locked");
|
|
6682
|
-
}
|
|
6683
|
-
async function openLockDatabase(databasePath) {
|
|
6684
|
-
await import_node_fs4.promises.mkdir(import_node_path8.default.dirname(databasePath), { recursive: true, mode: 448 });
|
|
6685
|
-
const sqlite = process.versions.bun ? await Function("return import('bun:sqlite')")() : await Function("return import('node:sqlite')")();
|
|
6686
|
-
const database = process.versions.bun ? new sqlite.Database(databasePath) : new sqlite.DatabaseSync(databasePath);
|
|
6687
|
-
try {
|
|
6688
|
-
if (process.platform !== "win32") {
|
|
6689
|
-
await import_node_fs4.promises.chmod(databasePath, 384);
|
|
6690
|
-
}
|
|
6691
|
-
return {
|
|
6692
|
-
exec: database.exec.bind(database),
|
|
6693
|
-
close: database.close.bind(database)
|
|
6694
|
-
};
|
|
6695
|
-
} catch (error) {
|
|
6696
|
-
database.close();
|
|
6697
|
-
throw error;
|
|
6698
|
-
}
|
|
6699
|
-
}
|
|
6700
|
-
async function acquireCrossProcessFileLockTransaction(filePath, mode) {
|
|
6701
|
-
const databasePath = `${import_node_path8.default.resolve(filePath)}.codexuse-lock.sqlite`;
|
|
6702
|
-
let database = null;
|
|
6703
|
-
try {
|
|
6704
|
-
database = await openLockDatabase(databasePath);
|
|
6705
|
-
database.exec("PRAGMA busy_timeout = 1000;");
|
|
6706
|
-
database.exec("CREATE TABLE IF NOT EXISTS codexuse_file_lock (id INTEGER PRIMARY KEY);");
|
|
6707
|
-
database.exec("PRAGMA busy_timeout = 0;");
|
|
6708
|
-
if (mode === "write") {
|
|
6709
|
-
database.exec("BEGIN EXCLUSIVE;");
|
|
6710
|
-
} else {
|
|
6711
|
-
database.exec("BEGIN;");
|
|
6712
|
-
database.exec("SELECT COUNT(*) FROM codexuse_file_lock;");
|
|
6713
|
-
}
|
|
6714
|
-
} catch (error) {
|
|
6715
|
-
database?.close();
|
|
6716
|
-
if (isSqliteBusyError2(error)) {
|
|
6717
|
-
return null;
|
|
6718
|
-
}
|
|
6719
|
-
throw error;
|
|
6720
|
-
}
|
|
6721
|
-
const acquiredDatabase = database;
|
|
6722
|
-
let released = false;
|
|
6723
|
-
return async () => {
|
|
6724
|
-
if (released) {
|
|
6725
|
-
return;
|
|
6726
|
-
}
|
|
6727
|
-
released = true;
|
|
6728
|
-
try {
|
|
6729
|
-
acquiredDatabase.exec("ROLLBACK;");
|
|
6730
|
-
} finally {
|
|
6731
|
-
acquiredDatabase.close();
|
|
6732
|
-
}
|
|
6733
|
-
};
|
|
6734
|
-
}
|
|
6735
|
-
async function acquireCrossProcessFileLock(filePath) {
|
|
6736
|
-
return acquireCrossProcessFileLockTransaction(filePath, "write");
|
|
6737
|
-
}
|
|
6738
|
-
async function acquireCrossProcessFileReadLock(filePath) {
|
|
6739
|
-
return acquireCrossProcessFileLockTransaction(filePath, "read");
|
|
6740
|
-
}
|
|
6741
|
-
|
|
6742
7379
|
// ../../packages/shared/src/core/logger.ts
|
|
6743
7380
|
var isTestEnv = process.env.NODE_ENV === "test" || process.env.VITEST === "true" || process.env.VITEST === "1";
|
|
6744
7381
|
function isMocked(fn2) {
|
|
@@ -23523,11 +24160,11 @@ function authWritebackPaths(filePath) {
|
|
|
23523
24160
|
};
|
|
23524
24161
|
}
|
|
23525
24162
|
function fingerprintAuth(content) {
|
|
23526
|
-
return (0,
|
|
24163
|
+
return (0, import_node_crypto9.createHash)("sha256").update(content).digest("hex");
|
|
23527
24164
|
}
|
|
23528
24165
|
async function readOptionalFile(filePath) {
|
|
23529
24166
|
try {
|
|
23530
|
-
return await
|
|
24167
|
+
return await import_node_fs6.promises.readFile(filePath, "utf8");
|
|
23531
24168
|
} catch (error) {
|
|
23532
24169
|
const code = error && typeof error === "object" && "code" in error ? error.code : null;
|
|
23533
24170
|
if (code === "ENOENT") return null;
|
|
@@ -23538,9 +24175,9 @@ async function writeAtomicPath(filePath, content) {
|
|
|
23538
24175
|
const dir = import_node_path9.default.dirname(filePath);
|
|
23539
24176
|
const tempPath = import_node_path9.default.join(
|
|
23540
24177
|
dir,
|
|
23541
|
-
`.${import_node_path9.default.basename(filePath)}.${process.pid}.${(0,
|
|
24178
|
+
`.${import_node_path9.default.basename(filePath)}.${process.pid}.${(0, import_node_crypto9.randomUUID)()}.tmp`
|
|
23542
24179
|
);
|
|
23543
|
-
const handle = await
|
|
24180
|
+
const handle = await import_node_fs6.promises.open(tempPath, "wx", 384);
|
|
23544
24181
|
try {
|
|
23545
24182
|
await handle.writeFile(content, "utf8");
|
|
23546
24183
|
await handle.sync();
|
|
@@ -23548,9 +24185,9 @@ async function writeAtomicPath(filePath, content) {
|
|
|
23548
24185
|
await handle.close();
|
|
23549
24186
|
}
|
|
23550
24187
|
try {
|
|
23551
|
-
await
|
|
24188
|
+
await import_node_fs6.promises.rename(tempPath, filePath);
|
|
23552
24189
|
if (process.platform !== "win32") {
|
|
23553
|
-
const dirHandle = await
|
|
24190
|
+
const dirHandle = await import_node_fs6.promises.open(dir, "r");
|
|
23554
24191
|
try {
|
|
23555
24192
|
await dirHandle.sync();
|
|
23556
24193
|
} finally {
|
|
@@ -23558,16 +24195,16 @@ async function writeAtomicPath(filePath, content) {
|
|
|
23558
24195
|
}
|
|
23559
24196
|
}
|
|
23560
24197
|
} finally {
|
|
23561
|
-
await
|
|
24198
|
+
await import_node_fs6.promises.rm(tempPath, { force: true }).catch(() => void 0);
|
|
23562
24199
|
}
|
|
23563
24200
|
}
|
|
23564
24201
|
async function installAuthFileIfAbsent(filePath, content) {
|
|
23565
24202
|
const dir = import_node_path9.default.dirname(filePath);
|
|
23566
24203
|
const tempPath = import_node_path9.default.join(
|
|
23567
24204
|
dir,
|
|
23568
|
-
`.${import_node_path9.default.basename(filePath)}.${process.pid}.${(0,
|
|
24205
|
+
`.${import_node_path9.default.basename(filePath)}.${process.pid}.${(0, import_node_crypto9.randomUUID)()}.install`
|
|
23569
24206
|
);
|
|
23570
|
-
const handle = await
|
|
24207
|
+
const handle = await import_node_fs6.promises.open(tempPath, "wx", 384);
|
|
23571
24208
|
try {
|
|
23572
24209
|
await handle.writeFile(content, "utf8");
|
|
23573
24210
|
await handle.sync();
|
|
@@ -23575,25 +24212,25 @@ async function installAuthFileIfAbsent(filePath, content) {
|
|
|
23575
24212
|
await handle.close();
|
|
23576
24213
|
}
|
|
23577
24214
|
try {
|
|
23578
|
-
await
|
|
24215
|
+
await import_node_fs6.promises.link(tempPath, filePath);
|
|
23579
24216
|
} finally {
|
|
23580
|
-
await
|
|
24217
|
+
await import_node_fs6.promises.rm(tempPath, { force: true }).catch(() => void 0);
|
|
23581
24218
|
}
|
|
23582
24219
|
}
|
|
23583
24220
|
async function linkAuthFileIfAbsent(sourcePath, targetPath) {
|
|
23584
|
-
await
|
|
24221
|
+
await import_node_fs6.promises.link(sourcePath, targetPath);
|
|
23585
24222
|
}
|
|
23586
24223
|
async function hasExternalOpenFileHandle(filePath) {
|
|
23587
24224
|
if (process.platform === "linux") {
|
|
23588
24225
|
let target;
|
|
23589
24226
|
try {
|
|
23590
|
-
target = await
|
|
24227
|
+
target = await import_node_fs6.promises.stat(filePath);
|
|
23591
24228
|
} catch {
|
|
23592
24229
|
return true;
|
|
23593
24230
|
}
|
|
23594
24231
|
let processes;
|
|
23595
24232
|
try {
|
|
23596
|
-
processes = await
|
|
24233
|
+
processes = await import_node_fs6.promises.readdir("/proc", { withFileTypes: true });
|
|
23597
24234
|
} catch {
|
|
23598
24235
|
return true;
|
|
23599
24236
|
}
|
|
@@ -23604,7 +24241,7 @@ async function hasExternalOpenFileHandle(filePath) {
|
|
|
23604
24241
|
}
|
|
23605
24242
|
const processPath = `/proc/${entry.name}`;
|
|
23606
24243
|
try {
|
|
23607
|
-
const processStats = await
|
|
24244
|
+
const processStats = await import_node_fs6.promises.stat(processPath);
|
|
23608
24245
|
if (currentUid !== void 0 && processStats.uid !== currentUid) {
|
|
23609
24246
|
continue;
|
|
23610
24247
|
}
|
|
@@ -23613,7 +24250,7 @@ async function hasExternalOpenFileHandle(filePath) {
|
|
|
23613
24250
|
}
|
|
23614
24251
|
let descriptors;
|
|
23615
24252
|
try {
|
|
23616
|
-
descriptors = await
|
|
24253
|
+
descriptors = await import_node_fs6.promises.readdir(`${processPath}/fd`);
|
|
23617
24254
|
} catch (error) {
|
|
23618
24255
|
const code = error && typeof error === "object" && "code" in error ? error.code : null;
|
|
23619
24256
|
if (code === "ENOENT" || code === "ESRCH") continue;
|
|
@@ -23621,7 +24258,7 @@ async function hasExternalOpenFileHandle(filePath) {
|
|
|
23621
24258
|
}
|
|
23622
24259
|
for (const descriptor2 of descriptors) {
|
|
23623
24260
|
try {
|
|
23624
|
-
const descriptorStats = await
|
|
24261
|
+
const descriptorStats = await import_node_fs6.promises.stat(`${processPath}/fd/${descriptor2}`);
|
|
23625
24262
|
if (descriptorStats.dev === target.dev && descriptorStats.ino === target.ino) {
|
|
23626
24263
|
return true;
|
|
23627
24264
|
}
|
|
@@ -23668,9 +24305,9 @@ async function hasExternalOpenFileHandle(filePath) {
|
|
|
23668
24305
|
async function cleanupAuthWriteback(filePath) {
|
|
23669
24306
|
const paths = authWritebackPaths(filePath);
|
|
23670
24307
|
await Promise.all([
|
|
23671
|
-
|
|
23672
|
-
|
|
23673
|
-
|
|
24308
|
+
import_node_fs6.promises.rm(paths.manifest, { force: true }),
|
|
24309
|
+
import_node_fs6.promises.rm(paths.backup, { force: true }),
|
|
24310
|
+
import_node_fs6.promises.rm(paths.replaced, { force: true })
|
|
23674
24311
|
]);
|
|
23675
24312
|
}
|
|
23676
24313
|
async function rollbackAuthWriteback(filePath, manifest) {
|
|
@@ -23691,8 +24328,8 @@ async function rollbackAuthWriteback(filePath, manifest) {
|
|
|
23691
24328
|
"Codex auth changed outside CodexUse during writeback rollback; recovery files were preserved."
|
|
23692
24329
|
);
|
|
23693
24330
|
}
|
|
23694
|
-
await
|
|
23695
|
-
if (fingerprintAuth(await
|
|
24331
|
+
await import_node_fs6.promises.rename(filePath, paths.replaced);
|
|
24332
|
+
if (fingerprintAuth(await import_node_fs6.promises.readFile(paths.replaced, "utf8")) !== manifest.targetFingerprint) {
|
|
23696
24333
|
const replaced = await readOptionalFile(paths.replaced);
|
|
23697
24334
|
if (await readOptionalFile(filePath) === null && replaced !== null) {
|
|
23698
24335
|
await installAuthFileIfAbsent(filePath, replaced);
|
|
@@ -23729,7 +24366,7 @@ async function replaceAuthFileIfCurrent(filePath, expectedCurrent, replacement)
|
|
|
23729
24366
|
await writeAtomicPath(paths.manifest, JSON.stringify(manifest));
|
|
23730
24367
|
let committed = false;
|
|
23731
24368
|
try {
|
|
23732
|
-
await
|
|
24369
|
+
await import_node_fs6.promises.rename(filePath, paths.backup);
|
|
23733
24370
|
if (await readOptionalFile(paths.backup) !== expectedCurrent) {
|
|
23734
24371
|
throw new Error("Codex auth changed while writeback began.");
|
|
23735
24372
|
}
|
|
@@ -23829,7 +24466,7 @@ async function acquireCodexAuthFileReadLock(filePath) {
|
|
|
23829
24466
|
async function readAuthFileCached(filePath) {
|
|
23830
24467
|
let stats;
|
|
23831
24468
|
try {
|
|
23832
|
-
stats = await
|
|
24469
|
+
stats = await import_node_fs6.promises.stat(filePath);
|
|
23833
24470
|
} catch {
|
|
23834
24471
|
authFileCache.delete(filePath);
|
|
23835
24472
|
return null;
|
|
@@ -23838,7 +24475,7 @@ async function readAuthFileCached(filePath) {
|
|
|
23838
24475
|
if (cached2 && cached2.mtimeMs === stats.mtimeMs && cached2.size === stats.size) {
|
|
23839
24476
|
return cached2.content;
|
|
23840
24477
|
}
|
|
23841
|
-
const content = await
|
|
24478
|
+
const content = await import_node_fs6.promises.readFile(filePath, "utf8");
|
|
23842
24479
|
authFileCache.set(filePath, {
|
|
23843
24480
|
mtimeMs: stats.mtimeMs,
|
|
23844
24481
|
size: stats.size,
|
|
@@ -23857,7 +24494,7 @@ async function writeAuthFileCached(filePath, content, expectedCurrent, options =
|
|
|
23857
24494
|
);
|
|
23858
24495
|
if (!written) return false;
|
|
23859
24496
|
try {
|
|
23860
|
-
const stats = await
|
|
24497
|
+
const stats = await import_node_fs6.promises.stat(filePath);
|
|
23861
24498
|
authFileCache.set(filePath, {
|
|
23862
24499
|
mtimeMs: stats.mtimeMs,
|
|
23863
24500
|
size: stats.size,
|
|
@@ -23996,13 +24633,13 @@ function resolveRpcAuthPath(envOverride, authPath) {
|
|
|
23996
24633
|
async function fetchRateLimitsViaRpc(envOverride, options = {}) {
|
|
23997
24634
|
const binaryPath = options.codexPath ?? await requireCodexCli();
|
|
23998
24635
|
const sourceAuthPath = resolveRpcAuthPath(envOverride, options.authPath);
|
|
23999
|
-
const tempHome = await
|
|
24636
|
+
const tempHome = await import_node_fs6.promises.mkdtemp(import_node_path9.default.join(import_node_os3.default.tmpdir(), "codex-rpc-"));
|
|
24000
24637
|
const tempAuthPath = import_node_path9.default.join(tempHome, "auth.json");
|
|
24001
24638
|
let initialSourceAuth;
|
|
24002
24639
|
try {
|
|
24003
24640
|
const authLock = await acquireCodexAuthFileReadLock(sourceAuthPath);
|
|
24004
24641
|
if (!authLock) {
|
|
24005
|
-
await
|
|
24642
|
+
await import_node_fs6.promises.rm(tempHome, { recursive: true, force: true });
|
|
24006
24643
|
return null;
|
|
24007
24644
|
}
|
|
24008
24645
|
try {
|
|
@@ -24011,15 +24648,15 @@ async function fetchRateLimitsViaRpc(envOverride, options = {}) {
|
|
|
24011
24648
|
await authLock.release();
|
|
24012
24649
|
}
|
|
24013
24650
|
if (!initialSourceAuth) {
|
|
24014
|
-
await
|
|
24651
|
+
await import_node_fs6.promises.rm(tempHome, { recursive: true, force: true });
|
|
24015
24652
|
return null;
|
|
24016
24653
|
}
|
|
24017
|
-
await
|
|
24654
|
+
await import_node_fs6.promises.writeFile(tempAuthPath, initialSourceAuth, {
|
|
24018
24655
|
encoding: "utf8",
|
|
24019
24656
|
mode: 384
|
|
24020
24657
|
});
|
|
24021
24658
|
} catch {
|
|
24022
|
-
await
|
|
24659
|
+
await import_node_fs6.promises.rm(tempHome, { recursive: true, force: true }).catch(() => {
|
|
24023
24660
|
});
|
|
24024
24661
|
return null;
|
|
24025
24662
|
}
|
|
@@ -24086,7 +24723,7 @@ async function fetchRateLimitsViaRpc(envOverride, options = {}) {
|
|
|
24086
24723
|
rl.close();
|
|
24087
24724
|
await stopChildAndWait(child);
|
|
24088
24725
|
try {
|
|
24089
|
-
const updatedAuth = await
|
|
24726
|
+
const updatedAuth = await import_node_fs6.promises.readFile(tempAuthPath, "utf8");
|
|
24090
24727
|
if (updatedAuth.trim().length > 0) {
|
|
24091
24728
|
const currentSourceAuth = await readAuthFileCached(sourceAuthPath);
|
|
24092
24729
|
if (shouldWriteBackAuth(initialSourceAuth, currentSourceAuth, updatedAuth)) {
|
|
@@ -24115,7 +24752,7 @@ async function fetchRateLimitsViaRpc(envOverride, options = {}) {
|
|
|
24115
24752
|
} catch (error) {
|
|
24116
24753
|
logWarn("Failed to sync refreshed auth after rate-limit probe:", error);
|
|
24117
24754
|
}
|
|
24118
|
-
await
|
|
24755
|
+
await import_node_fs6.promises.rm(tempHome, { recursive: true, force: true }).catch(() => {
|
|
24119
24756
|
});
|
|
24120
24757
|
}
|
|
24121
24758
|
}
|
|
@@ -24129,7 +24766,7 @@ async function activateResetWindowViaRpc(envOverride, options = {}) {
|
|
|
24129
24766
|
}
|
|
24130
24767
|
async function activateResetWindowViaRpcIsolated(envOverride, options, sourceAuthPath) {
|
|
24131
24768
|
const binaryPath = options.codexPath ?? await requireCodexCli();
|
|
24132
|
-
const tempHome = await
|
|
24769
|
+
const tempHome = await import_node_fs6.promises.mkdtemp(
|
|
24133
24770
|
import_node_path9.default.join(import_node_os3.default.tmpdir(), "codex-activation-")
|
|
24134
24771
|
);
|
|
24135
24772
|
const tempAuthPath = import_node_path9.default.join(tempHome, "auth.json");
|
|
@@ -24137,7 +24774,7 @@ async function activateResetWindowViaRpcIsolated(envOverride, options, sourceAut
|
|
|
24137
24774
|
try {
|
|
24138
24775
|
const authLock = await acquireCodexAuthFileReadLock(sourceAuthPath);
|
|
24139
24776
|
if (!authLock) {
|
|
24140
|
-
await
|
|
24777
|
+
await import_node_fs6.promises.rm(tempHome, { recursive: true, force: true });
|
|
24141
24778
|
return { status: "skipped", reason: "auth-busy" };
|
|
24142
24779
|
}
|
|
24143
24780
|
try {
|
|
@@ -24146,16 +24783,16 @@ async function activateResetWindowViaRpcIsolated(envOverride, options, sourceAut
|
|
|
24146
24783
|
await authLock.release();
|
|
24147
24784
|
}
|
|
24148
24785
|
if (!initialSourceAuth) {
|
|
24149
|
-
await
|
|
24786
|
+
await import_node_fs6.promises.rm(tempHome, { recursive: true, force: true }).catch(() => {
|
|
24150
24787
|
});
|
|
24151
24788
|
return { status: "skipped", reason: "auth-missing" };
|
|
24152
24789
|
}
|
|
24153
|
-
await
|
|
24790
|
+
await import_node_fs6.promises.writeFile(tempAuthPath, initialSourceAuth, {
|
|
24154
24791
|
encoding: "utf8",
|
|
24155
24792
|
mode: 384
|
|
24156
24793
|
});
|
|
24157
24794
|
} catch {
|
|
24158
|
-
await
|
|
24795
|
+
await import_node_fs6.promises.rm(tempHome, { recursive: true, force: true }).catch(() => {
|
|
24159
24796
|
});
|
|
24160
24797
|
return { status: "skipped", reason: "auth-missing" };
|
|
24161
24798
|
}
|
|
@@ -24168,7 +24805,7 @@ async function activateResetWindowViaRpcIsolated(envOverride, options, sourceAut
|
|
|
24168
24805
|
} catch {
|
|
24169
24806
|
}
|
|
24170
24807
|
const activationModel = resolveActivationModel(configuredModel);
|
|
24171
|
-
await
|
|
24808
|
+
await import_node_fs6.promises.writeFile(
|
|
24172
24809
|
import_node_path9.default.join(tempHome, "config.toml"),
|
|
24173
24810
|
`model = ${JSON.stringify(activationModel)}
|
|
24174
24811
|
`,
|
|
@@ -24306,7 +24943,7 @@ async function activateResetWindowViaRpcIsolated(envOverride, options, sourceAut
|
|
|
24306
24943
|
rl.close();
|
|
24307
24944
|
await stopChildAndWait(child);
|
|
24308
24945
|
try {
|
|
24309
|
-
const updatedAuth = await
|
|
24946
|
+
const updatedAuth = await import_node_fs6.promises.readFile(tempAuthPath, "utf8");
|
|
24310
24947
|
if (updatedAuth.trim().length > 0) {
|
|
24311
24948
|
const currentSourceAuth = await readAuthFileCached(sourceAuthPath);
|
|
24312
24949
|
if (shouldWriteBackAuth(initialSourceAuth, currentSourceAuth, updatedAuth)) {
|
|
@@ -24341,7 +24978,7 @@ async function activateResetWindowViaRpcIsolated(envOverride, options, sourceAut
|
|
|
24341
24978
|
} catch (error) {
|
|
24342
24979
|
writebackError = error instanceof Error ? error : new Error(String(error));
|
|
24343
24980
|
}
|
|
24344
|
-
await
|
|
24981
|
+
await import_node_fs6.promises.rm(tempHome, { recursive: true, force: true }).catch(() => {
|
|
24345
24982
|
});
|
|
24346
24983
|
}
|
|
24347
24984
|
if (activationError && writebackError) {
|
|
@@ -24364,13 +25001,13 @@ async function activateResetWindowViaRpcIsolated(envOverride, options, sourceAut
|
|
|
24364
25001
|
|
|
24365
25002
|
// ../../packages/runtime-codex/src/codex/officialAppRestart.ts
|
|
24366
25003
|
var import_node_child_process6 = require("child_process");
|
|
24367
|
-
var
|
|
24368
|
-
var
|
|
25004
|
+
var import_node_crypto10 = require("crypto");
|
|
25005
|
+
var import_node_fs8 = require("fs");
|
|
24369
25006
|
var import_node_os4 = require("os");
|
|
24370
25007
|
var import_node_path11 = __toESM(require("path"), 1);
|
|
24371
25008
|
|
|
24372
25009
|
// ../../packages/runtime-codex/src/codex/threadUsage.ts
|
|
24373
|
-
var
|
|
25010
|
+
var import_node_fs7 = require("fs");
|
|
24374
25011
|
var import_node_path10 = __toESM(require("path"), 1);
|
|
24375
25012
|
var ROLLOUT_DIRS = ["sessions", "archived_sessions"];
|
|
24376
25013
|
var SQLITE_EXTENSIONS = /* @__PURE__ */ new Set([".db", ".sqlite", ".sqlite3"]);
|
|
@@ -24383,7 +25020,7 @@ async function collectRolloutFiles(root) {
|
|
|
24383
25020
|
async function visit(dir) {
|
|
24384
25021
|
let entries3;
|
|
24385
25022
|
try {
|
|
24386
|
-
entries3 = await
|
|
25023
|
+
entries3 = await import_node_fs7.promises.readdir(dir, {
|
|
24387
25024
|
withFileTypes: true,
|
|
24388
25025
|
encoding: "utf8"
|
|
24389
25026
|
});
|
|
@@ -24411,7 +25048,7 @@ async function collectRolloutFiles(root) {
|
|
|
24411
25048
|
async function collectRolloutFilesStrict(root) {
|
|
24412
25049
|
const files = [];
|
|
24413
25050
|
async function visit(dir) {
|
|
24414
|
-
const entries3 = await
|
|
25051
|
+
const entries3 = await import_node_fs7.promises.readdir(dir, {
|
|
24415
25052
|
withFileTypes: true,
|
|
24416
25053
|
encoding: "utf8"
|
|
24417
25054
|
});
|
|
@@ -24436,7 +25073,7 @@ async function readOfficialCodexRolloutActivityHeat(profileHome) {
|
|
|
24436
25073
|
for (const dirname of ROLLOUT_DIRS) {
|
|
24437
25074
|
const root = import_node_path10.default.join(profileHome, dirname);
|
|
24438
25075
|
try {
|
|
24439
|
-
await
|
|
25076
|
+
await import_node_fs7.promises.access(root);
|
|
24440
25077
|
} catch (error) {
|
|
24441
25078
|
if (error.code === "ENOENT") {
|
|
24442
25079
|
continue;
|
|
@@ -24445,7 +25082,7 @@ async function readOfficialCodexRolloutActivityHeat(profileHome) {
|
|
|
24445
25082
|
}
|
|
24446
25083
|
const files = await collectRolloutFilesStrict(root);
|
|
24447
25084
|
for (const file of files) {
|
|
24448
|
-
const stat2 = await
|
|
25085
|
+
const stat2 = await import_node_fs7.promises.stat(file);
|
|
24449
25086
|
if (Number.isFinite(stat2.mtimeMs)) {
|
|
24450
25087
|
latestUpdatedAtMs = Math.max(latestUpdatedAtMs ?? 0, stat2.mtimeMs);
|
|
24451
25088
|
}
|
|
@@ -24473,7 +25110,7 @@ async function findRolloutFileByScan(profileHome, threadId) {
|
|
|
24473
25110
|
if (!variants.some((variant) => basename.includes(variant))) {
|
|
24474
25111
|
continue;
|
|
24475
25112
|
}
|
|
24476
|
-
const stat2 = await
|
|
25113
|
+
const stat2 = await import_node_fs7.promises.stat(file).catch(() => null);
|
|
24477
25114
|
const updatedAtMs = stat2 && Number.isFinite(stat2.mtimeMs) ? stat2.mtimeMs : null;
|
|
24478
25115
|
if (!best || (updatedAtMs ?? 0) > (best.updatedAtMs ?? 0) || (updatedAtMs ?? 0) === (best.updatedAtMs ?? 0) && file > best.path) {
|
|
24479
25116
|
best = { path: file, updatedAtMs };
|
|
@@ -24551,7 +25188,7 @@ async function collectSessionDatabasePaths(profileHome, sqliteHome = profileHome
|
|
|
24551
25188
|
const paths = [];
|
|
24552
25189
|
const sqliteDir = import_node_path10.default.join(sqliteHome, "sqlite");
|
|
24553
25190
|
try {
|
|
24554
|
-
const entries3 = await
|
|
25191
|
+
const entries3 = await import_node_fs7.promises.readdir(sqliteDir, {
|
|
24555
25192
|
withFileTypes: true,
|
|
24556
25193
|
encoding: "utf8"
|
|
24557
25194
|
});
|
|
@@ -24633,7 +25270,7 @@ function queryThreadRecordFromTable(db, profileHome, threadId, config) {
|
|
|
24633
25270
|
}
|
|
24634
25271
|
async function readThreadRecordFromDb(profileHome, dbPath, threadId) {
|
|
24635
25272
|
try {
|
|
24636
|
-
await
|
|
25273
|
+
await import_node_fs7.promises.access(dbPath);
|
|
24637
25274
|
} catch {
|
|
24638
25275
|
return null;
|
|
24639
25276
|
}
|
|
@@ -25053,7 +25690,7 @@ function hashProfileKey(profileKey) {
|
|
|
25053
25690
|
if (!profileKey) {
|
|
25054
25691
|
return null;
|
|
25055
25692
|
}
|
|
25056
|
-
return (0,
|
|
25693
|
+
return (0, import_node_crypto10.createHash)("sha256").update(profileKey).digest("hex").slice(0, 12);
|
|
25057
25694
|
}
|
|
25058
25695
|
function sanitizeOfficialCodexOverlayActionTargetsForRenderer(targets) {
|
|
25059
25696
|
const sanitized = [];
|
|
@@ -28665,7 +29302,7 @@ async function runCdpCommandSequence(debuggerUrl, commands, timeoutMs = CODEX_CD
|
|
|
28665
29302
|
});
|
|
28666
29303
|
}
|
|
28667
29304
|
async function verifyCdpBindingRoundTrip(debuggerUrl) {
|
|
28668
|
-
const nonce = (0,
|
|
29305
|
+
const nonce = (0, import_node_crypto10.randomUUID)();
|
|
28669
29306
|
const expression = `(() => {
|
|
28670
29307
|
const binding = window[${JSON.stringify(CODEXUSE_BRIDGE_BINDING_NAME)}];
|
|
28671
29308
|
if (typeof binding !== "function") return false;
|
|
@@ -29088,7 +29725,7 @@ async function startOfficialCodexBridgeActionListenerOnce(args2) {
|
|
|
29088
29725
|
let closeNotified = false;
|
|
29089
29726
|
let echoReceived = false;
|
|
29090
29727
|
const requiredCommandIds = /* @__PURE__ */ new Set();
|
|
29091
|
-
const echoId = (0,
|
|
29728
|
+
const echoId = (0, import_node_crypto10.randomUUID)();
|
|
29092
29729
|
const readyTimeout = setTimeout(() => {
|
|
29093
29730
|
settleReady(false);
|
|
29094
29731
|
try {
|
|
@@ -29162,7 +29799,7 @@ async function startOfficialCodexBridgeActionListenerOnce(args2) {
|
|
|
29162
29799
|
}
|
|
29163
29800
|
};
|
|
29164
29801
|
bridgeActionListenerVerifiers.set(args2.debuggerUrl, async () => {
|
|
29165
|
-
const id2 = (0,
|
|
29802
|
+
const id2 = (0, import_node_crypto10.randomUUID)();
|
|
29166
29803
|
return await new Promise((resolve2) => {
|
|
29167
29804
|
const waiters = bridgeActionListenerHealthWaiters.get(args2.debuggerUrl) ?? /* @__PURE__ */ new Map();
|
|
29168
29805
|
bridgeActionListenerHealthWaiters.set(args2.debuggerUrl, waiters);
|
|
@@ -29710,7 +30347,7 @@ async function recordOfficialCodexActivity(input) {
|
|
|
29710
30347
|
};
|
|
29711
30348
|
const finite2 = (value3, min4, max4) => typeof value3 === "number" && Number.isFinite(value3) ? Math.max(min4, Math.min(max4, value3)) : null;
|
|
29712
30349
|
const entry = {
|
|
29713
|
-
id: (0,
|
|
30350
|
+
id: (0, import_node_crypto10.randomUUID)(),
|
|
29714
30351
|
at: now2.toISOString(),
|
|
29715
30352
|
kind: input.kind,
|
|
29716
30353
|
status: bounded(input.status, 80) ?? "unknown",
|
|
@@ -30713,7 +31350,7 @@ var devToolsActivePortPaths = (appUserDataDir) => {
|
|
|
30713
31350
|
};
|
|
30714
31351
|
var readDevToolsActivePort = async (filePath) => {
|
|
30715
31352
|
try {
|
|
30716
|
-
const text = await
|
|
31353
|
+
const text = await import_node_fs8.promises.readFile(filePath, "utf8");
|
|
30717
31354
|
const port = Number(text.split(/\r?\n/, 1)[0]);
|
|
30718
31355
|
if (!Number.isInteger(port) || port <= 0 || port >= 65536) {
|
|
30719
31356
|
return null;
|
|
@@ -30750,7 +31387,7 @@ function classifyOpenCodexLaunchFailure(error) {
|
|
|
30750
31387
|
}
|
|
30751
31388
|
async function openCodexWithProfileHome(candidate, profileHome, profileName, previousPids, options = {}) {
|
|
30752
31389
|
const executablePath = getMainExecutablePath(candidate);
|
|
30753
|
-
if (!(0,
|
|
31390
|
+
if (!(0, import_node_fs8.existsSync)(executablePath)) {
|
|
30754
31391
|
return {
|
|
30755
31392
|
opened: false,
|
|
30756
31393
|
pid: null,
|
|
@@ -30768,7 +31405,7 @@ async function openCodexWithProfileHome(candidate, profileHome, profileName, pre
|
|
|
30768
31405
|
let child;
|
|
30769
31406
|
try {
|
|
30770
31407
|
if (appUserDataDir) {
|
|
30771
|
-
(0,
|
|
31408
|
+
(0, import_node_fs8.mkdirSync)(appUserDataDir, { recursive: true });
|
|
30772
31409
|
}
|
|
30773
31410
|
child = (0, import_node_child_process6.spawn)(
|
|
30774
31411
|
"/usr/bin/open",
|
|
@@ -30923,7 +31560,7 @@ function resolveCodexLaunchHome(profileHome) {
|
|
|
30923
31560
|
}
|
|
30924
31561
|
async function readBundleString(appPath, key) {
|
|
30925
31562
|
const plistPath = import_node_path11.default.join(appPath, "Contents", "Info.plist");
|
|
30926
|
-
if (!(0,
|
|
31563
|
+
if (!(0, import_node_fs8.existsSync)(plistPath)) {
|
|
30927
31564
|
return null;
|
|
30928
31565
|
}
|
|
30929
31566
|
const result2 = await runCommand2("/usr/bin/plutil", [
|
|
@@ -30953,7 +31590,7 @@ function officialCodexAppPriority(appPath) {
|
|
|
30953
31590
|
async function collectCodexAppCandidates(rawPaths) {
|
|
30954
31591
|
const candidates = [];
|
|
30955
31592
|
for (const appPath of rawPaths) {
|
|
30956
|
-
if (!(0,
|
|
31593
|
+
if (!(0, import_node_fs8.existsSync)(appPath) || !OFFICIAL_CODEX_APP_NAMES.includes(import_node_path11.default.basename(appPath)) || !(0, import_node_fs8.existsSync)(import_node_path11.default.join(appPath, "Contents", "Resources", "codex"))) {
|
|
30957
31594
|
continue;
|
|
30958
31595
|
}
|
|
30959
31596
|
const bundleId = await readBundleString(appPath, "CFBundleIdentifier");
|
|
@@ -31065,7 +31702,7 @@ function sharedCodexLaunchOptions(useDefaultUserData, profileIdentity) {
|
|
|
31065
31702
|
const userDataDir = !useDefaultUserData && profileIdentity ? import_node_path11.default.join(
|
|
31066
31703
|
SHARED_CODEX_HOME,
|
|
31067
31704
|
"codex-app-user-data",
|
|
31068
|
-
(0,
|
|
31705
|
+
(0, import_node_crypto10.createHash)("sha256").update(profileIdentity).digest("hex").slice(0, 16)
|
|
31069
31706
|
) : void 0;
|
|
31070
31707
|
return {
|
|
31071
31708
|
useDefaultUserData,
|
|
@@ -33476,7 +34113,7 @@ async function attemptOfficialCodexManagedLiveLogin(args2) {
|
|
|
33476
34113
|
}
|
|
33477
34114
|
}
|
|
33478
34115
|
async function applyOfficialCodexLiveAccountSwitchOnce(options = {}, takeoverTrace = {
|
|
33479
|
-
operationId: (0,
|
|
34116
|
+
operationId: (0, import_node_crypto10.randomUUID)(),
|
|
33480
34117
|
attempt: 1
|
|
33481
34118
|
}) {
|
|
33482
34119
|
let expectedWindowPreflight = options.expectedWindowPreflight;
|
|
@@ -34544,7 +35181,7 @@ async function applyOfficialCodexLiveAccountSwitchOnce(options = {}, takeoverTra
|
|
|
34544
35181
|
}
|
|
34545
35182
|
function applyOfficialCodexLiveAccountSwitch(options = {}) {
|
|
34546
35183
|
return enqueueProfileAction("shared-window", async () => {
|
|
34547
|
-
const operationId = (0,
|
|
35184
|
+
const operationId = (0, import_node_crypto10.randomUUID)();
|
|
34548
35185
|
let result2 = await applyOfficialCodexLiveAccountSwitchOnce(options, {
|
|
34549
35186
|
operationId,
|
|
34550
35187
|
attempt: 1
|
|
@@ -35269,7 +35906,7 @@ async function launchOfficialCodexProfileInstanceOnce(options) {
|
|
|
35269
35906
|
}
|
|
35270
35907
|
|
|
35271
35908
|
// ../../packages/runtime-app-state/src/app/profileHomeMutationCoordinator.ts
|
|
35272
|
-
var
|
|
35909
|
+
var import_node_crypto11 = require("crypto");
|
|
35273
35910
|
|
|
35274
35911
|
// ../../packages/runtime-app-state/src/app/processOwner.ts
|
|
35275
35912
|
var import_node_child_process7 = require("child_process");
|
|
@@ -35307,12 +35944,12 @@ function isProcessEpochAlive(pid, expectedStartedAt) {
|
|
|
35307
35944
|
// ../../packages/runtime-app-state/src/app/profileHomeMutationCoordinator.ts
|
|
35308
35945
|
var PROFILE_HOME_MUTATION_TTL_MS = 10 * 60 * 1e3;
|
|
35309
35946
|
var PROFILE_HOME_MUTATION_RENEW_MS = 30 * 1e3;
|
|
35310
|
-
var PROCESS_OWNER_ID = (0,
|
|
35947
|
+
var PROCESS_OWNER_ID = (0, import_node_crypto11.randomUUID)();
|
|
35311
35948
|
var PROCESS_STARTED_AT = readProcessStartedAt(process.pid);
|
|
35312
35949
|
var activeRenewals = /* @__PURE__ */ new Map();
|
|
35313
35950
|
async function acquireProfileHomeMutationIntent(input) {
|
|
35314
35951
|
const now2 = Date.now();
|
|
35315
|
-
const operationId = (0,
|
|
35952
|
+
const operationId = (0, import_node_crypto11.randomUUID)();
|
|
35316
35953
|
const renewal = {
|
|
35317
35954
|
timer: void 0,
|
|
35318
35955
|
pending: Promise.resolve(),
|
|
@@ -35394,7 +36031,7 @@ async function releaseProfileHomeMutationIntent(homeId, operationId) {
|
|
|
35394
36031
|
}
|
|
35395
36032
|
|
|
35396
36033
|
// ../../packages/runtime-profiles/src/profiles/rate-limit-cache.ts
|
|
35397
|
-
var
|
|
36034
|
+
var import_node_fs9 = require("fs");
|
|
35398
36035
|
var import_node_path12 = __toESM(require("path"), 1);
|
|
35399
36036
|
var memorySnapshots = /* @__PURE__ */ new Map();
|
|
35400
36037
|
var persistedSnapshotWriteLock = Promise.resolve();
|
|
@@ -35408,7 +36045,7 @@ function snapshotCachePath() {
|
|
|
35408
36045
|
async function loadPersistedSnapshots() {
|
|
35409
36046
|
let raw;
|
|
35410
36047
|
try {
|
|
35411
|
-
raw = (await
|
|
36048
|
+
raw = (await import_node_fs9.promises.readFile(snapshotCachePath(), "utf8")).trim();
|
|
35412
36049
|
} catch {
|
|
35413
36050
|
return /* @__PURE__ */ new Map();
|
|
35414
36051
|
}
|
|
@@ -35452,13 +36089,13 @@ async function writePersistedSnapshots(snapshots) {
|
|
|
35452
36089
|
2
|
|
35453
36090
|
);
|
|
35454
36091
|
try {
|
|
35455
|
-
await
|
|
35456
|
-
await
|
|
36092
|
+
await import_node_fs9.promises.mkdir(import_node_path12.default.dirname(filePath), { recursive: true });
|
|
36093
|
+
await import_node_fs9.promises.writeFile(tmpPath, `${payload}
|
|
35457
36094
|
`, "utf8");
|
|
35458
|
-
await
|
|
36095
|
+
await import_node_fs9.promises.rename(tmpPath, filePath);
|
|
35459
36096
|
} catch {
|
|
35460
36097
|
try {
|
|
35461
|
-
await
|
|
36098
|
+
await import_node_fs9.promises.rm(tmpPath, { force: true });
|
|
35462
36099
|
} catch {
|
|
35463
36100
|
}
|
|
35464
36101
|
}
|
|
@@ -35523,7 +36160,7 @@ var AUTH_MUTATION_MANIFEST_NAME = ".codexuse-auth-transaction.json";
|
|
|
35523
36160
|
var AUTH_MUTATION_BACKUP_NAME = ".codexuse-auth-transaction.backup";
|
|
35524
36161
|
var AUTH_MUTATION_REPLACED_NAME = ".codexuse-auth-transaction.replaced";
|
|
35525
36162
|
var PROFILE_HOME_MUTATION_MARKER_TTL_MS = 10 * 60 * 1e3;
|
|
35526
|
-
var PROCESS_OWNER_ID2 = (0,
|
|
36163
|
+
var PROCESS_OWNER_ID2 = (0, import_node_crypto12.randomUUID)();
|
|
35527
36164
|
var PROCESS_STARTED_AT2 = readProcessStartedAt(process.pid);
|
|
35528
36165
|
var globalAuthSwapLock = Promise.resolve();
|
|
35529
36166
|
var profileOperationLocks = /* @__PURE__ */ new Map();
|
|
@@ -36339,8 +36976,14 @@ var ProfileManager = class {
|
|
|
36339
36976
|
const homeIdsByProfileName = /* @__PURE__ */ new Map();
|
|
36340
36977
|
const profileNamesByHomeId = /* @__PURE__ */ new Map();
|
|
36341
36978
|
for (const [profileName, raw] of Object.entries(source)) {
|
|
36342
|
-
|
|
36343
|
-
|
|
36979
|
+
let record2;
|
|
36980
|
+
try {
|
|
36981
|
+
record2 = this.fromStateRecord(profileName, raw);
|
|
36982
|
+
} catch {
|
|
36983
|
+
continue;
|
|
36984
|
+
}
|
|
36985
|
+
const homeId = record2 ? normalizeProfileHomeId(raw.homeId) : null;
|
|
36986
|
+
if (!record2 || !homeId) {
|
|
36344
36987
|
continue;
|
|
36345
36988
|
}
|
|
36346
36989
|
const collisionKey = homeId.toLowerCase();
|
|
@@ -36363,7 +37006,7 @@ var ProfileManager = class {
|
|
|
36363
37006
|
let attempt = 0;
|
|
36364
37007
|
let homeId;
|
|
36365
37008
|
do {
|
|
36366
|
-
homeId = `legacy-${(0,
|
|
37009
|
+
homeId = `legacy-${(0, import_node_crypto12.createHash)("sha256").update(profileName).update("\0").update(String(attempt)).digest("hex").slice(0, 32)}`;
|
|
36367
37010
|
attempt += 1;
|
|
36368
37011
|
} while (profileNamesByHomeId.has(homeId.toLowerCase()));
|
|
36369
37012
|
homeIdsByProfileName.set(profileName, homeId);
|
|
@@ -36479,17 +37122,17 @@ var ProfileManager = class {
|
|
|
36479
37122
|
}
|
|
36480
37123
|
async reconcileProfileHomeLocationConflicts(source) {
|
|
36481
37124
|
for (const [profileName, raw] of Object.entries(source)) {
|
|
36482
|
-
const record2 = this.fromStateRecord(profileName, raw);
|
|
36483
|
-
if (!record2) {
|
|
36484
|
-
continue;
|
|
36485
|
-
}
|
|
36486
|
-
const conflict = findProfileCodexHomeLocationConflict(record2.homeId);
|
|
36487
|
-
if (!conflict) {
|
|
36488
|
-
continue;
|
|
36489
|
-
}
|
|
36490
|
-
const currentAuthPath = (0, import_path2.join)(conflict.current, "auth.json");
|
|
36491
|
-
const legacyAuthPath = (0, import_path2.join)(conflict.legacy, "auth.json");
|
|
36492
37125
|
try {
|
|
37126
|
+
const record2 = this.fromStateRecord(profileName, raw);
|
|
37127
|
+
if (!record2) {
|
|
37128
|
+
continue;
|
|
37129
|
+
}
|
|
37130
|
+
const conflict = findProfileCodexHomeLocationConflict(record2.homeId);
|
|
37131
|
+
if (!conflict) {
|
|
37132
|
+
continue;
|
|
37133
|
+
}
|
|
37134
|
+
const currentAuthPath = (0, import_path2.join)(conflict.current, "auth.json");
|
|
37135
|
+
const legacyAuthPath = (0, import_path2.join)(conflict.legacy, "auth.json");
|
|
36493
37136
|
await this.withProfileAuthFileLock(currentAuthPath, async (currentRaw) => {
|
|
36494
37137
|
await this.withProfileAuthFileLock(legacyAuthPath, async (legacyRaw) => {
|
|
36495
37138
|
if (!legacyRaw?.trim()) {
|
|
@@ -36573,7 +37216,7 @@ var ProfileManager = class {
|
|
|
36573
37216
|
const dir = import_path.default.dirname(filePath);
|
|
36574
37217
|
const tempPath = import_path.default.join(
|
|
36575
37218
|
dir,
|
|
36576
|
-
`.${import_path.default.basename(filePath)}.${process.pid}.${(0,
|
|
37219
|
+
`.${import_path.default.basename(filePath)}.${process.pid}.${(0, import_node_crypto12.randomUUID)()}.tmp`
|
|
36577
37220
|
);
|
|
36578
37221
|
await import_fs.promises.mkdir(dir, { recursive: true, mode: 448 });
|
|
36579
37222
|
if (process.platform !== "win32") {
|
|
@@ -36860,7 +37503,7 @@ var ProfileManager = class {
|
|
|
36860
37503
|
if (content === null) {
|
|
36861
37504
|
return null;
|
|
36862
37505
|
}
|
|
36863
|
-
return (0,
|
|
37506
|
+
return (0, import_node_crypto12.createHash)("sha256").update(content).digest("hex");
|
|
36864
37507
|
}
|
|
36865
37508
|
async readOptionalFile(filePath) {
|
|
36866
37509
|
try {
|
|
@@ -36918,7 +37561,7 @@ var ProfileManager = class {
|
|
|
36918
37561
|
const dir = import_path.default.dirname(filePath);
|
|
36919
37562
|
const tempPath = import_path.default.join(
|
|
36920
37563
|
dir,
|
|
36921
|
-
`.${import_path.default.basename(filePath)}.${process.pid}.${(0,
|
|
37564
|
+
`.${import_path.default.basename(filePath)}.${process.pid}.${(0, import_node_crypto12.randomUUID)()}.install`
|
|
36922
37565
|
);
|
|
36923
37566
|
const handle = await import_fs.promises.open(tempPath, "wx", 384);
|
|
36924
37567
|
try {
|
|
@@ -37036,7 +37679,7 @@ var ProfileManager = class {
|
|
|
37036
37679
|
});
|
|
37037
37680
|
const manifest = {
|
|
37038
37681
|
version: 1,
|
|
37039
|
-
id: (0,
|
|
37682
|
+
id: (0, import_node_crypto12.randomUUID)(),
|
|
37040
37683
|
operation,
|
|
37041
37684
|
phase: "prepared",
|
|
37042
37685
|
sourceFingerprint: this.fingerprintAuthContent(sourceRaw),
|
|
@@ -37151,22 +37794,43 @@ var ProfileManager = class {
|
|
|
37151
37794
|
const byIdentityWorkspace = /* @__PURE__ */ new Map();
|
|
37152
37795
|
let cacheable = true;
|
|
37153
37796
|
for (const [profileName, raw] of Object.entries(source)) {
|
|
37154
|
-
|
|
37797
|
+
let storedRecord;
|
|
37798
|
+
try {
|
|
37799
|
+
storedRecord = this.fromStateRecord(profileName, raw);
|
|
37800
|
+
} catch (error) {
|
|
37801
|
+
logWarn(`Failed to read saved profile '${profileName}':`, error);
|
|
37802
|
+
cacheable = false;
|
|
37803
|
+
continue;
|
|
37804
|
+
}
|
|
37155
37805
|
if (!storedRecord) {
|
|
37156
37806
|
continue;
|
|
37157
37807
|
}
|
|
37158
|
-
|
|
37808
|
+
let hydration;
|
|
37809
|
+
try {
|
|
37810
|
+
hydration = await this.hydrateProfileRecordWithStatus(storedRecord);
|
|
37811
|
+
} catch (error) {
|
|
37812
|
+
logWarn(
|
|
37813
|
+
`Failed to hydrate profile '${profileName}'; using its saved metadata:`,
|
|
37814
|
+
error
|
|
37815
|
+
);
|
|
37816
|
+
hydration = { record: storedRecord, cacheable: false };
|
|
37817
|
+
}
|
|
37159
37818
|
const record2 = hydration.record;
|
|
37160
37819
|
cacheable = cacheable && hydration.cacheable;
|
|
37161
37820
|
records.push(record2);
|
|
37162
|
-
|
|
37163
|
-
|
|
37164
|
-
|
|
37165
|
-
|
|
37166
|
-
|
|
37167
|
-
bucket
|
|
37168
|
-
|
|
37169
|
-
|
|
37821
|
+
try {
|
|
37822
|
+
const identityKey = this.resolveProfileIdentityFromRecord(record2);
|
|
37823
|
+
const workspaceId = record2.workspaceId ?? record2.data.workspace_id ?? DEFAULT_WORKSPACE_ID;
|
|
37824
|
+
const key = this.identityWorkspaceIndexKey(identityKey, workspaceId);
|
|
37825
|
+
const bucket = byIdentityWorkspace.get(key);
|
|
37826
|
+
if (bucket) {
|
|
37827
|
+
bucket.push(record2);
|
|
37828
|
+
} else {
|
|
37829
|
+
byIdentityWorkspace.set(key, [record2]);
|
|
37830
|
+
}
|
|
37831
|
+
} catch (error) {
|
|
37832
|
+
logWarn(`Failed to index saved profile '${profileName}':`, error);
|
|
37833
|
+
cacheable = false;
|
|
37170
37834
|
}
|
|
37171
37835
|
}
|
|
37172
37836
|
const index2 = { sourceFingerprint, records, byIdentityWorkspace };
|
|
@@ -37737,7 +38401,7 @@ var ProfileManager = class {
|
|
|
37737
38401
|
const displayName = typeof options?.displayName === "string" && options.displayName.trim().length > 0 ? options.displayName.trim() : existingRecord?.displayName ?? resolvedName;
|
|
37738
38402
|
const record2 = {
|
|
37739
38403
|
name: resolvedName,
|
|
37740
|
-
homeId: existingRecord?.homeId ?? (options?.homeId ? this.normalizeProfileHomeId(options.homeId, resolvedName) : (0,
|
|
38404
|
+
homeId: existingRecord?.homeId ?? (options?.homeId ? this.normalizeProfileHomeId(options.homeId, resolvedName) : (0, import_node_crypto12.randomUUID)()),
|
|
37741
38405
|
cloudHomeId: existingRecord?.cloudHomeId ?? null,
|
|
37742
38406
|
displayName,
|
|
37743
38407
|
data,
|
|
@@ -37842,7 +38506,7 @@ var ProfileManager = class {
|
|
|
37842
38506
|
const safeName = record2.name.replace(/[^A-Za-z0-9._-]+/g, "-").slice(0, 48) || "profile";
|
|
37843
38507
|
const destination = import_path.default.join(
|
|
37844
38508
|
trashRoot,
|
|
37845
|
-
`CodexUse-${safeName}-${(0,
|
|
38509
|
+
`CodexUse-${safeName}-${(0, import_node_crypto12.randomUUID)()}`
|
|
37846
38510
|
);
|
|
37847
38511
|
await import_fs.promises.rename(profileHome, destination);
|
|
37848
38512
|
return destination;
|
|
@@ -38270,7 +38934,7 @@ var ProfileManager = class {
|
|
|
38270
38934
|
async acquireProfileRuntimeLease(record2) {
|
|
38271
38935
|
const leaseDir = this.getProfileRuntimeLeaseDir(record2.homeId);
|
|
38272
38936
|
const deletingPath = (0, import_path2.join)(leaseDir, ".deleting");
|
|
38273
|
-
const leaseId = (0,
|
|
38937
|
+
const leaseId = (0, import_node_crypto12.randomUUID)();
|
|
38274
38938
|
const leasePath = (0, import_path2.join)(leaseDir, `${leaseId}.json`);
|
|
38275
38939
|
const backupPath = (0, import_path2.join)(leaseDir, `${leaseId}.auth.backup`);
|
|
38276
38940
|
const releaseIntent = await this.acquireProfileHomeWriteIntent(record2);
|
|
@@ -38481,7 +39145,7 @@ var ProfileManager = class {
|
|
|
38481
39145
|
async acquireProfileHomeMutationGuard(record2) {
|
|
38482
39146
|
const leaseDir = this.getProfileRuntimeLeaseDir(record2.homeId);
|
|
38483
39147
|
const deletingPath = (0, import_path2.join)(leaseDir, ".deleting");
|
|
38484
|
-
const mutationId = (0,
|
|
39148
|
+
const mutationId = (0, import_node_crypto12.randomUUID)();
|
|
38485
39149
|
const mutationIntent = await acquireProfileHomeMutationIntent({
|
|
38486
39150
|
homeId: record2.homeId,
|
|
38487
39151
|
profileName: record2.name
|
|
@@ -38772,7 +39436,18 @@ var ProfileManager = class {
|
|
|
38772
39436
|
await this.initialize();
|
|
38773
39437
|
try {
|
|
38774
39438
|
const records = await this.listProfileRecords();
|
|
38775
|
-
|
|
39439
|
+
const profiles = [];
|
|
39440
|
+
for (const record2 of records) {
|
|
39441
|
+
try {
|
|
39442
|
+
const profile = this.buildProfileFromRow(record2);
|
|
39443
|
+
if (!profile.authMethod || profile.authMethod === "codex-cli") {
|
|
39444
|
+
profiles.push(profile);
|
|
39445
|
+
}
|
|
39446
|
+
} catch (error) {
|
|
39447
|
+
logWarn(`Failed to build saved profile '${record2.name}':`, error);
|
|
39448
|
+
}
|
|
39449
|
+
}
|
|
39450
|
+
return profiles.sort((a, b) => {
|
|
38776
39451
|
const aLabel = a.displayName ?? a.name;
|
|
38777
39452
|
const bLabel = b.displayName ?? b.name;
|
|
38778
39453
|
const base2 = aLabel.localeCompare(bLabel);
|
|
@@ -38780,7 +39455,7 @@ var ProfileManager = class {
|
|
|
38780
39455
|
});
|
|
38781
39456
|
} catch (error) {
|
|
38782
39457
|
logError("Error reading profiles from disk:", error);
|
|
38783
|
-
|
|
39458
|
+
throw error;
|
|
38784
39459
|
}
|
|
38785
39460
|
}
|
|
38786
39461
|
async runWithPreparedProfileHome(name, action, options = {}) {
|
|
@@ -39822,8 +40497,8 @@ var ProfileManager = class {
|
|
|
39822
40497
|
}
|
|
39823
40498
|
cloudRenamesByOldName.set(renamedExisting.name, name);
|
|
39824
40499
|
}
|
|
39825
|
-
const homeId = (0,
|
|
39826
|
-
const cloudHomeId = remoteHomeId || existing?.cloudHomeId || existing?.homeId || renamedExisting?.cloudHomeId || renamedExisting?.homeId || (0,
|
|
40500
|
+
const homeId = (0, import_node_crypto12.randomUUID)();
|
|
40501
|
+
const cloudHomeId = remoteHomeId || existing?.cloudHomeId || existing?.homeId || renamedExisting?.cloudHomeId || renamedExisting?.homeId || (0, import_node_crypto12.randomUUID)();
|
|
39827
40502
|
const sourceRecord = renamedExisting ?? existing;
|
|
39828
40503
|
if (sourceRecord) {
|
|
39829
40504
|
sourceHomeIdByTargetHomeId.set(homeId, sourceRecord.homeId);
|
|
@@ -40118,9 +40793,11 @@ async function listManagedProfiles(profileManager) {
|
|
|
40118
40793
|
return labelOrder !== 0 ? labelOrder : left.name.localeCompare(right.name);
|
|
40119
40794
|
});
|
|
40120
40795
|
}
|
|
40121
|
-
async function getCurrentManagedProfile(profileManager) {
|
|
40796
|
+
async function getCurrentManagedProfile(profileManager, activeCodexAuth) {
|
|
40122
40797
|
const [currentOpenAiProfile, state] = await Promise.all([
|
|
40123
|
-
|
|
40798
|
+
activeCodexAuth ? Promise.resolve(
|
|
40799
|
+
activeCodexAuth.state === "matched" && activeCodexAuth.profileName ? { name: activeCodexAuth.profileName, trusted: true } : { name: null, trusted: false }
|
|
40800
|
+
) : profileManager.getCurrentProfile(),
|
|
40124
40801
|
getAppState()
|
|
40125
40802
|
]);
|
|
40126
40803
|
const lastProfileName = state.app.lastProfileName?.trim() || null;
|
|
@@ -40722,13 +41399,13 @@ async function listApiKeys(stateDir) {
|
|
|
40722
41399
|
return Object.values(store.apiKeysById).filter((key) => key.revokedAt === null).sort((left, right) => right.createdAt.localeCompare(left.createdAt)).map(accountPoolApiKeyView);
|
|
40723
41400
|
}
|
|
40724
41401
|
function hashToken(token) {
|
|
40725
|
-
return (0,
|
|
41402
|
+
return (0, import_node_crypto13.createHash)("sha256").update(token).digest("hex");
|
|
40726
41403
|
}
|
|
40727
41404
|
async function createApiKey(stateDir) {
|
|
40728
|
-
const plaintextToken = `cux_pool_${(0,
|
|
41405
|
+
const plaintextToken = `cux_pool_${(0, import_node_crypto13.randomBytes)(24).toString("hex")}`;
|
|
40729
41406
|
const now2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
40730
41407
|
const keyRecord = {
|
|
40731
|
-
id: (0,
|
|
41408
|
+
id: (0, import_node_crypto13.randomUUID)(),
|
|
40732
41409
|
tokenHash: hashToken(plaintextToken),
|
|
40733
41410
|
tokenPreview: `${plaintextToken.slice(0, 8)}...${plaintextToken.slice(-6)}`,
|
|
40734
41411
|
createdAt: now2,
|
|
@@ -41353,14 +42030,14 @@ async function assertProfileAccessAllowed(profileManager, profileName) {
|
|
|
41353
42030
|
}
|
|
41354
42031
|
|
|
41355
42032
|
// ../../packages/runtime-app-state/src/app/workspaceBindings.ts
|
|
41356
|
-
var
|
|
42033
|
+
var import_node_fs10 = require("fs");
|
|
41357
42034
|
var import_node_path14 = __toESM(require("path"), 1);
|
|
41358
42035
|
async function canonicalizeWorkspacePath(input, options = {}) {
|
|
41359
42036
|
const resolved = import_node_path14.default.resolve(input || process.cwd());
|
|
41360
42037
|
try {
|
|
41361
|
-
const canonical = await
|
|
42038
|
+
const canonical = await import_node_fs10.promises.realpath(resolved);
|
|
41362
42039
|
if (options.requireDirectory !== false) {
|
|
41363
|
-
const stats = await
|
|
42040
|
+
const stats = await import_node_fs10.promises.stat(canonical);
|
|
41364
42041
|
if (!stats.isDirectory()) {
|
|
41365
42042
|
throw new Error(`Workspace path is not a directory: ${resolved}`);
|
|
41366
42043
|
}
|
|
@@ -41445,14 +42122,14 @@ async function resolveWorkspaceProfileBinding(requestedPath) {
|
|
|
41445
42122
|
|
|
41446
42123
|
// src/platform/codexCli.ts
|
|
41447
42124
|
var import_node_child_process8 = require("child_process");
|
|
41448
|
-
var
|
|
42125
|
+
var import_node_fs11 = require("fs");
|
|
41449
42126
|
var import_node_path15 = __toESM(require("path"));
|
|
41450
42127
|
var ENV_HINTS2 = ["CODEX_BINARY", "CODEX_CLI_PATH", "CODEX_PATH"];
|
|
41451
42128
|
function fileExists2(candidate) {
|
|
41452
42129
|
if (!candidate) return null;
|
|
41453
42130
|
const resolved = import_node_path15.default.resolve(candidate);
|
|
41454
42131
|
try {
|
|
41455
|
-
const stat2 = (0,
|
|
42132
|
+
const stat2 = (0, import_node_fs11.statSync)(resolved);
|
|
41456
42133
|
if (stat2.isFile()) return resolved;
|
|
41457
42134
|
} catch {
|
|
41458
42135
|
return null;
|
|
@@ -41911,17 +42588,17 @@ async function handleLicense(args2, version) {
|
|
|
41911
42588
|
}
|
|
41912
42589
|
|
|
41913
42590
|
// src/commands/profile.ts
|
|
41914
|
-
var
|
|
42591
|
+
var import_node_fs13 = require("fs");
|
|
41915
42592
|
var import_node_os7 = __toESM(require("os"));
|
|
41916
42593
|
var import_node_path17 = __toESM(require("path"));
|
|
41917
42594
|
|
|
41918
42595
|
// ../../packages/runtime-app-state/src/app/officialCodexSwitchCoordinator.ts
|
|
41919
|
-
var
|
|
41920
|
-
var
|
|
42596
|
+
var import_node_crypto14 = require("crypto");
|
|
42597
|
+
var import_node_fs12 = require("fs");
|
|
41921
42598
|
var import_node_path16 = __toESM(require("path"), 1);
|
|
41922
42599
|
var DEFAULT_SWITCH_INTENT_TTL_MS = 10 * 60 * 1e3;
|
|
41923
42600
|
var SWITCH_INTENT_RENEW_MS = 30 * 1e3;
|
|
41924
|
-
var PROCESS_OWNER_ID3 = (0,
|
|
42601
|
+
var PROCESS_OWNER_ID3 = (0, import_node_crypto14.randomUUID)();
|
|
41925
42602
|
var PROCESS_STARTED_AT3 = readProcessStartedAt(process.pid);
|
|
41926
42603
|
var localIntentDepth = /* @__PURE__ */ new Map();
|
|
41927
42604
|
var pendingLocalIntentAcquisitions = /* @__PURE__ */ new Map();
|
|
@@ -41931,7 +42608,7 @@ function nextSwitchIntentGeneration(current) {
|
|
|
41931
42608
|
}
|
|
41932
42609
|
async function acquireOfficialCodexSwitchIntent(input) {
|
|
41933
42610
|
const now2 = Date.now();
|
|
41934
|
-
const operationId = input.operationId?.trim() || (0,
|
|
42611
|
+
const operationId = input.operationId?.trim() || (0, import_node_crypto14.randomUUID)();
|
|
41935
42612
|
const targetProfileName = input.targetProfileName.trim();
|
|
41936
42613
|
if (!targetProfileName) {
|
|
41937
42614
|
throw new Error("Profile name is required");
|
|
@@ -42425,7 +43102,7 @@ function formatProfileLabel(name, displayName) {
|
|
|
42425
43102
|
}
|
|
42426
43103
|
var AUTO_ROLL_ACCESS_REQUIRED_MESSAGE = "Auto-roll requires a Pro license or an active trial.";
|
|
42427
43104
|
async function withIsolatedCodexLogin(mode, action) {
|
|
42428
|
-
const home = await
|
|
43105
|
+
const home = await import_node_fs13.promises.mkdtemp(import_node_path17.default.join(import_node_os7.default.tmpdir(), "codexuse-cli-login-"));
|
|
42429
43106
|
try {
|
|
42430
43107
|
await runCodexLogin(mode, {
|
|
42431
43108
|
HOME: home,
|
|
@@ -42435,7 +43112,7 @@ async function withIsolatedCodexLogin(mode, action) {
|
|
|
42435
43112
|
});
|
|
42436
43113
|
return await action(import_node_path17.default.join(home, "auth.json"));
|
|
42437
43114
|
} finally {
|
|
42438
|
-
await
|
|
43115
|
+
await import_node_fs13.promises.rm(home, { recursive: true, force: true }).catch(() => void 0);
|
|
42439
43116
|
}
|
|
42440
43117
|
}
|
|
42441
43118
|
async function assertOfficialCodexProfileStopped(profileName) {
|
|
@@ -43953,7 +44630,7 @@ async function pushRemoteSnapshot(access, snapshot2, options) {
|
|
|
43953
44630
|
|
|
43954
44631
|
// ../../packages/runtime-profiles/src/cloud-sync/encryption.ts
|
|
43955
44632
|
var import_node_child_process10 = require("child_process");
|
|
43956
|
-
var
|
|
44633
|
+
var import_node_crypto15 = require("crypto");
|
|
43957
44634
|
var KEYCHAIN_SERVICE2 = "CODEXUSE_CLOUD_SYNC_PASSPHRASE";
|
|
43958
44635
|
var KEYCHAIN_ACCOUNT_PREFIX2 = "license-sha256:";
|
|
43959
44636
|
var ENCRYPTION_AAD = Buffer.from("codexuse-cloud-sync-v2", "utf8");
|
|
@@ -43978,7 +44655,7 @@ function requireCloudSyncPassphrase(value3) {
|
|
|
43978
44655
|
}
|
|
43979
44656
|
async function deriveKey(passphrase, salt, params = SCRYPT_PARAMS) {
|
|
43980
44657
|
return new Promise((resolve2, reject) => {
|
|
43981
|
-
(0,
|
|
44658
|
+
(0, import_node_crypto15.scrypt)(passphrase, salt, params.keyLength, {
|
|
43982
44659
|
N: params.N,
|
|
43983
44660
|
r: params.r,
|
|
43984
44661
|
p: params.p,
|
|
@@ -44015,10 +44692,10 @@ function normalizeDecryptedSnapshot(value3) {
|
|
|
44015
44692
|
};
|
|
44016
44693
|
}
|
|
44017
44694
|
async function encryptCloudSyncSnapshot(snapshot2, passphrase) {
|
|
44018
|
-
const salt = (0,
|
|
44019
|
-
const iv = (0,
|
|
44695
|
+
const salt = (0, import_node_crypto15.randomBytes)(16);
|
|
44696
|
+
const iv = (0, import_node_crypto15.randomBytes)(12);
|
|
44020
44697
|
const key = await deriveKey(requireCloudSyncPassphrase(passphrase), salt);
|
|
44021
|
-
const cipher = (0,
|
|
44698
|
+
const cipher = (0, import_node_crypto15.createCipheriv)("aes-256-gcm", key, iv);
|
|
44022
44699
|
cipher.setAAD(ENCRYPTION_AAD);
|
|
44023
44700
|
const plaintext = Buffer.from(JSON.stringify(snapshot2), "utf8");
|
|
44024
44701
|
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
@@ -44045,7 +44722,7 @@ async function decryptCloudSyncSnapshot(snapshot2, passphrase) {
|
|
|
44045
44722
|
const tag2 = fromBase64(snapshot2.encryption.tag);
|
|
44046
44723
|
const ciphertext = fromBase64(snapshot2.encryption.ciphertext);
|
|
44047
44724
|
const key = await deriveKey(requireCloudSyncPassphrase(passphrase), salt, snapshot2.encryption.kdfParams);
|
|
44048
|
-
const decipher = (0,
|
|
44725
|
+
const decipher = (0, import_node_crypto15.createDecipheriv)("aes-256-gcm", key, iv);
|
|
44049
44726
|
decipher.setAAD(ENCRYPTION_AAD);
|
|
44050
44727
|
decipher.setAuthTag(tag2);
|
|
44051
44728
|
const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
@@ -44060,7 +44737,7 @@ async function decryptCloudSyncSnapshot(snapshot2, passphrase) {
|
|
|
44060
44737
|
}
|
|
44061
44738
|
}
|
|
44062
44739
|
function keychainAccountForLicense(licenseKey) {
|
|
44063
|
-
const digest = (0,
|
|
44740
|
+
const digest = (0, import_node_crypto15.createHash)("sha256").update(licenseKey).digest("hex");
|
|
44064
44741
|
return KEYCHAIN_ACCOUNT_PREFIX2 + digest;
|
|
44065
44742
|
}
|
|
44066
44743
|
function runSecurityCommand2(args2) {
|
|
@@ -44626,7 +45303,7 @@ async function handleSync(args2, version) {
|
|
|
44626
45303
|
}
|
|
44627
45304
|
|
|
44628
45305
|
// src/commands/workspace.ts
|
|
44629
|
-
var
|
|
45306
|
+
var import_node_fs14 = require("fs");
|
|
44630
45307
|
function printWorkspaceHelp() {
|
|
44631
45308
|
console.log(`Usage:
|
|
44632
45309
|
codexuse workspace bind <path> <profile>
|
|
@@ -44656,7 +45333,7 @@ async function handleWorkspaceCommand(args2) {
|
|
|
44656
45333
|
return;
|
|
44657
45334
|
}
|
|
44658
45335
|
for (const binding of bindings) {
|
|
44659
|
-
const pathState = await
|
|
45336
|
+
const pathState = await import_node_fs14.promises.stat(binding.rootPath).then(() => "").catch(() => " (path missing)");
|
|
44660
45337
|
const profileState = profiles.has(binding.profileName) ? "" : " (profile missing)";
|
|
44661
45338
|
console.log(`${binding.rootPath} -> ${binding.profileName}${pathState}${profileState}`);
|
|
44662
45339
|
}
|
|
@@ -44720,7 +45397,7 @@ async function ensureCliStorageReady() {
|
|
|
44720
45397
|
}
|
|
44721
45398
|
|
|
44722
45399
|
// src/app/main.ts
|
|
44723
|
-
var VERSION = true ? "6.0.
|
|
45400
|
+
var VERSION = true ? "6.0.3" : "0.0.0";
|
|
44724
45401
|
async function runCli() {
|
|
44725
45402
|
const args2 = process.argv.slice(2);
|
|
44726
45403
|
if (args2.length === 0) {
|