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/sdk.js
CHANGED
|
@@ -468,70 +468,79 @@ function getDatabase(dataDir) {
|
|
|
468
468
|
loadBetterSqlite3();
|
|
469
469
|
fs.mkdirSync(dataDir, { recursive: true });
|
|
470
470
|
const dbPath = path3.join(dataDir, "memorix.db");
|
|
471
|
-
|
|
472
|
-
db2.pragma("journal_mode = WAL");
|
|
473
|
-
db2.pragma("busy_timeout = 5000");
|
|
474
|
-
db2.pragma("foreign_keys = ON");
|
|
475
|
-
db2.exec(CREATE_OBSERVATIONS_TABLE);
|
|
476
|
-
db2.exec(CREATE_MINI_SKILLS_TABLE);
|
|
477
|
-
db2.exec(CREATE_SESSIONS_TABLE);
|
|
478
|
-
db2.exec(CREATE_META_TABLE);
|
|
479
|
-
db2.exec(CREATE_TEAM_AGENTS_TABLE);
|
|
480
|
-
db2.exec(CREATE_TEAM_TASKS_TABLE);
|
|
481
|
-
db2.exec(CREATE_TEAM_TASK_DEPS_TABLE);
|
|
482
|
-
db2.exec(CREATE_TEAM_MESSAGES_TABLE);
|
|
483
|
-
db2.exec(CREATE_TEAM_LOCKS_TABLE);
|
|
484
|
-
db2.exec(CREATE_TEAM_ROLES_TABLE);
|
|
485
|
-
db2.exec(CREATE_GRAPH_ENTITIES_TABLE);
|
|
486
|
-
db2.exec(CREATE_GRAPH_RELATIONS_TABLE);
|
|
487
|
-
db2.exec(CREATE_CHAT_TRANSCRIPT_TABLE);
|
|
488
|
-
db2.exec(CREATE_CODE_FILES_TABLE);
|
|
489
|
-
db2.exec(CREATE_CODE_SYMBOLS_TABLE);
|
|
490
|
-
db2.exec(CREATE_CODE_EDGES_TABLE);
|
|
491
|
-
db2.exec(CREATE_OBSERVATION_CODE_REFS_TABLE);
|
|
492
|
-
db2.exec(CREATE_MAINTENANCE_JOBS_TABLE);
|
|
493
|
-
db2.exec(CREATE_MAINTENANCE_TARGETS_TABLE);
|
|
494
|
-
db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
|
|
471
|
+
let db2;
|
|
495
472
|
try {
|
|
496
|
-
db2
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
db2.exec(
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
db2.exec(
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
db2.exec(
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
db2.exec(
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
db2.exec(
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
473
|
+
db2 = createDatabase(dbPath);
|
|
474
|
+
db2.pragma("busy_timeout = 5000");
|
|
475
|
+
db2.pragma("journal_mode = WAL");
|
|
476
|
+
db2.pragma("foreign_keys = ON");
|
|
477
|
+
db2.exec(CREATE_OBSERVATIONS_TABLE);
|
|
478
|
+
db2.exec(CREATE_MINI_SKILLS_TABLE);
|
|
479
|
+
db2.exec(CREATE_SESSIONS_TABLE);
|
|
480
|
+
db2.exec(CREATE_META_TABLE);
|
|
481
|
+
db2.exec(CREATE_TEAM_AGENTS_TABLE);
|
|
482
|
+
db2.exec(CREATE_TEAM_TASKS_TABLE);
|
|
483
|
+
db2.exec(CREATE_TEAM_TASK_DEPS_TABLE);
|
|
484
|
+
db2.exec(CREATE_TEAM_MESSAGES_TABLE);
|
|
485
|
+
db2.exec(CREATE_TEAM_LOCKS_TABLE);
|
|
486
|
+
db2.exec(CREATE_TEAM_ROLES_TABLE);
|
|
487
|
+
db2.exec(CREATE_GRAPH_ENTITIES_TABLE);
|
|
488
|
+
db2.exec(CREATE_GRAPH_RELATIONS_TABLE);
|
|
489
|
+
db2.exec(CREATE_CHAT_TRANSCRIPT_TABLE);
|
|
490
|
+
db2.exec(CREATE_CODE_FILES_TABLE);
|
|
491
|
+
db2.exec(CREATE_CODE_SYMBOLS_TABLE);
|
|
492
|
+
db2.exec(CREATE_CODE_EDGES_TABLE);
|
|
493
|
+
db2.exec(CREATE_OBSERVATION_CODE_REFS_TABLE);
|
|
494
|
+
db2.exec(CREATE_MAINTENANCE_JOBS_TABLE);
|
|
495
|
+
db2.exec(CREATE_MAINTENANCE_TARGETS_TABLE);
|
|
496
|
+
db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
|
|
497
|
+
try {
|
|
498
|
+
db2.exec(`ALTER TABLE mini_skills ADD COLUMN sourceSnapshot TEXT NOT NULL DEFAULT ''`);
|
|
499
|
+
} catch {
|
|
500
|
+
}
|
|
501
|
+
try {
|
|
502
|
+
db2.exec(`ALTER TABLE mini_skills ADD COLUMN updatedAt TEXT`);
|
|
503
|
+
} catch {
|
|
504
|
+
}
|
|
505
|
+
try {
|
|
506
|
+
db2.exec(`ALTER TABLE observations ADD COLUMN createdByAgentId TEXT`);
|
|
507
|
+
} catch {
|
|
508
|
+
}
|
|
509
|
+
try {
|
|
510
|
+
db2.exec(`ALTER TABLE observations ADD COLUMN writeGeneration INTEGER DEFAULT 0`);
|
|
511
|
+
} catch {
|
|
512
|
+
}
|
|
513
|
+
try {
|
|
514
|
+
db2.exec(`ALTER TABLE team_tasks ADD COLUMN required_role TEXT`);
|
|
515
|
+
} catch {
|
|
516
|
+
}
|
|
517
|
+
try {
|
|
518
|
+
db2.exec(`ALTER TABLE team_tasks ADD COLUMN preferred_role TEXT`);
|
|
519
|
+
} catch {
|
|
520
|
+
}
|
|
521
|
+
try {
|
|
522
|
+
db2.exec(`ALTER TABLE team_messages ADD COLUMN to_role TEXT`);
|
|
523
|
+
} catch {
|
|
524
|
+
}
|
|
525
|
+
try {
|
|
526
|
+
db2.exec(`ALTER TABLE team_messages ADD COLUMN handoff_status TEXT`);
|
|
527
|
+
} catch {
|
|
528
|
+
}
|
|
529
|
+
applySchemaMigrations(db2);
|
|
530
|
+
db2.exec(CREATE_INDEXES);
|
|
531
|
+
initializeObservationLexicalIndex(db2);
|
|
532
|
+
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('storage_generation', '0')`).run();
|
|
533
|
+
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('next_id', '1')`).run();
|
|
534
|
+
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('mini_skills_generation', '0')`).run();
|
|
535
|
+
_dbCache.set(normalized, db2);
|
|
536
|
+
return db2;
|
|
537
|
+
} catch (error) {
|
|
538
|
+
try {
|
|
539
|
+
db2?.close();
|
|
540
|
+
} catch {
|
|
541
|
+
}
|
|
542
|
+
throw error;
|
|
526
543
|
}
|
|
527
|
-
applySchemaMigrations(db2);
|
|
528
|
-
db2.exec(CREATE_INDEXES);
|
|
529
|
-
initializeObservationLexicalIndex(db2);
|
|
530
|
-
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('storage_generation', '0')`).run();
|
|
531
|
-
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('next_id', '1')`).run();
|
|
532
|
-
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('mini_skills_generation', '0')`).run();
|
|
533
|
-
_dbCache.set(normalized, db2);
|
|
534
|
-
return db2;
|
|
535
544
|
}
|
|
536
545
|
function closeDatabase(dataDir) {
|
|
537
546
|
const normalized = path3.resolve(dataDir);
|
|
@@ -2369,6 +2378,74 @@ var init_types = __esm({
|
|
|
2369
2378
|
}
|
|
2370
2379
|
});
|
|
2371
2380
|
|
|
2381
|
+
// src/store/sqlite-reliability.ts
|
|
2382
|
+
function isTransientSqliteError(error) {
|
|
2383
|
+
const code = error?.code;
|
|
2384
|
+
if (typeof code === "string") {
|
|
2385
|
+
return /^SQLITE_BUSY(?:_|$)/i.test(code);
|
|
2386
|
+
}
|
|
2387
|
+
return error instanceof Error && /\bdatabase is locked\b|\bdatabase is busy\b/i.test(error.message);
|
|
2388
|
+
}
|
|
2389
|
+
function isSqliteUnavailableError(error) {
|
|
2390
|
+
return error instanceof SqliteUnavailableError || error instanceof Error && /SQLite is not available|better-sqlite3.*failed|node:sqlite.*failed|bun:sqlite.*failed/i.test(error.message);
|
|
2391
|
+
}
|
|
2392
|
+
function degradedReadError(storeName) {
|
|
2393
|
+
return new Error(`[memorix] Cannot read ${storeName}: SQLite backend unavailable (memory is not loaded)`);
|
|
2394
|
+
}
|
|
2395
|
+
function degradedWriteError(storeName) {
|
|
2396
|
+
return new Error(`[memorix] Cannot write ${storeName}: SQLite backend unavailable (degraded mode; read-only)`);
|
|
2397
|
+
}
|
|
2398
|
+
function formatSqliteFailure(error) {
|
|
2399
|
+
return error instanceof Error && error.message ? error.message : String(error);
|
|
2400
|
+
}
|
|
2401
|
+
function delay(ms) {
|
|
2402
|
+
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
2403
|
+
}
|
|
2404
|
+
async function retrySqliteBusy(operation, label) {
|
|
2405
|
+
for (let attempt = 0; ; attempt++) {
|
|
2406
|
+
try {
|
|
2407
|
+
return await operation();
|
|
2408
|
+
} catch (error) {
|
|
2409
|
+
if (!isTransientSqliteError(error) || attempt >= SQLITE_BUSY_RETRY_DELAYS_MS.length) throw error;
|
|
2410
|
+
const waitMs = SQLITE_BUSY_RETRY_DELAYS_MS[attempt];
|
|
2411
|
+
console.error(
|
|
2412
|
+
`[memorix] ${label} SQLite busy (attempt ${attempt + 1}/${SQLITE_BUSY_RETRY_DELAYS_MS.length + 1}), retrying in ${waitMs}ms`
|
|
2413
|
+
);
|
|
2414
|
+
await delay(waitMs);
|
|
2415
|
+
}
|
|
2416
|
+
}
|
|
2417
|
+
}
|
|
2418
|
+
async function initializeSqliteStore(factory, dataDir, label) {
|
|
2419
|
+
try {
|
|
2420
|
+
loadBetterSqlite3();
|
|
2421
|
+
} catch (error) {
|
|
2422
|
+
throw new SqliteUnavailableError(error);
|
|
2423
|
+
}
|
|
2424
|
+
return retrySqliteBusy(async () => {
|
|
2425
|
+
const store = factory();
|
|
2426
|
+
await store.init(dataDir);
|
|
2427
|
+
return store;
|
|
2428
|
+
}, label);
|
|
2429
|
+
}
|
|
2430
|
+
var SQLITE_BUSY_RETRY_DELAYS_MS, SqliteUnavailableError;
|
|
2431
|
+
var init_sqlite_reliability = __esm({
|
|
2432
|
+
"src/store/sqlite-reliability.ts"() {
|
|
2433
|
+
"use strict";
|
|
2434
|
+
init_esm_shims();
|
|
2435
|
+
init_sqlite_db();
|
|
2436
|
+
SQLITE_BUSY_RETRY_DELAYS_MS = [50, 150, 400, 1e3, 2500];
|
|
2437
|
+
SqliteUnavailableError = class extends Error {
|
|
2438
|
+
code = "MEMORIX_SQLITE_UNAVAILABLE";
|
|
2439
|
+
constructor(cause) {
|
|
2440
|
+
super(
|
|
2441
|
+
cause instanceof Error && cause.message ? cause.message : "[memorix] SQLite is unavailable (install a supported SQLite runtime)"
|
|
2442
|
+
);
|
|
2443
|
+
this.name = "SqliteUnavailableError";
|
|
2444
|
+
}
|
|
2445
|
+
};
|
|
2446
|
+
}
|
|
2447
|
+
});
|
|
2448
|
+
|
|
2372
2449
|
// src/store/mini-skill-store.ts
|
|
2373
2450
|
var mini_skill_store_exports = {};
|
|
2374
2451
|
__export(mini_skill_store_exports, {
|
|
@@ -2440,16 +2517,18 @@ async function initMiniSkillStore(dataDir) {
|
|
|
2440
2517
|
if (_store && _storeDataDir === dataDir) return _store;
|
|
2441
2518
|
_store = null;
|
|
2442
2519
|
_storeDataDir = null;
|
|
2520
|
+
let degradedReason = "SQLite runtime unavailable";
|
|
2443
2521
|
try {
|
|
2444
|
-
const store2 = new MiniSkillSqliteStore();
|
|
2445
|
-
await store2.init(dataDir);
|
|
2522
|
+
const store2 = await initializeSqliteStore(() => new MiniSkillSqliteStore(), dataDir, "Mini-skill store");
|
|
2446
2523
|
_store = store2;
|
|
2447
2524
|
_storeDataDir = dataDir;
|
|
2448
2525
|
return store2;
|
|
2449
2526
|
} catch (err) {
|
|
2450
|
-
|
|
2527
|
+
if (!isSqliteUnavailableError(err)) throw err;
|
|
2528
|
+
degradedReason = err instanceof Error ? err.message : String(err);
|
|
2529
|
+
console.error(`[memorix] MiniSkillSqliteStore unavailable, running in degraded read-only mode: ${degradedReason}`);
|
|
2451
2530
|
}
|
|
2452
|
-
const store = new MiniSkillGracefulDegrade();
|
|
2531
|
+
const store = new MiniSkillGracefulDegrade(degradedReason);
|
|
2453
2532
|
await store.init(dataDir);
|
|
2454
2533
|
_store = store;
|
|
2455
2534
|
_storeDataDir = dataDir;
|
|
@@ -2461,6 +2540,7 @@ var init_mini_skill_store = __esm({
|
|
|
2461
2540
|
"use strict";
|
|
2462
2541
|
init_esm_shims();
|
|
2463
2542
|
init_sqlite_db();
|
|
2543
|
+
init_sqlite_reliability();
|
|
2464
2544
|
MiniSkillSqliteStore = class {
|
|
2465
2545
|
db = null;
|
|
2466
2546
|
dataDir = "";
|
|
@@ -2569,7 +2649,7 @@ var init_mini_skill_store = __esm({
|
|
|
2569
2649
|
* SQLite serializes write transactions, so concurrent calls are safely sequenced.
|
|
2570
2650
|
*/
|
|
2571
2651
|
async atomicInsertWithId(skillWithoutId) {
|
|
2572
|
-
|
|
2652
|
+
return retrySqliteBusy(async () => this.db.transaction(() => {
|
|
2573
2653
|
const row = this.stmtGetMeta.get("mini_skills_next_id");
|
|
2574
2654
|
const nextId2 = row ? parseInt(row.value, 10) : 1;
|
|
2575
2655
|
const skill2 = { ...skillWithoutId, id: nextId2 };
|
|
@@ -2578,8 +2658,7 @@ var init_mini_skill_store = __esm({
|
|
|
2578
2658
|
this.stmtBumpGeneration.run();
|
|
2579
2659
|
this.knownGeneration = this.readGeneration();
|
|
2580
2660
|
return skill2;
|
|
2581
|
-
})();
|
|
2582
|
-
return result;
|
|
2661
|
+
})(), "Mini-skill promotion");
|
|
2583
2662
|
}
|
|
2584
2663
|
// ── Freshness ────────────────────────────────────────────────────
|
|
2585
2664
|
async ensureFresh() {
|
|
@@ -2598,10 +2677,17 @@ var init_mini_skill_store = __esm({
|
|
|
2598
2677
|
}
|
|
2599
2678
|
};
|
|
2600
2679
|
MiniSkillGracefulDegrade = class {
|
|
2680
|
+
constructor(reason = "SQLite runtime unavailable") {
|
|
2681
|
+
this.reason = reason;
|
|
2682
|
+
}
|
|
2683
|
+
reason;
|
|
2601
2684
|
warned = false;
|
|
2685
|
+
unavailableRead() {
|
|
2686
|
+
return degradedReadError("mini-skills");
|
|
2687
|
+
}
|
|
2602
2688
|
warn() {
|
|
2603
2689
|
if (!this.warned) {
|
|
2604
|
-
console.error("[memorix] MiniSkillStore: SQLite unavailable \u2014 mini-skills
|
|
2690
|
+
console.error("[memorix] MiniSkillStore: SQLite unavailable \u2014 mini-skills cannot be read or written. Install a supported SQLite runtime.");
|
|
2605
2691
|
this.warned = true;
|
|
2606
2692
|
}
|
|
2607
2693
|
}
|
|
@@ -2609,28 +2695,33 @@ var init_mini_skill_store = __esm({
|
|
|
2609
2695
|
this.warn();
|
|
2610
2696
|
}
|
|
2611
2697
|
async loadAll() {
|
|
2612
|
-
|
|
2698
|
+
throw this.unavailableRead();
|
|
2613
2699
|
}
|
|
2614
2700
|
async loadByProject(_projectId) {
|
|
2615
|
-
|
|
2701
|
+
throw this.unavailableRead();
|
|
2616
2702
|
}
|
|
2617
2703
|
async loadIdCounter() {
|
|
2618
|
-
|
|
2704
|
+
throw this.unavailableRead();
|
|
2619
2705
|
}
|
|
2620
2706
|
async insert(_skill) {
|
|
2621
2707
|
this.warn();
|
|
2708
|
+
throw degradedWriteError("mini-skills");
|
|
2622
2709
|
}
|
|
2623
2710
|
async update(_skill) {
|
|
2624
2711
|
this.warn();
|
|
2712
|
+
throw degradedWriteError("mini-skills");
|
|
2625
2713
|
}
|
|
2626
2714
|
async remove(_id) {
|
|
2627
2715
|
this.warn();
|
|
2716
|
+
throw degradedWriteError("mini-skills");
|
|
2628
2717
|
}
|
|
2629
2718
|
async saveIdCounter(_nextId) {
|
|
2719
|
+
this.warn();
|
|
2720
|
+
throw degradedWriteError("mini-skills");
|
|
2630
2721
|
}
|
|
2631
2722
|
async atomicInsertWithId(skillWithoutId) {
|
|
2632
2723
|
this.warn();
|
|
2633
|
-
|
|
2724
|
+
throw degradedWriteError("mini-skills");
|
|
2634
2725
|
}
|
|
2635
2726
|
async ensureFresh() {
|
|
2636
2727
|
return false;
|
|
@@ -2641,6 +2732,9 @@ var init_mini_skill_store = __esm({
|
|
|
2641
2732
|
getBackendName() {
|
|
2642
2733
|
return "degraded";
|
|
2643
2734
|
}
|
|
2735
|
+
getBackendReason() {
|
|
2736
|
+
return this.reason;
|
|
2737
|
+
}
|
|
2644
2738
|
};
|
|
2645
2739
|
_store = null;
|
|
2646
2740
|
_storeDataDir = null;
|
|
@@ -4843,10 +4937,10 @@ async function fetchWithRetry(url, apiKey, body, options = {}, attempt = 0, nati
|
|
|
4843
4937
|
);
|
|
4844
4938
|
}
|
|
4845
4939
|
if (options.retry !== false && (response.status === 429 || response.status >= 500) && attempt < MAX_RETRIES2) {
|
|
4846
|
-
const
|
|
4940
|
+
const delay3 = BASE_DELAY_MS * Math.pow(2, attempt);
|
|
4847
4941
|
const retryAfter = response.headers.get("retry-after");
|
|
4848
4942
|
const parsedRetryAfter = retryAfter ? parseInt(retryAfter, 10) * 1e3 : NaN;
|
|
4849
|
-
const waitMs = Number.isFinite(parsedRetryAfter) ? parsedRetryAfter :
|
|
4943
|
+
const waitMs = Number.isFinite(parsedRetryAfter) ? parsedRetryAfter : delay3;
|
|
4850
4944
|
console.error(`[memorix] Embedding API ${response.status}, retry ${attempt + 1}/${MAX_RETRIES2} in ${waitMs}ms`);
|
|
4851
4945
|
await waitForRetry(waitMs, options.signal);
|
|
4852
4946
|
return fetchWithRetry(url, apiKey, body, options, attempt + 1, nativeGemini);
|
|
@@ -6878,6 +6972,7 @@ var init_sqlite_store = __esm({
|
|
|
6878
6972
|
"use strict";
|
|
6879
6973
|
init_esm_shims();
|
|
6880
6974
|
init_sqlite_db();
|
|
6975
|
+
init_sqlite_reliability();
|
|
6881
6976
|
init_sqlite_fts();
|
|
6882
6977
|
SqliteBackend = class {
|
|
6883
6978
|
db = null;
|
|
@@ -7155,7 +7250,9 @@ var init_sqlite_store = __esm({
|
|
|
7155
7250
|
// ── Compound atomic operation ────────────────────────────────────
|
|
7156
7251
|
async atomic(fn) {
|
|
7157
7252
|
const run = this._atomicQueue.catch(() => void 0).then(async () => {
|
|
7158
|
-
|
|
7253
|
+
await retrySqliteBusy(async () => {
|
|
7254
|
+
this.db.prepare("BEGIN IMMEDIATE").run();
|
|
7255
|
+
}, "Observation atomic write");
|
|
7159
7256
|
try {
|
|
7160
7257
|
const tx = {
|
|
7161
7258
|
loadAll: async () => this.rawLoadAll(),
|
|
@@ -7254,15 +7351,15 @@ function resetObservationStore() {
|
|
|
7254
7351
|
async function createObservationStore(dataDir) {
|
|
7255
7352
|
try {
|
|
7256
7353
|
const { SqliteBackend: SqliteBackend2 } = await Promise.resolve().then(() => (init_sqlite_store(), sqlite_store_exports));
|
|
7257
|
-
|
|
7258
|
-
await store2.init(dataDir);
|
|
7259
|
-
return store2;
|
|
7354
|
+
return await initializeSqliteStore(() => new SqliteBackend2(), dataDir, "Observation store");
|
|
7260
7355
|
} catch (err) {
|
|
7261
|
-
|
|
7356
|
+
if (!isSqliteUnavailableError(err)) throw err;
|
|
7357
|
+
const reason = formatSqliteFailure(err);
|
|
7358
|
+
console.error(`[memorix] SQLite module unavailable \u2014 degraded mode (reads/writes disabled): ${reason}`);
|
|
7359
|
+
const degraded = new DegradedBackend(reason);
|
|
7360
|
+
await degraded.init(dataDir);
|
|
7361
|
+
return degraded;
|
|
7262
7362
|
}
|
|
7263
|
-
const store = new DegradedBackend();
|
|
7264
|
-
await store.init(dataDir);
|
|
7265
|
-
return store;
|
|
7266
7363
|
}
|
|
7267
7364
|
async function initObservationStore(dataDir) {
|
|
7268
7365
|
if (_store2 && _storeDataDir2 === dataDir) {
|
|
@@ -7286,36 +7383,44 @@ var init_obs_store = __esm({
|
|
|
7286
7383
|
"src/store/obs-store.ts"() {
|
|
7287
7384
|
"use strict";
|
|
7288
7385
|
init_esm_shims();
|
|
7386
|
+
init_sqlite_reliability();
|
|
7289
7387
|
_store2 = null;
|
|
7290
7388
|
_storeDataDir2 = null;
|
|
7291
7389
|
DegradedBackend = class {
|
|
7390
|
+
constructor(reason = "SQLite runtime unavailable") {
|
|
7391
|
+
this.reason = reason;
|
|
7392
|
+
}
|
|
7393
|
+
reason;
|
|
7292
7394
|
dataDir = "";
|
|
7395
|
+
unavailableRead() {
|
|
7396
|
+
return degradedReadError("observations");
|
|
7397
|
+
}
|
|
7293
7398
|
async init(dataDir) {
|
|
7294
7399
|
this.dataDir = dataDir;
|
|
7295
7400
|
}
|
|
7296
7401
|
async loadAll() {
|
|
7297
|
-
|
|
7402
|
+
throw this.unavailableRead();
|
|
7298
7403
|
}
|
|
7299
7404
|
async loadByProject(_projectId, _options) {
|
|
7300
|
-
|
|
7405
|
+
throw this.unavailableRead();
|
|
7301
7406
|
}
|
|
7302
7407
|
async countByProject(_projectId, _options) {
|
|
7303
|
-
|
|
7408
|
+
throw this.unavailableRead();
|
|
7304
7409
|
}
|
|
7305
7410
|
async getById(_id) {
|
|
7306
|
-
|
|
7411
|
+
throw this.unavailableRead();
|
|
7307
7412
|
}
|
|
7308
7413
|
async loadIdCounter() {
|
|
7309
|
-
|
|
7414
|
+
throw this.unavailableRead();
|
|
7310
7415
|
}
|
|
7311
7416
|
async countAll() {
|
|
7312
|
-
|
|
7417
|
+
throw this.unavailableRead();
|
|
7313
7418
|
}
|
|
7314
7419
|
async listProjectIds() {
|
|
7315
|
-
|
|
7420
|
+
throw this.unavailableRead();
|
|
7316
7421
|
}
|
|
7317
7422
|
async searchLexical(_options) {
|
|
7318
|
-
|
|
7423
|
+
throw this.unavailableRead();
|
|
7319
7424
|
}
|
|
7320
7425
|
hasLexicalIndex() {
|
|
7321
7426
|
return false;
|
|
@@ -7324,25 +7429,25 @@ var init_obs_store = __esm({
|
|
|
7324
7429
|
return false;
|
|
7325
7430
|
}
|
|
7326
7431
|
async insert(_obs) {
|
|
7327
|
-
throw
|
|
7432
|
+
throw degradedWriteError("observations");
|
|
7328
7433
|
}
|
|
7329
7434
|
async update(_obs) {
|
|
7330
|
-
throw
|
|
7435
|
+
throw degradedWriteError("observations");
|
|
7331
7436
|
}
|
|
7332
7437
|
async remove(_id) {
|
|
7333
|
-
throw
|
|
7438
|
+
throw degradedWriteError("observations");
|
|
7334
7439
|
}
|
|
7335
7440
|
async bulkReplace(_obs) {
|
|
7336
|
-
throw
|
|
7441
|
+
throw degradedWriteError("observations");
|
|
7337
7442
|
}
|
|
7338
7443
|
async bulkRemoveByIds(_ids) {
|
|
7339
|
-
throw
|
|
7444
|
+
throw degradedWriteError("observations");
|
|
7340
7445
|
}
|
|
7341
7446
|
async saveIdCounter(_nextId) {
|
|
7342
|
-
throw
|
|
7447
|
+
throw degradedWriteError("observations");
|
|
7343
7448
|
}
|
|
7344
7449
|
async atomic(_fn) {
|
|
7345
|
-
throw
|
|
7450
|
+
throw degradedWriteError("observations");
|
|
7346
7451
|
}
|
|
7347
7452
|
async ensureFresh() {
|
|
7348
7453
|
return false;
|
|
@@ -7355,6 +7460,9 @@ var init_obs_store = __esm({
|
|
|
7355
7460
|
getBackendName() {
|
|
7356
7461
|
return "degraded";
|
|
7357
7462
|
}
|
|
7463
|
+
getBackendReason() {
|
|
7464
|
+
return this.reason;
|
|
7465
|
+
}
|
|
7358
7466
|
};
|
|
7359
7467
|
}
|
|
7360
7468
|
});
|
|
@@ -57009,10 +57117,10 @@ var require_retry3 = __commonJS({
|
|
|
57009
57117
|
if (!await shouldRetryFn(err)) {
|
|
57010
57118
|
return { shouldRetry: false, config: err.config };
|
|
57011
57119
|
}
|
|
57012
|
-
const
|
|
57120
|
+
const delay3 = getNextRetryDelay(config);
|
|
57013
57121
|
err.config.retryConfig.currentRetryAttempt += 1;
|
|
57014
|
-
const backoff = config.retryBackoff ? config.retryBackoff(err,
|
|
57015
|
-
setTimeout(resolve5,
|
|
57122
|
+
const backoff = config.retryBackoff ? config.retryBackoff(err, delay3) : new Promise((resolve5) => {
|
|
57123
|
+
setTimeout(resolve5, delay3);
|
|
57016
57124
|
});
|
|
57017
57125
|
if (config.onRetryAttempt) {
|
|
57018
57126
|
await config.onRetryAttempt(err);
|
|
@@ -98798,7 +98906,7 @@ async function retryBackoff(fn, strategy) {
|
|
|
98798
98906
|
retryInterval = initialInterval * Math.pow(x2, exponent) + Math.random() * 1e3;
|
|
98799
98907
|
}
|
|
98800
98908
|
const d = Math.min(retryInterval, maxInterval);
|
|
98801
|
-
await
|
|
98909
|
+
await delay2(d);
|
|
98802
98910
|
x2++;
|
|
98803
98911
|
}
|
|
98804
98912
|
}
|
|
@@ -98819,8 +98927,8 @@ function retryIntervalFromResponse(res) {
|
|
|
98819
98927
|
}
|
|
98820
98928
|
return 0;
|
|
98821
98929
|
}
|
|
98822
|
-
async function
|
|
98823
|
-
return new Promise((resolve5) => setTimeout(resolve5,
|
|
98930
|
+
async function delay2(delay3) {
|
|
98931
|
+
return new Promise((resolve5) => setTimeout(resolve5, delay3));
|
|
98824
98932
|
}
|
|
98825
98933
|
var defaultBackoff, PermanentError, TemporaryError, codeRangeRE2;
|
|
98826
98934
|
var init_retries = __esm({
|
|
@@ -154276,16 +154384,18 @@ async function initSessionStore(dataDir) {
|
|
|
154276
154384
|
if (_store3 && _storeDataDir3 === dataDir) return _store3;
|
|
154277
154385
|
_store3 = null;
|
|
154278
154386
|
_storeDataDir3 = null;
|
|
154387
|
+
let degradedReason = "SQLite runtime unavailable";
|
|
154279
154388
|
try {
|
|
154280
|
-
const store2 = new SessionSqliteStore();
|
|
154281
|
-
await store2.init(dataDir);
|
|
154389
|
+
const store2 = await initializeSqliteStore(() => new SessionSqliteStore(), dataDir, "Session store");
|
|
154282
154390
|
_store3 = store2;
|
|
154283
154391
|
_storeDataDir3 = dataDir;
|
|
154284
154392
|
return store2;
|
|
154285
154393
|
} catch (err) {
|
|
154286
|
-
|
|
154394
|
+
if (!isSqliteUnavailableError(err)) throw err;
|
|
154395
|
+
degradedReason = formatSqliteFailure(err);
|
|
154396
|
+
console.error(`[memorix] SessionSqliteStore unavailable, running in degraded read-only mode: ${degradedReason}`);
|
|
154287
154397
|
}
|
|
154288
|
-
const store = new SessionGracefulDegrade();
|
|
154398
|
+
const store = new SessionGracefulDegrade(degradedReason);
|
|
154289
154399
|
await store.init(dataDir);
|
|
154290
154400
|
_store3 = store;
|
|
154291
154401
|
_storeDataDir3 = dataDir;
|
|
@@ -154297,6 +154407,7 @@ var init_session_store = __esm({
|
|
|
154297
154407
|
"use strict";
|
|
154298
154408
|
init_esm_shims();
|
|
154299
154409
|
init_sqlite_db();
|
|
154410
|
+
init_sqlite_reliability();
|
|
154300
154411
|
SessionSqliteStore = class {
|
|
154301
154412
|
db = null;
|
|
154302
154413
|
dataDir = "";
|
|
@@ -154385,7 +154496,7 @@ var init_session_store = __esm({
|
|
|
154385
154496
|
}
|
|
154386
154497
|
const stmtComplete = this._stmtCompleteActive;
|
|
154387
154498
|
const stmtIns = this.stmtInsert;
|
|
154388
|
-
|
|
154499
|
+
return retrySqliteBusy(async () => this.db.transaction(() => {
|
|
154389
154500
|
let completedCount = 0;
|
|
154390
154501
|
for (const pid of projectIds) {
|
|
154391
154502
|
const info = stmtComplete.run({ pid, now: now3 });
|
|
@@ -154393,18 +154504,24 @@ var init_session_store = __esm({
|
|
|
154393
154504
|
}
|
|
154394
154505
|
stmtIns.run(sessionToRow(newSession));
|
|
154395
154506
|
return completedCount;
|
|
154396
|
-
})();
|
|
154397
|
-
return result;
|
|
154507
|
+
})(), "Session rollover");
|
|
154398
154508
|
}
|
|
154399
154509
|
getBackendName() {
|
|
154400
154510
|
return "sqlite";
|
|
154401
154511
|
}
|
|
154402
154512
|
};
|
|
154403
154513
|
SessionGracefulDegrade = class {
|
|
154514
|
+
constructor(reason = "SQLite runtime unavailable") {
|
|
154515
|
+
this.reason = reason;
|
|
154516
|
+
}
|
|
154517
|
+
reason;
|
|
154404
154518
|
warned = false;
|
|
154519
|
+
unavailableRead() {
|
|
154520
|
+
return degradedReadError("sessions");
|
|
154521
|
+
}
|
|
154405
154522
|
warn() {
|
|
154406
154523
|
if (!this.warned) {
|
|
154407
|
-
console.error("[memorix] SessionStore: SQLite unavailable \u2014 sessions
|
|
154524
|
+
console.error("[memorix] SessionStore: SQLite unavailable \u2014 sessions cannot be read or written. Install a supported SQLite runtime.");
|
|
154408
154525
|
this.warned = true;
|
|
154409
154526
|
}
|
|
154410
154527
|
}
|
|
@@ -154412,33 +154529,39 @@ var init_session_store = __esm({
|
|
|
154412
154529
|
this.warn();
|
|
154413
154530
|
}
|
|
154414
154531
|
async loadAll() {
|
|
154415
|
-
|
|
154532
|
+
throw this.unavailableRead();
|
|
154416
154533
|
}
|
|
154417
154534
|
async getById(_id) {
|
|
154418
|
-
|
|
154535
|
+
throw this.unavailableRead();
|
|
154419
154536
|
}
|
|
154420
154537
|
async loadByProject(_projectId) {
|
|
154421
|
-
|
|
154538
|
+
throw this.unavailableRead();
|
|
154422
154539
|
}
|
|
154423
154540
|
async loadActive(_projectId) {
|
|
154424
|
-
|
|
154541
|
+
throw this.unavailableRead();
|
|
154425
154542
|
}
|
|
154426
154543
|
async insert(_session) {
|
|
154427
154544
|
this.warn();
|
|
154545
|
+
throw degradedWriteError("sessions");
|
|
154428
154546
|
}
|
|
154429
154547
|
async update(_session) {
|
|
154430
154548
|
this.warn();
|
|
154549
|
+
throw degradedWriteError("sessions");
|
|
154431
154550
|
}
|
|
154432
154551
|
async bulkUpdate(_sessions) {
|
|
154433
154552
|
this.warn();
|
|
154553
|
+
throw degradedWriteError("sessions");
|
|
154434
154554
|
}
|
|
154435
154555
|
async atomicRolloverInsert(_newSession, _projectIds, _now) {
|
|
154436
154556
|
this.warn();
|
|
154437
|
-
|
|
154557
|
+
throw degradedWriteError("sessions");
|
|
154438
154558
|
}
|
|
154439
154559
|
getBackendName() {
|
|
154440
154560
|
return "degraded";
|
|
154441
154561
|
}
|
|
154562
|
+
getBackendReason() {
|
|
154563
|
+
return this.reason;
|
|
154564
|
+
}
|
|
154442
154565
|
};
|
|
154443
154566
|
_store3 = null;
|
|
154444
154567
|
_storeDataDir3 = null;
|
|
@@ -169896,7 +170019,7 @@ var MCP_SERVER_INFO_META_KEY = "io.modelcontextprotocol/serverInfo";
|
|
|
169896
170019
|
function getMcpServerInfo() {
|
|
169897
170020
|
return {
|
|
169898
170021
|
name: "memorix",
|
|
169899
|
-
version: true ? "1.9.
|
|
170022
|
+
version: true ? "1.9.3" : "1.0.1"
|
|
169900
170023
|
};
|
|
169901
170024
|
}
|
|
169902
170025
|
function createMcpDiscoverResult(capabilities, serverInfo) {
|