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
|
@@ -155,15 +155,20 @@ var init_dotenv_loader = __esm({
|
|
|
155
155
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
156
156
|
import { homedir as homedir2 } from "os";
|
|
157
157
|
import { parse as parseYamlDocument } from "yaml";
|
|
158
|
+
function cacheKey(homeDir, projectRoot) {
|
|
159
|
+
return `${homeDir}\0${projectRoot ?? ""}`;
|
|
160
|
+
}
|
|
158
161
|
function initProjectRoot(root) {
|
|
159
162
|
globalProjectRoot = root;
|
|
160
|
-
configCache.delete(root);
|
|
163
|
+
configCache.delete(cacheKey(homedir2(), root));
|
|
161
164
|
}
|
|
162
|
-
function loadYamlConfig(projectRoot) {
|
|
165
|
+
function loadYamlConfig(projectRoot, options = {}) {
|
|
166
|
+
const homeDir = options.homeDir ?? homedir2();
|
|
163
167
|
const resolvedRoot = projectRoot === null ? null : projectRoot ?? globalProjectRoot ?? null;
|
|
164
|
-
const
|
|
168
|
+
const key = cacheKey(homeDir, resolvedRoot);
|
|
169
|
+
const cached = configCache.get(key);
|
|
165
170
|
if (cached) return cached;
|
|
166
|
-
const userYaml = getGlobalYamlPath(
|
|
171
|
+
const userYaml = getGlobalYamlPath(homeDir);
|
|
167
172
|
const projectYaml = resolvedRoot ? getProjectYamlPath(resolvedRoot) : null;
|
|
168
173
|
let userConfig = {};
|
|
169
174
|
let projectConfig = {};
|
|
@@ -195,7 +200,7 @@ function loadYamlConfig(projectRoot) {
|
|
|
195
200
|
server: { ...userConfig.server, ...projectConfig.server },
|
|
196
201
|
team: { ...userConfig.team, ...projectConfig.team }
|
|
197
202
|
};
|
|
198
|
-
configCache.set(
|
|
203
|
+
configCache.set(key, merged);
|
|
199
204
|
return merged;
|
|
200
205
|
}
|
|
201
206
|
function parseYaml(content) {
|
|
@@ -384,6 +389,74 @@ var init_launch_root = __esm({
|
|
|
384
389
|
}
|
|
385
390
|
});
|
|
386
391
|
|
|
392
|
+
// src/store/sqlite-reliability.ts
|
|
393
|
+
function isTransientSqliteError(error) {
|
|
394
|
+
const code = error?.code;
|
|
395
|
+
if (typeof code === "string") {
|
|
396
|
+
return /^SQLITE_BUSY(?:_|$)/i.test(code);
|
|
397
|
+
}
|
|
398
|
+
return error instanceof Error && /\bdatabase is locked\b|\bdatabase is busy\b/i.test(error.message);
|
|
399
|
+
}
|
|
400
|
+
function isSqliteUnavailableError(error) {
|
|
401
|
+
return error instanceof SqliteUnavailableError || error instanceof Error && /SQLite is not available|better-sqlite3.*failed|node:sqlite.*failed|bun:sqlite.*failed/i.test(error.message);
|
|
402
|
+
}
|
|
403
|
+
function degradedReadError(storeName) {
|
|
404
|
+
return new Error(`[memorix] Cannot read ${storeName}: SQLite backend unavailable (memory is not loaded)`);
|
|
405
|
+
}
|
|
406
|
+
function degradedWriteError(storeName) {
|
|
407
|
+
return new Error(`[memorix] Cannot write ${storeName}: SQLite backend unavailable (degraded mode; read-only)`);
|
|
408
|
+
}
|
|
409
|
+
function formatSqliteFailure(error) {
|
|
410
|
+
return error instanceof Error && error.message ? error.message : String(error);
|
|
411
|
+
}
|
|
412
|
+
function delay(ms) {
|
|
413
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
414
|
+
}
|
|
415
|
+
async function retrySqliteBusy(operation, label) {
|
|
416
|
+
for (let attempt = 0; ; attempt++) {
|
|
417
|
+
try {
|
|
418
|
+
return await operation();
|
|
419
|
+
} catch (error) {
|
|
420
|
+
if (!isTransientSqliteError(error) || attempt >= SQLITE_BUSY_RETRY_DELAYS_MS.length) throw error;
|
|
421
|
+
const waitMs = SQLITE_BUSY_RETRY_DELAYS_MS[attempt];
|
|
422
|
+
console.error(
|
|
423
|
+
`[memorix] ${label} SQLite busy (attempt ${attempt + 1}/${SQLITE_BUSY_RETRY_DELAYS_MS.length + 1}), retrying in ${waitMs}ms`
|
|
424
|
+
);
|
|
425
|
+
await delay(waitMs);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
async function initializeSqliteStore(factory, dataDir, label) {
|
|
430
|
+
try {
|
|
431
|
+
loadBetterSqlite3();
|
|
432
|
+
} catch (error) {
|
|
433
|
+
throw new SqliteUnavailableError(error);
|
|
434
|
+
}
|
|
435
|
+
return retrySqliteBusy(async () => {
|
|
436
|
+
const store = factory();
|
|
437
|
+
await store.init(dataDir);
|
|
438
|
+
return store;
|
|
439
|
+
}, label);
|
|
440
|
+
}
|
|
441
|
+
var SQLITE_BUSY_RETRY_DELAYS_MS, SqliteUnavailableError;
|
|
442
|
+
var init_sqlite_reliability = __esm({
|
|
443
|
+
"src/store/sqlite-reliability.ts"() {
|
|
444
|
+
"use strict";
|
|
445
|
+
init_esm_shims();
|
|
446
|
+
init_sqlite_db();
|
|
447
|
+
SQLITE_BUSY_RETRY_DELAYS_MS = [50, 150, 400, 1e3, 2500];
|
|
448
|
+
SqliteUnavailableError = class extends Error {
|
|
449
|
+
code = "MEMORIX_SQLITE_UNAVAILABLE";
|
|
450
|
+
constructor(cause) {
|
|
451
|
+
super(
|
|
452
|
+
cause instanceof Error && cause.message ? cause.message : "[memorix] SQLite is unavailable (install a supported SQLite runtime)"
|
|
453
|
+
);
|
|
454
|
+
this.name = "SqliteUnavailableError";
|
|
455
|
+
}
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
});
|
|
459
|
+
|
|
387
460
|
// src/store/sqlite-fts.ts
|
|
388
461
|
function normalizeFtsToken(token) {
|
|
389
462
|
return token.replace(/"/g, '""');
|
|
@@ -397,22 +470,27 @@ function buildFtsQuery(query) {
|
|
|
397
470
|
function initializeObservationLexicalIndex(db2) {
|
|
398
471
|
const known = ftsAvailability.get(db2);
|
|
399
472
|
if (known !== void 0) return known;
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
db2.
|
|
473
|
+
let lastError;
|
|
474
|
+
for (let attempt = 1; attempt <= FTS_INIT_MAX_ATTEMPTS; attempt++) {
|
|
475
|
+
try {
|
|
476
|
+
db2.exec(CREATE_OBSERVATION_FTS);
|
|
477
|
+
const observationCount = Number(db2.prepare("SELECT COUNT(*) AS count FROM observations").get()?.count ?? 0);
|
|
478
|
+
const indexedCount = Number(db2.prepare(`SELECT COUNT(*) AS count FROM ${FTS_TABLE}`).get()?.count ?? 0);
|
|
479
|
+
if (observationCount !== indexedCount) {
|
|
480
|
+
db2.exec(`INSERT INTO ${FTS_TABLE}(${FTS_TABLE}) VALUES ('rebuild')`);
|
|
481
|
+
}
|
|
482
|
+
ftsAvailability.set(db2, true);
|
|
483
|
+
return true;
|
|
484
|
+
} catch (error) {
|
|
485
|
+
lastError = error;
|
|
486
|
+
if (!isTransientSqliteError(error) || attempt === FTS_INIT_MAX_ATTEMPTS) break;
|
|
406
487
|
}
|
|
407
|
-
ftsAvailability.set(db2, true);
|
|
408
|
-
return true;
|
|
409
|
-
} catch (error) {
|
|
410
|
-
ftsAvailability.set(db2, false);
|
|
411
|
-
console.warn(
|
|
412
|
-
`[memorix] SQLite FTS5 unavailable; using the existing search fallback: ${error instanceof Error ? error.message : String(error)}`
|
|
413
|
-
);
|
|
414
|
-
return false;
|
|
415
488
|
}
|
|
489
|
+
ftsAvailability.set(db2, false);
|
|
490
|
+
console.warn(
|
|
491
|
+
`[memorix] SQLite FTS5 unavailable; using the existing search fallback: ${lastError instanceof Error ? lastError.message : String(lastError)}`
|
|
492
|
+
);
|
|
493
|
+
return false;
|
|
416
494
|
}
|
|
417
495
|
function isObservationLexicalIndexEnabled(db2) {
|
|
418
496
|
return ftsAvailability.get(db2) === true;
|
|
@@ -466,11 +544,12 @@ function searchObservationLexically(db2, options) {
|
|
|
466
544
|
score: Math.max(0, Number(row.lexical_score ?? 0))
|
|
467
545
|
}));
|
|
468
546
|
}
|
|
469
|
-
var ftsAvailability, FTS_TABLE, CREATE_OBSERVATION_FTS;
|
|
547
|
+
var ftsAvailability, FTS_TABLE, CREATE_OBSERVATION_FTS, FTS_INIT_MAX_ATTEMPTS;
|
|
470
548
|
var init_sqlite_fts = __esm({
|
|
471
549
|
"src/store/sqlite-fts.ts"() {
|
|
472
550
|
"use strict";
|
|
473
551
|
init_esm_shims();
|
|
552
|
+
init_sqlite_reliability();
|
|
474
553
|
ftsAvailability = /* @__PURE__ */ new WeakMap();
|
|
475
554
|
FTS_TABLE = "observations_fts";
|
|
476
555
|
CREATE_OBSERVATION_FTS = `
|
|
@@ -504,6 +583,7 @@ CREATE TRIGGER IF NOT EXISTS observations_fts_au AFTER UPDATE ON observations BE
|
|
|
504
583
|
VALUES (new.id, new.entityName, new.title, new.narrative, new.facts, new.filesModified, new.concepts, new.attachments);
|
|
505
584
|
END;
|
|
506
585
|
`;
|
|
586
|
+
FTS_INIT_MAX_ATTEMPTS = 3;
|
|
507
587
|
}
|
|
508
588
|
});
|
|
509
589
|
|
|
@@ -542,11 +622,21 @@ function applySchemaMigrations(db2) {
|
|
|
542
622
|
apply();
|
|
543
623
|
}
|
|
544
624
|
}
|
|
625
|
+
function normalizeDataDir(dataDir) {
|
|
626
|
+
return path3.resolve(dataDir);
|
|
627
|
+
}
|
|
628
|
+
function touchDatabase(normalized, db2) {
|
|
629
|
+
_dbCache.delete(normalized);
|
|
630
|
+
_dbCache.set(normalized, db2);
|
|
631
|
+
}
|
|
545
632
|
function getDatabase(dataDir) {
|
|
546
|
-
const normalized =
|
|
633
|
+
const normalized = normalizeDataDir(dataDir);
|
|
547
634
|
assertNotHomeDataDir(normalized);
|
|
548
635
|
const existing = _dbCache.get(normalized);
|
|
549
|
-
if (existing)
|
|
636
|
+
if (existing) {
|
|
637
|
+
touchDatabase(normalized, existing);
|
|
638
|
+
return existing;
|
|
639
|
+
}
|
|
550
640
|
loadBetterSqlite3();
|
|
551
641
|
fs.mkdirSync(dataDir, { recursive: true });
|
|
552
642
|
const dbPath = path3.join(dataDir, "memorix.db");
|
|
@@ -576,6 +666,8 @@ function getDatabase(dataDir) {
|
|
|
576
666
|
db2.exec(CREATE_MAINTENANCE_JOBS_TABLE);
|
|
577
667
|
db2.exec(CREATE_MAINTENANCE_TARGETS_TABLE);
|
|
578
668
|
db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
|
|
669
|
+
db2.exec(CREATE_TASK_CONTINUITY_EVENTS_TABLE);
|
|
670
|
+
db2.exec(CREATE_AGENT_EFFECTS_TABLE);
|
|
579
671
|
try {
|
|
580
672
|
db2.exec(`ALTER TABLE mini_skills ADD COLUMN sourceSnapshot TEXT NOT NULL DEFAULT ''`);
|
|
581
673
|
} catch {
|
|
@@ -614,7 +706,7 @@ function getDatabase(dataDir) {
|
|
|
614
706
|
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('storage_generation', '0')`).run();
|
|
615
707
|
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('next_id', '1')`).run();
|
|
616
708
|
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('mini_skills_generation', '0')`).run();
|
|
617
|
-
|
|
709
|
+
touchDatabase(normalized, db2);
|
|
618
710
|
return db2;
|
|
619
711
|
} catch (error) {
|
|
620
712
|
try {
|
|
@@ -632,8 +724,9 @@ function closeAllDatabases() {
|
|
|
632
724
|
}
|
|
633
725
|
_dbCache.delete(key);
|
|
634
726
|
}
|
|
727
|
+
_dbLeases.clear();
|
|
635
728
|
}
|
|
636
|
-
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;
|
|
729
|
+
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;
|
|
637
730
|
var init_sqlite_db = __esm({
|
|
638
731
|
"src/store/sqlite-db.ts"() {
|
|
639
732
|
"use strict";
|
|
@@ -1350,6 +1443,43 @@ CREATE TABLE IF NOT EXISTS memory_feedback_events (
|
|
|
1350
1443
|
delta REAL NOT NULL DEFAULT 0,
|
|
1351
1444
|
observed_at TEXT NOT NULL
|
|
1352
1445
|
);
|
|
1446
|
+
`;
|
|
1447
|
+
CREATE_TASK_CONTINUITY_EVENTS_TABLE = `
|
|
1448
|
+
CREATE TABLE IF NOT EXISTS task_continuity_events (
|
|
1449
|
+
id TEXT PRIMARY KEY,
|
|
1450
|
+
project_id TEXT NOT NULL,
|
|
1451
|
+
task_id TEXT NOT NULL,
|
|
1452
|
+
task TEXT NOT NULL,
|
|
1453
|
+
kind TEXT NOT NULL,
|
|
1454
|
+
content TEXT NOT NULL,
|
|
1455
|
+
item_status TEXT,
|
|
1456
|
+
source_ref TEXT,
|
|
1457
|
+
evidence_json TEXT NOT NULL DEFAULT '[]',
|
|
1458
|
+
actor TEXT,
|
|
1459
|
+
created_at TEXT NOT NULL,
|
|
1460
|
+
event_key TEXT,
|
|
1461
|
+
item_key TEXT,
|
|
1462
|
+
supersedes_id TEXT
|
|
1463
|
+
);
|
|
1464
|
+
`;
|
|
1465
|
+
CREATE_AGENT_EFFECTS_TABLE = `
|
|
1466
|
+
CREATE TABLE IF NOT EXISTS agent_effects (
|
|
1467
|
+
id TEXT PRIMARY KEY,
|
|
1468
|
+
pipeline_id TEXT NOT NULL,
|
|
1469
|
+
task_id TEXT NOT NULL,
|
|
1470
|
+
attempt INTEGER NOT NULL,
|
|
1471
|
+
effect_key TEXT NOT NULL,
|
|
1472
|
+
tool TEXT NOT NULL,
|
|
1473
|
+
risk_tier TEXT NOT NULL,
|
|
1474
|
+
replay_policy TEXT NOT NULL,
|
|
1475
|
+
status TEXT NOT NULL,
|
|
1476
|
+
call_id TEXT,
|
|
1477
|
+
idempotency_key TEXT NOT NULL,
|
|
1478
|
+
input_fingerprint TEXT,
|
|
1479
|
+
detail TEXT,
|
|
1480
|
+
started_at INTEGER NOT NULL,
|
|
1481
|
+
finished_at INTEGER
|
|
1482
|
+
);
|
|
1353
1483
|
`;
|
|
1354
1484
|
CREATE_MCP_BINDINGS_TABLE = `
|
|
1355
1485
|
CREATE TABLE IF NOT EXISTS mcp_bindings (
|
|
@@ -1428,7 +1558,18 @@ CREATE INDEX IF NOT EXISTS idx_evidence_cards_candidate ON evidence_cards(projec
|
|
|
1428
1558
|
CREATE INDEX IF NOT EXISTS idx_evidence_card_events_card ON evidence_card_events(card_id, created_at);
|
|
1429
1559
|
CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC);
|
|
1430
1560
|
CREATE INDEX IF NOT EXISTS idx_memory_feedback_events_candidate ON memory_feedback_events(project_id, candidate_kind, candidate_id, observed_at DESC);
|
|
1561
|
+
CREATE INDEX IF NOT EXISTS idx_task_continuity_project_task ON task_continuity_events(project_id, task_id, created_at ASC);
|
|
1562
|
+
CREATE INDEX IF NOT EXISTS idx_task_continuity_project_recent ON task_continuity_events(project_id, created_at DESC);
|
|
1563
|
+
CREATE INDEX IF NOT EXISTS idx_task_continuity_item ON task_continuity_events(project_id, task_id, kind, item_key, created_at DESC);
|
|
1564
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_task_continuity_event_key
|
|
1565
|
+
ON task_continuity_events(project_id, task_id, event_key)
|
|
1566
|
+
WHERE event_key IS NOT NULL;
|
|
1567
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_effect_identity
|
|
1568
|
+
ON agent_effects(pipeline_id, task_id, attempt, effect_key);
|
|
1569
|
+
CREATE INDEX IF NOT EXISTS idx_agent_effect_pipeline ON agent_effects(pipeline_id, started_at ASC);
|
|
1431
1570
|
CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC);
|
|
1571
|
+
CREATE INDEX IF NOT EXISTS idx_mcp_bindings_root ON mcp_bindings(project_root, last_used_at DESC);
|
|
1572
|
+
CREATE INDEX IF NOT EXISTS idx_mcp_bindings_expiry ON mcp_bindings(expires_at);
|
|
1432
1573
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
|
|
1433
1574
|
ON maintenance_jobs(project_id, kind, dedupe_key)
|
|
1434
1575
|
WHERE status IN ('pending', 'running', 'retry');
|
|
@@ -1599,6 +1740,8 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
|
|
|
1599
1740
|
db2.exec("CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC)");
|
|
1600
1741
|
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)");
|
|
1601
1742
|
db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC)");
|
|
1743
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_root ON mcp_bindings(project_root, last_used_at DESC)");
|
|
1744
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_expiry ON mcp_bindings(expires_at)");
|
|
1602
1745
|
}
|
|
1603
1746
|
},
|
|
1604
1747
|
{
|
|
@@ -1609,9 +1752,22 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
|
|
|
1609
1752
|
addColumnIfMissing(db2, "code_symbols", "source", "source TEXT");
|
|
1610
1753
|
addColumnIfMissing(db2, "code_edges", "source", "source TEXT");
|
|
1611
1754
|
}
|
|
1755
|
+
},
|
|
1756
|
+
{
|
|
1757
|
+
id: "1.9-continuity-v2",
|
|
1758
|
+
apply: (db2) => {
|
|
1759
|
+
addColumnIfMissing(db2, "task_continuity_events", "event_key", "event_key TEXT");
|
|
1760
|
+
addColumnIfMissing(db2, "task_continuity_events", "item_key", "item_key TEXT");
|
|
1761
|
+
addColumnIfMissing(db2, "task_continuity_events", "supersedes_id", "supersedes_id TEXT");
|
|
1762
|
+
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)");
|
|
1763
|
+
db2.exec(`CREATE UNIQUE INDEX IF NOT EXISTS idx_task_continuity_event_key
|
|
1764
|
+
ON task_continuity_events(project_id, task_id, event_key)
|
|
1765
|
+
WHERE event_key IS NOT NULL`);
|
|
1766
|
+
}
|
|
1612
1767
|
}
|
|
1613
1768
|
];
|
|
1614
1769
|
_dbCache = /* @__PURE__ */ new Map();
|
|
1770
|
+
_dbLeases = /* @__PURE__ */ new Map();
|
|
1615
1771
|
}
|
|
1616
1772
|
});
|
|
1617
1773
|
|
|
@@ -2127,6 +2283,7 @@ var init_media_store = __esm({
|
|
|
2127
2283
|
// src/runtime/maintenance-jobs.ts
|
|
2128
2284
|
var maintenance_jobs_exports = {};
|
|
2129
2285
|
__export(maintenance_jobs_exports, {
|
|
2286
|
+
DEFAULT_FAILED_HISTORY_RETENTION_MS: () => DEFAULT_FAILED_HISTORY_RETENTION_MS,
|
|
2130
2287
|
MAINTENANCE_JOB_KINDS: () => MAINTENANCE_JOB_KINDS,
|
|
2131
2288
|
MaintenanceJobStore: () => MaintenanceJobStore,
|
|
2132
2289
|
MaintenanceJobWorker: () => MaintenanceJobWorker,
|
|
@@ -2176,7 +2333,7 @@ function normalizedKinds(kinds) {
|
|
|
2176
2333
|
function getMaintenanceRetryDelayMs(attempts) {
|
|
2177
2334
|
return Math.min(6e4, 1e3 * 2 ** Math.max(0, attempts - 1));
|
|
2178
2335
|
}
|
|
2179
|
-
var MAINTENANCE_JOB_KINDS, DEFAULT_MAX_ATTEMPTS, DEFAULT_LEASE_MS, DEFAULT_POLL_INTERVAL_MS, MAX_ERROR_LENGTH, DEFAULT_COMPLETED_HISTORY_RETENTION_MS, MaintenanceJobStore, MaintenanceJobWorker;
|
|
2336
|
+
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;
|
|
2180
2337
|
var init_maintenance_jobs = __esm({
|
|
2181
2338
|
"src/runtime/maintenance-jobs.ts"() {
|
|
2182
2339
|
"use strict";
|
|
@@ -2203,6 +2360,7 @@ var init_maintenance_jobs = __esm({
|
|
|
2203
2360
|
DEFAULT_POLL_INTERVAL_MS = 2e3;
|
|
2204
2361
|
MAX_ERROR_LENGTH = 1e3;
|
|
2205
2362
|
DEFAULT_COMPLETED_HISTORY_RETENTION_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
2363
|
+
DEFAULT_FAILED_HISTORY_RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
2206
2364
|
MaintenanceJobStore = class {
|
|
2207
2365
|
db;
|
|
2208
2366
|
constructor(dataDir) {
|
|
@@ -2329,18 +2487,21 @@ var init_maintenance_jobs = __esm({
|
|
|
2329
2487
|
}
|
|
2330
2488
|
/**
|
|
2331
2489
|
* Completed jobs are useful recent operator history, not permanent data.
|
|
2332
|
-
* Failed
|
|
2333
|
-
*
|
|
2490
|
+
* Failed diagnostics are retained longer, but are still bounded so a
|
|
2491
|
+
* permanently failing job kind cannot grow the database forever.
|
|
2334
2492
|
*/
|
|
2335
2493
|
pruneCompletedHistory(options = {}) {
|
|
2336
2494
|
const now3 = options.now ?? Date.now();
|
|
2337
2495
|
const maxAgeMs = Number.isFinite(options.maxAgeMs) ? Math.max(0, Math.floor(options.maxAgeMs)) : DEFAULT_COMPLETED_HISTORY_RETENTION_MS;
|
|
2496
|
+
const failedMaxAgeMs = Number.isFinite(options.failedMaxAgeMs) ? Math.max(0, Math.floor(options.failedMaxAgeMs)) : DEFAULT_FAILED_HISTORY_RETENTION_MS;
|
|
2338
2497
|
const result = this.db.prepare(`
|
|
2339
2498
|
DELETE FROM maintenance_jobs
|
|
2340
|
-
WHERE status = 'completed'
|
|
2499
|
+
WHERE (status = 'completed'
|
|
2341
2500
|
AND completed_at IS NOT NULL
|
|
2342
|
-
AND completed_at < ?
|
|
2343
|
-
|
|
2501
|
+
AND completed_at < ?)
|
|
2502
|
+
OR (status = 'failed'
|
|
2503
|
+
AND updated_at < ?)
|
|
2504
|
+
`).run(now3 - maxAgeMs, now3 - failedMaxAgeMs);
|
|
2344
2505
|
return Number(result.changes ?? 0);
|
|
2345
2506
|
}
|
|
2346
2507
|
claimNext(options) {
|
|
@@ -2628,74 +2789,6 @@ var init_types = __esm({
|
|
|
2628
2789
|
}
|
|
2629
2790
|
});
|
|
2630
2791
|
|
|
2631
|
-
// src/store/sqlite-reliability.ts
|
|
2632
|
-
function isTransientSqliteError(error) {
|
|
2633
|
-
const code = error?.code;
|
|
2634
|
-
if (typeof code === "string") {
|
|
2635
|
-
return /^SQLITE_BUSY(?:_|$)/i.test(code);
|
|
2636
|
-
}
|
|
2637
|
-
return error instanceof Error && /\bdatabase is locked\b|\bdatabase is busy\b/i.test(error.message);
|
|
2638
|
-
}
|
|
2639
|
-
function isSqliteUnavailableError(error) {
|
|
2640
|
-
return error instanceof SqliteUnavailableError || error instanceof Error && /SQLite is not available|better-sqlite3.*failed|node:sqlite.*failed|bun:sqlite.*failed/i.test(error.message);
|
|
2641
|
-
}
|
|
2642
|
-
function degradedReadError(storeName) {
|
|
2643
|
-
return new Error(`[memorix] Cannot read ${storeName}: SQLite backend unavailable (memory is not loaded)`);
|
|
2644
|
-
}
|
|
2645
|
-
function degradedWriteError(storeName) {
|
|
2646
|
-
return new Error(`[memorix] Cannot write ${storeName}: SQLite backend unavailable (degraded mode; read-only)`);
|
|
2647
|
-
}
|
|
2648
|
-
function formatSqliteFailure(error) {
|
|
2649
|
-
return error instanceof Error && error.message ? error.message : String(error);
|
|
2650
|
-
}
|
|
2651
|
-
function delay(ms) {
|
|
2652
|
-
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
2653
|
-
}
|
|
2654
|
-
async function retrySqliteBusy(operation, label) {
|
|
2655
|
-
for (let attempt = 0; ; attempt++) {
|
|
2656
|
-
try {
|
|
2657
|
-
return await operation();
|
|
2658
|
-
} catch (error) {
|
|
2659
|
-
if (!isTransientSqliteError(error) || attempt >= SQLITE_BUSY_RETRY_DELAYS_MS.length) throw error;
|
|
2660
|
-
const waitMs = SQLITE_BUSY_RETRY_DELAYS_MS[attempt];
|
|
2661
|
-
console.error(
|
|
2662
|
-
`[memorix] ${label} SQLite busy (attempt ${attempt + 1}/${SQLITE_BUSY_RETRY_DELAYS_MS.length + 1}), retrying in ${waitMs}ms`
|
|
2663
|
-
);
|
|
2664
|
-
await delay(waitMs);
|
|
2665
|
-
}
|
|
2666
|
-
}
|
|
2667
|
-
}
|
|
2668
|
-
async function initializeSqliteStore(factory, dataDir, label) {
|
|
2669
|
-
try {
|
|
2670
|
-
loadBetterSqlite3();
|
|
2671
|
-
} catch (error) {
|
|
2672
|
-
throw new SqliteUnavailableError(error);
|
|
2673
|
-
}
|
|
2674
|
-
return retrySqliteBusy(async () => {
|
|
2675
|
-
const store = factory();
|
|
2676
|
-
await store.init(dataDir);
|
|
2677
|
-
return store;
|
|
2678
|
-
}, label);
|
|
2679
|
-
}
|
|
2680
|
-
var SQLITE_BUSY_RETRY_DELAYS_MS, SqliteUnavailableError;
|
|
2681
|
-
var init_sqlite_reliability = __esm({
|
|
2682
|
-
"src/store/sqlite-reliability.ts"() {
|
|
2683
|
-
"use strict";
|
|
2684
|
-
init_esm_shims();
|
|
2685
|
-
init_sqlite_db();
|
|
2686
|
-
SQLITE_BUSY_RETRY_DELAYS_MS = [50, 150, 400, 1e3, 2500];
|
|
2687
|
-
SqliteUnavailableError = class extends Error {
|
|
2688
|
-
code = "MEMORIX_SQLITE_UNAVAILABLE";
|
|
2689
|
-
constructor(cause) {
|
|
2690
|
-
super(
|
|
2691
|
-
cause instanceof Error && cause.message ? cause.message : "[memorix] SQLite is unavailable (install a supported SQLite runtime)"
|
|
2692
|
-
);
|
|
2693
|
-
this.name = "SqliteUnavailableError";
|
|
2694
|
-
}
|
|
2695
|
-
};
|
|
2696
|
-
}
|
|
2697
|
-
});
|
|
2698
|
-
|
|
2699
2792
|
// src/store/file-lock.ts
|
|
2700
2793
|
import { promises as fs2 } from "fs";
|
|
2701
2794
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
@@ -3114,9 +3207,9 @@ var init_detector = __esm({
|
|
|
3114
3207
|
// src/config/legacy-loader.ts
|
|
3115
3208
|
import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
|
|
3116
3209
|
import { homedir as homedir3 } from "os";
|
|
3117
|
-
function loadFileConfig() {
|
|
3210
|
+
function loadFileConfig(homeDir = homedir3()) {
|
|
3118
3211
|
if (cachedConfig !== null) return cachedConfig;
|
|
3119
|
-
const configPath = getLegacyConfigJsonPath(
|
|
3212
|
+
const configPath = getLegacyConfigJsonPath(homeDir);
|
|
3120
3213
|
try {
|
|
3121
3214
|
if (existsSync5(configPath)) {
|
|
3122
3215
|
cachedConfig = JSON.parse(readFileSync5(configPath, "utf-8"));
|
|
@@ -3146,15 +3239,15 @@ import { homedir as homedir4 } from "os";
|
|
|
3146
3239
|
function loadTomlConfig(options = {}) {
|
|
3147
3240
|
const homeDir = options.homeDir ?? homedir4();
|
|
3148
3241
|
const projectRoot = options.projectRoot ?? null;
|
|
3149
|
-
const
|
|
3150
|
-
const cached = configCache2.get(
|
|
3242
|
+
const cacheKey3 = `${homeDir}\0${projectRoot ?? ""}`;
|
|
3243
|
+
const cached = configCache2.get(cacheKey3);
|
|
3151
3244
|
if (cached) return cached;
|
|
3152
3245
|
const userToml = getGlobalConfigTomlPath(homeDir);
|
|
3153
3246
|
const projectToml = projectRoot ? getProjectConfigTomlPath(projectRoot) : null;
|
|
3154
3247
|
const userConfig = existsSync6(userToml) ? parseTomlConfig(readFileSync6(userToml, "utf8"), userToml) : {};
|
|
3155
3248
|
const projectConfig = projectToml && existsSync6(projectToml) ? parseTomlConfig(readFileSync6(projectToml, "utf8"), projectToml) : {};
|
|
3156
3249
|
const merged = mergeTomlConfig(userConfig, projectConfig);
|
|
3157
|
-
configCache2.set(
|
|
3250
|
+
configCache2.set(cacheKey3, merged);
|
|
3158
3251
|
return merged;
|
|
3159
3252
|
}
|
|
3160
3253
|
function mergeTomlConfig(base, override) {
|
|
@@ -3275,8 +3368,8 @@ function getResolvedConfig(options = {}) {
|
|
|
3275
3368
|
const projectRoot = options.projectRoot === void 0 ? detectProject()?.rootPath ?? null : options.projectRoot;
|
|
3276
3369
|
loadDotenv(projectRoot === null ? void 0 : projectRoot ?? void 0, { userHomeDir: homeDir });
|
|
3277
3370
|
const toml = loadTomlConfig({ projectRoot: projectRoot ?? null, homeDir });
|
|
3278
|
-
const yaml = loadYamlConfig(projectRoot ?? null);
|
|
3279
|
-
const legacy = loadFileConfig();
|
|
3371
|
+
const yaml = loadYamlConfig(projectRoot ?? null, { homeDir });
|
|
3372
|
+
const legacy = loadFileConfig(homeDir);
|
|
3280
3373
|
const embeddingBaseUrl = first(process.env.MEMORIX_EMBEDDING_BASE_URL, toml.embedding?.base_url, yaml.embedding?.baseUrl, legacy.embeddingApi?.baseUrl);
|
|
3281
3374
|
const openRouterEmbeddingApiKey = isOpenRouterUrl(embeddingBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
|
|
3282
3375
|
const memoryLlmProvider = first(
|
|
@@ -3298,15 +3391,17 @@ function getResolvedConfig(options = {}) {
|
|
|
3298
3391
|
legacy.llm?.baseUrl
|
|
3299
3392
|
);
|
|
3300
3393
|
const openRouterMemoryLlmApiKey = isOpenRouterMemoryLane(memoryLlmProvider, memoryLlmBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
|
|
3394
|
+
const isAtlasCloud = memoryLlmProvider === "atlascloud";
|
|
3301
3395
|
const memoryLlmApiKey = first(
|
|
3302
3396
|
process.env.MEMORIX_LLM_API_KEY,
|
|
3303
3397
|
process.env.MEMORIX_API_KEY,
|
|
3304
3398
|
toml.memory?.llm?.api_key,
|
|
3305
3399
|
yaml.llm?.apiKey,
|
|
3306
3400
|
legacy.llm?.apiKey,
|
|
3307
|
-
|
|
3308
|
-
process.env.
|
|
3309
|
-
|
|
3401
|
+
// Never borrow another provider's credentials for the Atlas Cloud preset.
|
|
3402
|
+
isAtlasCloud ? process.env.ATLASCLOUD_API_KEY : process.env.OPENAI_API_KEY,
|
|
3403
|
+
isAtlasCloud ? void 0 : process.env.ANTHROPIC_API_KEY,
|
|
3404
|
+
isAtlasCloud ? void 0 : openRouterMemoryLlmApiKey
|
|
3310
3405
|
);
|
|
3311
3406
|
const resolved = {
|
|
3312
3407
|
agent: {
|
|
@@ -3485,7 +3580,8 @@ function getEnvSourceNames() {
|
|
|
3485
3580
|
"MEMORIX_CODEGRAPH_EXTERNAL_CONTEXT",
|
|
3486
3581
|
"MEMORIX_CODEGRAPH_EXTERNAL_COMMAND",
|
|
3487
3582
|
"MEMORIX_CODEGRAPH_EXTERNAL_TIMEOUT_MS",
|
|
3488
|
-
"OPENROUTER_API_KEY"
|
|
3583
|
+
"OPENROUTER_API_KEY",
|
|
3584
|
+
"ATLASCLOUD_API_KEY"
|
|
3489
3585
|
].filter((name) => process.env[name]);
|
|
3490
3586
|
}
|
|
3491
3587
|
function isOpenRouterUrl(value) {
|
|
@@ -3704,12 +3800,45 @@ function textHash(text2) {
|
|
|
3704
3800
|
async function loadDiskCache() {
|
|
3705
3801
|
try {
|
|
3706
3802
|
const raw = await readFile(CACHE_FILE, "utf-8");
|
|
3803
|
+
if (Buffer.byteLength(raw, "utf8") > MAX_CACHE_FILE_BYTES) {
|
|
3804
|
+
console.error("[memorix] FastEmbed cache exceeds the disk load limit; starting with an empty cache");
|
|
3805
|
+
return;
|
|
3806
|
+
}
|
|
3707
3807
|
const entries = JSON.parse(raw);
|
|
3708
|
-
|
|
3709
|
-
|
|
3808
|
+
if (!Array.isArray(entries)) return;
|
|
3809
|
+
for (const entry of entries) {
|
|
3810
|
+
if (!Array.isArray(entry) || typeof entry[0] !== "string" || !isVector(entry[1])) continue;
|
|
3811
|
+
cacheSet(entry[0], entry[1], false);
|
|
3812
|
+
}
|
|
3813
|
+
console.error(`[memorix] Loaded ${cache.size} cached embeddings from disk`);
|
|
3710
3814
|
} catch {
|
|
3711
3815
|
}
|
|
3712
3816
|
}
|
|
3817
|
+
function isVector(value) {
|
|
3818
|
+
return Array.isArray(value) && value.every((entry) => typeof entry === "number");
|
|
3819
|
+
}
|
|
3820
|
+
function maxCachePayloadBytes() {
|
|
3821
|
+
const raw = Number.parseInt(process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES ?? "", 10);
|
|
3822
|
+
return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_CACHE_PAYLOAD_BYTES;
|
|
3823
|
+
}
|
|
3824
|
+
function cacheSet(hash4, value, markDirty = true) {
|
|
3825
|
+
const incomingBytes = value.length * 8;
|
|
3826
|
+
if (incomingBytes > maxCachePayloadBytes()) return;
|
|
3827
|
+
const existing = cache.get(hash4);
|
|
3828
|
+
if (existing) cachePayloadBytes -= existing.length * 8;
|
|
3829
|
+
else {
|
|
3830
|
+
while (cache.size >= MAX_CACHE_SIZE || cachePayloadBytes + incomingBytes > maxCachePayloadBytes()) {
|
|
3831
|
+
const firstKey = cache.keys().next().value;
|
|
3832
|
+
if (firstKey === void 0) break;
|
|
3833
|
+
const old = cache.get(firstKey);
|
|
3834
|
+
cache.delete(firstKey);
|
|
3835
|
+
if (old) cachePayloadBytes -= old.length * 8;
|
|
3836
|
+
}
|
|
3837
|
+
}
|
|
3838
|
+
cache.set(hash4, value);
|
|
3839
|
+
cachePayloadBytes += incomingBytes;
|
|
3840
|
+
if (markDirty) diskCacheDirty = true;
|
|
3841
|
+
}
|
|
3713
3842
|
async function saveDiskCache() {
|
|
3714
3843
|
if (!diskCacheDirty) return;
|
|
3715
3844
|
try {
|
|
@@ -3720,7 +3849,7 @@ async function saveDiskCache() {
|
|
|
3720
3849
|
} catch {
|
|
3721
3850
|
}
|
|
3722
3851
|
}
|
|
3723
|
-
var CACHE_DIR, CACHE_FILE, cache, MAX_CACHE_SIZE, diskCacheDirty, FastEmbedProvider;
|
|
3852
|
+
var CACHE_DIR, CACHE_FILE, cache, MAX_CACHE_SIZE, DEFAULT_CACHE_PAYLOAD_BYTES, MAX_CACHE_FILE_BYTES, cachePayloadBytes, diskCacheDirty, FastEmbedProvider;
|
|
3724
3853
|
var init_fastembed_provider = __esm({
|
|
3725
3854
|
"src/embedding/fastembed-provider.ts"() {
|
|
3726
3855
|
"use strict";
|
|
@@ -3730,6 +3859,9 @@ var init_fastembed_provider = __esm({
|
|
|
3730
3859
|
CACHE_FILE = join2(CACHE_DIR, ".embedding-cache.json");
|
|
3731
3860
|
cache = /* @__PURE__ */ new Map();
|
|
3732
3861
|
MAX_CACHE_SIZE = 5e3;
|
|
3862
|
+
DEFAULT_CACHE_PAYLOAD_BYTES = 64 * 1024 * 1024;
|
|
3863
|
+
MAX_CACHE_FILE_BYTES = 128 * 1024 * 1024;
|
|
3864
|
+
cachePayloadBytes = 0;
|
|
3733
3865
|
diskCacheDirty = false;
|
|
3734
3866
|
FastEmbedProvider = class _FastEmbedProvider {
|
|
3735
3867
|
name = "fastembed-bge-small";
|
|
@@ -3771,7 +3903,7 @@ var init_fastembed_provider = __esm({
|
|
|
3771
3903
|
if (result.length !== this.dimensions) {
|
|
3772
3904
|
throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);
|
|
3773
3905
|
}
|
|
3774
|
-
|
|
3906
|
+
cacheSet(hash4, result);
|
|
3775
3907
|
return result;
|
|
3776
3908
|
}
|
|
3777
3909
|
async embedBatch(texts) {
|
|
@@ -3796,7 +3928,7 @@ var init_fastembed_provider = __esm({
|
|
|
3796
3928
|
const originalIdx = uncachedIndices[batchIdx];
|
|
3797
3929
|
const plain = Array.from(vec);
|
|
3798
3930
|
results[originalIdx] = plain;
|
|
3799
|
-
|
|
3931
|
+
cacheSet(textHash(uncachedTexts[batchIdx]), plain);
|
|
3800
3932
|
batchIdx++;
|
|
3801
3933
|
}
|
|
3802
3934
|
}
|
|
@@ -3804,14 +3936,6 @@ var init_fastembed_provider = __esm({
|
|
|
3804
3936
|
}
|
|
3805
3937
|
return results;
|
|
3806
3938
|
}
|
|
3807
|
-
cacheSet(hash4, value) {
|
|
3808
|
-
if (cache.size >= MAX_CACHE_SIZE) {
|
|
3809
|
-
const firstKey = cache.keys().next().value;
|
|
3810
|
-
if (firstKey !== void 0) cache.delete(firstKey);
|
|
3811
|
-
}
|
|
3812
|
-
cache.set(hash4, value);
|
|
3813
|
-
diskCacheDirty = true;
|
|
3814
|
-
}
|
|
3815
3939
|
};
|
|
3816
3940
|
}
|
|
3817
3941
|
});
|
|
@@ -3821,7 +3945,15 @@ var transformers_provider_exports = {};
|
|
|
3821
3945
|
__export(transformers_provider_exports, {
|
|
3822
3946
|
TransformersProvider: () => TransformersProvider
|
|
3823
3947
|
});
|
|
3824
|
-
|
|
3948
|
+
import { createHash as createHash2 } from "crypto";
|
|
3949
|
+
function cacheKey2(text2) {
|
|
3950
|
+
return createHash2("sha256").update(text2).digest("hex");
|
|
3951
|
+
}
|
|
3952
|
+
function maxCachePayloadBytes2() {
|
|
3953
|
+
const raw = Number.parseInt(process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES ?? "", 10);
|
|
3954
|
+
return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_CACHE_PAYLOAD_BYTES2;
|
|
3955
|
+
}
|
|
3956
|
+
var cache2, MAX_CACHE_SIZE2, DEFAULT_CACHE_PAYLOAD_BYTES2, cachePayloadBytes2, TransformersProvider;
|
|
3825
3957
|
var init_transformers_provider = __esm({
|
|
3826
3958
|
"src/embedding/transformers-provider.ts"() {
|
|
3827
3959
|
"use strict";
|
|
@@ -3829,6 +3961,8 @@ var init_transformers_provider = __esm({
|
|
|
3829
3961
|
init_provider();
|
|
3830
3962
|
cache2 = /* @__PURE__ */ new Map();
|
|
3831
3963
|
MAX_CACHE_SIZE2 = 5e3;
|
|
3964
|
+
DEFAULT_CACHE_PAYLOAD_BYTES2 = 64 * 1024 * 1024;
|
|
3965
|
+
cachePayloadBytes2 = 0;
|
|
3832
3966
|
TransformersProvider = class _TransformersProvider {
|
|
3833
3967
|
name = "transformers-minilm";
|
|
3834
3968
|
dimensions = 384;
|
|
@@ -3863,7 +3997,7 @@ var init_transformers_provider = __esm({
|
|
|
3863
3997
|
return Promise.all(inputs.map((input) => this.embedInput(input, options)));
|
|
3864
3998
|
}
|
|
3865
3999
|
async embed(text2) {
|
|
3866
|
-
const cached = cache2.get(text2);
|
|
4000
|
+
const cached = cache2.get(cacheKey2(text2));
|
|
3867
4001
|
if (cached) return cached;
|
|
3868
4002
|
const output = await this.extractor(text2, {
|
|
3869
4003
|
pooling: "mean",
|
|
@@ -3873,7 +4007,7 @@ var init_transformers_provider = __esm({
|
|
|
3873
4007
|
if (result.length !== this.dimensions) {
|
|
3874
4008
|
throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);
|
|
3875
4009
|
}
|
|
3876
|
-
this.cacheSet(text2, result);
|
|
4010
|
+
this.cacheSet(cacheKey2(text2), result);
|
|
3877
4011
|
return result;
|
|
3878
4012
|
}
|
|
3879
4013
|
async embedBatch(texts) {
|
|
@@ -3881,7 +4015,7 @@ var init_transformers_provider = __esm({
|
|
|
3881
4015
|
const uncachedIndices = [];
|
|
3882
4016
|
const uncachedTexts = [];
|
|
3883
4017
|
for (let i2 = 0; i2 < texts.length; i2++) {
|
|
3884
|
-
const cached = cache2.get(texts[i2]);
|
|
4018
|
+
const cached = cache2.get(cacheKey2(texts[i2]));
|
|
3885
4019
|
if (cached) {
|
|
3886
4020
|
results[i2] = cached;
|
|
3887
4021
|
} else {
|
|
@@ -3899,17 +4033,27 @@ var init_transformers_provider = __esm({
|
|
|
3899
4033
|
const vec = Array.from(allVecs[i2]);
|
|
3900
4034
|
const originalIdx = uncachedIndices[i2];
|
|
3901
4035
|
results[originalIdx] = vec;
|
|
3902
|
-
this.cacheSet(uncachedTexts[i2], vec);
|
|
4036
|
+
this.cacheSet(cacheKey2(uncachedTexts[i2]), vec);
|
|
3903
4037
|
}
|
|
3904
4038
|
}
|
|
3905
4039
|
return results;
|
|
3906
4040
|
}
|
|
3907
4041
|
cacheSet(key, value) {
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
4042
|
+
const incomingBytes = value.length * 8;
|
|
4043
|
+
if (incomingBytes > maxCachePayloadBytes2()) return;
|
|
4044
|
+
const existing = cache2.get(key);
|
|
4045
|
+
if (existing) cachePayloadBytes2 -= existing.length * 8;
|
|
4046
|
+
else {
|
|
4047
|
+
while (cache2.size >= MAX_CACHE_SIZE2 || cachePayloadBytes2 + incomingBytes > maxCachePayloadBytes2()) {
|
|
4048
|
+
const firstKey = cache2.keys().next().value;
|
|
4049
|
+
if (firstKey === void 0) break;
|
|
4050
|
+
const old = cache2.get(firstKey);
|
|
4051
|
+
cache2.delete(firstKey);
|
|
4052
|
+
if (old) cachePayloadBytes2 -= old.length * 8;
|
|
4053
|
+
}
|
|
3911
4054
|
}
|
|
3912
4055
|
cache2.set(key, value);
|
|
4056
|
+
cachePayloadBytes2 += incomingBytes;
|
|
3913
4057
|
}
|
|
3914
4058
|
};
|
|
3915
4059
|
}
|
|
@@ -3931,7 +4075,7 @@ __export(api_provider_exports, {
|
|
|
3931
4075
|
saveDiskCacheNow: () => saveDiskCacheNow,
|
|
3932
4076
|
seedApiEmbeddingCacheForTests: () => seedApiEmbeddingCacheForTests
|
|
3933
4077
|
});
|
|
3934
|
-
import { createHash as
|
|
4078
|
+
import { createHash as createHash3 } from "crypto";
|
|
3935
4079
|
import { createReadStream, createWriteStream, constants as fsConstants } from "fs";
|
|
3936
4080
|
import { access, readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, rename, stat, unlink } from "fs/promises";
|
|
3937
4081
|
import { join as join3 } from "path";
|
|
@@ -3958,7 +4102,7 @@ function cacheStatFile() {
|
|
|
3958
4102
|
function payloadBytes(vector) {
|
|
3959
4103
|
return vector.length * BYTES_PER_DIM;
|
|
3960
4104
|
}
|
|
3961
|
-
function
|
|
4105
|
+
function maxCachePayloadBytes3() {
|
|
3962
4106
|
const raw = process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES;
|
|
3963
4107
|
if (raw) {
|
|
3964
4108
|
const parsed = Number.parseInt(raw, 10);
|
|
@@ -3968,7 +4112,7 @@ function maxCachePayloadBytes() {
|
|
|
3968
4112
|
}
|
|
3969
4113
|
function maxEntriesForDimensions(dimensions) {
|
|
3970
4114
|
const dim = Math.max(1, Math.floor(dimensions));
|
|
3971
|
-
const byBytes = Math.floor(
|
|
4115
|
+
const byBytes = Math.floor(maxCachePayloadBytes3() / (dim * BYTES_PER_DIM));
|
|
3972
4116
|
return Math.max(1, Math.min(MAX_CACHE_ENTRIES, byBytes));
|
|
3973
4117
|
}
|
|
3974
4118
|
function rememberDimensions(vector) {
|
|
@@ -3981,13 +4125,15 @@ function evictOldest() {
|
|
|
3981
4125
|
if (firstKey === void 0) return;
|
|
3982
4126
|
const old = cache3.get(firstKey);
|
|
3983
4127
|
cache3.delete(firstKey);
|
|
3984
|
-
if (old)
|
|
4128
|
+
if (old) cachePayloadBytes3 -= payloadBytes(old);
|
|
3985
4129
|
}
|
|
3986
4130
|
function evictToFit(incomingBytes, incomingDims) {
|
|
4131
|
+
if (incomingBytes > maxCachePayloadBytes3()) return false;
|
|
3987
4132
|
const limit2 = maxEntriesForDimensions(incomingDims);
|
|
3988
|
-
while (cache3.size > 0 && (cache3.size >= limit2 ||
|
|
4133
|
+
while (cache3.size > 0 && (cache3.size >= limit2 || cachePayloadBytes3 + incomingBytes > maxCachePayloadBytes3())) {
|
|
3989
4134
|
evictOldest();
|
|
3990
4135
|
}
|
|
4136
|
+
return true;
|
|
3991
4137
|
}
|
|
3992
4138
|
function isNumberArray(value) {
|
|
3993
4139
|
return Array.isArray(value) && value.every((entry) => typeof entry === "number");
|
|
@@ -4014,12 +4160,12 @@ function cacheInsert(hash4, value, dirty) {
|
|
|
4014
4160
|
const incoming = payloadBytes(value);
|
|
4015
4161
|
const existing = cache3.get(hash4);
|
|
4016
4162
|
if (existing) {
|
|
4017
|
-
|
|
4163
|
+
cachePayloadBytes3 -= payloadBytes(existing);
|
|
4018
4164
|
cache3.delete(hash4);
|
|
4019
4165
|
}
|
|
4020
|
-
evictToFit(incoming, value.length || cacheDimensions || DEFAULT_ASSUMED_DIMENSIONS);
|
|
4166
|
+
if (!evictToFit(incoming, value.length || cacheDimensions || DEFAULT_ASSUMED_DIMENSIONS)) return;
|
|
4021
4167
|
cache3.set(hash4, value);
|
|
4022
|
-
|
|
4168
|
+
cachePayloadBytes3 += incoming;
|
|
4023
4169
|
if (dirty) diskCacheDirty2 = true;
|
|
4024
4170
|
}
|
|
4025
4171
|
async function readCacheStat() {
|
|
@@ -4055,7 +4201,7 @@ function cacheNamespace(config) {
|
|
|
4055
4201
|
].join("|");
|
|
4056
4202
|
}
|
|
4057
4203
|
function textHash2(text2, namespace) {
|
|
4058
|
-
return
|
|
4204
|
+
return createHash3("sha256").update(`${namespace}\0${text2}`).digest("hex").slice(0, 16);
|
|
4059
4205
|
}
|
|
4060
4206
|
function inputIdentity(input, options = {}) {
|
|
4061
4207
|
return JSON.stringify({
|
|
@@ -4397,7 +4543,7 @@ function getApiEmbeddingDiskCacheLoadCountForTests() {
|
|
|
4397
4543
|
}
|
|
4398
4544
|
function resetApiEmbeddingCacheForTests() {
|
|
4399
4545
|
cache3.clear();
|
|
4400
|
-
|
|
4546
|
+
cachePayloadBytes3 = 0;
|
|
4401
4547
|
cacheDimensions = null;
|
|
4402
4548
|
diskCacheEntryCount = 0;
|
|
4403
4549
|
diskCacheLoaded = false;
|
|
@@ -4408,14 +4554,14 @@ function resetApiEmbeddingCacheForTests() {
|
|
|
4408
4554
|
}
|
|
4409
4555
|
function seedApiEmbeddingCacheForTests(entries) {
|
|
4410
4556
|
cache3.clear();
|
|
4411
|
-
|
|
4557
|
+
cachePayloadBytes3 = 0;
|
|
4412
4558
|
cacheDimensions = null;
|
|
4413
4559
|
for (const [key, value] of entries) cacheInsert(key, value, true);
|
|
4414
4560
|
diskCacheLoaded = true;
|
|
4415
4561
|
diskCacheDirty2 = true;
|
|
4416
4562
|
}
|
|
4417
4563
|
function getApiEmbeddingCachePayloadBytesForTests() {
|
|
4418
|
-
return
|
|
4564
|
+
return cachePayloadBytes3;
|
|
4419
4565
|
}
|
|
4420
4566
|
function getApiEmbeddingJsonlLineCountCallsForTests() {
|
|
4421
4567
|
return jsonlLineCountCalls;
|
|
@@ -4589,7 +4735,7 @@ function scheduleDiskSave() {
|
|
|
4589
4735
|
diskSaveTimer = null;
|
|
4590
4736
|
}, DISK_SAVE_DEBOUNCE_MS);
|
|
4591
4737
|
}
|
|
4592
|
-
function
|
|
4738
|
+
function cacheSet2(hash4, value) {
|
|
4593
4739
|
cacheInsert(hash4, value, true);
|
|
4594
4740
|
}
|
|
4595
4741
|
function resolveEnvEmbeddingApiKey() {
|
|
@@ -4709,7 +4855,7 @@ async function waitForRetry(waitMs, signal) {
|
|
|
4709
4855
|
abortSignal.addEventListener("abort", onAbort, { once: true });
|
|
4710
4856
|
});
|
|
4711
4857
|
}
|
|
4712
|
-
var cache3, MAX_CACHE_ENTRIES, MAX_CACHE_PAYLOAD_BYTES, BYTES_PER_DIM, DEFAULT_ASSUMED_DIMENSIONS, MAX_MIGRATION_VALUE_BYTES,
|
|
4858
|
+
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;
|
|
4713
4859
|
var init_api_provider = __esm({
|
|
4714
4860
|
"src/embedding/api-provider.ts"() {
|
|
4715
4861
|
"use strict";
|
|
@@ -4721,7 +4867,7 @@ var init_api_provider = __esm({
|
|
|
4721
4867
|
BYTES_PER_DIM = 8;
|
|
4722
4868
|
DEFAULT_ASSUMED_DIMENSIONS = 4096;
|
|
4723
4869
|
MAX_MIGRATION_VALUE_BYTES = 16 * 1024 * 1024;
|
|
4724
|
-
|
|
4870
|
+
cachePayloadBytes3 = 0;
|
|
4725
4871
|
cacheDimensions = null;
|
|
4726
4872
|
diskCacheEntryCount = 0;
|
|
4727
4873
|
diskCacheDirty2 = false;
|
|
@@ -4906,7 +5052,7 @@ var init_api_provider = __esm({
|
|
|
4906
5052
|
} else {
|
|
4907
5053
|
embedding = await apiCall();
|
|
4908
5054
|
}
|
|
4909
|
-
|
|
5055
|
+
cacheSet2(hash4, embedding);
|
|
4910
5056
|
scheduleDiskSave();
|
|
4911
5057
|
return embedding;
|
|
4912
5058
|
}
|
|
@@ -4954,7 +5100,7 @@ var init_api_provider = __esm({
|
|
|
4954
5100
|
for (const item of response.data) {
|
|
4955
5101
|
const originalIdx = chunkIndices[item.index];
|
|
4956
5102
|
results[originalIdx] = item.embedding;
|
|
4957
|
-
|
|
5103
|
+
cacheSet2(textHash2(normalizedTexts[originalIdx], this.cacheKeyNamespace), item.embedding);
|
|
4958
5104
|
}
|
|
4959
5105
|
} catch (error) {
|
|
4960
5106
|
const providerLimit = parseBatchLimit(error);
|
|
@@ -5032,7 +5178,7 @@ var init_api_provider = __esm({
|
|
|
5032
5178
|
throw new Error(`Expected ${this.dimensions}d, got ${embedding.length}d; dimension mismatch`);
|
|
5033
5179
|
}
|
|
5034
5180
|
this.trackUsage(response);
|
|
5035
|
-
|
|
5181
|
+
cacheSet2(hash4, embedding);
|
|
5036
5182
|
scheduleDiskSave();
|
|
5037
5183
|
return embedding;
|
|
5038
5184
|
}
|
|
@@ -6415,6 +6561,7 @@ var init_provider2 = __esm({
|
|
|
6415
6561
|
openai: { baseUrl: "https://api.openai.com/v1", model: "gpt-4.1-nano" },
|
|
6416
6562
|
anthropic: { baseUrl: "https://api.anthropic.com/v1", model: "claude-3-5-haiku-latest" },
|
|
6417
6563
|
openrouter: { baseUrl: "https://openrouter.ai/api/v1", model: "openai/gpt-4.1-nano" },
|
|
6564
|
+
atlascloud: { baseUrl: "https://api.atlascloud.ai/v1", model: "deepseek-ai/deepseek-v3.2" },
|
|
6418
6565
|
custom: { baseUrl: "http://localhost:11434/v1", model: "llama3" }
|
|
6419
6566
|
};
|
|
6420
6567
|
currentConfig = null;
|
|
@@ -7178,7 +7325,7 @@ var init_obs_store = __esm({
|
|
|
7178
7325
|
});
|
|
7179
7326
|
|
|
7180
7327
|
// src/search/semantic-index.ts
|
|
7181
|
-
import { createHash as
|
|
7328
|
+
import { createHash as createHash4 } from "crypto";
|
|
7182
7329
|
import { createRequire as createRequire3 } from "module";
|
|
7183
7330
|
import path8 from "path";
|
|
7184
7331
|
function createSemanticIndexProfile(provider2) {
|
|
@@ -7192,7 +7339,7 @@ function stateKey(dataDir, profile) {
|
|
|
7192
7339
|
return `${path8.resolve(dataDir)}::${profile.key}`;
|
|
7193
7340
|
}
|
|
7194
7341
|
function tableName(profile) {
|
|
7195
|
-
const digest2 =
|
|
7342
|
+
const digest2 = createHash4("sha256").update(profile.key).digest("hex").slice(0, 20);
|
|
7196
7343
|
return `${TABLE_PREFIX}${digest2}`;
|
|
7197
7344
|
}
|
|
7198
7345
|
function indexRoot(dataDir) {
|
|
@@ -8534,6 +8681,7 @@ async function searchObservations(options) {
|
|
|
8534
8681
|
};
|
|
8535
8682
|
let queryVector = null;
|
|
8536
8683
|
let embeddingProviderForSearch = null;
|
|
8684
|
+
let embeddingUnavailable = false;
|
|
8537
8685
|
if (quality !== "fast" && embeddingEnabled && hasQuery && tier !== "fast") {
|
|
8538
8686
|
try {
|
|
8539
8687
|
const provider2 = await getEmbeddingProvider();
|
|
@@ -8541,6 +8689,7 @@ async function searchObservations(options) {
|
|
|
8541
8689
|
embeddingProviderForSearch = provider2;
|
|
8542
8690
|
const activeVectorDimensions = getVectorDimensions();
|
|
8543
8691
|
if (activeVectorDimensions !== null && provider2.dimensions !== activeVectorDimensions) {
|
|
8692
|
+
embeddingUnavailable = true;
|
|
8544
8693
|
rememberSearchMode(
|
|
8545
8694
|
modeKey,
|
|
8546
8695
|
`fulltext (embedding dimension mismatch: provider ${provider2.dimensions}d vs index ${activeVectorDimensions}d)`
|
|
@@ -8580,8 +8729,11 @@ async function searchObservations(options) {
|
|
|
8580
8729
|
hybridWeights: isCJKHeavy ? { text: 0.2, vector: 0.8 } : { text: 0.6, vector: 0.4 }
|
|
8581
8730
|
};
|
|
8582
8731
|
}
|
|
8732
|
+
} else {
|
|
8733
|
+
embeddingUnavailable = true;
|
|
8583
8734
|
}
|
|
8584
8735
|
} catch (error) {
|
|
8736
|
+
embeddingUnavailable = true;
|
|
8585
8737
|
rememberSearchMode(modeKey, "fulltext (embedding unavailable)");
|
|
8586
8738
|
console.error("[memorix] Embedding failed or timed out, falling back to fulltext search");
|
|
8587
8739
|
}
|
|
@@ -8589,7 +8741,7 @@ async function searchObservations(options) {
|
|
|
8589
8741
|
mark("preSearch");
|
|
8590
8742
|
let results;
|
|
8591
8743
|
const persistentCorpusEligible = await shouldUsePersistentSearch(projectIds, options.projectId);
|
|
8592
|
-
const canUsePersistentLexical = persistentCorpusEligible && Boolean(hasQuery) && !queryVector && (quality === "fast" || tier === "fast" || !embeddingEnabled);
|
|
8744
|
+
const canUsePersistentLexical = persistentCorpusEligible && Boolean(hasQuery) && !queryVector && (quality === "fast" || tier === "fast" || !embeddingEnabled || embeddingUnavailable);
|
|
8593
8745
|
let persistent = persistentCorpusEligible && queryVector && embeddingProviderForSearch ? await searchPersistentSemantically(options, projectIds, requestLimit, queryVector, embeddingProviderForSearch) : canUsePersistentLexical ? await searchPersistentLexically(options, projectIds, requestLimit) : null;
|
|
8594
8746
|
const durableStore = getOptionalObservationStore();
|
|
8595
8747
|
if (!persistent && queryVector && durableStore?.hasLexicalIndex?.() && count(database) === 0) {
|
|
@@ -9270,7 +9422,7 @@ var init_lifecycle = __esm({
|
|
|
9270
9422
|
});
|
|
9271
9423
|
|
|
9272
9424
|
// src/store/evidence-store.ts
|
|
9273
|
-
import { createHash as
|
|
9425
|
+
import { createHash as createHash5, randomUUID as randomUUID4 } from "crypto";
|
|
9274
9426
|
function safeJson(value, fallback) {
|
|
9275
9427
|
if (typeof value !== "string" || value.length === 0) return fallback;
|
|
9276
9428
|
try {
|
|
@@ -9304,7 +9456,7 @@ function rowToCard(row) {
|
|
|
9304
9456
|
};
|
|
9305
9457
|
}
|
|
9306
9458
|
function observationHash(observation) {
|
|
9307
|
-
return
|
|
9459
|
+
return createHash5("sha256").update(JSON.stringify({
|
|
9308
9460
|
projectId: observation.projectId,
|
|
9309
9461
|
id: observation.id,
|
|
9310
9462
|
title: observation.title,
|
|
@@ -9734,13 +9886,13 @@ __export(workspace_exports, {
|
|
|
9734
9886
|
loadKnowledgeWorkspace: () => loadKnowledgeWorkspace,
|
|
9735
9887
|
resolveKnowledgeWorkspaceFile: () => resolveKnowledgeWorkspaceFile
|
|
9736
9888
|
});
|
|
9737
|
-
import { createHash as
|
|
9889
|
+
import { createHash as createHash6 } from "crypto";
|
|
9738
9890
|
import { execFile } from "child_process";
|
|
9739
9891
|
import { promises as fs6 } from "fs";
|
|
9740
9892
|
import path10 from "path";
|
|
9741
9893
|
import { promisify } from "util";
|
|
9742
9894
|
function hash(value) {
|
|
9743
|
-
return
|
|
9895
|
+
return createHash6("sha256").update(value).digest("hex");
|
|
9744
9896
|
}
|
|
9745
9897
|
function workspaceId(projectId, mode) {
|
|
9746
9898
|
return "workspace:" + hash(projectId + ":" + mode).slice(0, 24);
|
|
@@ -10348,14 +10500,14 @@ var init_types2 = __esm({
|
|
|
10348
10500
|
});
|
|
10349
10501
|
|
|
10350
10502
|
// src/media/asset-store.ts
|
|
10351
|
-
import { createHash as
|
|
10503
|
+
import { createHash as createHash7, randomUUID as randomUUID6 } from "crypto";
|
|
10352
10504
|
import { copyFile, lstat, mkdir as mkdir3, open, readFile as readFile3, readdir, rename as rename2, rm, stat as stat2, writeFile as writeFile3 } from "fs/promises";
|
|
10353
10505
|
import path11 from "path";
|
|
10354
10506
|
function mediaRoot(dataDir) {
|
|
10355
10507
|
return path11.resolve(dataDir, "media");
|
|
10356
10508
|
}
|
|
10357
10509
|
function projectStorageKey(projectId) {
|
|
10358
|
-
return
|
|
10510
|
+
return createHash7("sha256").update(projectId).digest("hex").slice(0, 16);
|
|
10359
10511
|
}
|
|
10360
10512
|
function validateUnderRoot(root, candidate) {
|
|
10361
10513
|
const resolved = path11.resolve(candidate);
|
|
@@ -10464,7 +10616,7 @@ async function importMediaBuffer(input) {
|
|
|
10464
10616
|
if (input.bytes.length === 0) throw new Error("Media import rejects empty payloads");
|
|
10465
10617
|
if (input.bytes.length > maxBytes) throw new Error(`Media payload is too large (${input.bytes.length} bytes; limit ${maxBytes})`);
|
|
10466
10618
|
const detected = detectMedia(input.bytes.subarray(0, 32));
|
|
10467
|
-
const sha256 =
|
|
10619
|
+
const sha256 = createHash7("sha256").update(input.bytes).digest("hex");
|
|
10468
10620
|
return importKnownMedia({
|
|
10469
10621
|
dataDir: input.dataDir,
|
|
10470
10622
|
projectId: input.projectId,
|
|
@@ -10482,7 +10634,7 @@ async function readMediaAsset(dataDir, asset, maxBytes = DEFAULT_MAX_MEDIA_BYTES
|
|
|
10482
10634
|
if (asset.byteSize > maxBytes) throw new Error(`Media asset exceeds read limit (${asset.byteSize} bytes; limit ${maxBytes})`);
|
|
10483
10635
|
const bytes = await readFile3(getMediaAssetPath(dataDir, asset));
|
|
10484
10636
|
if (bytes.length !== asset.byteSize) throw new Error(`Media asset size no longer matches metadata: ${asset.id}`);
|
|
10485
|
-
const sha256 =
|
|
10637
|
+
const sha256 = createHash7("sha256").update(bytes).digest("hex");
|
|
10486
10638
|
if (sha256 !== asset.sha256) throw new Error(`Media asset hash no longer matches metadata: ${asset.id}`);
|
|
10487
10639
|
return bytes;
|
|
10488
10640
|
}
|
|
@@ -69178,16 +69330,16 @@ var require_jwtaccess = __commonJS({
|
|
|
69178
69330
|
* @returns A string that returns the cached key.
|
|
69179
69331
|
*/
|
|
69180
69332
|
getCachedKey(url, scopes) {
|
|
69181
|
-
let
|
|
69333
|
+
let cacheKey3 = url;
|
|
69182
69334
|
if (scopes && Array.isArray(scopes) && scopes.length) {
|
|
69183
|
-
|
|
69335
|
+
cacheKey3 = url ? `${url}_${scopes.join("_")}` : `${scopes.join("_")}`;
|
|
69184
69336
|
} else if (typeof scopes === "string") {
|
|
69185
|
-
|
|
69337
|
+
cacheKey3 = url ? `${url}_${scopes}` : scopes;
|
|
69186
69338
|
}
|
|
69187
|
-
if (!
|
|
69339
|
+
if (!cacheKey3) {
|
|
69188
69340
|
throw Error("Scopes or url must be provided");
|
|
69189
69341
|
}
|
|
69190
|
-
return
|
|
69342
|
+
return cacheKey3;
|
|
69191
69343
|
}
|
|
69192
69344
|
/**
|
|
69193
69345
|
* Get a non-expired access token, after refreshing if necessary.
|
|
@@ -75733,7 +75885,7 @@ var require_websocket = __commonJS({
|
|
|
75733
75885
|
var http3 = __require("http");
|
|
75734
75886
|
var net = __require("net");
|
|
75735
75887
|
var tls = __require("tls");
|
|
75736
|
-
var { randomBytes, createHash:
|
|
75888
|
+
var { randomBytes, createHash: createHash17 } = __require("crypto");
|
|
75737
75889
|
var { Duplex, Readable: Readable2 } = __require("stream");
|
|
75738
75890
|
var { URL: URL2 } = __require("url");
|
|
75739
75891
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -76401,7 +76553,7 @@ var require_websocket = __commonJS({
|
|
|
76401
76553
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
76402
76554
|
return;
|
|
76403
76555
|
}
|
|
76404
|
-
const digest2 =
|
|
76556
|
+
const digest2 = createHash17("sha1").update(key + GUID).digest("base64");
|
|
76405
76557
|
if (res.headers["sec-websocket-accept"] !== digest2) {
|
|
76406
76558
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
76407
76559
|
return;
|
|
@@ -76773,7 +76925,7 @@ var require_websocket_server = __commonJS({
|
|
|
76773
76925
|
var EventEmitter = __require("events");
|
|
76774
76926
|
var http3 = __require("http");
|
|
76775
76927
|
var { Duplex } = __require("stream");
|
|
76776
|
-
var { createHash:
|
|
76928
|
+
var { createHash: createHash17 } = __require("crypto");
|
|
76777
76929
|
var extension3 = require_extension();
|
|
76778
76930
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
76779
76931
|
var subprotocol2 = require_subprotocol();
|
|
@@ -77080,7 +77232,7 @@ var require_websocket_server = __commonJS({
|
|
|
77080
77232
|
);
|
|
77081
77233
|
}
|
|
77082
77234
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
77083
|
-
const digest2 =
|
|
77235
|
+
const digest2 = createHash17("sha1").update(key + GUID).digest("base64");
|
|
77084
77236
|
const headers = [
|
|
77085
77237
|
"HTTP/1.1 101 Switching Protocols",
|
|
77086
77238
|
"Upgrade: websocket",
|
|
@@ -145365,9 +145517,9 @@ var init_long_term = __esm({
|
|
|
145365
145517
|
});
|
|
145366
145518
|
|
|
145367
145519
|
// src/codegraph/ids.ts
|
|
145368
|
-
import { createHash as
|
|
145520
|
+
import { createHash as createHash8 } from "crypto";
|
|
145369
145521
|
function digest(input) {
|
|
145370
|
-
return
|
|
145522
|
+
return createHash8("sha256").update(input).digest("hex").slice(0, 16);
|
|
145371
145523
|
}
|
|
145372
145524
|
function normalizeCodePath(path23) {
|
|
145373
145525
|
return path23.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+/g, "/");
|
|
@@ -146415,7 +146567,7 @@ var init_store = __esm({
|
|
|
146415
146567
|
|
|
146416
146568
|
// src/codegraph/code-state.ts
|
|
146417
146569
|
import { execFile as execFile2 } from "child_process";
|
|
146418
|
-
import { createHash as
|
|
146570
|
+
import { createHash as createHash9 } from "crypto";
|
|
146419
146571
|
import { promisify as promisify3 } from "util";
|
|
146420
146572
|
async function runGit(rootPath, args) {
|
|
146421
146573
|
try {
|
|
@@ -146444,7 +146596,7 @@ function changedPathCount(status) {
|
|
|
146444
146596
|
return count2;
|
|
146445
146597
|
}
|
|
146446
146598
|
function fingerprint(baseRevision, status) {
|
|
146447
|
-
return
|
|
146599
|
+
return createHash9("sha256").update(baseRevision ?? "").update("\0").update(status).digest("hex");
|
|
146448
146600
|
}
|
|
146449
146601
|
async function collectCodeStateSnapshot(input) {
|
|
146450
146602
|
const [revision, status] = await Promise.all([
|
|
@@ -146538,12 +146690,12 @@ var init_exclude3 = __esm({
|
|
|
146538
146690
|
});
|
|
146539
146691
|
|
|
146540
146692
|
// src/codegraph/semantic-provider.ts
|
|
146541
|
-
import { createHash as
|
|
146693
|
+
import { createHash as createHash10 } from "crypto";
|
|
146542
146694
|
import "fs";
|
|
146543
146695
|
import { resolve } from "path";
|
|
146544
146696
|
import ts from "typescript";
|
|
146545
146697
|
function hashText(value) {
|
|
146546
|
-
return
|
|
146698
|
+
return createHash10("sha256").update(value).digest("hex");
|
|
146547
146699
|
}
|
|
146548
146700
|
function canonicalPath(value) {
|
|
146549
146701
|
const normalized = resolve(value).replace(/\\/g, "/");
|
|
@@ -146888,11 +147040,11 @@ __export(lite_provider_exports, {
|
|
|
146888
147040
|
indexProjectLite: () => indexProjectLite,
|
|
146889
147041
|
refreshProjectLite: () => refreshProjectLite
|
|
146890
147042
|
});
|
|
146891
|
-
import { createHash as
|
|
147043
|
+
import { createHash as createHash11 } from "crypto";
|
|
146892
147044
|
import { existsSync as existsSync10, readdirSync as readdirSync2, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
|
|
146893
147045
|
import { join as join4, relative as relative2 } from "path";
|
|
146894
147046
|
function hashText2(text2) {
|
|
146895
|
-
return
|
|
147047
|
+
return createHash11("sha256").update(text2).digest("hex");
|
|
146896
147048
|
}
|
|
146897
147049
|
function extension2(path23) {
|
|
146898
147050
|
const index = path23.lastIndexOf(".");
|
|
@@ -147525,7 +147677,7 @@ var claim_store_exports = {};
|
|
|
147525
147677
|
__export(claim_store_exports, {
|
|
147526
147678
|
ClaimStore: () => ClaimStore
|
|
147527
147679
|
});
|
|
147528
|
-
import { createHash as
|
|
147680
|
+
import { createHash as createHash12, randomUUID as randomUUID12 } from "crypto";
|
|
147529
147681
|
function optionalText3(value) {
|
|
147530
147682
|
return typeof value === "string" && value ? value : void 0;
|
|
147531
147683
|
}
|
|
@@ -147578,7 +147730,7 @@ function rowToEvent3(row) {
|
|
|
147578
147730
|
};
|
|
147579
147731
|
}
|
|
147580
147732
|
function evidenceKey(input) {
|
|
147581
|
-
return
|
|
147733
|
+
return createHash12("sha256").update(JSON.stringify([
|
|
147582
147734
|
input.evidenceKind,
|
|
147583
147735
|
input.evidenceId,
|
|
147584
147736
|
input.relation,
|
|
@@ -147776,7 +147928,7 @@ __export(claims_exports, {
|
|
|
147776
147928
|
supersedeClaim: () => supersedeClaim,
|
|
147777
147929
|
writeClaim: () => writeClaim
|
|
147778
147930
|
});
|
|
147779
|
-
import { createHash as
|
|
147931
|
+
import { createHash as createHash13, randomUUID as randomUUID13 } from "crypto";
|
|
147780
147932
|
function compactText2(value, field) {
|
|
147781
147933
|
if (typeof value !== "string") throw new Error("Claim " + field + " must be text");
|
|
147782
147934
|
const sanitized = sanitizeCredentials(value).trim().replace(/\s+/g, " ");
|
|
@@ -147788,7 +147940,7 @@ function normalizedTerm(value) {
|
|
|
147788
147940
|
return compactText2(value, "identity").toLocaleLowerCase("en-US");
|
|
147789
147941
|
}
|
|
147790
147942
|
function hashIdentity(parts) {
|
|
147791
|
-
return
|
|
147943
|
+
return createHash13("sha256").update(parts.join(String.fromCharCode(31))).digest("hex");
|
|
147792
147944
|
}
|
|
147793
147945
|
function buildClaimIdentity(input) {
|
|
147794
147946
|
const subject = normalizedTerm(input.subject);
|
|
@@ -148029,7 +148181,7 @@ function supersedeClaim(store, input) {
|
|
|
148029
148181
|
});
|
|
148030
148182
|
}
|
|
148031
148183
|
function hashObservation(observation) {
|
|
148032
|
-
return
|
|
148184
|
+
return createHash13("sha256").update(JSON.stringify([
|
|
148033
148185
|
observation.title,
|
|
148034
148186
|
observation.narrative,
|
|
148035
148187
|
observation.facts,
|
|
@@ -148273,11 +148425,11 @@ var init_frontmatter = __esm({
|
|
|
148273
148425
|
});
|
|
148274
148426
|
|
|
148275
148427
|
// src/knowledge/markdown.ts
|
|
148276
|
-
import { createHash as
|
|
148428
|
+
import { createHash as createHash14 } from "crypto";
|
|
148277
148429
|
import { promises as fs10 } from "fs";
|
|
148278
148430
|
import path17 from "path";
|
|
148279
148431
|
function hashContent(content) {
|
|
148280
|
-
return
|
|
148432
|
+
return createHash14("sha256").update(content).digest("hex");
|
|
148281
148433
|
}
|
|
148282
148434
|
function stringField(data, key) {
|
|
148283
148435
|
const value = data[key];
|
|
@@ -148403,11 +148555,11 @@ __export(wiki_exports, {
|
|
|
148403
148555
|
lintKnowledgeWorkspace: () => lintKnowledgeWorkspace,
|
|
148404
148556
|
readKnowledgePage: () => readKnowledgePage
|
|
148405
148557
|
});
|
|
148406
|
-
import { createHash as
|
|
148558
|
+
import { createHash as createHash15 } from "crypto";
|
|
148407
148559
|
import { promises as fs11 } from "fs";
|
|
148408
148560
|
import path18 from "path";
|
|
148409
148561
|
function hash2(value) {
|
|
148410
|
-
return
|
|
148562
|
+
return createHash15("sha256").update(value).digest("hex");
|
|
148411
148563
|
}
|
|
148412
148564
|
function now() {
|
|
148413
148565
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -149264,11 +149416,11 @@ __export(workflows_exports, {
|
|
|
149264
149416
|
syncCanonicalWorkflows: () => syncCanonicalWorkflows,
|
|
149265
149417
|
writeCanonicalWorkflow: () => writeCanonicalWorkflow
|
|
149266
149418
|
});
|
|
149267
|
-
import { createHash as
|
|
149419
|
+
import { createHash as createHash16 } from "crypto";
|
|
149268
149420
|
import { promises as fs12 } from "fs";
|
|
149269
149421
|
import path19 from "path";
|
|
149270
149422
|
function hash3(value) {
|
|
149271
|
-
return
|
|
149423
|
+
return createHash16("sha256").update(value).digest("hex");
|
|
149272
149424
|
}
|
|
149273
149425
|
function now2() {
|
|
149274
149426
|
return (/* @__PURE__ */ new Date()).toISOString();
|