codexuse-cli 3.9.9 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2216,6 +2216,17 @@ var SQLITE_BUSY_MAX_ATTEMPTS = 3;
2216
2216
  var SQLITE_BUSY_RETRY_DELAY_MS = 100;
2217
2217
  var writeQueueByDbPath = /* @__PURE__ */ new Map();
2218
2218
  var initializedDbPaths = /* @__PURE__ */ new Set();
2219
+ var AppStorageCorruptionError = class extends Error {
2220
+ constructor(message, options) {
2221
+ super(message);
2222
+ this.name = "AppStorageCorruptionError";
2223
+ this.dbPath = options.dbPath;
2224
+ this.namespace = options.namespace ?? null;
2225
+ if (options.cause !== void 0) {
2226
+ this.cause = options.cause;
2227
+ }
2228
+ }
2229
+ };
2219
2230
  function isRecord(value) {
2220
2231
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
2221
2232
  }
@@ -2232,6 +2243,23 @@ function safeParseJson(raw) {
2232
2243
  return null;
2233
2244
  }
2234
2245
  }
2246
+ function parseJsonStrict(raw, options) {
2247
+ if (typeof raw !== "string" || raw.trim().length === 0) {
2248
+ return null;
2249
+ }
2250
+ try {
2251
+ return JSON.parse(raw);
2252
+ } catch (error) {
2253
+ throw new AppStorageCorruptionError(
2254
+ `App storage document ${options.namespace} contains invalid JSON.`,
2255
+ {
2256
+ dbPath: options.dbPath,
2257
+ namespace: options.namespace,
2258
+ cause: error
2259
+ }
2260
+ );
2261
+ }
2262
+ }
2235
2263
  function sleep(ms) {
2236
2264
  return new Promise((resolve) => setTimeout(resolve, ms));
2237
2265
  }
@@ -2240,9 +2268,32 @@ function isSqliteBusyError(error) {
2240
2268
  return false;
2241
2269
  }
2242
2270
  const sqliteError = error;
2243
- const message = typeof sqliteError.message === "string" ? sqliteError.message.toLowerCase() : "";
2271
+ if (sqliteError.cause && sqliteError.cause !== error && isSqliteBusyError(sqliteError.cause)) {
2272
+ return true;
2273
+ }
2274
+ if (sqliteError.error && sqliteError.error !== error && isSqliteBusyError(sqliteError.error)) {
2275
+ return true;
2276
+ }
2277
+ const message = typeof sqliteError.message === "string" ? sqliteError.message.toLowerCase() : String(error).toLowerCase();
2244
2278
  return sqliteError.code === "SQLITE_BUSY" || sqliteError.errno === 5 || message.includes("sqlite_busy") || message.includes("database is locked");
2245
2279
  }
2280
+ function isSqliteCorruptionError(error) {
2281
+ if (!error || typeof error !== "object") {
2282
+ return false;
2283
+ }
2284
+ const sqliteError = error;
2285
+ if (sqliteError.cause && sqliteError.cause !== error && isSqliteCorruptionError(sqliteError.cause)) {
2286
+ return true;
2287
+ }
2288
+ if (sqliteError.error && sqliteError.error !== error && isSqliteCorruptionError(sqliteError.error)) {
2289
+ return true;
2290
+ }
2291
+ const message = typeof sqliteError.message === "string" ? sqliteError.message.toLowerCase() : "";
2292
+ 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");
2293
+ }
2294
+ function isAppStorageCorruptionError(error) {
2295
+ return error instanceof AppStorageCorruptionError || isSqliteCorruptionError(error);
2296
+ }
2246
2297
  function beginImmediate(db) {
2247
2298
  db.exec("BEGIN IMMEDIATE");
2248
2299
  }
@@ -2317,19 +2368,55 @@ async function openDatabase(dbPath) {
2317
2368
  close: database.close.bind(database)
2318
2369
  };
2319
2370
  }
2371
+ function resetAppStorageInitialization(dbPath) {
2372
+ initializedDbPaths.delete(dbPath);
2373
+ }
2374
+ async function backupCorruptAppStorageDb(dbPath) {
2375
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
2376
+ const backupPath = `${dbPath}.corrupt-${stamp}`;
2377
+ let moved = false;
2378
+ for (const suffix of ["", "-wal", "-shm"]) {
2379
+ const source = `${dbPath}${suffix}`;
2380
+ const destination = `${backupPath}${suffix}`;
2381
+ try {
2382
+ const stats = await import_node_fs.promises.stat(source);
2383
+ if (!stats.isFile()) {
2384
+ continue;
2385
+ }
2386
+ await import_node_fs.promises.rename(source, destination);
2387
+ moved = true;
2388
+ } catch (error) {
2389
+ if (error.code !== "ENOENT") {
2390
+ throw error;
2391
+ }
2392
+ }
2393
+ }
2394
+ resetAppStorageInitialization(dbPath);
2395
+ return moved ? backupPath : null;
2396
+ }
2320
2397
  async function withDatabase(dbPath, task) {
2321
2398
  for (let attempt = 1; attempt <= SQLITE_BUSY_MAX_ATTEMPTS; attempt += 1) {
2322
- const db = await openDatabase(dbPath);
2399
+ let db = null;
2323
2400
  try {
2401
+ db = await openDatabase(dbPath);
2324
2402
  applyConnectionPragmas(db);
2325
2403
  ensureSchema(db, dbPath);
2326
2404
  return task(db);
2327
2405
  } catch (error) {
2406
+ if (error instanceof AppStorageCorruptionError) {
2407
+ throw error;
2408
+ }
2409
+ if (isSqliteCorruptionError(error)) {
2410
+ throw new AppStorageCorruptionError(
2411
+ "App storage database is corrupt.",
2412
+ { dbPath, cause: error }
2413
+ );
2414
+ }
2328
2415
  if (!isSqliteBusyError(error) || attempt >= SQLITE_BUSY_MAX_ATTEMPTS) {
2329
2416
  throw error;
2330
2417
  }
2331
2418
  } finally {
2332
- db.close();
2419
+ db?.close();
2333
2420
  }
2334
2421
  await sleep(SQLITE_BUSY_RETRY_DELAY_MS * attempt);
2335
2422
  }
@@ -2352,6 +2439,40 @@ async function readDocument(dbPath, namespace, normalize) {
2352
2439
  return normalize(parsed);
2353
2440
  });
2354
2441
  }
2442
+ async function readDocumentStrict(dbPath, namespace, normalize) {
2443
+ return withDatabase(dbPath, (db) => {
2444
+ const row = useStatement(
2445
+ db,
2446
+ `SELECT value_json AS valueJson FROM ${APP_STORAGE_TABLE} WHERE namespace = ?`,
2447
+ (statement) => statement.get(namespace)
2448
+ );
2449
+ if (!isRecord(row)) {
2450
+ return null;
2451
+ }
2452
+ const parsed = parseJsonStrict(row.valueJson, {
2453
+ dbPath,
2454
+ namespace
2455
+ });
2456
+ if (parsed === null) {
2457
+ throw new AppStorageCorruptionError(
2458
+ `App storage document ${namespace} is empty.`,
2459
+ { dbPath, namespace }
2460
+ );
2461
+ }
2462
+ try {
2463
+ return normalize(parsed);
2464
+ } catch (error) {
2465
+ throw new AppStorageCorruptionError(
2466
+ `App storage document ${namespace} failed normalization.`,
2467
+ {
2468
+ dbPath,
2469
+ namespace,
2470
+ cause: error
2471
+ }
2472
+ );
2473
+ }
2474
+ });
2475
+ }
2355
2476
  async function writeDocument(dbPath, namespace, value) {
2356
2477
  return withWriteQueue(
2357
2478
  dbPath,
@@ -3031,7 +3152,7 @@ async function readLegacyAppStateFromDisk() {
3031
3152
  }
3032
3153
  }
3033
3154
  async function readAppStateFromStorage() {
3034
- return readDocument(
3155
+ return readDocumentStrict(
3035
3156
  resolveStorageDbPath(),
3036
3157
  APP_STATE_DOCUMENT,
3037
3158
  normalizeAppState
@@ -3044,11 +3165,42 @@ async function writeAppStateToStorage(state) {
3044
3165
  normalizeAppState(state)
3045
3166
  );
3046
3167
  }
3168
+ function compactRecoveryMessage(error) {
3169
+ const message = error instanceof Error ? error.message : typeof error === "string" ? error : String(error);
3170
+ return message.replace(/\s+/g, " ").trim().slice(0, 240) || "unknown corruption";
3171
+ }
3172
+ async function recoverCorruptAppStateStorage(error) {
3173
+ const dbPath = resolveStorageDbPath();
3174
+ if (error instanceof AppStorageCorruptionError && error.namespace === APP_STATE_DOCUMENT) {
3175
+ appStateCache = null;
3176
+ resetAppStorageInitialization(dbPath);
3177
+ const legacyState2 = await readLegacyAppStateFromDisk().catch(() => null);
3178
+ const recovered2 = normalizeAppState(legacyState2 ?? null);
3179
+ recovered2.migration.lastError = `Recovered app-state document after corruption (${compactRecoveryMessage(error)}). Shared storage database preserved.`;
3180
+ return writeAppStateToStorage(recovered2);
3181
+ }
3182
+ const backupPath = await backupCorruptAppStorageDb(dbPath);
3183
+ appStateCache = null;
3184
+ resetAppStorageInitialization(dbPath);
3185
+ const legacyState = await readLegacyAppStateFromDisk().catch(() => null);
3186
+ const recovered = normalizeAppState(legacyState ?? null);
3187
+ recovered.migration.lastError = backupPath ? `Recovered app-state storage after corruption (${compactRecoveryMessage(error)}). Backup: ${import_node_path2.default.basename(backupPath)}` : `Recovered app-state storage after corruption (${compactRecoveryMessage(error)}). No existing DB file was present.`;
3188
+ return writeAppStateToStorage(recovered);
3189
+ }
3047
3190
  async function ensureInitialized() {
3048
3191
  if (appStateCache) {
3049
3192
  return appStateCache;
3050
3193
  }
3051
- const loaded = await readAppStateFromStorage() ?? await readLegacyAppStateFromDisk();
3194
+ let loaded = null;
3195
+ try {
3196
+ loaded = await readAppStateFromStorage() ?? await readLegacyAppStateFromDisk();
3197
+ } catch (error) {
3198
+ if (!isAppStorageCorruptionError(error)) {
3199
+ throw error;
3200
+ }
3201
+ appStateCache = await recoverCorruptAppStateStorage(error);
3202
+ return clone2(appStateCache);
3203
+ }
3052
3204
  const normalized = loaded ?? normalizeAppState(null);
3053
3205
  appStateCache = await writeAppStateToStorage(normalized);
3054
3206
  return clone2(appStateCache);
@@ -3072,7 +3224,11 @@ async function withWriteLock(task) {
3072
3224
  }
3073
3225
  }
3074
3226
  async function initializeAppState(userDataDir) {
3075
- configuredUserDataDir = userDataDir;
3227
+ if (configuredUserDataDir !== userDataDir) {
3228
+ configuredUserDataDir = userDataDir;
3229
+ appStateCache = null;
3230
+ resetAppStorageInitialization(resolveStorageDbPath());
3231
+ }
3076
3232
  const state = await ensureInitialized();
3077
3233
  return clone2(state);
3078
3234
  }
@@ -12549,7 +12705,7 @@ async function ensureCliStorageReady() {
12549
12705
  }
12550
12706
 
12551
12707
  // src/app/main.ts
12552
- var VERSION = true ? "3.9.9" : "0.0.0";
12708
+ var VERSION = true ? "4.0.0" : "0.0.0";
12553
12709
  async function runCli() {
12554
12710
  const args = process.argv.slice(2);
12555
12711
  if (args.length === 0) {