memorix 1.9.2 → 1.9.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/CHANGELOG.md +11 -0
- package/dist/cli/index.js +318 -141
- package/dist/index.js +243 -120
- package/dist/maintenance-runner.js +184 -93
- package/dist/media-audio-runner.js +184 -93
- package/dist/media-video-runner.js +184 -93
- package/dist/memcode-runtime/CHANGELOG.md +11 -0
- package/dist/sdk.js +242 -119
- package/dist/vector-backfill-runner.js +184 -93
- package/docs/AGENT_OPERATOR_PLAYBOOK.md +15 -0
- package/docs/ARCHITECTURE.md +23 -0
- package/docs/DEVELOPMENT.md +1 -1
- package/docs/PERFORMANCE.md +50 -0
- package/docs/README.md +1 -1
- package/package.json +1 -1
- package/plugins/antigravity/memorix/plugin.json +1 -1
- package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
- package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
- package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/copilot/memorix/plugin.json +1 -1
- package/plugins/gemini/memorix/gemini-extension.json +1 -1
- package/plugins/hermes/memorix/plugin.yaml +1 -1
- package/plugins/omp/memorix/package.json +1 -1
- package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/pi/memorix/package.json +1 -1
- package/server.json +2 -2
- package/src/cli/commands/doctor.ts +78 -17
- package/src/store/mini-skill-store.ts +31 -22
- package/src/store/obs-store.ts +46 -30
- package/src/store/session-store.ts +35 -21
- package/src/store/sqlite-db.ts +16 -7
- package/src/store/sqlite-reliability.ts +87 -0
- package/src/store/sqlite-store.ts +4 -1
package/dist/index.js
CHANGED
|
@@ -452,70 +452,79 @@ function getDatabase(dataDir) {
|
|
|
452
452
|
loadBetterSqlite3();
|
|
453
453
|
fs.mkdirSync(dataDir, { recursive: true });
|
|
454
454
|
const dbPath = path3.join(dataDir, "memorix.db");
|
|
455
|
-
|
|
456
|
-
db2.pragma("journal_mode = WAL");
|
|
457
|
-
db2.pragma("busy_timeout = 5000");
|
|
458
|
-
db2.pragma("foreign_keys = ON");
|
|
459
|
-
db2.exec(CREATE_OBSERVATIONS_TABLE);
|
|
460
|
-
db2.exec(CREATE_MINI_SKILLS_TABLE);
|
|
461
|
-
db2.exec(CREATE_SESSIONS_TABLE);
|
|
462
|
-
db2.exec(CREATE_META_TABLE);
|
|
463
|
-
db2.exec(CREATE_TEAM_AGENTS_TABLE);
|
|
464
|
-
db2.exec(CREATE_TEAM_TASKS_TABLE);
|
|
465
|
-
db2.exec(CREATE_TEAM_TASK_DEPS_TABLE);
|
|
466
|
-
db2.exec(CREATE_TEAM_MESSAGES_TABLE);
|
|
467
|
-
db2.exec(CREATE_TEAM_LOCKS_TABLE);
|
|
468
|
-
db2.exec(CREATE_TEAM_ROLES_TABLE);
|
|
469
|
-
db2.exec(CREATE_GRAPH_ENTITIES_TABLE);
|
|
470
|
-
db2.exec(CREATE_GRAPH_RELATIONS_TABLE);
|
|
471
|
-
db2.exec(CREATE_CHAT_TRANSCRIPT_TABLE);
|
|
472
|
-
db2.exec(CREATE_CODE_FILES_TABLE);
|
|
473
|
-
db2.exec(CREATE_CODE_SYMBOLS_TABLE);
|
|
474
|
-
db2.exec(CREATE_CODE_EDGES_TABLE);
|
|
475
|
-
db2.exec(CREATE_OBSERVATION_CODE_REFS_TABLE);
|
|
476
|
-
db2.exec(CREATE_MAINTENANCE_JOBS_TABLE);
|
|
477
|
-
db2.exec(CREATE_MAINTENANCE_TARGETS_TABLE);
|
|
478
|
-
db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
|
|
455
|
+
let db2;
|
|
479
456
|
try {
|
|
480
|
-
db2
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
db2.exec(
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
db2.exec(
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
db2.exec(
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
db2.exec(
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
db2.exec(
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
457
|
+
db2 = createDatabase(dbPath);
|
|
458
|
+
db2.pragma("busy_timeout = 5000");
|
|
459
|
+
db2.pragma("journal_mode = WAL");
|
|
460
|
+
db2.pragma("foreign_keys = ON");
|
|
461
|
+
db2.exec(CREATE_OBSERVATIONS_TABLE);
|
|
462
|
+
db2.exec(CREATE_MINI_SKILLS_TABLE);
|
|
463
|
+
db2.exec(CREATE_SESSIONS_TABLE);
|
|
464
|
+
db2.exec(CREATE_META_TABLE);
|
|
465
|
+
db2.exec(CREATE_TEAM_AGENTS_TABLE);
|
|
466
|
+
db2.exec(CREATE_TEAM_TASKS_TABLE);
|
|
467
|
+
db2.exec(CREATE_TEAM_TASK_DEPS_TABLE);
|
|
468
|
+
db2.exec(CREATE_TEAM_MESSAGES_TABLE);
|
|
469
|
+
db2.exec(CREATE_TEAM_LOCKS_TABLE);
|
|
470
|
+
db2.exec(CREATE_TEAM_ROLES_TABLE);
|
|
471
|
+
db2.exec(CREATE_GRAPH_ENTITIES_TABLE);
|
|
472
|
+
db2.exec(CREATE_GRAPH_RELATIONS_TABLE);
|
|
473
|
+
db2.exec(CREATE_CHAT_TRANSCRIPT_TABLE);
|
|
474
|
+
db2.exec(CREATE_CODE_FILES_TABLE);
|
|
475
|
+
db2.exec(CREATE_CODE_SYMBOLS_TABLE);
|
|
476
|
+
db2.exec(CREATE_CODE_EDGES_TABLE);
|
|
477
|
+
db2.exec(CREATE_OBSERVATION_CODE_REFS_TABLE);
|
|
478
|
+
db2.exec(CREATE_MAINTENANCE_JOBS_TABLE);
|
|
479
|
+
db2.exec(CREATE_MAINTENANCE_TARGETS_TABLE);
|
|
480
|
+
db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
|
|
481
|
+
try {
|
|
482
|
+
db2.exec(`ALTER TABLE mini_skills ADD COLUMN sourceSnapshot TEXT NOT NULL DEFAULT ''`);
|
|
483
|
+
} catch {
|
|
484
|
+
}
|
|
485
|
+
try {
|
|
486
|
+
db2.exec(`ALTER TABLE mini_skills ADD COLUMN updatedAt TEXT`);
|
|
487
|
+
} catch {
|
|
488
|
+
}
|
|
489
|
+
try {
|
|
490
|
+
db2.exec(`ALTER TABLE observations ADD COLUMN createdByAgentId TEXT`);
|
|
491
|
+
} catch {
|
|
492
|
+
}
|
|
493
|
+
try {
|
|
494
|
+
db2.exec(`ALTER TABLE observations ADD COLUMN writeGeneration INTEGER DEFAULT 0`);
|
|
495
|
+
} catch {
|
|
496
|
+
}
|
|
497
|
+
try {
|
|
498
|
+
db2.exec(`ALTER TABLE team_tasks ADD COLUMN required_role TEXT`);
|
|
499
|
+
} catch {
|
|
500
|
+
}
|
|
501
|
+
try {
|
|
502
|
+
db2.exec(`ALTER TABLE team_tasks ADD COLUMN preferred_role TEXT`);
|
|
503
|
+
} catch {
|
|
504
|
+
}
|
|
505
|
+
try {
|
|
506
|
+
db2.exec(`ALTER TABLE team_messages ADD COLUMN to_role TEXT`);
|
|
507
|
+
} catch {
|
|
508
|
+
}
|
|
509
|
+
try {
|
|
510
|
+
db2.exec(`ALTER TABLE team_messages ADD COLUMN handoff_status TEXT`);
|
|
511
|
+
} catch {
|
|
512
|
+
}
|
|
513
|
+
applySchemaMigrations(db2);
|
|
514
|
+
db2.exec(CREATE_INDEXES);
|
|
515
|
+
initializeObservationLexicalIndex(db2);
|
|
516
|
+
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('storage_generation', '0')`).run();
|
|
517
|
+
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('next_id', '1')`).run();
|
|
518
|
+
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('mini_skills_generation', '0')`).run();
|
|
519
|
+
_dbCache.set(normalized, db2);
|
|
520
|
+
return db2;
|
|
521
|
+
} catch (error) {
|
|
522
|
+
try {
|
|
523
|
+
db2?.close();
|
|
524
|
+
} catch {
|
|
525
|
+
}
|
|
526
|
+
throw error;
|
|
510
527
|
}
|
|
511
|
-
applySchemaMigrations(db2);
|
|
512
|
-
db2.exec(CREATE_INDEXES);
|
|
513
|
-
initializeObservationLexicalIndex(db2);
|
|
514
|
-
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('storage_generation', '0')`).run();
|
|
515
|
-
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('next_id', '1')`).run();
|
|
516
|
-
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('mini_skills_generation', '0')`).run();
|
|
517
|
-
_dbCache.set(normalized, db2);
|
|
518
|
-
return db2;
|
|
519
528
|
}
|
|
520
529
|
function closeAllDatabases() {
|
|
521
530
|
for (const [key, db2] of _dbCache) {
|
|
@@ -2329,6 +2338,74 @@ var init_types = __esm({
|
|
|
2329
2338
|
}
|
|
2330
2339
|
});
|
|
2331
2340
|
|
|
2341
|
+
// src/store/sqlite-reliability.ts
|
|
2342
|
+
function isTransientSqliteError(error) {
|
|
2343
|
+
const code = error?.code;
|
|
2344
|
+
if (typeof code === "string") {
|
|
2345
|
+
return /^SQLITE_BUSY(?:_|$)/i.test(code);
|
|
2346
|
+
}
|
|
2347
|
+
return error instanceof Error && /\bdatabase is locked\b|\bdatabase is busy\b/i.test(error.message);
|
|
2348
|
+
}
|
|
2349
|
+
function isSqliteUnavailableError(error) {
|
|
2350
|
+
return error instanceof SqliteUnavailableError || error instanceof Error && /SQLite is not available|better-sqlite3.*failed|node:sqlite.*failed|bun:sqlite.*failed/i.test(error.message);
|
|
2351
|
+
}
|
|
2352
|
+
function degradedReadError(storeName) {
|
|
2353
|
+
return new Error(`[memorix] Cannot read ${storeName}: SQLite backend unavailable (memory is not loaded)`);
|
|
2354
|
+
}
|
|
2355
|
+
function degradedWriteError(storeName) {
|
|
2356
|
+
return new Error(`[memorix] Cannot write ${storeName}: SQLite backend unavailable (degraded mode; read-only)`);
|
|
2357
|
+
}
|
|
2358
|
+
function formatSqliteFailure(error) {
|
|
2359
|
+
return error instanceof Error && error.message ? error.message : String(error);
|
|
2360
|
+
}
|
|
2361
|
+
function delay(ms) {
|
|
2362
|
+
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
2363
|
+
}
|
|
2364
|
+
async function retrySqliteBusy(operation, label) {
|
|
2365
|
+
for (let attempt = 0; ; attempt++) {
|
|
2366
|
+
try {
|
|
2367
|
+
return await operation();
|
|
2368
|
+
} catch (error) {
|
|
2369
|
+
if (!isTransientSqliteError(error) || attempt >= SQLITE_BUSY_RETRY_DELAYS_MS.length) throw error;
|
|
2370
|
+
const waitMs = SQLITE_BUSY_RETRY_DELAYS_MS[attempt];
|
|
2371
|
+
console.error(
|
|
2372
|
+
`[memorix] ${label} SQLite busy (attempt ${attempt + 1}/${SQLITE_BUSY_RETRY_DELAYS_MS.length + 1}), retrying in ${waitMs}ms`
|
|
2373
|
+
);
|
|
2374
|
+
await delay(waitMs);
|
|
2375
|
+
}
|
|
2376
|
+
}
|
|
2377
|
+
}
|
|
2378
|
+
async function initializeSqliteStore(factory, dataDir, label) {
|
|
2379
|
+
try {
|
|
2380
|
+
loadBetterSqlite3();
|
|
2381
|
+
} catch (error) {
|
|
2382
|
+
throw new SqliteUnavailableError(error);
|
|
2383
|
+
}
|
|
2384
|
+
return retrySqliteBusy(async () => {
|
|
2385
|
+
const store = factory();
|
|
2386
|
+
await store.init(dataDir);
|
|
2387
|
+
return store;
|
|
2388
|
+
}, label);
|
|
2389
|
+
}
|
|
2390
|
+
var SQLITE_BUSY_RETRY_DELAYS_MS, SqliteUnavailableError;
|
|
2391
|
+
var init_sqlite_reliability = __esm({
|
|
2392
|
+
"src/store/sqlite-reliability.ts"() {
|
|
2393
|
+
"use strict";
|
|
2394
|
+
init_esm_shims();
|
|
2395
|
+
init_sqlite_db();
|
|
2396
|
+
SQLITE_BUSY_RETRY_DELAYS_MS = [50, 150, 400, 1e3, 2500];
|
|
2397
|
+
SqliteUnavailableError = class extends Error {
|
|
2398
|
+
code = "MEMORIX_SQLITE_UNAVAILABLE";
|
|
2399
|
+
constructor(cause) {
|
|
2400
|
+
super(
|
|
2401
|
+
cause instanceof Error && cause.message ? cause.message : "[memorix] SQLite is unavailable (install a supported SQLite runtime)"
|
|
2402
|
+
);
|
|
2403
|
+
this.name = "SqliteUnavailableError";
|
|
2404
|
+
}
|
|
2405
|
+
};
|
|
2406
|
+
}
|
|
2407
|
+
});
|
|
2408
|
+
|
|
2332
2409
|
// src/store/mini-skill-store.ts
|
|
2333
2410
|
var mini_skill_store_exports = {};
|
|
2334
2411
|
__export(mini_skill_store_exports, {
|
|
@@ -2400,16 +2477,18 @@ async function initMiniSkillStore(dataDir) {
|
|
|
2400
2477
|
if (_store && _storeDataDir === dataDir) return _store;
|
|
2401
2478
|
_store = null;
|
|
2402
2479
|
_storeDataDir = null;
|
|
2480
|
+
let degradedReason = "SQLite runtime unavailable";
|
|
2403
2481
|
try {
|
|
2404
|
-
const store2 = new MiniSkillSqliteStore();
|
|
2405
|
-
await store2.init(dataDir);
|
|
2482
|
+
const store2 = await initializeSqliteStore(() => new MiniSkillSqliteStore(), dataDir, "Mini-skill store");
|
|
2406
2483
|
_store = store2;
|
|
2407
2484
|
_storeDataDir = dataDir;
|
|
2408
2485
|
return store2;
|
|
2409
2486
|
} catch (err) {
|
|
2410
|
-
|
|
2487
|
+
if (!isSqliteUnavailableError(err)) throw err;
|
|
2488
|
+
degradedReason = err instanceof Error ? err.message : String(err);
|
|
2489
|
+
console.error(`[memorix] MiniSkillSqliteStore unavailable, running in degraded read-only mode: ${degradedReason}`);
|
|
2411
2490
|
}
|
|
2412
|
-
const store = new MiniSkillGracefulDegrade();
|
|
2491
|
+
const store = new MiniSkillGracefulDegrade(degradedReason);
|
|
2413
2492
|
await store.init(dataDir);
|
|
2414
2493
|
_store = store;
|
|
2415
2494
|
_storeDataDir = dataDir;
|
|
@@ -2421,6 +2500,7 @@ var init_mini_skill_store = __esm({
|
|
|
2421
2500
|
"use strict";
|
|
2422
2501
|
init_esm_shims();
|
|
2423
2502
|
init_sqlite_db();
|
|
2503
|
+
init_sqlite_reliability();
|
|
2424
2504
|
MiniSkillSqliteStore = class {
|
|
2425
2505
|
db = null;
|
|
2426
2506
|
dataDir = "";
|
|
@@ -2529,7 +2609,7 @@ var init_mini_skill_store = __esm({
|
|
|
2529
2609
|
* SQLite serializes write transactions, so concurrent calls are safely sequenced.
|
|
2530
2610
|
*/
|
|
2531
2611
|
async atomicInsertWithId(skillWithoutId) {
|
|
2532
|
-
|
|
2612
|
+
return retrySqliteBusy(async () => this.db.transaction(() => {
|
|
2533
2613
|
const row = this.stmtGetMeta.get("mini_skills_next_id");
|
|
2534
2614
|
const nextId2 = row ? parseInt(row.value, 10) : 1;
|
|
2535
2615
|
const skill2 = { ...skillWithoutId, id: nextId2 };
|
|
@@ -2538,8 +2618,7 @@ var init_mini_skill_store = __esm({
|
|
|
2538
2618
|
this.stmtBumpGeneration.run();
|
|
2539
2619
|
this.knownGeneration = this.readGeneration();
|
|
2540
2620
|
return skill2;
|
|
2541
|
-
})();
|
|
2542
|
-
return result;
|
|
2621
|
+
})(), "Mini-skill promotion");
|
|
2543
2622
|
}
|
|
2544
2623
|
// ── Freshness ────────────────────────────────────────────────────
|
|
2545
2624
|
async ensureFresh() {
|
|
@@ -2558,10 +2637,17 @@ var init_mini_skill_store = __esm({
|
|
|
2558
2637
|
}
|
|
2559
2638
|
};
|
|
2560
2639
|
MiniSkillGracefulDegrade = class {
|
|
2640
|
+
constructor(reason = "SQLite runtime unavailable") {
|
|
2641
|
+
this.reason = reason;
|
|
2642
|
+
}
|
|
2643
|
+
reason;
|
|
2561
2644
|
warned = false;
|
|
2645
|
+
unavailableRead() {
|
|
2646
|
+
return degradedReadError("mini-skills");
|
|
2647
|
+
}
|
|
2562
2648
|
warn() {
|
|
2563
2649
|
if (!this.warned) {
|
|
2564
|
-
console.error("[memorix] MiniSkillStore: SQLite unavailable \u2014 mini-skills
|
|
2650
|
+
console.error("[memorix] MiniSkillStore: SQLite unavailable \u2014 mini-skills cannot be read or written. Install a supported SQLite runtime.");
|
|
2565
2651
|
this.warned = true;
|
|
2566
2652
|
}
|
|
2567
2653
|
}
|
|
@@ -2569,28 +2655,33 @@ var init_mini_skill_store = __esm({
|
|
|
2569
2655
|
this.warn();
|
|
2570
2656
|
}
|
|
2571
2657
|
async loadAll() {
|
|
2572
|
-
|
|
2658
|
+
throw this.unavailableRead();
|
|
2573
2659
|
}
|
|
2574
2660
|
async loadByProject(_projectId) {
|
|
2575
|
-
|
|
2661
|
+
throw this.unavailableRead();
|
|
2576
2662
|
}
|
|
2577
2663
|
async loadIdCounter() {
|
|
2578
|
-
|
|
2664
|
+
throw this.unavailableRead();
|
|
2579
2665
|
}
|
|
2580
2666
|
async insert(_skill) {
|
|
2581
2667
|
this.warn();
|
|
2668
|
+
throw degradedWriteError("mini-skills");
|
|
2582
2669
|
}
|
|
2583
2670
|
async update(_skill) {
|
|
2584
2671
|
this.warn();
|
|
2672
|
+
throw degradedWriteError("mini-skills");
|
|
2585
2673
|
}
|
|
2586
2674
|
async remove(_id) {
|
|
2587
2675
|
this.warn();
|
|
2676
|
+
throw degradedWriteError("mini-skills");
|
|
2588
2677
|
}
|
|
2589
2678
|
async saveIdCounter(_nextId) {
|
|
2679
|
+
this.warn();
|
|
2680
|
+
throw degradedWriteError("mini-skills");
|
|
2590
2681
|
}
|
|
2591
2682
|
async atomicInsertWithId(skillWithoutId) {
|
|
2592
2683
|
this.warn();
|
|
2593
|
-
|
|
2684
|
+
throw degradedWriteError("mini-skills");
|
|
2594
2685
|
}
|
|
2595
2686
|
async ensureFresh() {
|
|
2596
2687
|
return false;
|
|
@@ -2601,6 +2692,9 @@ var init_mini_skill_store = __esm({
|
|
|
2601
2692
|
getBackendName() {
|
|
2602
2693
|
return "degraded";
|
|
2603
2694
|
}
|
|
2695
|
+
getBackendReason() {
|
|
2696
|
+
return this.reason;
|
|
2697
|
+
}
|
|
2604
2698
|
};
|
|
2605
2699
|
_store = null;
|
|
2606
2700
|
_storeDataDir = null;
|
|
@@ -4855,10 +4949,10 @@ async function fetchWithRetry(url, apiKey, body, options = {}, attempt = 0, nati
|
|
|
4855
4949
|
);
|
|
4856
4950
|
}
|
|
4857
4951
|
if (options.retry !== false && (response.status === 429 || response.status >= 500) && attempt < MAX_RETRIES2) {
|
|
4858
|
-
const
|
|
4952
|
+
const delay3 = BASE_DELAY_MS * Math.pow(2, attempt);
|
|
4859
4953
|
const retryAfter = response.headers.get("retry-after");
|
|
4860
4954
|
const parsedRetryAfter = retryAfter ? parseInt(retryAfter, 10) * 1e3 : NaN;
|
|
4861
|
-
const waitMs = Number.isFinite(parsedRetryAfter) ? parsedRetryAfter :
|
|
4955
|
+
const waitMs = Number.isFinite(parsedRetryAfter) ? parsedRetryAfter : delay3;
|
|
4862
4956
|
console.error(`[memorix] Embedding API ${response.status}, retry ${attempt + 1}/${MAX_RETRIES2} in ${waitMs}ms`);
|
|
4863
4957
|
await waitForRetry(waitMs, options.signal);
|
|
4864
4958
|
return fetchWithRetry(url, apiKey, body, options, attempt + 1, nativeGemini);
|
|
@@ -6890,6 +6984,7 @@ var init_sqlite_store = __esm({
|
|
|
6890
6984
|
"use strict";
|
|
6891
6985
|
init_esm_shims();
|
|
6892
6986
|
init_sqlite_db();
|
|
6987
|
+
init_sqlite_reliability();
|
|
6893
6988
|
init_sqlite_fts();
|
|
6894
6989
|
SqliteBackend = class {
|
|
6895
6990
|
db = null;
|
|
@@ -7167,7 +7262,9 @@ var init_sqlite_store = __esm({
|
|
|
7167
7262
|
// ── Compound atomic operation ────────────────────────────────────
|
|
7168
7263
|
async atomic(fn) {
|
|
7169
7264
|
const run = this._atomicQueue.catch(() => void 0).then(async () => {
|
|
7170
|
-
|
|
7265
|
+
await retrySqliteBusy(async () => {
|
|
7266
|
+
this.db.prepare("BEGIN IMMEDIATE").run();
|
|
7267
|
+
}, "Observation atomic write");
|
|
7171
7268
|
try {
|
|
7172
7269
|
const tx = {
|
|
7173
7270
|
loadAll: async () => this.rawLoadAll(),
|
|
@@ -7266,15 +7363,15 @@ function resetObservationStore() {
|
|
|
7266
7363
|
async function createObservationStore(dataDir) {
|
|
7267
7364
|
try {
|
|
7268
7365
|
const { SqliteBackend: SqliteBackend2 } = await Promise.resolve().then(() => (init_sqlite_store(), sqlite_store_exports));
|
|
7269
|
-
|
|
7270
|
-
await store2.init(dataDir);
|
|
7271
|
-
return store2;
|
|
7366
|
+
return await initializeSqliteStore(() => new SqliteBackend2(), dataDir, "Observation store");
|
|
7272
7367
|
} catch (err) {
|
|
7273
|
-
|
|
7368
|
+
if (!isSqliteUnavailableError(err)) throw err;
|
|
7369
|
+
const reason = formatSqliteFailure(err);
|
|
7370
|
+
console.error(`[memorix] SQLite module unavailable \u2014 degraded mode (reads/writes disabled): ${reason}`);
|
|
7371
|
+
const degraded = new DegradedBackend(reason);
|
|
7372
|
+
await degraded.init(dataDir);
|
|
7373
|
+
return degraded;
|
|
7274
7374
|
}
|
|
7275
|
-
const store = new DegradedBackend();
|
|
7276
|
-
await store.init(dataDir);
|
|
7277
|
-
return store;
|
|
7278
7375
|
}
|
|
7279
7376
|
async function initObservationStore(dataDir) {
|
|
7280
7377
|
if (_store2 && _storeDataDir2 === dataDir) {
|
|
@@ -7298,36 +7395,44 @@ var init_obs_store = __esm({
|
|
|
7298
7395
|
"src/store/obs-store.ts"() {
|
|
7299
7396
|
"use strict";
|
|
7300
7397
|
init_esm_shims();
|
|
7398
|
+
init_sqlite_reliability();
|
|
7301
7399
|
_store2 = null;
|
|
7302
7400
|
_storeDataDir2 = null;
|
|
7303
7401
|
DegradedBackend = class {
|
|
7402
|
+
constructor(reason = "SQLite runtime unavailable") {
|
|
7403
|
+
this.reason = reason;
|
|
7404
|
+
}
|
|
7405
|
+
reason;
|
|
7304
7406
|
dataDir = "";
|
|
7407
|
+
unavailableRead() {
|
|
7408
|
+
return degradedReadError("observations");
|
|
7409
|
+
}
|
|
7305
7410
|
async init(dataDir) {
|
|
7306
7411
|
this.dataDir = dataDir;
|
|
7307
7412
|
}
|
|
7308
7413
|
async loadAll() {
|
|
7309
|
-
|
|
7414
|
+
throw this.unavailableRead();
|
|
7310
7415
|
}
|
|
7311
7416
|
async loadByProject(_projectId, _options) {
|
|
7312
|
-
|
|
7417
|
+
throw this.unavailableRead();
|
|
7313
7418
|
}
|
|
7314
7419
|
async countByProject(_projectId, _options) {
|
|
7315
|
-
|
|
7420
|
+
throw this.unavailableRead();
|
|
7316
7421
|
}
|
|
7317
7422
|
async getById(_id) {
|
|
7318
|
-
|
|
7423
|
+
throw this.unavailableRead();
|
|
7319
7424
|
}
|
|
7320
7425
|
async loadIdCounter() {
|
|
7321
|
-
|
|
7426
|
+
throw this.unavailableRead();
|
|
7322
7427
|
}
|
|
7323
7428
|
async countAll() {
|
|
7324
|
-
|
|
7429
|
+
throw this.unavailableRead();
|
|
7325
7430
|
}
|
|
7326
7431
|
async listProjectIds() {
|
|
7327
|
-
|
|
7432
|
+
throw this.unavailableRead();
|
|
7328
7433
|
}
|
|
7329
7434
|
async searchLexical(_options) {
|
|
7330
|
-
|
|
7435
|
+
throw this.unavailableRead();
|
|
7331
7436
|
}
|
|
7332
7437
|
hasLexicalIndex() {
|
|
7333
7438
|
return false;
|
|
@@ -7336,25 +7441,25 @@ var init_obs_store = __esm({
|
|
|
7336
7441
|
return false;
|
|
7337
7442
|
}
|
|
7338
7443
|
async insert(_obs) {
|
|
7339
|
-
throw
|
|
7444
|
+
throw degradedWriteError("observations");
|
|
7340
7445
|
}
|
|
7341
7446
|
async update(_obs) {
|
|
7342
|
-
throw
|
|
7447
|
+
throw degradedWriteError("observations");
|
|
7343
7448
|
}
|
|
7344
7449
|
async remove(_id) {
|
|
7345
|
-
throw
|
|
7450
|
+
throw degradedWriteError("observations");
|
|
7346
7451
|
}
|
|
7347
7452
|
async bulkReplace(_obs) {
|
|
7348
|
-
throw
|
|
7453
|
+
throw degradedWriteError("observations");
|
|
7349
7454
|
}
|
|
7350
7455
|
async bulkRemoveByIds(_ids) {
|
|
7351
|
-
throw
|
|
7456
|
+
throw degradedWriteError("observations");
|
|
7352
7457
|
}
|
|
7353
7458
|
async saveIdCounter(_nextId) {
|
|
7354
|
-
throw
|
|
7459
|
+
throw degradedWriteError("observations");
|
|
7355
7460
|
}
|
|
7356
7461
|
async atomic(_fn) {
|
|
7357
|
-
throw
|
|
7462
|
+
throw degradedWriteError("observations");
|
|
7358
7463
|
}
|
|
7359
7464
|
async ensureFresh() {
|
|
7360
7465
|
return false;
|
|
@@ -7367,6 +7472,9 @@ var init_obs_store = __esm({
|
|
|
7367
7472
|
getBackendName() {
|
|
7368
7473
|
return "degraded";
|
|
7369
7474
|
}
|
|
7475
|
+
getBackendReason() {
|
|
7476
|
+
return this.reason;
|
|
7477
|
+
}
|
|
7370
7478
|
};
|
|
7371
7479
|
}
|
|
7372
7480
|
});
|
|
@@ -56963,10 +57071,10 @@ var require_retry3 = __commonJS({
|
|
|
56963
57071
|
if (!await shouldRetryFn(err)) {
|
|
56964
57072
|
return { shouldRetry: false, config: err.config };
|
|
56965
57073
|
}
|
|
56966
|
-
const
|
|
57074
|
+
const delay3 = getNextRetryDelay(config);
|
|
56967
57075
|
err.config.retryConfig.currentRetryAttempt += 1;
|
|
56968
|
-
const backoff = config.retryBackoff ? config.retryBackoff(err,
|
|
56969
|
-
setTimeout(resolve5,
|
|
57076
|
+
const backoff = config.retryBackoff ? config.retryBackoff(err, delay3) : new Promise((resolve5) => {
|
|
57077
|
+
setTimeout(resolve5, delay3);
|
|
56970
57078
|
});
|
|
56971
57079
|
if (config.onRetryAttempt) {
|
|
56972
57080
|
await config.onRetryAttempt(err);
|
|
@@ -98752,7 +98860,7 @@ async function retryBackoff(fn, strategy) {
|
|
|
98752
98860
|
retryInterval = initialInterval * Math.pow(x2, exponent) + Math.random() * 1e3;
|
|
98753
98861
|
}
|
|
98754
98862
|
const d = Math.min(retryInterval, maxInterval);
|
|
98755
|
-
await
|
|
98863
|
+
await delay2(d);
|
|
98756
98864
|
x2++;
|
|
98757
98865
|
}
|
|
98758
98866
|
}
|
|
@@ -98773,8 +98881,8 @@ function retryIntervalFromResponse(res) {
|
|
|
98773
98881
|
}
|
|
98774
98882
|
return 0;
|
|
98775
98883
|
}
|
|
98776
|
-
async function
|
|
98777
|
-
return new Promise((resolve5) => setTimeout(resolve5,
|
|
98884
|
+
async function delay2(delay3) {
|
|
98885
|
+
return new Promise((resolve5) => setTimeout(resolve5, delay3));
|
|
98778
98886
|
}
|
|
98779
98887
|
var defaultBackoff, PermanentError, TemporaryError, codeRangeRE2;
|
|
98780
98888
|
var init_retries = __esm({
|
|
@@ -154230,16 +154338,18 @@ async function initSessionStore(dataDir) {
|
|
|
154230
154338
|
if (_store3 && _storeDataDir3 === dataDir) return _store3;
|
|
154231
154339
|
_store3 = null;
|
|
154232
154340
|
_storeDataDir3 = null;
|
|
154341
|
+
let degradedReason = "SQLite runtime unavailable";
|
|
154233
154342
|
try {
|
|
154234
|
-
const store2 = new SessionSqliteStore();
|
|
154235
|
-
await store2.init(dataDir);
|
|
154343
|
+
const store2 = await initializeSqliteStore(() => new SessionSqliteStore(), dataDir, "Session store");
|
|
154236
154344
|
_store3 = store2;
|
|
154237
154345
|
_storeDataDir3 = dataDir;
|
|
154238
154346
|
return store2;
|
|
154239
154347
|
} catch (err) {
|
|
154240
|
-
|
|
154348
|
+
if (!isSqliteUnavailableError(err)) throw err;
|
|
154349
|
+
degradedReason = formatSqliteFailure(err);
|
|
154350
|
+
console.error(`[memorix] SessionSqliteStore unavailable, running in degraded read-only mode: ${degradedReason}`);
|
|
154241
154351
|
}
|
|
154242
|
-
const store = new SessionGracefulDegrade();
|
|
154352
|
+
const store = new SessionGracefulDegrade(degradedReason);
|
|
154243
154353
|
await store.init(dataDir);
|
|
154244
154354
|
_store3 = store;
|
|
154245
154355
|
_storeDataDir3 = dataDir;
|
|
@@ -154251,6 +154361,7 @@ var init_session_store = __esm({
|
|
|
154251
154361
|
"use strict";
|
|
154252
154362
|
init_esm_shims();
|
|
154253
154363
|
init_sqlite_db();
|
|
154364
|
+
init_sqlite_reliability();
|
|
154254
154365
|
SessionSqliteStore = class {
|
|
154255
154366
|
db = null;
|
|
154256
154367
|
dataDir = "";
|
|
@@ -154339,7 +154450,7 @@ var init_session_store = __esm({
|
|
|
154339
154450
|
}
|
|
154340
154451
|
const stmtComplete = this._stmtCompleteActive;
|
|
154341
154452
|
const stmtIns = this.stmtInsert;
|
|
154342
|
-
|
|
154453
|
+
return retrySqliteBusy(async () => this.db.transaction(() => {
|
|
154343
154454
|
let completedCount = 0;
|
|
154344
154455
|
for (const pid of projectIds) {
|
|
154345
154456
|
const info = stmtComplete.run({ pid, now: now3 });
|
|
@@ -154347,18 +154458,24 @@ var init_session_store = __esm({
|
|
|
154347
154458
|
}
|
|
154348
154459
|
stmtIns.run(sessionToRow(newSession));
|
|
154349
154460
|
return completedCount;
|
|
154350
|
-
})();
|
|
154351
|
-
return result;
|
|
154461
|
+
})(), "Session rollover");
|
|
154352
154462
|
}
|
|
154353
154463
|
getBackendName() {
|
|
154354
154464
|
return "sqlite";
|
|
154355
154465
|
}
|
|
154356
154466
|
};
|
|
154357
154467
|
SessionGracefulDegrade = class {
|
|
154468
|
+
constructor(reason = "SQLite runtime unavailable") {
|
|
154469
|
+
this.reason = reason;
|
|
154470
|
+
}
|
|
154471
|
+
reason;
|
|
154358
154472
|
warned = false;
|
|
154473
|
+
unavailableRead() {
|
|
154474
|
+
return degradedReadError("sessions");
|
|
154475
|
+
}
|
|
154359
154476
|
warn() {
|
|
154360
154477
|
if (!this.warned) {
|
|
154361
|
-
console.error("[memorix] SessionStore: SQLite unavailable \u2014 sessions
|
|
154478
|
+
console.error("[memorix] SessionStore: SQLite unavailable \u2014 sessions cannot be read or written. Install a supported SQLite runtime.");
|
|
154362
154479
|
this.warned = true;
|
|
154363
154480
|
}
|
|
154364
154481
|
}
|
|
@@ -154366,33 +154483,39 @@ var init_session_store = __esm({
|
|
|
154366
154483
|
this.warn();
|
|
154367
154484
|
}
|
|
154368
154485
|
async loadAll() {
|
|
154369
|
-
|
|
154486
|
+
throw this.unavailableRead();
|
|
154370
154487
|
}
|
|
154371
154488
|
async getById(_id) {
|
|
154372
|
-
|
|
154489
|
+
throw this.unavailableRead();
|
|
154373
154490
|
}
|
|
154374
154491
|
async loadByProject(_projectId) {
|
|
154375
|
-
|
|
154492
|
+
throw this.unavailableRead();
|
|
154376
154493
|
}
|
|
154377
154494
|
async loadActive(_projectId) {
|
|
154378
|
-
|
|
154495
|
+
throw this.unavailableRead();
|
|
154379
154496
|
}
|
|
154380
154497
|
async insert(_session) {
|
|
154381
154498
|
this.warn();
|
|
154499
|
+
throw degradedWriteError("sessions");
|
|
154382
154500
|
}
|
|
154383
154501
|
async update(_session) {
|
|
154384
154502
|
this.warn();
|
|
154503
|
+
throw degradedWriteError("sessions");
|
|
154385
154504
|
}
|
|
154386
154505
|
async bulkUpdate(_sessions) {
|
|
154387
154506
|
this.warn();
|
|
154507
|
+
throw degradedWriteError("sessions");
|
|
154388
154508
|
}
|
|
154389
154509
|
async atomicRolloverInsert(_newSession, _projectIds, _now) {
|
|
154390
154510
|
this.warn();
|
|
154391
|
-
|
|
154511
|
+
throw degradedWriteError("sessions");
|
|
154392
154512
|
}
|
|
154393
154513
|
getBackendName() {
|
|
154394
154514
|
return "degraded";
|
|
154395
154515
|
}
|
|
154516
|
+
getBackendReason() {
|
|
154517
|
+
return this.reason;
|
|
154518
|
+
}
|
|
154396
154519
|
};
|
|
154397
154520
|
_store3 = null;
|
|
154398
154521
|
_storeDataDir3 = null;
|
|
@@ -159648,7 +159771,7 @@ var init_request_context = __esm({
|
|
|
159648
159771
|
function getMcpServerInfo() {
|
|
159649
159772
|
return {
|
|
159650
159773
|
name: "memorix",
|
|
159651
|
-
version: true ? "1.9.
|
|
159774
|
+
version: true ? "1.9.3" : "1.0.1"
|
|
159652
159775
|
};
|
|
159653
159776
|
}
|
|
159654
159777
|
function createMcpDiscoverResult(capabilities, serverInfo) {
|
|
@@ -175357,7 +175480,7 @@ var init_serve_shared = __esm({
|
|
|
175357
175480
|
|
|
175358
175481
|
// src/cli/version.ts
|
|
175359
175482
|
function getCliVersion() {
|
|
175360
|
-
return true ? "1.9.
|
|
175483
|
+
return true ? "1.9.3" : pkg.version;
|
|
175361
175484
|
}
|
|
175362
175485
|
var init_version3 = __esm({
|
|
175363
175486
|
"src/cli/version.ts"() {
|