memorix 1.9.5 → 1.9.7
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 +53 -0
- package/README.md +6 -1
- package/README.zh-CN.md +6 -1
- package/dist/cli/index.js +1743 -348
- package/dist/index.d.ts +12 -7
- package/dist/index.js +1048 -266
- package/dist/maintenance-runner.js +339 -187
- package/dist/media-audio-runner.js +339 -187
- package/dist/media-video-runner.js +339 -187
- package/dist/memcode-runtime/CHANGELOG.md +53 -0
- package/dist/sdk.js +967 -241
- package/dist/vector-backfill-runner.js +339 -187
- package/docs/API_REFERENCE.md +36 -0
- package/docs/CONFIGURATION.md +43 -0
- package/docs/DEVELOPMENT.md +1 -1
- package/docs/KNOWN_ISSUES_AND_ROADMAP.md +49 -14
- package/docs/PERFORMANCE.md +46 -2
- package/docs/README.md +2 -1
- package/docs/SETUP.md +1 -1
- package/package.json +2 -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/capability-map.ts +1 -0
- package/src/cli/command-guide.ts +13 -1
- package/src/cli/commands/context.ts +2 -0
- package/src/cli/commands/continuity.ts +155 -0
- package/src/cli/commands/init.ts +5 -2
- package/src/cli/commands/serve-http.ts +242 -42
- package/src/cli/index.ts +3 -1
- package/src/cli/tui/ConfigureView.tsx +2 -0
- package/src/codegraph/auto-context.ts +17 -0
- package/src/config/legacy-loader.ts +2 -2
- package/src/config/resolved-config.ts +8 -5
- package/src/config/yaml-loader.ts +20 -10
- package/src/embedding/api-provider.ts +4 -2
- package/src/embedding/fastembed-provider.ts +47 -14
- package/src/embedding/transformers-provider.ts +29 -7
- package/src/evaluation/memory-quality-gate.ts +90 -0
- package/src/hooks/official-skills.ts +2 -0
- package/src/knowledge/context-assembly.ts +1 -0
- package/src/knowledge/context-receipt.ts +15 -0
- package/src/knowledge/task-continuity.ts +413 -0
- package/src/knowledge/workset.ts +77 -0
- package/src/llm/provider.ts +2 -1
- package/src/orchestrate/coordinator.ts +60 -0
- package/src/orchestrate/effect-ledger.ts +160 -0
- package/src/orchestrate/pipeline-trace.ts +40 -6
- package/src/runtime/maintenance-jobs.ts +12 -6
- package/src/server/modern-mcp-bridge.ts +153 -27
- package/src/server/tool-profile.ts +3 -2
- package/src/server.ts +129 -5
- package/src/store/orama-store.ts +16 -1
- package/src/store/sqlite-db.ts +144 -4
- package/src/store/sqlite-fts.ts +38 -16
- package/src/team/team-store.ts +62 -27
|
@@ -222,6 +222,74 @@ var init_launch_root = __esm({
|
|
|
222
222
|
}
|
|
223
223
|
});
|
|
224
224
|
|
|
225
|
+
// src/store/sqlite-reliability.ts
|
|
226
|
+
function isTransientSqliteError(error) {
|
|
227
|
+
const code = error?.code;
|
|
228
|
+
if (typeof code === "string") {
|
|
229
|
+
return /^SQLITE_BUSY(?:_|$)/i.test(code);
|
|
230
|
+
}
|
|
231
|
+
return error instanceof Error && /\bdatabase is locked\b|\bdatabase is busy\b/i.test(error.message);
|
|
232
|
+
}
|
|
233
|
+
function isSqliteUnavailableError(error) {
|
|
234
|
+
return error instanceof SqliteUnavailableError || error instanceof Error && /SQLite is not available|better-sqlite3.*failed|node:sqlite.*failed|bun:sqlite.*failed/i.test(error.message);
|
|
235
|
+
}
|
|
236
|
+
function degradedReadError(storeName) {
|
|
237
|
+
return new Error(`[memorix] Cannot read ${storeName}: SQLite backend unavailable (memory is not loaded)`);
|
|
238
|
+
}
|
|
239
|
+
function degradedWriteError(storeName) {
|
|
240
|
+
return new Error(`[memorix] Cannot write ${storeName}: SQLite backend unavailable (degraded mode; read-only)`);
|
|
241
|
+
}
|
|
242
|
+
function formatSqliteFailure(error) {
|
|
243
|
+
return error instanceof Error && error.message ? error.message : String(error);
|
|
244
|
+
}
|
|
245
|
+
function delay(ms) {
|
|
246
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
247
|
+
}
|
|
248
|
+
async function retrySqliteBusy(operation, label) {
|
|
249
|
+
for (let attempt = 0; ; attempt++) {
|
|
250
|
+
try {
|
|
251
|
+
return await operation();
|
|
252
|
+
} catch (error) {
|
|
253
|
+
if (!isTransientSqliteError(error) || attempt >= SQLITE_BUSY_RETRY_DELAYS_MS.length) throw error;
|
|
254
|
+
const waitMs = SQLITE_BUSY_RETRY_DELAYS_MS[attempt];
|
|
255
|
+
console.error(
|
|
256
|
+
`[memorix] ${label} SQLite busy (attempt ${attempt + 1}/${SQLITE_BUSY_RETRY_DELAYS_MS.length + 1}), retrying in ${waitMs}ms`
|
|
257
|
+
);
|
|
258
|
+
await delay(waitMs);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
async function initializeSqliteStore(factory, dataDir, label) {
|
|
263
|
+
try {
|
|
264
|
+
loadBetterSqlite3();
|
|
265
|
+
} catch (error) {
|
|
266
|
+
throw new SqliteUnavailableError(error);
|
|
267
|
+
}
|
|
268
|
+
return retrySqliteBusy(async () => {
|
|
269
|
+
const store = factory();
|
|
270
|
+
await store.init(dataDir);
|
|
271
|
+
return store;
|
|
272
|
+
}, label);
|
|
273
|
+
}
|
|
274
|
+
var SQLITE_BUSY_RETRY_DELAYS_MS, SqliteUnavailableError;
|
|
275
|
+
var init_sqlite_reliability = __esm({
|
|
276
|
+
"src/store/sqlite-reliability.ts"() {
|
|
277
|
+
"use strict";
|
|
278
|
+
init_esm_shims();
|
|
279
|
+
init_sqlite_db();
|
|
280
|
+
SQLITE_BUSY_RETRY_DELAYS_MS = [50, 150, 400, 1e3, 2500];
|
|
281
|
+
SqliteUnavailableError = class extends Error {
|
|
282
|
+
code = "MEMORIX_SQLITE_UNAVAILABLE";
|
|
283
|
+
constructor(cause) {
|
|
284
|
+
super(
|
|
285
|
+
cause instanceof Error && cause.message ? cause.message : "[memorix] SQLite is unavailable (install a supported SQLite runtime)"
|
|
286
|
+
);
|
|
287
|
+
this.name = "SqliteUnavailableError";
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
|
|
225
293
|
// src/store/sqlite-fts.ts
|
|
226
294
|
function normalizeFtsToken(token) {
|
|
227
295
|
return token.replace(/"/g, '""');
|
|
@@ -235,22 +303,27 @@ function buildFtsQuery(query) {
|
|
|
235
303
|
function initializeObservationLexicalIndex(db2) {
|
|
236
304
|
const known = ftsAvailability.get(db2);
|
|
237
305
|
if (known !== void 0) return known;
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
db2.
|
|
306
|
+
let lastError;
|
|
307
|
+
for (let attempt = 1; attempt <= FTS_INIT_MAX_ATTEMPTS; attempt++) {
|
|
308
|
+
try {
|
|
309
|
+
db2.exec(CREATE_OBSERVATION_FTS);
|
|
310
|
+
const observationCount = Number(db2.prepare("SELECT COUNT(*) AS count FROM observations").get()?.count ?? 0);
|
|
311
|
+
const indexedCount = Number(db2.prepare(`SELECT COUNT(*) AS count FROM ${FTS_TABLE}`).get()?.count ?? 0);
|
|
312
|
+
if (observationCount !== indexedCount) {
|
|
313
|
+
db2.exec(`INSERT INTO ${FTS_TABLE}(${FTS_TABLE}) VALUES ('rebuild')`);
|
|
314
|
+
}
|
|
315
|
+
ftsAvailability.set(db2, true);
|
|
316
|
+
return true;
|
|
317
|
+
} catch (error) {
|
|
318
|
+
lastError = error;
|
|
319
|
+
if (!isTransientSqliteError(error) || attempt === FTS_INIT_MAX_ATTEMPTS) break;
|
|
244
320
|
}
|
|
245
|
-
ftsAvailability.set(db2, true);
|
|
246
|
-
return true;
|
|
247
|
-
} catch (error) {
|
|
248
|
-
ftsAvailability.set(db2, false);
|
|
249
|
-
console.warn(
|
|
250
|
-
`[memorix] SQLite FTS5 unavailable; using the existing search fallback: ${error instanceof Error ? error.message : String(error)}`
|
|
251
|
-
);
|
|
252
|
-
return false;
|
|
253
321
|
}
|
|
322
|
+
ftsAvailability.set(db2, false);
|
|
323
|
+
console.warn(
|
|
324
|
+
`[memorix] SQLite FTS5 unavailable; using the existing search fallback: ${lastError instanceof Error ? lastError.message : String(lastError)}`
|
|
325
|
+
);
|
|
326
|
+
return false;
|
|
254
327
|
}
|
|
255
328
|
function isObservationLexicalIndexEnabled(db2) {
|
|
256
329
|
return ftsAvailability.get(db2) === true;
|
|
@@ -304,11 +377,12 @@ function searchObservationLexically(db2, options) {
|
|
|
304
377
|
score: Math.max(0, Number(row.lexical_score ?? 0))
|
|
305
378
|
}));
|
|
306
379
|
}
|
|
307
|
-
var ftsAvailability, FTS_TABLE, CREATE_OBSERVATION_FTS;
|
|
380
|
+
var ftsAvailability, FTS_TABLE, CREATE_OBSERVATION_FTS, FTS_INIT_MAX_ATTEMPTS;
|
|
308
381
|
var init_sqlite_fts = __esm({
|
|
309
382
|
"src/store/sqlite-fts.ts"() {
|
|
310
383
|
"use strict";
|
|
311
384
|
init_esm_shims();
|
|
385
|
+
init_sqlite_reliability();
|
|
312
386
|
ftsAvailability = /* @__PURE__ */ new WeakMap();
|
|
313
387
|
FTS_TABLE = "observations_fts";
|
|
314
388
|
CREATE_OBSERVATION_FTS = `
|
|
@@ -342,6 +416,7 @@ CREATE TRIGGER IF NOT EXISTS observations_fts_au AFTER UPDATE ON observations BE
|
|
|
342
416
|
VALUES (new.id, new.entityName, new.title, new.narrative, new.facts, new.filesModified, new.concepts, new.attachments);
|
|
343
417
|
END;
|
|
344
418
|
`;
|
|
419
|
+
FTS_INIT_MAX_ATTEMPTS = 3;
|
|
345
420
|
}
|
|
346
421
|
});
|
|
347
422
|
|
|
@@ -380,11 +455,21 @@ function applySchemaMigrations(db2) {
|
|
|
380
455
|
apply();
|
|
381
456
|
}
|
|
382
457
|
}
|
|
458
|
+
function normalizeDataDir(dataDir) {
|
|
459
|
+
return path3.resolve(dataDir);
|
|
460
|
+
}
|
|
461
|
+
function touchDatabase(normalized, db2) {
|
|
462
|
+
_dbCache.delete(normalized);
|
|
463
|
+
_dbCache.set(normalized, db2);
|
|
464
|
+
}
|
|
383
465
|
function getDatabase(dataDir) {
|
|
384
|
-
const normalized =
|
|
466
|
+
const normalized = normalizeDataDir(dataDir);
|
|
385
467
|
assertNotHomeDataDir(normalized);
|
|
386
468
|
const existing = _dbCache.get(normalized);
|
|
387
|
-
if (existing)
|
|
469
|
+
if (existing) {
|
|
470
|
+
touchDatabase(normalized, existing);
|
|
471
|
+
return existing;
|
|
472
|
+
}
|
|
388
473
|
loadBetterSqlite3();
|
|
389
474
|
fs.mkdirSync(dataDir, { recursive: true });
|
|
390
475
|
const dbPath = path3.join(dataDir, "memorix.db");
|
|
@@ -414,6 +499,8 @@ function getDatabase(dataDir) {
|
|
|
414
499
|
db2.exec(CREATE_MAINTENANCE_JOBS_TABLE);
|
|
415
500
|
db2.exec(CREATE_MAINTENANCE_TARGETS_TABLE);
|
|
416
501
|
db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
|
|
502
|
+
db2.exec(CREATE_TASK_CONTINUITY_EVENTS_TABLE);
|
|
503
|
+
db2.exec(CREATE_AGENT_EFFECTS_TABLE);
|
|
417
504
|
try {
|
|
418
505
|
db2.exec(`ALTER TABLE mini_skills ADD COLUMN sourceSnapshot TEXT NOT NULL DEFAULT ''`);
|
|
419
506
|
} catch {
|
|
@@ -452,7 +539,7 @@ function getDatabase(dataDir) {
|
|
|
452
539
|
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('storage_generation', '0')`).run();
|
|
453
540
|
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('next_id', '1')`).run();
|
|
454
541
|
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('mini_skills_generation', '0')`).run();
|
|
455
|
-
|
|
542
|
+
touchDatabase(normalized, db2);
|
|
456
543
|
return db2;
|
|
457
544
|
} catch (error) {
|
|
458
545
|
try {
|
|
@@ -470,8 +557,9 @@ function closeAllDatabases() {
|
|
|
470
557
|
}
|
|
471
558
|
_dbCache.delete(key);
|
|
472
559
|
}
|
|
560
|
+
_dbLeases.clear();
|
|
473
561
|
}
|
|
474
|
-
var BetterSqlite3, CREATE_OBSERVATIONS_TABLE, CREATE_MINI_SKILLS_TABLE, CREATE_SESSIONS_TABLE, CREATE_META_TABLE, CREATE_TEAM_AGENTS_TABLE, CREATE_TEAM_MESSAGES_TABLE, CREATE_TEAM_TASKS_TABLE, CREATE_TEAM_TASK_DEPS_TABLE, CREATE_TEAM_LOCKS_TABLE, CREATE_TEAM_ROLES_TABLE, CREATE_CHAT_TRANSCRIPT_TABLE, CREATE_GRAPH_ENTITIES_TABLE, CREATE_GRAPH_RELATIONS_TABLE, CREATE_CODE_FILES_TABLE, CREATE_CODE_SYMBOLS_TABLE, CREATE_CODE_EDGES_TABLE, CREATE_OBSERVATION_CODE_REFS_TABLE, CREATE_SCHEMA_MIGRATIONS_TABLE, CREATE_CODE_STATE_SNAPSHOTS_TABLE, CREATE_CODE_STATE_SNAPSHOT_FILES_TABLE, CREATE_KNOWLEDGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_CLAIM_EVIDENCE_TABLE, CREATE_KNOWLEDGE_CLAIM_EVENTS_TABLE, CREATE_KNOWLEDGE_WORKSPACES_TABLE, CREATE_KNOWLEDGE_PAGES_TABLE, CREATE_KNOWLEDGE_PAGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_PAGE_LINKS_TABLE, CREATE_KNOWLEDGE_PROPOSALS_TABLE, CREATE_KNOWLEDGE_WORKFLOWS_TABLE, CREATE_KNOWLEDGE_WORKFLOW_RUNS_TABLE, CREATE_LONG_TERM_MEMORIES_TABLE, CREATE_LONG_TERM_MEMORY_EVIDENCE_TABLE, CREATE_LONG_TERM_MEMORY_EVENTS_TABLE, CREATE_MEMORY_OUTCOME_SIGNALS_TABLE, CREATE_MEDIA_ASSETS_TABLE, CREATE_MEDIA_ASSET_LINKS_TABLE, CREATE_MEDIA_DERIVATIONS_TABLE, CREATE_MEDIA_EMBEDDING_PROFILES_TABLE, CREATE_MEDIA_EMBEDDINGS_TABLE, CREATE_MEDIA_JOBS_TABLE, CREATE_MAINTENANCE_JOBS_TABLE, CREATE_MAINTENANCE_TARGETS_TABLE, CREATE_COMPACTION_CHECKPOINTS_TABLE, CREATE_EVIDENCE_CARDS_TABLE, CREATE_EVIDENCE_CARD_EVENTS_TABLE, CREATE_MEMORY_FEEDBACK_STATES_TABLE, CREATE_MEMORY_FEEDBACK_EVENTS_TABLE, CREATE_MCP_BINDINGS_TABLE, CREATE_INDEXES, SCHEMA_MIGRATIONS, _dbCache;
|
|
562
|
+
var BetterSqlite3, CREATE_OBSERVATIONS_TABLE, CREATE_MINI_SKILLS_TABLE, CREATE_SESSIONS_TABLE, CREATE_META_TABLE, CREATE_TEAM_AGENTS_TABLE, CREATE_TEAM_MESSAGES_TABLE, CREATE_TEAM_TASKS_TABLE, CREATE_TEAM_TASK_DEPS_TABLE, CREATE_TEAM_LOCKS_TABLE, CREATE_TEAM_ROLES_TABLE, CREATE_CHAT_TRANSCRIPT_TABLE, CREATE_GRAPH_ENTITIES_TABLE, CREATE_GRAPH_RELATIONS_TABLE, CREATE_CODE_FILES_TABLE, CREATE_CODE_SYMBOLS_TABLE, CREATE_CODE_EDGES_TABLE, CREATE_OBSERVATION_CODE_REFS_TABLE, CREATE_SCHEMA_MIGRATIONS_TABLE, CREATE_CODE_STATE_SNAPSHOTS_TABLE, CREATE_CODE_STATE_SNAPSHOT_FILES_TABLE, CREATE_KNOWLEDGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_CLAIM_EVIDENCE_TABLE, CREATE_KNOWLEDGE_CLAIM_EVENTS_TABLE, CREATE_KNOWLEDGE_WORKSPACES_TABLE, CREATE_KNOWLEDGE_PAGES_TABLE, CREATE_KNOWLEDGE_PAGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_PAGE_LINKS_TABLE, CREATE_KNOWLEDGE_PROPOSALS_TABLE, CREATE_KNOWLEDGE_WORKFLOWS_TABLE, CREATE_KNOWLEDGE_WORKFLOW_RUNS_TABLE, CREATE_LONG_TERM_MEMORIES_TABLE, CREATE_LONG_TERM_MEMORY_EVIDENCE_TABLE, CREATE_LONG_TERM_MEMORY_EVENTS_TABLE, CREATE_MEMORY_OUTCOME_SIGNALS_TABLE, CREATE_MEDIA_ASSETS_TABLE, CREATE_MEDIA_ASSET_LINKS_TABLE, CREATE_MEDIA_DERIVATIONS_TABLE, CREATE_MEDIA_EMBEDDING_PROFILES_TABLE, CREATE_MEDIA_EMBEDDINGS_TABLE, CREATE_MEDIA_JOBS_TABLE, CREATE_MAINTENANCE_JOBS_TABLE, CREATE_MAINTENANCE_TARGETS_TABLE, CREATE_COMPACTION_CHECKPOINTS_TABLE, CREATE_EVIDENCE_CARDS_TABLE, CREATE_EVIDENCE_CARD_EVENTS_TABLE, CREATE_MEMORY_FEEDBACK_STATES_TABLE, CREATE_MEMORY_FEEDBACK_EVENTS_TABLE, CREATE_TASK_CONTINUITY_EVENTS_TABLE, CREATE_AGENT_EFFECTS_TABLE, CREATE_MCP_BINDINGS_TABLE, CREATE_INDEXES, SCHEMA_MIGRATIONS, _dbCache, _dbLeases;
|
|
475
563
|
var init_sqlite_db = __esm({
|
|
476
564
|
"src/store/sqlite-db.ts"() {
|
|
477
565
|
"use strict";
|
|
@@ -1188,6 +1276,43 @@ CREATE TABLE IF NOT EXISTS memory_feedback_events (
|
|
|
1188
1276
|
delta REAL NOT NULL DEFAULT 0,
|
|
1189
1277
|
observed_at TEXT NOT NULL
|
|
1190
1278
|
);
|
|
1279
|
+
`;
|
|
1280
|
+
CREATE_TASK_CONTINUITY_EVENTS_TABLE = `
|
|
1281
|
+
CREATE TABLE IF NOT EXISTS task_continuity_events (
|
|
1282
|
+
id TEXT PRIMARY KEY,
|
|
1283
|
+
project_id TEXT NOT NULL,
|
|
1284
|
+
task_id TEXT NOT NULL,
|
|
1285
|
+
task TEXT NOT NULL,
|
|
1286
|
+
kind TEXT NOT NULL,
|
|
1287
|
+
content TEXT NOT NULL,
|
|
1288
|
+
item_status TEXT,
|
|
1289
|
+
source_ref TEXT,
|
|
1290
|
+
evidence_json TEXT NOT NULL DEFAULT '[]',
|
|
1291
|
+
actor TEXT,
|
|
1292
|
+
created_at TEXT NOT NULL,
|
|
1293
|
+
event_key TEXT,
|
|
1294
|
+
item_key TEXT,
|
|
1295
|
+
supersedes_id TEXT
|
|
1296
|
+
);
|
|
1297
|
+
`;
|
|
1298
|
+
CREATE_AGENT_EFFECTS_TABLE = `
|
|
1299
|
+
CREATE TABLE IF NOT EXISTS agent_effects (
|
|
1300
|
+
id TEXT PRIMARY KEY,
|
|
1301
|
+
pipeline_id TEXT NOT NULL,
|
|
1302
|
+
task_id TEXT NOT NULL,
|
|
1303
|
+
attempt INTEGER NOT NULL,
|
|
1304
|
+
effect_key TEXT NOT NULL,
|
|
1305
|
+
tool TEXT NOT NULL,
|
|
1306
|
+
risk_tier TEXT NOT NULL,
|
|
1307
|
+
replay_policy TEXT NOT NULL,
|
|
1308
|
+
status TEXT NOT NULL,
|
|
1309
|
+
call_id TEXT,
|
|
1310
|
+
idempotency_key TEXT NOT NULL,
|
|
1311
|
+
input_fingerprint TEXT,
|
|
1312
|
+
detail TEXT,
|
|
1313
|
+
started_at INTEGER NOT NULL,
|
|
1314
|
+
finished_at INTEGER
|
|
1315
|
+
);
|
|
1191
1316
|
`;
|
|
1192
1317
|
CREATE_MCP_BINDINGS_TABLE = `
|
|
1193
1318
|
CREATE TABLE IF NOT EXISTS mcp_bindings (
|
|
@@ -1266,7 +1391,18 @@ CREATE INDEX IF NOT EXISTS idx_evidence_cards_candidate ON evidence_cards(projec
|
|
|
1266
1391
|
CREATE INDEX IF NOT EXISTS idx_evidence_card_events_card ON evidence_card_events(card_id, created_at);
|
|
1267
1392
|
CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC);
|
|
1268
1393
|
CREATE INDEX IF NOT EXISTS idx_memory_feedback_events_candidate ON memory_feedback_events(project_id, candidate_kind, candidate_id, observed_at DESC);
|
|
1394
|
+
CREATE INDEX IF NOT EXISTS idx_task_continuity_project_task ON task_continuity_events(project_id, task_id, created_at ASC);
|
|
1395
|
+
CREATE INDEX IF NOT EXISTS idx_task_continuity_project_recent ON task_continuity_events(project_id, created_at DESC);
|
|
1396
|
+
CREATE INDEX IF NOT EXISTS idx_task_continuity_item ON task_continuity_events(project_id, task_id, kind, item_key, created_at DESC);
|
|
1397
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_task_continuity_event_key
|
|
1398
|
+
ON task_continuity_events(project_id, task_id, event_key)
|
|
1399
|
+
WHERE event_key IS NOT NULL;
|
|
1400
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_effect_identity
|
|
1401
|
+
ON agent_effects(pipeline_id, task_id, attempt, effect_key);
|
|
1402
|
+
CREATE INDEX IF NOT EXISTS idx_agent_effect_pipeline ON agent_effects(pipeline_id, started_at ASC);
|
|
1269
1403
|
CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC);
|
|
1404
|
+
CREATE INDEX IF NOT EXISTS idx_mcp_bindings_root ON mcp_bindings(project_root, last_used_at DESC);
|
|
1405
|
+
CREATE INDEX IF NOT EXISTS idx_mcp_bindings_expiry ON mcp_bindings(expires_at);
|
|
1270
1406
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
|
|
1271
1407
|
ON maintenance_jobs(project_id, kind, dedupe_key)
|
|
1272
1408
|
WHERE status IN ('pending', 'running', 'retry');
|
|
@@ -1437,6 +1573,8 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
|
|
|
1437
1573
|
db2.exec("CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC)");
|
|
1438
1574
|
db2.exec("CREATE INDEX IF NOT EXISTS idx_memory_feedback_events_candidate ON memory_feedback_events(project_id, candidate_kind, candidate_id, observed_at DESC)");
|
|
1439
1575
|
db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC)");
|
|
1576
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_root ON mcp_bindings(project_root, last_used_at DESC)");
|
|
1577
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_expiry ON mcp_bindings(expires_at)");
|
|
1440
1578
|
}
|
|
1441
1579
|
},
|
|
1442
1580
|
{
|
|
@@ -1447,9 +1585,22 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
|
|
|
1447
1585
|
addColumnIfMissing(db2, "code_symbols", "source", "source TEXT");
|
|
1448
1586
|
addColumnIfMissing(db2, "code_edges", "source", "source TEXT");
|
|
1449
1587
|
}
|
|
1588
|
+
},
|
|
1589
|
+
{
|
|
1590
|
+
id: "1.9-continuity-v2",
|
|
1591
|
+
apply: (db2) => {
|
|
1592
|
+
addColumnIfMissing(db2, "task_continuity_events", "event_key", "event_key TEXT");
|
|
1593
|
+
addColumnIfMissing(db2, "task_continuity_events", "item_key", "item_key TEXT");
|
|
1594
|
+
addColumnIfMissing(db2, "task_continuity_events", "supersedes_id", "supersedes_id TEXT");
|
|
1595
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_task_continuity_item ON task_continuity_events(project_id, task_id, kind, item_key, created_at DESC)");
|
|
1596
|
+
db2.exec(`CREATE UNIQUE INDEX IF NOT EXISTS idx_task_continuity_event_key
|
|
1597
|
+
ON task_continuity_events(project_id, task_id, event_key)
|
|
1598
|
+
WHERE event_key IS NOT NULL`);
|
|
1599
|
+
}
|
|
1450
1600
|
}
|
|
1451
1601
|
];
|
|
1452
1602
|
_dbCache = /* @__PURE__ */ new Map();
|
|
1603
|
+
_dbLeases = /* @__PURE__ */ new Map();
|
|
1453
1604
|
}
|
|
1454
1605
|
});
|
|
1455
1606
|
|
|
@@ -1552,15 +1703,20 @@ var init_dotenv_loader = __esm({
|
|
|
1552
1703
|
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
|
|
1553
1704
|
import { homedir as homedir2 } from "os";
|
|
1554
1705
|
import { parse as parseYamlDocument } from "yaml";
|
|
1706
|
+
function cacheKey(homeDir, projectRoot) {
|
|
1707
|
+
return `${homeDir}\0${projectRoot ?? ""}`;
|
|
1708
|
+
}
|
|
1555
1709
|
function initProjectRoot(root) {
|
|
1556
1710
|
globalProjectRoot = root;
|
|
1557
|
-
configCache.delete(root);
|
|
1711
|
+
configCache.delete(cacheKey(homedir2(), root));
|
|
1558
1712
|
}
|
|
1559
|
-
function loadYamlConfig(projectRoot) {
|
|
1713
|
+
function loadYamlConfig(projectRoot, options = {}) {
|
|
1714
|
+
const homeDir = options.homeDir ?? homedir2();
|
|
1560
1715
|
const resolvedRoot = projectRoot === null ? null : projectRoot ?? globalProjectRoot ?? null;
|
|
1561
|
-
const
|
|
1716
|
+
const key = cacheKey(homeDir, resolvedRoot);
|
|
1717
|
+
const cached = configCache.get(key);
|
|
1562
1718
|
if (cached) return cached;
|
|
1563
|
-
const userYaml = getGlobalYamlPath(
|
|
1719
|
+
const userYaml = getGlobalYamlPath(homeDir);
|
|
1564
1720
|
const projectYaml = resolvedRoot ? getProjectYamlPath(resolvedRoot) : null;
|
|
1565
1721
|
let userConfig = {};
|
|
1566
1722
|
let projectConfig = {};
|
|
@@ -1592,7 +1748,7 @@ function loadYamlConfig(projectRoot) {
|
|
|
1592
1748
|
server: { ...userConfig.server, ...projectConfig.server },
|
|
1593
1749
|
team: { ...userConfig.team, ...projectConfig.team }
|
|
1594
1750
|
};
|
|
1595
|
-
configCache.set(
|
|
1751
|
+
configCache.set(key, merged);
|
|
1596
1752
|
return merged;
|
|
1597
1753
|
}
|
|
1598
1754
|
function parseYaml(content) {
|
|
@@ -1768,9 +1924,9 @@ var init_detector = __esm({
|
|
|
1768
1924
|
// src/config/legacy-loader.ts
|
|
1769
1925
|
import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
|
|
1770
1926
|
import { homedir as homedir3 } from "os";
|
|
1771
|
-
function loadFileConfig() {
|
|
1927
|
+
function loadFileConfig(homeDir = homedir3()) {
|
|
1772
1928
|
if (cachedConfig !== null) return cachedConfig;
|
|
1773
|
-
const configPath = getLegacyConfigJsonPath(
|
|
1929
|
+
const configPath = getLegacyConfigJsonPath(homeDir);
|
|
1774
1930
|
try {
|
|
1775
1931
|
if (existsSync5(configPath)) {
|
|
1776
1932
|
cachedConfig = JSON.parse(readFileSync5(configPath, "utf-8"));
|
|
@@ -1800,15 +1956,15 @@ import { homedir as homedir4 } from "os";
|
|
|
1800
1956
|
function loadTomlConfig(options = {}) {
|
|
1801
1957
|
const homeDir = options.homeDir ?? homedir4();
|
|
1802
1958
|
const projectRoot = options.projectRoot ?? null;
|
|
1803
|
-
const
|
|
1804
|
-
const cached = configCache2.get(
|
|
1959
|
+
const cacheKey3 = `${homeDir}\0${projectRoot ?? ""}`;
|
|
1960
|
+
const cached = configCache2.get(cacheKey3);
|
|
1805
1961
|
if (cached) return cached;
|
|
1806
1962
|
const userToml = getGlobalConfigTomlPath(homeDir);
|
|
1807
1963
|
const projectToml = projectRoot ? getProjectConfigTomlPath(projectRoot) : null;
|
|
1808
1964
|
const userConfig = existsSync6(userToml) ? parseTomlConfig(readFileSync6(userToml, "utf8"), userToml) : {};
|
|
1809
1965
|
const projectConfig = projectToml && existsSync6(projectToml) ? parseTomlConfig(readFileSync6(projectToml, "utf8"), projectToml) : {};
|
|
1810
1966
|
const merged = mergeTomlConfig(userConfig, projectConfig);
|
|
1811
|
-
configCache2.set(
|
|
1967
|
+
configCache2.set(cacheKey3, merged);
|
|
1812
1968
|
return merged;
|
|
1813
1969
|
}
|
|
1814
1970
|
function mergeTomlConfig(base, override) {
|
|
@@ -1929,8 +2085,8 @@ function getResolvedConfig(options = {}) {
|
|
|
1929
2085
|
const projectRoot = options.projectRoot === void 0 ? detectProject()?.rootPath ?? null : options.projectRoot;
|
|
1930
2086
|
loadDotenv(projectRoot === null ? void 0 : projectRoot ?? void 0, { userHomeDir: homeDir });
|
|
1931
2087
|
const toml = loadTomlConfig({ projectRoot: projectRoot ?? null, homeDir });
|
|
1932
|
-
const yaml = loadYamlConfig(projectRoot ?? null);
|
|
1933
|
-
const legacy = loadFileConfig();
|
|
2088
|
+
const yaml = loadYamlConfig(projectRoot ?? null, { homeDir });
|
|
2089
|
+
const legacy = loadFileConfig(homeDir);
|
|
1934
2090
|
const embeddingBaseUrl = first(process.env.MEMORIX_EMBEDDING_BASE_URL, toml.embedding?.base_url, yaml.embedding?.baseUrl, legacy.embeddingApi?.baseUrl);
|
|
1935
2091
|
const openRouterEmbeddingApiKey = isOpenRouterUrl(embeddingBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
|
|
1936
2092
|
const memoryLlmProvider = first(
|
|
@@ -1952,15 +2108,17 @@ function getResolvedConfig(options = {}) {
|
|
|
1952
2108
|
legacy.llm?.baseUrl
|
|
1953
2109
|
);
|
|
1954
2110
|
const openRouterMemoryLlmApiKey = isOpenRouterMemoryLane(memoryLlmProvider, memoryLlmBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
|
|
2111
|
+
const isAtlasCloud = memoryLlmProvider === "atlascloud";
|
|
1955
2112
|
const memoryLlmApiKey = first(
|
|
1956
2113
|
process.env.MEMORIX_LLM_API_KEY,
|
|
1957
2114
|
process.env.MEMORIX_API_KEY,
|
|
1958
2115
|
toml.memory?.llm?.api_key,
|
|
1959
2116
|
yaml.llm?.apiKey,
|
|
1960
2117
|
legacy.llm?.apiKey,
|
|
1961
|
-
|
|
1962
|
-
process.env.
|
|
1963
|
-
|
|
2118
|
+
// Never borrow another provider's credentials for the Atlas Cloud preset.
|
|
2119
|
+
isAtlasCloud ? process.env.ATLASCLOUD_API_KEY : process.env.OPENAI_API_KEY,
|
|
2120
|
+
isAtlasCloud ? void 0 : process.env.ANTHROPIC_API_KEY,
|
|
2121
|
+
isAtlasCloud ? void 0 : openRouterMemoryLlmApiKey
|
|
1964
2122
|
);
|
|
1965
2123
|
const resolved = {
|
|
1966
2124
|
agent: {
|
|
@@ -2139,7 +2297,8 @@ function getEnvSourceNames() {
|
|
|
2139
2297
|
"MEMORIX_CODEGRAPH_EXTERNAL_CONTEXT",
|
|
2140
2298
|
"MEMORIX_CODEGRAPH_EXTERNAL_COMMAND",
|
|
2141
2299
|
"MEMORIX_CODEGRAPH_EXTERNAL_TIMEOUT_MS",
|
|
2142
|
-
"OPENROUTER_API_KEY"
|
|
2300
|
+
"OPENROUTER_API_KEY",
|
|
2301
|
+
"ATLASCLOUD_API_KEY"
|
|
2143
2302
|
].filter((name) => process.env[name]);
|
|
2144
2303
|
}
|
|
2145
2304
|
function isOpenRouterUrl(value) {
|
|
@@ -2970,80 +3129,13 @@ var init_provider = __esm({
|
|
|
2970
3129
|
openai: { baseUrl: "https://api.openai.com/v1", model: "gpt-4.1-nano" },
|
|
2971
3130
|
anthropic: { baseUrl: "https://api.anthropic.com/v1", model: "claude-3-5-haiku-latest" },
|
|
2972
3131
|
openrouter: { baseUrl: "https://openrouter.ai/api/v1", model: "openai/gpt-4.1-nano" },
|
|
3132
|
+
atlascloud: { baseUrl: "https://api.atlascloud.ai/v1", model: "deepseek-ai/deepseek-v3.2" },
|
|
2973
3133
|
custom: { baseUrl: "http://localhost:11434/v1", model: "llama3" }
|
|
2974
3134
|
};
|
|
2975
3135
|
currentConfig = null;
|
|
2976
3136
|
}
|
|
2977
3137
|
});
|
|
2978
3138
|
|
|
2979
|
-
// src/store/sqlite-reliability.ts
|
|
2980
|
-
function isTransientSqliteError(error) {
|
|
2981
|
-
const code = error?.code;
|
|
2982
|
-
if (typeof code === "string") {
|
|
2983
|
-
return /^SQLITE_BUSY(?:_|$)/i.test(code);
|
|
2984
|
-
}
|
|
2985
|
-
return error instanceof Error && /\bdatabase is locked\b|\bdatabase is busy\b/i.test(error.message);
|
|
2986
|
-
}
|
|
2987
|
-
function isSqliteUnavailableError(error) {
|
|
2988
|
-
return error instanceof SqliteUnavailableError || error instanceof Error && /SQLite is not available|better-sqlite3.*failed|node:sqlite.*failed|bun:sqlite.*failed/i.test(error.message);
|
|
2989
|
-
}
|
|
2990
|
-
function degradedReadError(storeName) {
|
|
2991
|
-
return new Error(`[memorix] Cannot read ${storeName}: SQLite backend unavailable (memory is not loaded)`);
|
|
2992
|
-
}
|
|
2993
|
-
function degradedWriteError(storeName) {
|
|
2994
|
-
return new Error(`[memorix] Cannot write ${storeName}: SQLite backend unavailable (degraded mode; read-only)`);
|
|
2995
|
-
}
|
|
2996
|
-
function formatSqliteFailure(error) {
|
|
2997
|
-
return error instanceof Error && error.message ? error.message : String(error);
|
|
2998
|
-
}
|
|
2999
|
-
function delay(ms) {
|
|
3000
|
-
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
3001
|
-
}
|
|
3002
|
-
async function retrySqliteBusy(operation, label) {
|
|
3003
|
-
for (let attempt = 0; ; attempt++) {
|
|
3004
|
-
try {
|
|
3005
|
-
return await operation();
|
|
3006
|
-
} catch (error) {
|
|
3007
|
-
if (!isTransientSqliteError(error) || attempt >= SQLITE_BUSY_RETRY_DELAYS_MS.length) throw error;
|
|
3008
|
-
const waitMs = SQLITE_BUSY_RETRY_DELAYS_MS[attempt];
|
|
3009
|
-
console.error(
|
|
3010
|
-
`[memorix] ${label} SQLite busy (attempt ${attempt + 1}/${SQLITE_BUSY_RETRY_DELAYS_MS.length + 1}), retrying in ${waitMs}ms`
|
|
3011
|
-
);
|
|
3012
|
-
await delay(waitMs);
|
|
3013
|
-
}
|
|
3014
|
-
}
|
|
3015
|
-
}
|
|
3016
|
-
async function initializeSqliteStore(factory, dataDir, label) {
|
|
3017
|
-
try {
|
|
3018
|
-
loadBetterSqlite3();
|
|
3019
|
-
} catch (error) {
|
|
3020
|
-
throw new SqliteUnavailableError(error);
|
|
3021
|
-
}
|
|
3022
|
-
return retrySqliteBusy(async () => {
|
|
3023
|
-
const store = factory();
|
|
3024
|
-
await store.init(dataDir);
|
|
3025
|
-
return store;
|
|
3026
|
-
}, label);
|
|
3027
|
-
}
|
|
3028
|
-
var SQLITE_BUSY_RETRY_DELAYS_MS, SqliteUnavailableError;
|
|
3029
|
-
var init_sqlite_reliability = __esm({
|
|
3030
|
-
"src/store/sqlite-reliability.ts"() {
|
|
3031
|
-
"use strict";
|
|
3032
|
-
init_esm_shims();
|
|
3033
|
-
init_sqlite_db();
|
|
3034
|
-
SQLITE_BUSY_RETRY_DELAYS_MS = [50, 150, 400, 1e3, 2500];
|
|
3035
|
-
SqliteUnavailableError = class extends Error {
|
|
3036
|
-
code = "MEMORIX_SQLITE_UNAVAILABLE";
|
|
3037
|
-
constructor(cause) {
|
|
3038
|
-
super(
|
|
3039
|
-
cause instanceof Error && cause.message ? cause.message : "[memorix] SQLite is unavailable (install a supported SQLite runtime)"
|
|
3040
|
-
);
|
|
3041
|
-
this.name = "SqliteUnavailableError";
|
|
3042
|
-
}
|
|
3043
|
-
};
|
|
3044
|
-
}
|
|
3045
|
-
});
|
|
3046
|
-
|
|
3047
3139
|
// src/store/file-lock.ts
|
|
3048
3140
|
import { promises as fs2 } from "fs";
|
|
3049
3141
|
import { randomUUID } from "crypto";
|
|
@@ -3946,12 +4038,45 @@ function textHash(text2) {
|
|
|
3946
4038
|
async function loadDiskCache() {
|
|
3947
4039
|
try {
|
|
3948
4040
|
const raw = await readFile(CACHE_FILE, "utf-8");
|
|
4041
|
+
if (Buffer.byteLength(raw, "utf8") > MAX_CACHE_FILE_BYTES) {
|
|
4042
|
+
console.error("[memorix] FastEmbed cache exceeds the disk load limit; starting with an empty cache");
|
|
4043
|
+
return;
|
|
4044
|
+
}
|
|
3949
4045
|
const entries = JSON.parse(raw);
|
|
3950
|
-
|
|
3951
|
-
|
|
4046
|
+
if (!Array.isArray(entries)) return;
|
|
4047
|
+
for (const entry of entries) {
|
|
4048
|
+
if (!Array.isArray(entry) || typeof entry[0] !== "string" || !isVector(entry[1])) continue;
|
|
4049
|
+
cacheSet(entry[0], entry[1], false);
|
|
4050
|
+
}
|
|
4051
|
+
console.error(`[memorix] Loaded ${cache.size} cached embeddings from disk`);
|
|
3952
4052
|
} catch {
|
|
3953
4053
|
}
|
|
3954
4054
|
}
|
|
4055
|
+
function isVector(value) {
|
|
4056
|
+
return Array.isArray(value) && value.every((entry) => typeof entry === "number");
|
|
4057
|
+
}
|
|
4058
|
+
function maxCachePayloadBytes() {
|
|
4059
|
+
const raw = Number.parseInt(process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES ?? "", 10);
|
|
4060
|
+
return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_CACHE_PAYLOAD_BYTES;
|
|
4061
|
+
}
|
|
4062
|
+
function cacheSet(hash4, value, markDirty = true) {
|
|
4063
|
+
const incomingBytes = value.length * 8;
|
|
4064
|
+
if (incomingBytes > maxCachePayloadBytes()) return;
|
|
4065
|
+
const existing = cache.get(hash4);
|
|
4066
|
+
if (existing) cachePayloadBytes -= existing.length * 8;
|
|
4067
|
+
else {
|
|
4068
|
+
while (cache.size >= MAX_CACHE_SIZE || cachePayloadBytes + incomingBytes > maxCachePayloadBytes()) {
|
|
4069
|
+
const firstKey = cache.keys().next().value;
|
|
4070
|
+
if (firstKey === void 0) break;
|
|
4071
|
+
const old = cache.get(firstKey);
|
|
4072
|
+
cache.delete(firstKey);
|
|
4073
|
+
if (old) cachePayloadBytes -= old.length * 8;
|
|
4074
|
+
}
|
|
4075
|
+
}
|
|
4076
|
+
cache.set(hash4, value);
|
|
4077
|
+
cachePayloadBytes += incomingBytes;
|
|
4078
|
+
if (markDirty) diskCacheDirty = true;
|
|
4079
|
+
}
|
|
3955
4080
|
async function saveDiskCache() {
|
|
3956
4081
|
if (!diskCacheDirty) return;
|
|
3957
4082
|
try {
|
|
@@ -3962,7 +4087,7 @@ async function saveDiskCache() {
|
|
|
3962
4087
|
} catch {
|
|
3963
4088
|
}
|
|
3964
4089
|
}
|
|
3965
|
-
var CACHE_DIR, CACHE_FILE, cache, MAX_CACHE_SIZE, diskCacheDirty, FastEmbedProvider;
|
|
4090
|
+
var CACHE_DIR, CACHE_FILE, cache, MAX_CACHE_SIZE, DEFAULT_CACHE_PAYLOAD_BYTES, MAX_CACHE_FILE_BYTES, cachePayloadBytes, diskCacheDirty, FastEmbedProvider;
|
|
3966
4091
|
var init_fastembed_provider = __esm({
|
|
3967
4092
|
"src/embedding/fastembed-provider.ts"() {
|
|
3968
4093
|
"use strict";
|
|
@@ -3972,6 +4097,9 @@ var init_fastembed_provider = __esm({
|
|
|
3972
4097
|
CACHE_FILE = join2(CACHE_DIR, ".embedding-cache.json");
|
|
3973
4098
|
cache = /* @__PURE__ */ new Map();
|
|
3974
4099
|
MAX_CACHE_SIZE = 5e3;
|
|
4100
|
+
DEFAULT_CACHE_PAYLOAD_BYTES = 64 * 1024 * 1024;
|
|
4101
|
+
MAX_CACHE_FILE_BYTES = 128 * 1024 * 1024;
|
|
4102
|
+
cachePayloadBytes = 0;
|
|
3975
4103
|
diskCacheDirty = false;
|
|
3976
4104
|
FastEmbedProvider = class _FastEmbedProvider {
|
|
3977
4105
|
name = "fastembed-bge-small";
|
|
@@ -4013,7 +4141,7 @@ var init_fastembed_provider = __esm({
|
|
|
4013
4141
|
if (result.length !== this.dimensions) {
|
|
4014
4142
|
throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);
|
|
4015
4143
|
}
|
|
4016
|
-
|
|
4144
|
+
cacheSet(hash4, result);
|
|
4017
4145
|
return result;
|
|
4018
4146
|
}
|
|
4019
4147
|
async embedBatch(texts) {
|
|
@@ -4038,7 +4166,7 @@ var init_fastembed_provider = __esm({
|
|
|
4038
4166
|
const originalIdx = uncachedIndices[batchIdx];
|
|
4039
4167
|
const plain = Array.from(vec);
|
|
4040
4168
|
results[originalIdx] = plain;
|
|
4041
|
-
|
|
4169
|
+
cacheSet(textHash(uncachedTexts[batchIdx]), plain);
|
|
4042
4170
|
batchIdx++;
|
|
4043
4171
|
}
|
|
4044
4172
|
}
|
|
@@ -4046,14 +4174,6 @@ var init_fastembed_provider = __esm({
|
|
|
4046
4174
|
}
|
|
4047
4175
|
return results;
|
|
4048
4176
|
}
|
|
4049
|
-
cacheSet(hash4, value) {
|
|
4050
|
-
if (cache.size >= MAX_CACHE_SIZE) {
|
|
4051
|
-
const firstKey = cache.keys().next().value;
|
|
4052
|
-
if (firstKey !== void 0) cache.delete(firstKey);
|
|
4053
|
-
}
|
|
4054
|
-
cache.set(hash4, value);
|
|
4055
|
-
diskCacheDirty = true;
|
|
4056
|
-
}
|
|
4057
4177
|
};
|
|
4058
4178
|
}
|
|
4059
4179
|
});
|
|
@@ -4063,7 +4183,15 @@ var transformers_provider_exports = {};
|
|
|
4063
4183
|
__export(transformers_provider_exports, {
|
|
4064
4184
|
TransformersProvider: () => TransformersProvider
|
|
4065
4185
|
});
|
|
4066
|
-
|
|
4186
|
+
import { createHash as createHash2 } from "crypto";
|
|
4187
|
+
function cacheKey2(text2) {
|
|
4188
|
+
return createHash2("sha256").update(text2).digest("hex");
|
|
4189
|
+
}
|
|
4190
|
+
function maxCachePayloadBytes2() {
|
|
4191
|
+
const raw = Number.parseInt(process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES ?? "", 10);
|
|
4192
|
+
return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_CACHE_PAYLOAD_BYTES2;
|
|
4193
|
+
}
|
|
4194
|
+
var cache2, MAX_CACHE_SIZE2, DEFAULT_CACHE_PAYLOAD_BYTES2, cachePayloadBytes2, TransformersProvider;
|
|
4067
4195
|
var init_transformers_provider = __esm({
|
|
4068
4196
|
"src/embedding/transformers-provider.ts"() {
|
|
4069
4197
|
"use strict";
|
|
@@ -4071,6 +4199,8 @@ var init_transformers_provider = __esm({
|
|
|
4071
4199
|
init_provider2();
|
|
4072
4200
|
cache2 = /* @__PURE__ */ new Map();
|
|
4073
4201
|
MAX_CACHE_SIZE2 = 5e3;
|
|
4202
|
+
DEFAULT_CACHE_PAYLOAD_BYTES2 = 64 * 1024 * 1024;
|
|
4203
|
+
cachePayloadBytes2 = 0;
|
|
4074
4204
|
TransformersProvider = class _TransformersProvider {
|
|
4075
4205
|
name = "transformers-minilm";
|
|
4076
4206
|
dimensions = 384;
|
|
@@ -4105,7 +4235,7 @@ var init_transformers_provider = __esm({
|
|
|
4105
4235
|
return Promise.all(inputs.map((input) => this.embedInput(input, options)));
|
|
4106
4236
|
}
|
|
4107
4237
|
async embed(text2) {
|
|
4108
|
-
const cached = cache2.get(text2);
|
|
4238
|
+
const cached = cache2.get(cacheKey2(text2));
|
|
4109
4239
|
if (cached) return cached;
|
|
4110
4240
|
const output = await this.extractor(text2, {
|
|
4111
4241
|
pooling: "mean",
|
|
@@ -4115,7 +4245,7 @@ var init_transformers_provider = __esm({
|
|
|
4115
4245
|
if (result.length !== this.dimensions) {
|
|
4116
4246
|
throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);
|
|
4117
4247
|
}
|
|
4118
|
-
this.cacheSet(text2, result);
|
|
4248
|
+
this.cacheSet(cacheKey2(text2), result);
|
|
4119
4249
|
return result;
|
|
4120
4250
|
}
|
|
4121
4251
|
async embedBatch(texts) {
|
|
@@ -4123,7 +4253,7 @@ var init_transformers_provider = __esm({
|
|
|
4123
4253
|
const uncachedIndices = [];
|
|
4124
4254
|
const uncachedTexts = [];
|
|
4125
4255
|
for (let i2 = 0; i2 < texts.length; i2++) {
|
|
4126
|
-
const cached = cache2.get(texts[i2]);
|
|
4256
|
+
const cached = cache2.get(cacheKey2(texts[i2]));
|
|
4127
4257
|
if (cached) {
|
|
4128
4258
|
results[i2] = cached;
|
|
4129
4259
|
} else {
|
|
@@ -4141,17 +4271,27 @@ var init_transformers_provider = __esm({
|
|
|
4141
4271
|
const vec = Array.from(allVecs[i2]);
|
|
4142
4272
|
const originalIdx = uncachedIndices[i2];
|
|
4143
4273
|
results[originalIdx] = vec;
|
|
4144
|
-
this.cacheSet(uncachedTexts[i2], vec);
|
|
4274
|
+
this.cacheSet(cacheKey2(uncachedTexts[i2]), vec);
|
|
4145
4275
|
}
|
|
4146
4276
|
}
|
|
4147
4277
|
return results;
|
|
4148
4278
|
}
|
|
4149
4279
|
cacheSet(key, value) {
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4280
|
+
const incomingBytes = value.length * 8;
|
|
4281
|
+
if (incomingBytes > maxCachePayloadBytes2()) return;
|
|
4282
|
+
const existing = cache2.get(key);
|
|
4283
|
+
if (existing) cachePayloadBytes2 -= existing.length * 8;
|
|
4284
|
+
else {
|
|
4285
|
+
while (cache2.size >= MAX_CACHE_SIZE2 || cachePayloadBytes2 + incomingBytes > maxCachePayloadBytes2()) {
|
|
4286
|
+
const firstKey = cache2.keys().next().value;
|
|
4287
|
+
if (firstKey === void 0) break;
|
|
4288
|
+
const old = cache2.get(firstKey);
|
|
4289
|
+
cache2.delete(firstKey);
|
|
4290
|
+
if (old) cachePayloadBytes2 -= old.length * 8;
|
|
4291
|
+
}
|
|
4153
4292
|
}
|
|
4154
4293
|
cache2.set(key, value);
|
|
4294
|
+
cachePayloadBytes2 += incomingBytes;
|
|
4155
4295
|
}
|
|
4156
4296
|
};
|
|
4157
4297
|
}
|
|
@@ -4173,7 +4313,7 @@ __export(api_provider_exports, {
|
|
|
4173
4313
|
saveDiskCacheNow: () => saveDiskCacheNow,
|
|
4174
4314
|
seedApiEmbeddingCacheForTests: () => seedApiEmbeddingCacheForTests
|
|
4175
4315
|
});
|
|
4176
|
-
import { createHash as
|
|
4316
|
+
import { createHash as createHash3 } from "crypto";
|
|
4177
4317
|
import { createReadStream, createWriteStream, constants as fsConstants } from "fs";
|
|
4178
4318
|
import { access, readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, rename, stat, unlink } from "fs/promises";
|
|
4179
4319
|
import { join as join3 } from "path";
|
|
@@ -4200,7 +4340,7 @@ function cacheStatFile() {
|
|
|
4200
4340
|
function payloadBytes(vector) {
|
|
4201
4341
|
return vector.length * BYTES_PER_DIM;
|
|
4202
4342
|
}
|
|
4203
|
-
function
|
|
4343
|
+
function maxCachePayloadBytes3() {
|
|
4204
4344
|
const raw = process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES;
|
|
4205
4345
|
if (raw) {
|
|
4206
4346
|
const parsed = Number.parseInt(raw, 10);
|
|
@@ -4210,7 +4350,7 @@ function maxCachePayloadBytes() {
|
|
|
4210
4350
|
}
|
|
4211
4351
|
function maxEntriesForDimensions(dimensions) {
|
|
4212
4352
|
const dim = Math.max(1, Math.floor(dimensions));
|
|
4213
|
-
const byBytes = Math.floor(
|
|
4353
|
+
const byBytes = Math.floor(maxCachePayloadBytes3() / (dim * BYTES_PER_DIM));
|
|
4214
4354
|
return Math.max(1, Math.min(MAX_CACHE_ENTRIES, byBytes));
|
|
4215
4355
|
}
|
|
4216
4356
|
function rememberDimensions(vector) {
|
|
@@ -4223,13 +4363,15 @@ function evictOldest() {
|
|
|
4223
4363
|
if (firstKey === void 0) return;
|
|
4224
4364
|
const old = cache3.get(firstKey);
|
|
4225
4365
|
cache3.delete(firstKey);
|
|
4226
|
-
if (old)
|
|
4366
|
+
if (old) cachePayloadBytes3 -= payloadBytes(old);
|
|
4227
4367
|
}
|
|
4228
4368
|
function evictToFit(incomingBytes, incomingDims) {
|
|
4369
|
+
if (incomingBytes > maxCachePayloadBytes3()) return false;
|
|
4229
4370
|
const limit2 = maxEntriesForDimensions(incomingDims);
|
|
4230
|
-
while (cache3.size > 0 && (cache3.size >= limit2 ||
|
|
4371
|
+
while (cache3.size > 0 && (cache3.size >= limit2 || cachePayloadBytes3 + incomingBytes > maxCachePayloadBytes3())) {
|
|
4231
4372
|
evictOldest();
|
|
4232
4373
|
}
|
|
4374
|
+
return true;
|
|
4233
4375
|
}
|
|
4234
4376
|
function isNumberArray(value) {
|
|
4235
4377
|
return Array.isArray(value) && value.every((entry) => typeof entry === "number");
|
|
@@ -4256,12 +4398,12 @@ function cacheInsert(hash4, value, dirty) {
|
|
|
4256
4398
|
const incoming = payloadBytes(value);
|
|
4257
4399
|
const existing = cache3.get(hash4);
|
|
4258
4400
|
if (existing) {
|
|
4259
|
-
|
|
4401
|
+
cachePayloadBytes3 -= payloadBytes(existing);
|
|
4260
4402
|
cache3.delete(hash4);
|
|
4261
4403
|
}
|
|
4262
|
-
evictToFit(incoming, value.length || cacheDimensions || DEFAULT_ASSUMED_DIMENSIONS);
|
|
4404
|
+
if (!evictToFit(incoming, value.length || cacheDimensions || DEFAULT_ASSUMED_DIMENSIONS)) return;
|
|
4263
4405
|
cache3.set(hash4, value);
|
|
4264
|
-
|
|
4406
|
+
cachePayloadBytes3 += incoming;
|
|
4265
4407
|
if (dirty) diskCacheDirty2 = true;
|
|
4266
4408
|
}
|
|
4267
4409
|
async function readCacheStat() {
|
|
@@ -4297,7 +4439,7 @@ function cacheNamespace(config) {
|
|
|
4297
4439
|
].join("|");
|
|
4298
4440
|
}
|
|
4299
4441
|
function textHash2(text2, namespace) {
|
|
4300
|
-
return
|
|
4442
|
+
return createHash3("sha256").update(`${namespace}\0${text2}`).digest("hex").slice(0, 16);
|
|
4301
4443
|
}
|
|
4302
4444
|
function inputIdentity(input, options = {}) {
|
|
4303
4445
|
return JSON.stringify({
|
|
@@ -4639,7 +4781,7 @@ function getApiEmbeddingDiskCacheLoadCountForTests() {
|
|
|
4639
4781
|
}
|
|
4640
4782
|
function resetApiEmbeddingCacheForTests() {
|
|
4641
4783
|
cache3.clear();
|
|
4642
|
-
|
|
4784
|
+
cachePayloadBytes3 = 0;
|
|
4643
4785
|
cacheDimensions = null;
|
|
4644
4786
|
diskCacheEntryCount = 0;
|
|
4645
4787
|
diskCacheLoaded = false;
|
|
@@ -4650,14 +4792,14 @@ function resetApiEmbeddingCacheForTests() {
|
|
|
4650
4792
|
}
|
|
4651
4793
|
function seedApiEmbeddingCacheForTests(entries) {
|
|
4652
4794
|
cache3.clear();
|
|
4653
|
-
|
|
4795
|
+
cachePayloadBytes3 = 0;
|
|
4654
4796
|
cacheDimensions = null;
|
|
4655
4797
|
for (const [key, value] of entries) cacheInsert(key, value, true);
|
|
4656
4798
|
diskCacheLoaded = true;
|
|
4657
4799
|
diskCacheDirty2 = true;
|
|
4658
4800
|
}
|
|
4659
4801
|
function getApiEmbeddingCachePayloadBytesForTests() {
|
|
4660
|
-
return
|
|
4802
|
+
return cachePayloadBytes3;
|
|
4661
4803
|
}
|
|
4662
4804
|
function getApiEmbeddingJsonlLineCountCallsForTests() {
|
|
4663
4805
|
return jsonlLineCountCalls;
|
|
@@ -4831,7 +4973,7 @@ function scheduleDiskSave() {
|
|
|
4831
4973
|
diskSaveTimer = null;
|
|
4832
4974
|
}, DISK_SAVE_DEBOUNCE_MS);
|
|
4833
4975
|
}
|
|
4834
|
-
function
|
|
4976
|
+
function cacheSet2(hash4, value) {
|
|
4835
4977
|
cacheInsert(hash4, value, true);
|
|
4836
4978
|
}
|
|
4837
4979
|
function resolveEnvEmbeddingApiKey() {
|
|
@@ -4951,7 +5093,7 @@ async function waitForRetry(waitMs, signal) {
|
|
|
4951
5093
|
abortSignal.addEventListener("abort", onAbort, { once: true });
|
|
4952
5094
|
});
|
|
4953
5095
|
}
|
|
4954
|
-
var cache3, MAX_CACHE_ENTRIES, MAX_CACHE_PAYLOAD_BYTES, BYTES_PER_DIM, DEFAULT_ASSUMED_DIMENSIONS, MAX_MIGRATION_VALUE_BYTES,
|
|
5096
|
+
var cache3, MAX_CACHE_ENTRIES, MAX_CACHE_PAYLOAD_BYTES, BYTES_PER_DIM, DEFAULT_ASSUMED_DIMENSIONS, MAX_MIGRATION_VALUE_BYTES, cachePayloadBytes3, cacheDimensions, diskCacheEntryCount, diskCacheDirty2, diskSaveTimer, diskCacheLoaded, diskCacheLoadPromise, diskCacheLoadCount, jsonlLineCountCalls, MAX_INPUT_CHARS, MAX_CONCURRENCY, DISK_SAVE_DEBOUNCE_MS, DEFAULT_MAX_BATCH_SIZE, DASHSCOPE_MAX_BATCH_SIZE, MAX_RETRIES2, BASE_DELAY_MS, EmbeddingAPIError, APIEmbeddingProvider;
|
|
4955
5097
|
var init_api_provider = __esm({
|
|
4956
5098
|
"src/embedding/api-provider.ts"() {
|
|
4957
5099
|
"use strict";
|
|
@@ -4963,7 +5105,7 @@ var init_api_provider = __esm({
|
|
|
4963
5105
|
BYTES_PER_DIM = 8;
|
|
4964
5106
|
DEFAULT_ASSUMED_DIMENSIONS = 4096;
|
|
4965
5107
|
MAX_MIGRATION_VALUE_BYTES = 16 * 1024 * 1024;
|
|
4966
|
-
|
|
5108
|
+
cachePayloadBytes3 = 0;
|
|
4967
5109
|
cacheDimensions = null;
|
|
4968
5110
|
diskCacheEntryCount = 0;
|
|
4969
5111
|
diskCacheDirty2 = false;
|
|
@@ -5148,7 +5290,7 @@ var init_api_provider = __esm({
|
|
|
5148
5290
|
} else {
|
|
5149
5291
|
embedding = await apiCall();
|
|
5150
5292
|
}
|
|
5151
|
-
|
|
5293
|
+
cacheSet2(hash4, embedding);
|
|
5152
5294
|
scheduleDiskSave();
|
|
5153
5295
|
return embedding;
|
|
5154
5296
|
}
|
|
@@ -5196,7 +5338,7 @@ var init_api_provider = __esm({
|
|
|
5196
5338
|
for (const item of response.data) {
|
|
5197
5339
|
const originalIdx = chunkIndices[item.index];
|
|
5198
5340
|
results[originalIdx] = item.embedding;
|
|
5199
|
-
|
|
5341
|
+
cacheSet2(textHash2(normalizedTexts[originalIdx], this.cacheKeyNamespace), item.embedding);
|
|
5200
5342
|
}
|
|
5201
5343
|
} catch (error) {
|
|
5202
5344
|
const providerLimit = parseBatchLimit(error);
|
|
@@ -5274,7 +5416,7 @@ var init_api_provider = __esm({
|
|
|
5274
5416
|
throw new Error(`Expected ${this.dimensions}d, got ${embedding.length}d; dimension mismatch`);
|
|
5275
5417
|
}
|
|
5276
5418
|
this.trackUsage(response);
|
|
5277
|
-
|
|
5419
|
+
cacheSet2(hash4, embedding);
|
|
5278
5420
|
scheduleDiskSave();
|
|
5279
5421
|
return embedding;
|
|
5280
5422
|
}
|
|
@@ -6195,7 +6337,7 @@ var init_timeout = __esm({
|
|
|
6195
6337
|
});
|
|
6196
6338
|
|
|
6197
6339
|
// src/search/semantic-index.ts
|
|
6198
|
-
import { createHash as
|
|
6340
|
+
import { createHash as createHash4 } from "crypto";
|
|
6199
6341
|
import { createRequire as createRequire3 } from "module";
|
|
6200
6342
|
import path8 from "path";
|
|
6201
6343
|
function createSemanticIndexProfile(provider2) {
|
|
@@ -6209,7 +6351,7 @@ function stateKey(dataDir, profile) {
|
|
|
6209
6351
|
return `${path8.resolve(dataDir)}::${profile.key}`;
|
|
6210
6352
|
}
|
|
6211
6353
|
function tableName(profile) {
|
|
6212
|
-
const digest2 =
|
|
6354
|
+
const digest2 = createHash4("sha256").update(profile.key).digest("hex").slice(0, 20);
|
|
6213
6355
|
return `${TABLE_PREFIX}${digest2}`;
|
|
6214
6356
|
}
|
|
6215
6357
|
function indexRoot(dataDir) {
|
|
@@ -7551,6 +7693,7 @@ async function searchObservations(options) {
|
|
|
7551
7693
|
};
|
|
7552
7694
|
let queryVector = null;
|
|
7553
7695
|
let embeddingProviderForSearch = null;
|
|
7696
|
+
let embeddingUnavailable = false;
|
|
7554
7697
|
if (quality !== "fast" && embeddingEnabled && hasQuery && tier !== "fast") {
|
|
7555
7698
|
try {
|
|
7556
7699
|
const provider2 = await getEmbeddingProvider();
|
|
@@ -7558,6 +7701,7 @@ async function searchObservations(options) {
|
|
|
7558
7701
|
embeddingProviderForSearch = provider2;
|
|
7559
7702
|
const activeVectorDimensions = getVectorDimensions();
|
|
7560
7703
|
if (activeVectorDimensions !== null && provider2.dimensions !== activeVectorDimensions) {
|
|
7704
|
+
embeddingUnavailable = true;
|
|
7561
7705
|
rememberSearchMode(
|
|
7562
7706
|
modeKey,
|
|
7563
7707
|
`fulltext (embedding dimension mismatch: provider ${provider2.dimensions}d vs index ${activeVectorDimensions}d)`
|
|
@@ -7597,8 +7741,11 @@ async function searchObservations(options) {
|
|
|
7597
7741
|
hybridWeights: isCJKHeavy ? { text: 0.2, vector: 0.8 } : { text: 0.6, vector: 0.4 }
|
|
7598
7742
|
};
|
|
7599
7743
|
}
|
|
7744
|
+
} else {
|
|
7745
|
+
embeddingUnavailable = true;
|
|
7600
7746
|
}
|
|
7601
7747
|
} catch (error) {
|
|
7748
|
+
embeddingUnavailable = true;
|
|
7602
7749
|
rememberSearchMode(modeKey, "fulltext (embedding unavailable)");
|
|
7603
7750
|
console.error("[memorix] Embedding failed or timed out, falling back to fulltext search");
|
|
7604
7751
|
}
|
|
@@ -7606,7 +7753,7 @@ async function searchObservations(options) {
|
|
|
7606
7753
|
mark("preSearch");
|
|
7607
7754
|
let results;
|
|
7608
7755
|
const persistentCorpusEligible = await shouldUsePersistentSearch(projectIds, options.projectId);
|
|
7609
|
-
const canUsePersistentLexical = persistentCorpusEligible && Boolean(hasQuery) && !queryVector && (quality === "fast" || tier === "fast" || !embeddingEnabled);
|
|
7756
|
+
const canUsePersistentLexical = persistentCorpusEligible && Boolean(hasQuery) && !queryVector && (quality === "fast" || tier === "fast" || !embeddingEnabled || embeddingUnavailable);
|
|
7610
7757
|
let persistent = persistentCorpusEligible && queryVector && embeddingProviderForSearch ? await searchPersistentSemantically(options, projectIds, requestLimit, queryVector, embeddingProviderForSearch) : canUsePersistentLexical ? await searchPersistentLexically(options, projectIds, requestLimit) : null;
|
|
7611
7758
|
const durableStore = getOptionalObservationStore();
|
|
7612
7759
|
if (!persistent && queryVector && durableStore?.hasLexicalIndex?.() && count(database) === 0) {
|
|
@@ -8249,6 +8396,7 @@ var init_secret_filter = __esm({
|
|
|
8249
8396
|
// src/runtime/maintenance-jobs.ts
|
|
8250
8397
|
var maintenance_jobs_exports = {};
|
|
8251
8398
|
__export(maintenance_jobs_exports, {
|
|
8399
|
+
DEFAULT_FAILED_HISTORY_RETENTION_MS: () => DEFAULT_FAILED_HISTORY_RETENTION_MS,
|
|
8252
8400
|
MAINTENANCE_JOB_KINDS: () => MAINTENANCE_JOB_KINDS,
|
|
8253
8401
|
MaintenanceJobStore: () => MaintenanceJobStore,
|
|
8254
8402
|
MaintenanceJobWorker: () => MaintenanceJobWorker,
|
|
@@ -8298,7 +8446,7 @@ function normalizedKinds(kinds) {
|
|
|
8298
8446
|
function getMaintenanceRetryDelayMs(attempts) {
|
|
8299
8447
|
return Math.min(6e4, 1e3 * 2 ** Math.max(0, attempts - 1));
|
|
8300
8448
|
}
|
|
8301
|
-
var MAINTENANCE_JOB_KINDS, DEFAULT_MAX_ATTEMPTS, DEFAULT_LEASE_MS, DEFAULT_POLL_INTERVAL_MS, MAX_ERROR_LENGTH, DEFAULT_COMPLETED_HISTORY_RETENTION_MS, MaintenanceJobStore, MaintenanceJobWorker;
|
|
8449
|
+
var MAINTENANCE_JOB_KINDS, DEFAULT_MAX_ATTEMPTS, DEFAULT_LEASE_MS, DEFAULT_POLL_INTERVAL_MS, MAX_ERROR_LENGTH, DEFAULT_COMPLETED_HISTORY_RETENTION_MS, DEFAULT_FAILED_HISTORY_RETENTION_MS, MaintenanceJobStore, MaintenanceJobWorker;
|
|
8302
8450
|
var init_maintenance_jobs = __esm({
|
|
8303
8451
|
"src/runtime/maintenance-jobs.ts"() {
|
|
8304
8452
|
"use strict";
|
|
@@ -8325,6 +8473,7 @@ var init_maintenance_jobs = __esm({
|
|
|
8325
8473
|
DEFAULT_POLL_INTERVAL_MS = 2e3;
|
|
8326
8474
|
MAX_ERROR_LENGTH = 1e3;
|
|
8327
8475
|
DEFAULT_COMPLETED_HISTORY_RETENTION_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
8476
|
+
DEFAULT_FAILED_HISTORY_RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
8328
8477
|
MaintenanceJobStore = class {
|
|
8329
8478
|
db;
|
|
8330
8479
|
constructor(dataDir) {
|
|
@@ -8451,18 +8600,21 @@ var init_maintenance_jobs = __esm({
|
|
|
8451
8600
|
}
|
|
8452
8601
|
/**
|
|
8453
8602
|
* Completed jobs are useful recent operator history, not permanent data.
|
|
8454
|
-
* Failed
|
|
8455
|
-
*
|
|
8603
|
+
* Failed diagnostics are retained longer, but are still bounded so a
|
|
8604
|
+
* permanently failing job kind cannot grow the database forever.
|
|
8456
8605
|
*/
|
|
8457
8606
|
pruneCompletedHistory(options = {}) {
|
|
8458
8607
|
const now3 = options.now ?? Date.now();
|
|
8459
8608
|
const maxAgeMs = Number.isFinite(options.maxAgeMs) ? Math.max(0, Math.floor(options.maxAgeMs)) : DEFAULT_COMPLETED_HISTORY_RETENTION_MS;
|
|
8609
|
+
const failedMaxAgeMs = Number.isFinite(options.failedMaxAgeMs) ? Math.max(0, Math.floor(options.failedMaxAgeMs)) : DEFAULT_FAILED_HISTORY_RETENTION_MS;
|
|
8460
8610
|
const result = this.db.prepare(`
|
|
8461
8611
|
DELETE FROM maintenance_jobs
|
|
8462
|
-
WHERE status = 'completed'
|
|
8612
|
+
WHERE (status = 'completed'
|
|
8463
8613
|
AND completed_at IS NOT NULL
|
|
8464
|
-
AND completed_at < ?
|
|
8465
|
-
|
|
8614
|
+
AND completed_at < ?)
|
|
8615
|
+
OR (status = 'failed'
|
|
8616
|
+
AND updated_at < ?)
|
|
8617
|
+
`).run(now3 - maxAgeMs, now3 - failedMaxAgeMs);
|
|
8466
8618
|
return Number(result.changes ?? 0);
|
|
8467
8619
|
}
|
|
8468
8620
|
claimNext(options) {
|
|
@@ -8788,7 +8940,7 @@ var init_lifecycle = __esm({
|
|
|
8788
8940
|
});
|
|
8789
8941
|
|
|
8790
8942
|
// src/store/evidence-store.ts
|
|
8791
|
-
import { createHash as
|
|
8943
|
+
import { createHash as createHash5, randomUUID as randomUUID3 } from "crypto";
|
|
8792
8944
|
function safeJson(value, fallback) {
|
|
8793
8945
|
if (typeof value !== "string" || value.length === 0) return fallback;
|
|
8794
8946
|
try {
|
|
@@ -8822,7 +8974,7 @@ function rowToCard(row) {
|
|
|
8822
8974
|
};
|
|
8823
8975
|
}
|
|
8824
8976
|
function observationHash(observation) {
|
|
8825
|
-
return
|
|
8977
|
+
return createHash5("sha256").update(JSON.stringify({
|
|
8826
8978
|
projectId: observation.projectId,
|
|
8827
8979
|
id: observation.id,
|
|
8828
8980
|
title: observation.title,
|
|
@@ -9282,13 +9434,13 @@ __export(workspace_exports, {
|
|
|
9282
9434
|
loadKnowledgeWorkspace: () => loadKnowledgeWorkspace,
|
|
9283
9435
|
resolveKnowledgeWorkspaceFile: () => resolveKnowledgeWorkspaceFile
|
|
9284
9436
|
});
|
|
9285
|
-
import { createHash as
|
|
9437
|
+
import { createHash as createHash6 } from "crypto";
|
|
9286
9438
|
import { execFile } from "child_process";
|
|
9287
9439
|
import { promises as fs6 } from "fs";
|
|
9288
9440
|
import path11 from "path";
|
|
9289
9441
|
import { promisify } from "util";
|
|
9290
9442
|
function hash(value) {
|
|
9291
|
-
return
|
|
9443
|
+
return createHash6("sha256").update(value).digest("hex");
|
|
9292
9444
|
}
|
|
9293
9445
|
function workspaceId(projectId, mode) {
|
|
9294
9446
|
return "workspace:" + hash(projectId + ":" + mode).slice(0, 24);
|
|
@@ -10423,14 +10575,14 @@ var init_types2 = __esm({
|
|
|
10423
10575
|
});
|
|
10424
10576
|
|
|
10425
10577
|
// src/media/asset-store.ts
|
|
10426
|
-
import { createHash as
|
|
10578
|
+
import { createHash as createHash7, randomUUID as randomUUID6 } from "crypto";
|
|
10427
10579
|
import { copyFile, lstat, mkdir as mkdir3, open, readFile as readFile3, readdir, rename as rename2, rm, stat as stat2, writeFile as writeFile3 } from "fs/promises";
|
|
10428
10580
|
import path12 from "path";
|
|
10429
10581
|
function mediaRoot(dataDir) {
|
|
10430
10582
|
return path12.resolve(dataDir, "media");
|
|
10431
10583
|
}
|
|
10432
10584
|
function projectStorageKey(projectId) {
|
|
10433
|
-
return
|
|
10585
|
+
return createHash7("sha256").update(projectId).digest("hex").slice(0, 16);
|
|
10434
10586
|
}
|
|
10435
10587
|
function validateUnderRoot(root, candidate) {
|
|
10436
10588
|
const resolved = path12.resolve(candidate);
|
|
@@ -10539,7 +10691,7 @@ async function importMediaBuffer(input) {
|
|
|
10539
10691
|
if (input.bytes.length === 0) throw new Error("Media import rejects empty payloads");
|
|
10540
10692
|
if (input.bytes.length > maxBytes) throw new Error(`Media payload is too large (${input.bytes.length} bytes; limit ${maxBytes})`);
|
|
10541
10693
|
const detected = detectMedia(input.bytes.subarray(0, 32));
|
|
10542
|
-
const sha256 =
|
|
10694
|
+
const sha256 = createHash7("sha256").update(input.bytes).digest("hex");
|
|
10543
10695
|
return importKnownMedia({
|
|
10544
10696
|
dataDir: input.dataDir,
|
|
10545
10697
|
projectId: input.projectId,
|
|
@@ -10557,7 +10709,7 @@ async function readMediaAsset(dataDir, asset, maxBytes = DEFAULT_MAX_MEDIA_BYTES
|
|
|
10557
10709
|
if (asset.byteSize > maxBytes) throw new Error(`Media asset exceeds read limit (${asset.byteSize} bytes; limit ${maxBytes})`);
|
|
10558
10710
|
const bytes = await readFile3(getMediaAssetPath(dataDir, asset));
|
|
10559
10711
|
if (bytes.length !== asset.byteSize) throw new Error(`Media asset size no longer matches metadata: ${asset.id}`);
|
|
10560
|
-
const sha256 =
|
|
10712
|
+
const sha256 = createHash7("sha256").update(bytes).digest("hex");
|
|
10561
10713
|
if (sha256 !== asset.sha256) throw new Error(`Media asset hash no longer matches metadata: ${asset.id}`);
|
|
10562
10714
|
return bytes;
|
|
10563
10715
|
}
|
|
@@ -69253,16 +69405,16 @@ var require_jwtaccess = __commonJS({
|
|
|
69253
69405
|
* @returns A string that returns the cached key.
|
|
69254
69406
|
*/
|
|
69255
69407
|
getCachedKey(url, scopes) {
|
|
69256
|
-
let
|
|
69408
|
+
let cacheKey3 = url;
|
|
69257
69409
|
if (scopes && Array.isArray(scopes) && scopes.length) {
|
|
69258
|
-
|
|
69410
|
+
cacheKey3 = url ? `${url}_${scopes.join("_")}` : `${scopes.join("_")}`;
|
|
69259
69411
|
} else if (typeof scopes === "string") {
|
|
69260
|
-
|
|
69412
|
+
cacheKey3 = url ? `${url}_${scopes}` : scopes;
|
|
69261
69413
|
}
|
|
69262
|
-
if (!
|
|
69414
|
+
if (!cacheKey3) {
|
|
69263
69415
|
throw Error("Scopes or url must be provided");
|
|
69264
69416
|
}
|
|
69265
|
-
return
|
|
69417
|
+
return cacheKey3;
|
|
69266
69418
|
}
|
|
69267
69419
|
/**
|
|
69268
69420
|
* Get a non-expired access token, after refreshing if necessary.
|
|
@@ -75808,7 +75960,7 @@ var require_websocket = __commonJS({
|
|
|
75808
75960
|
var http3 = __require("http");
|
|
75809
75961
|
var net = __require("net");
|
|
75810
75962
|
var tls = __require("tls");
|
|
75811
|
-
var { randomBytes, createHash:
|
|
75963
|
+
var { randomBytes, createHash: createHash17 } = __require("crypto");
|
|
75812
75964
|
var { Duplex, Readable: Readable2 } = __require("stream");
|
|
75813
75965
|
var { URL: URL2 } = __require("url");
|
|
75814
75966
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -76476,7 +76628,7 @@ var require_websocket = __commonJS({
|
|
|
76476
76628
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
76477
76629
|
return;
|
|
76478
76630
|
}
|
|
76479
|
-
const digest2 =
|
|
76631
|
+
const digest2 = createHash17("sha1").update(key + GUID).digest("base64");
|
|
76480
76632
|
if (res.headers["sec-websocket-accept"] !== digest2) {
|
|
76481
76633
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
76482
76634
|
return;
|
|
@@ -76848,7 +77000,7 @@ var require_websocket_server = __commonJS({
|
|
|
76848
77000
|
var EventEmitter = __require("events");
|
|
76849
77001
|
var http3 = __require("http");
|
|
76850
77002
|
var { Duplex } = __require("stream");
|
|
76851
|
-
var { createHash:
|
|
77003
|
+
var { createHash: createHash17 } = __require("crypto");
|
|
76852
77004
|
var extension3 = require_extension();
|
|
76853
77005
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
76854
77006
|
var subprotocol2 = require_subprotocol();
|
|
@@ -77155,7 +77307,7 @@ var require_websocket_server = __commonJS({
|
|
|
77155
77307
|
);
|
|
77156
77308
|
}
|
|
77157
77309
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
77158
|
-
const digest2 =
|
|
77310
|
+
const digest2 = createHash17("sha1").update(key + GUID).digest("base64");
|
|
77159
77311
|
const headers = [
|
|
77160
77312
|
"HTTP/1.1 101 Switching Protocols",
|
|
77161
77313
|
"Upgrade: websocket",
|
|
@@ -145734,9 +145886,9 @@ var init_long_term = __esm({
|
|
|
145734
145886
|
});
|
|
145735
145887
|
|
|
145736
145888
|
// src/codegraph/ids.ts
|
|
145737
|
-
import { createHash as
|
|
145889
|
+
import { createHash as createHash8 } from "crypto";
|
|
145738
145890
|
function digest(input) {
|
|
145739
|
-
return
|
|
145891
|
+
return createHash8("sha256").update(input).digest("hex").slice(0, 16);
|
|
145740
145892
|
}
|
|
145741
145893
|
function normalizeCodePath(path23) {
|
|
145742
145894
|
return path23.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+/g, "/");
|
|
@@ -146784,7 +146936,7 @@ var init_store = __esm({
|
|
|
146784
146936
|
|
|
146785
146937
|
// src/codegraph/code-state.ts
|
|
146786
146938
|
import { execFile as execFile2 } from "child_process";
|
|
146787
|
-
import { createHash as
|
|
146939
|
+
import { createHash as createHash9 } from "crypto";
|
|
146788
146940
|
import { promisify as promisify3 } from "util";
|
|
146789
146941
|
async function runGit(rootPath, args) {
|
|
146790
146942
|
try {
|
|
@@ -146813,7 +146965,7 @@ function changedPathCount(status) {
|
|
|
146813
146965
|
return count2;
|
|
146814
146966
|
}
|
|
146815
146967
|
function fingerprint(baseRevision, status) {
|
|
146816
|
-
return
|
|
146968
|
+
return createHash9("sha256").update(baseRevision ?? "").update("\0").update(status).digest("hex");
|
|
146817
146969
|
}
|
|
146818
146970
|
async function collectCodeStateSnapshot(input) {
|
|
146819
146971
|
const [revision, status] = await Promise.all([
|
|
@@ -146907,12 +147059,12 @@ var init_exclude3 = __esm({
|
|
|
146907
147059
|
});
|
|
146908
147060
|
|
|
146909
147061
|
// src/codegraph/semantic-provider.ts
|
|
146910
|
-
import { createHash as
|
|
147062
|
+
import { createHash as createHash10 } from "crypto";
|
|
146911
147063
|
import "fs";
|
|
146912
147064
|
import { resolve } from "path";
|
|
146913
147065
|
import ts from "typescript";
|
|
146914
147066
|
function hashText(value) {
|
|
146915
|
-
return
|
|
147067
|
+
return createHash10("sha256").update(value).digest("hex");
|
|
146916
147068
|
}
|
|
146917
147069
|
function canonicalPath(value) {
|
|
146918
147070
|
const normalized = resolve(value).replace(/\\/g, "/");
|
|
@@ -147257,11 +147409,11 @@ __export(lite_provider_exports, {
|
|
|
147257
147409
|
indexProjectLite: () => indexProjectLite,
|
|
147258
147410
|
refreshProjectLite: () => refreshProjectLite
|
|
147259
147411
|
});
|
|
147260
|
-
import { createHash as
|
|
147412
|
+
import { createHash as createHash11 } from "crypto";
|
|
147261
147413
|
import { existsSync as existsSync12, readdirSync as readdirSync2, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
|
|
147262
147414
|
import { join as join4, relative as relative2 } from "path";
|
|
147263
147415
|
function hashText2(text2) {
|
|
147264
|
-
return
|
|
147416
|
+
return createHash11("sha256").update(text2).digest("hex");
|
|
147265
147417
|
}
|
|
147266
147418
|
function extension2(path23) {
|
|
147267
147419
|
const index = path23.lastIndexOf(".");
|
|
@@ -147894,7 +148046,7 @@ var claim_store_exports = {};
|
|
|
147894
148046
|
__export(claim_store_exports, {
|
|
147895
148047
|
ClaimStore: () => ClaimStore
|
|
147896
148048
|
});
|
|
147897
|
-
import { createHash as
|
|
148049
|
+
import { createHash as createHash12, randomUUID as randomUUID12 } from "crypto";
|
|
147898
148050
|
function optionalText3(value) {
|
|
147899
148051
|
return typeof value === "string" && value ? value : void 0;
|
|
147900
148052
|
}
|
|
@@ -147947,7 +148099,7 @@ function rowToEvent3(row) {
|
|
|
147947
148099
|
};
|
|
147948
148100
|
}
|
|
147949
148101
|
function evidenceKey(input) {
|
|
147950
|
-
return
|
|
148102
|
+
return createHash12("sha256").update(JSON.stringify([
|
|
147951
148103
|
input.evidenceKind,
|
|
147952
148104
|
input.evidenceId,
|
|
147953
148105
|
input.relation,
|
|
@@ -148145,7 +148297,7 @@ __export(claims_exports, {
|
|
|
148145
148297
|
supersedeClaim: () => supersedeClaim,
|
|
148146
148298
|
writeClaim: () => writeClaim
|
|
148147
148299
|
});
|
|
148148
|
-
import { createHash as
|
|
148300
|
+
import { createHash as createHash13, randomUUID as randomUUID13 } from "crypto";
|
|
148149
148301
|
function compactText2(value, field) {
|
|
148150
148302
|
if (typeof value !== "string") throw new Error("Claim " + field + " must be text");
|
|
148151
148303
|
const sanitized = sanitizeCredentials(value).trim().replace(/\s+/g, " ");
|
|
@@ -148157,7 +148309,7 @@ function normalizedTerm(value) {
|
|
|
148157
148309
|
return compactText2(value, "identity").toLocaleLowerCase("en-US");
|
|
148158
148310
|
}
|
|
148159
148311
|
function hashIdentity(parts) {
|
|
148160
|
-
return
|
|
148312
|
+
return createHash13("sha256").update(parts.join(String.fromCharCode(31))).digest("hex");
|
|
148161
148313
|
}
|
|
148162
148314
|
function buildClaimIdentity(input) {
|
|
148163
148315
|
const subject = normalizedTerm(input.subject);
|
|
@@ -148398,7 +148550,7 @@ function supersedeClaim(store, input) {
|
|
|
148398
148550
|
});
|
|
148399
148551
|
}
|
|
148400
148552
|
function hashObservation(observation) {
|
|
148401
|
-
return
|
|
148553
|
+
return createHash13("sha256").update(JSON.stringify([
|
|
148402
148554
|
observation.title,
|
|
148403
148555
|
observation.narrative,
|
|
148404
148556
|
observation.facts,
|
|
@@ -148642,11 +148794,11 @@ var init_frontmatter = __esm({
|
|
|
148642
148794
|
});
|
|
148643
148795
|
|
|
148644
148796
|
// src/knowledge/markdown.ts
|
|
148645
|
-
import { createHash as
|
|
148797
|
+
import { createHash as createHash14 } from "crypto";
|
|
148646
148798
|
import { promises as fs10 } from "fs";
|
|
148647
148799
|
import path19 from "path";
|
|
148648
148800
|
function hashContent(content) {
|
|
148649
|
-
return
|
|
148801
|
+
return createHash14("sha256").update(content).digest("hex");
|
|
148650
148802
|
}
|
|
148651
148803
|
function stringField(data, key) {
|
|
148652
148804
|
const value = data[key];
|
|
@@ -148772,11 +148924,11 @@ __export(wiki_exports, {
|
|
|
148772
148924
|
lintKnowledgeWorkspace: () => lintKnowledgeWorkspace,
|
|
148773
148925
|
readKnowledgePage: () => readKnowledgePage
|
|
148774
148926
|
});
|
|
148775
|
-
import { createHash as
|
|
148927
|
+
import { createHash as createHash15 } from "crypto";
|
|
148776
148928
|
import { promises as fs11 } from "fs";
|
|
148777
148929
|
import path20 from "path";
|
|
148778
148930
|
function hash2(value) {
|
|
148779
|
-
return
|
|
148931
|
+
return createHash15("sha256").update(value).digest("hex");
|
|
148780
148932
|
}
|
|
148781
148933
|
function now() {
|
|
148782
148934
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -149633,11 +149785,11 @@ __export(workflows_exports, {
|
|
|
149633
149785
|
syncCanonicalWorkflows: () => syncCanonicalWorkflows,
|
|
149634
149786
|
writeCanonicalWorkflow: () => writeCanonicalWorkflow
|
|
149635
149787
|
});
|
|
149636
|
-
import { createHash as
|
|
149788
|
+
import { createHash as createHash16 } from "crypto";
|
|
149637
149789
|
import { promises as fs12 } from "fs";
|
|
149638
149790
|
import path21 from "path";
|
|
149639
149791
|
function hash3(value) {
|
|
149640
|
-
return
|
|
149792
|
+
return createHash16("sha256").update(value).digest("hex");
|
|
149641
149793
|
}
|
|
149642
149794
|
function now2() {
|
|
149643
149795
|
return (/* @__PURE__ */ new Date()).toISOString();
|