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) {
|
|
@@ -414,6 +419,74 @@ var init_launch_root = __esm({
|
|
|
414
419
|
}
|
|
415
420
|
});
|
|
416
421
|
|
|
422
|
+
// src/store/sqlite-reliability.ts
|
|
423
|
+
function isTransientSqliteError(error) {
|
|
424
|
+
const code = error?.code;
|
|
425
|
+
if (typeof code === "string") {
|
|
426
|
+
return /^SQLITE_BUSY(?:_|$)/i.test(code);
|
|
427
|
+
}
|
|
428
|
+
return error instanceof Error && /\bdatabase is locked\b|\bdatabase is busy\b/i.test(error.message);
|
|
429
|
+
}
|
|
430
|
+
function isSqliteUnavailableError(error) {
|
|
431
|
+
return error instanceof SqliteUnavailableError || error instanceof Error && /SQLite is not available|better-sqlite3.*failed|node:sqlite.*failed|bun:sqlite.*failed/i.test(error.message);
|
|
432
|
+
}
|
|
433
|
+
function degradedReadError(storeName) {
|
|
434
|
+
return new Error(`[memorix] Cannot read ${storeName}: SQLite backend unavailable (memory is not loaded)`);
|
|
435
|
+
}
|
|
436
|
+
function degradedWriteError(storeName) {
|
|
437
|
+
return new Error(`[memorix] Cannot write ${storeName}: SQLite backend unavailable (degraded mode; read-only)`);
|
|
438
|
+
}
|
|
439
|
+
function formatSqliteFailure(error) {
|
|
440
|
+
return error instanceof Error && error.message ? error.message : String(error);
|
|
441
|
+
}
|
|
442
|
+
function delay(ms) {
|
|
443
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
444
|
+
}
|
|
445
|
+
async function retrySqliteBusy(operation, label) {
|
|
446
|
+
for (let attempt = 0; ; attempt++) {
|
|
447
|
+
try {
|
|
448
|
+
return await operation();
|
|
449
|
+
} catch (error) {
|
|
450
|
+
if (!isTransientSqliteError(error) || attempt >= SQLITE_BUSY_RETRY_DELAYS_MS.length) throw error;
|
|
451
|
+
const waitMs = SQLITE_BUSY_RETRY_DELAYS_MS[attempt];
|
|
452
|
+
console.error(
|
|
453
|
+
`[memorix] ${label} SQLite busy (attempt ${attempt + 1}/${SQLITE_BUSY_RETRY_DELAYS_MS.length + 1}), retrying in ${waitMs}ms`
|
|
454
|
+
);
|
|
455
|
+
await delay(waitMs);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
async function initializeSqliteStore(factory, dataDir, label) {
|
|
460
|
+
try {
|
|
461
|
+
loadBetterSqlite3();
|
|
462
|
+
} catch (error) {
|
|
463
|
+
throw new SqliteUnavailableError(error);
|
|
464
|
+
}
|
|
465
|
+
return retrySqliteBusy(async () => {
|
|
466
|
+
const store = factory();
|
|
467
|
+
await store.init(dataDir);
|
|
468
|
+
return store;
|
|
469
|
+
}, label);
|
|
470
|
+
}
|
|
471
|
+
var SQLITE_BUSY_RETRY_DELAYS_MS, SqliteUnavailableError;
|
|
472
|
+
var init_sqlite_reliability = __esm({
|
|
473
|
+
"src/store/sqlite-reliability.ts"() {
|
|
474
|
+
"use strict";
|
|
475
|
+
init_esm_shims();
|
|
476
|
+
init_sqlite_db();
|
|
477
|
+
SQLITE_BUSY_RETRY_DELAYS_MS = [50, 150, 400, 1e3, 2500];
|
|
478
|
+
SqliteUnavailableError = class extends Error {
|
|
479
|
+
code = "MEMORIX_SQLITE_UNAVAILABLE";
|
|
480
|
+
constructor(cause) {
|
|
481
|
+
super(
|
|
482
|
+
cause instanceof Error && cause.message ? cause.message : "[memorix] SQLite is unavailable (install a supported SQLite runtime)"
|
|
483
|
+
);
|
|
484
|
+
this.name = "SqliteUnavailableError";
|
|
485
|
+
}
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
});
|
|
489
|
+
|
|
417
490
|
// src/store/sqlite-fts.ts
|
|
418
491
|
function normalizeFtsToken(token) {
|
|
419
492
|
return token.replace(/"/g, '""');
|
|
@@ -427,22 +500,27 @@ function buildFtsQuery(query) {
|
|
|
427
500
|
function initializeObservationLexicalIndex(db2) {
|
|
428
501
|
const known = ftsAvailability.get(db2);
|
|
429
502
|
if (known !== void 0) return known;
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
db2.
|
|
503
|
+
let lastError;
|
|
504
|
+
for (let attempt = 1; attempt <= FTS_INIT_MAX_ATTEMPTS; attempt++) {
|
|
505
|
+
try {
|
|
506
|
+
db2.exec(CREATE_OBSERVATION_FTS);
|
|
507
|
+
const observationCount = Number(db2.prepare("SELECT COUNT(*) AS count FROM observations").get()?.count ?? 0);
|
|
508
|
+
const indexedCount = Number(db2.prepare(`SELECT COUNT(*) AS count FROM ${FTS_TABLE}`).get()?.count ?? 0);
|
|
509
|
+
if (observationCount !== indexedCount) {
|
|
510
|
+
db2.exec(`INSERT INTO ${FTS_TABLE}(${FTS_TABLE}) VALUES ('rebuild')`);
|
|
511
|
+
}
|
|
512
|
+
ftsAvailability.set(db2, true);
|
|
513
|
+
return true;
|
|
514
|
+
} catch (error) {
|
|
515
|
+
lastError = error;
|
|
516
|
+
if (!isTransientSqliteError(error) || attempt === FTS_INIT_MAX_ATTEMPTS) break;
|
|
436
517
|
}
|
|
437
|
-
ftsAvailability.set(db2, true);
|
|
438
|
-
return true;
|
|
439
|
-
} catch (error) {
|
|
440
|
-
ftsAvailability.set(db2, false);
|
|
441
|
-
console.warn(
|
|
442
|
-
`[memorix] SQLite FTS5 unavailable; using the existing search fallback: ${error instanceof Error ? error.message : String(error)}`
|
|
443
|
-
);
|
|
444
|
-
return false;
|
|
445
518
|
}
|
|
519
|
+
ftsAvailability.set(db2, false);
|
|
520
|
+
console.warn(
|
|
521
|
+
`[memorix] SQLite FTS5 unavailable; using the existing search fallback: ${lastError instanceof Error ? lastError.message : String(lastError)}`
|
|
522
|
+
);
|
|
523
|
+
return false;
|
|
446
524
|
}
|
|
447
525
|
function isObservationLexicalIndexEnabled(db2) {
|
|
448
526
|
return ftsAvailability.get(db2) === true;
|
|
@@ -496,11 +574,12 @@ function searchObservationLexically(db2, options) {
|
|
|
496
574
|
score: Math.max(0, Number(row.lexical_score ?? 0))
|
|
497
575
|
}));
|
|
498
576
|
}
|
|
499
|
-
var ftsAvailability, FTS_TABLE, CREATE_OBSERVATION_FTS;
|
|
577
|
+
var ftsAvailability, FTS_TABLE, CREATE_OBSERVATION_FTS, FTS_INIT_MAX_ATTEMPTS;
|
|
500
578
|
var init_sqlite_fts = __esm({
|
|
501
579
|
"src/store/sqlite-fts.ts"() {
|
|
502
580
|
"use strict";
|
|
503
581
|
init_esm_shims();
|
|
582
|
+
init_sqlite_reliability();
|
|
504
583
|
ftsAvailability = /* @__PURE__ */ new WeakMap();
|
|
505
584
|
FTS_TABLE = "observations_fts";
|
|
506
585
|
CREATE_OBSERVATION_FTS = `
|
|
@@ -534,6 +613,7 @@ CREATE TRIGGER IF NOT EXISTS observations_fts_au AFTER UPDATE ON observations BE
|
|
|
534
613
|
VALUES (new.id, new.entityName, new.title, new.narrative, new.facts, new.filesModified, new.concepts, new.attachments);
|
|
535
614
|
END;
|
|
536
615
|
`;
|
|
616
|
+
FTS_INIT_MAX_ATTEMPTS = 3;
|
|
537
617
|
}
|
|
538
618
|
});
|
|
539
619
|
|
|
@@ -572,11 +652,21 @@ function applySchemaMigrations(db2) {
|
|
|
572
652
|
apply();
|
|
573
653
|
}
|
|
574
654
|
}
|
|
655
|
+
function normalizeDataDir(dataDir) {
|
|
656
|
+
return path3.resolve(dataDir);
|
|
657
|
+
}
|
|
658
|
+
function touchDatabase(normalized, db2) {
|
|
659
|
+
_dbCache.delete(normalized);
|
|
660
|
+
_dbCache.set(normalized, db2);
|
|
661
|
+
}
|
|
575
662
|
function getDatabase(dataDir) {
|
|
576
|
-
const normalized =
|
|
663
|
+
const normalized = normalizeDataDir(dataDir);
|
|
577
664
|
assertNotHomeDataDir(normalized);
|
|
578
665
|
const existing = _dbCache.get(normalized);
|
|
579
|
-
if (existing)
|
|
666
|
+
if (existing) {
|
|
667
|
+
touchDatabase(normalized, existing);
|
|
668
|
+
return existing;
|
|
669
|
+
}
|
|
580
670
|
loadBetterSqlite3();
|
|
581
671
|
fs.mkdirSync(dataDir, { recursive: true });
|
|
582
672
|
const dbPath = path3.join(dataDir, "memorix.db");
|
|
@@ -606,6 +696,8 @@ function getDatabase(dataDir) {
|
|
|
606
696
|
db2.exec(CREATE_MAINTENANCE_JOBS_TABLE);
|
|
607
697
|
db2.exec(CREATE_MAINTENANCE_TARGETS_TABLE);
|
|
608
698
|
db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
|
|
699
|
+
db2.exec(CREATE_TASK_CONTINUITY_EVENTS_TABLE);
|
|
700
|
+
db2.exec(CREATE_AGENT_EFFECTS_TABLE);
|
|
609
701
|
try {
|
|
610
702
|
db2.exec(`ALTER TABLE mini_skills ADD COLUMN sourceSnapshot TEXT NOT NULL DEFAULT ''`);
|
|
611
703
|
} catch {
|
|
@@ -644,7 +736,7 @@ function getDatabase(dataDir) {
|
|
|
644
736
|
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('storage_generation', '0')`).run();
|
|
645
737
|
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('next_id', '1')`).run();
|
|
646
738
|
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('mini_skills_generation', '0')`).run();
|
|
647
|
-
|
|
739
|
+
touchDatabase(normalized, db2);
|
|
648
740
|
return db2;
|
|
649
741
|
} catch (error) {
|
|
650
742
|
try {
|
|
@@ -662,8 +754,9 @@ function closeAllDatabases() {
|
|
|
662
754
|
}
|
|
663
755
|
_dbCache.delete(key);
|
|
664
756
|
}
|
|
757
|
+
_dbLeases.clear();
|
|
665
758
|
}
|
|
666
|
-
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;
|
|
759
|
+
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;
|
|
667
760
|
var init_sqlite_db = __esm({
|
|
668
761
|
"src/store/sqlite-db.ts"() {
|
|
669
762
|
"use strict";
|
|
@@ -1380,6 +1473,43 @@ CREATE TABLE IF NOT EXISTS memory_feedback_events (
|
|
|
1380
1473
|
delta REAL NOT NULL DEFAULT 0,
|
|
1381
1474
|
observed_at TEXT NOT NULL
|
|
1382
1475
|
);
|
|
1476
|
+
`;
|
|
1477
|
+
CREATE_TASK_CONTINUITY_EVENTS_TABLE = `
|
|
1478
|
+
CREATE TABLE IF NOT EXISTS task_continuity_events (
|
|
1479
|
+
id TEXT PRIMARY KEY,
|
|
1480
|
+
project_id TEXT NOT NULL,
|
|
1481
|
+
task_id TEXT NOT NULL,
|
|
1482
|
+
task TEXT NOT NULL,
|
|
1483
|
+
kind TEXT NOT NULL,
|
|
1484
|
+
content TEXT NOT NULL,
|
|
1485
|
+
item_status TEXT,
|
|
1486
|
+
source_ref TEXT,
|
|
1487
|
+
evidence_json TEXT NOT NULL DEFAULT '[]',
|
|
1488
|
+
actor TEXT,
|
|
1489
|
+
created_at TEXT NOT NULL,
|
|
1490
|
+
event_key TEXT,
|
|
1491
|
+
item_key TEXT,
|
|
1492
|
+
supersedes_id TEXT
|
|
1493
|
+
);
|
|
1494
|
+
`;
|
|
1495
|
+
CREATE_AGENT_EFFECTS_TABLE = `
|
|
1496
|
+
CREATE TABLE IF NOT EXISTS agent_effects (
|
|
1497
|
+
id TEXT PRIMARY KEY,
|
|
1498
|
+
pipeline_id TEXT NOT NULL,
|
|
1499
|
+
task_id TEXT NOT NULL,
|
|
1500
|
+
attempt INTEGER NOT NULL,
|
|
1501
|
+
effect_key TEXT NOT NULL,
|
|
1502
|
+
tool TEXT NOT NULL,
|
|
1503
|
+
risk_tier TEXT NOT NULL,
|
|
1504
|
+
replay_policy TEXT NOT NULL,
|
|
1505
|
+
status TEXT NOT NULL,
|
|
1506
|
+
call_id TEXT,
|
|
1507
|
+
idempotency_key TEXT NOT NULL,
|
|
1508
|
+
input_fingerprint TEXT,
|
|
1509
|
+
detail TEXT,
|
|
1510
|
+
started_at INTEGER NOT NULL,
|
|
1511
|
+
finished_at INTEGER
|
|
1512
|
+
);
|
|
1383
1513
|
`;
|
|
1384
1514
|
CREATE_MCP_BINDINGS_TABLE = `
|
|
1385
1515
|
CREATE TABLE IF NOT EXISTS mcp_bindings (
|
|
@@ -1458,7 +1588,18 @@ CREATE INDEX IF NOT EXISTS idx_evidence_cards_candidate ON evidence_cards(projec
|
|
|
1458
1588
|
CREATE INDEX IF NOT EXISTS idx_evidence_card_events_card ON evidence_card_events(card_id, created_at);
|
|
1459
1589
|
CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC);
|
|
1460
1590
|
CREATE INDEX IF NOT EXISTS idx_memory_feedback_events_candidate ON memory_feedback_events(project_id, candidate_kind, candidate_id, observed_at DESC);
|
|
1591
|
+
CREATE INDEX IF NOT EXISTS idx_task_continuity_project_task ON task_continuity_events(project_id, task_id, created_at ASC);
|
|
1592
|
+
CREATE INDEX IF NOT EXISTS idx_task_continuity_project_recent ON task_continuity_events(project_id, created_at DESC);
|
|
1593
|
+
CREATE INDEX IF NOT EXISTS idx_task_continuity_item ON task_continuity_events(project_id, task_id, kind, item_key, created_at DESC);
|
|
1594
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_task_continuity_event_key
|
|
1595
|
+
ON task_continuity_events(project_id, task_id, event_key)
|
|
1596
|
+
WHERE event_key IS NOT NULL;
|
|
1597
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_effect_identity
|
|
1598
|
+
ON agent_effects(pipeline_id, task_id, attempt, effect_key);
|
|
1599
|
+
CREATE INDEX IF NOT EXISTS idx_agent_effect_pipeline ON agent_effects(pipeline_id, started_at ASC);
|
|
1461
1600
|
CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC);
|
|
1601
|
+
CREATE INDEX IF NOT EXISTS idx_mcp_bindings_root ON mcp_bindings(project_root, last_used_at DESC);
|
|
1602
|
+
CREATE INDEX IF NOT EXISTS idx_mcp_bindings_expiry ON mcp_bindings(expires_at);
|
|
1462
1603
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
|
|
1463
1604
|
ON maintenance_jobs(project_id, kind, dedupe_key)
|
|
1464
1605
|
WHERE status IN ('pending', 'running', 'retry');
|
|
@@ -1629,6 +1770,8 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
|
|
|
1629
1770
|
db2.exec("CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC)");
|
|
1630
1771
|
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)");
|
|
1631
1772
|
db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC)");
|
|
1773
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_root ON mcp_bindings(project_root, last_used_at DESC)");
|
|
1774
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_expiry ON mcp_bindings(expires_at)");
|
|
1632
1775
|
}
|
|
1633
1776
|
},
|
|
1634
1777
|
{
|
|
@@ -1639,77 +1782,22 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
|
|
|
1639
1782
|
addColumnIfMissing(db2, "code_symbols", "source", "source TEXT");
|
|
1640
1783
|
addColumnIfMissing(db2, "code_edges", "source", "source TEXT");
|
|
1641
1784
|
}
|
|
1785
|
+
},
|
|
1786
|
+
{
|
|
1787
|
+
id: "1.9-continuity-v2",
|
|
1788
|
+
apply: (db2) => {
|
|
1789
|
+
addColumnIfMissing(db2, "task_continuity_events", "event_key", "event_key TEXT");
|
|
1790
|
+
addColumnIfMissing(db2, "task_continuity_events", "item_key", "item_key TEXT");
|
|
1791
|
+
addColumnIfMissing(db2, "task_continuity_events", "supersedes_id", "supersedes_id TEXT");
|
|
1792
|
+
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)");
|
|
1793
|
+
db2.exec(`CREATE UNIQUE INDEX IF NOT EXISTS idx_task_continuity_event_key
|
|
1794
|
+
ON task_continuity_events(project_id, task_id, event_key)
|
|
1795
|
+
WHERE event_key IS NOT NULL`);
|
|
1796
|
+
}
|
|
1642
1797
|
}
|
|
1643
1798
|
];
|
|
1644
1799
|
_dbCache = /* @__PURE__ */ new Map();
|
|
1645
|
-
|
|
1646
|
-
});
|
|
1647
|
-
|
|
1648
|
-
// src/store/sqlite-reliability.ts
|
|
1649
|
-
function isTransientSqliteError(error) {
|
|
1650
|
-
const code = error?.code;
|
|
1651
|
-
if (typeof code === "string") {
|
|
1652
|
-
return /^SQLITE_BUSY(?:_|$)/i.test(code);
|
|
1653
|
-
}
|
|
1654
|
-
return error instanceof Error && /\bdatabase is locked\b|\bdatabase is busy\b/i.test(error.message);
|
|
1655
|
-
}
|
|
1656
|
-
function isSqliteUnavailableError(error) {
|
|
1657
|
-
return error instanceof SqliteUnavailableError || error instanceof Error && /SQLite is not available|better-sqlite3.*failed|node:sqlite.*failed|bun:sqlite.*failed/i.test(error.message);
|
|
1658
|
-
}
|
|
1659
|
-
function degradedReadError(storeName) {
|
|
1660
|
-
return new Error(`[memorix] Cannot read ${storeName}: SQLite backend unavailable (memory is not loaded)`);
|
|
1661
|
-
}
|
|
1662
|
-
function degradedWriteError(storeName) {
|
|
1663
|
-
return new Error(`[memorix] Cannot write ${storeName}: SQLite backend unavailable (degraded mode; read-only)`);
|
|
1664
|
-
}
|
|
1665
|
-
function formatSqliteFailure(error) {
|
|
1666
|
-
return error instanceof Error && error.message ? error.message : String(error);
|
|
1667
|
-
}
|
|
1668
|
-
function delay(ms) {
|
|
1669
|
-
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
1670
|
-
}
|
|
1671
|
-
async function retrySqliteBusy(operation, label) {
|
|
1672
|
-
for (let attempt = 0; ; attempt++) {
|
|
1673
|
-
try {
|
|
1674
|
-
return await operation();
|
|
1675
|
-
} catch (error) {
|
|
1676
|
-
if (!isTransientSqliteError(error) || attempt >= SQLITE_BUSY_RETRY_DELAYS_MS.length) throw error;
|
|
1677
|
-
const waitMs = SQLITE_BUSY_RETRY_DELAYS_MS[attempt];
|
|
1678
|
-
console.error(
|
|
1679
|
-
`[memorix] ${label} SQLite busy (attempt ${attempt + 1}/${SQLITE_BUSY_RETRY_DELAYS_MS.length + 1}), retrying in ${waitMs}ms`
|
|
1680
|
-
);
|
|
1681
|
-
await delay(waitMs);
|
|
1682
|
-
}
|
|
1683
|
-
}
|
|
1684
|
-
}
|
|
1685
|
-
async function initializeSqliteStore(factory, dataDir, label) {
|
|
1686
|
-
try {
|
|
1687
|
-
loadBetterSqlite3();
|
|
1688
|
-
} catch (error) {
|
|
1689
|
-
throw new SqliteUnavailableError(error);
|
|
1690
|
-
}
|
|
1691
|
-
return retrySqliteBusy(async () => {
|
|
1692
|
-
const store = factory();
|
|
1693
|
-
await store.init(dataDir);
|
|
1694
|
-
return store;
|
|
1695
|
-
}, label);
|
|
1696
|
-
}
|
|
1697
|
-
var SQLITE_BUSY_RETRY_DELAYS_MS, SqliteUnavailableError;
|
|
1698
|
-
var init_sqlite_reliability = __esm({
|
|
1699
|
-
"src/store/sqlite-reliability.ts"() {
|
|
1700
|
-
"use strict";
|
|
1701
|
-
init_esm_shims();
|
|
1702
|
-
init_sqlite_db();
|
|
1703
|
-
SQLITE_BUSY_RETRY_DELAYS_MS = [50, 150, 400, 1e3, 2500];
|
|
1704
|
-
SqliteUnavailableError = class extends Error {
|
|
1705
|
-
code = "MEMORIX_SQLITE_UNAVAILABLE";
|
|
1706
|
-
constructor(cause) {
|
|
1707
|
-
super(
|
|
1708
|
-
cause instanceof Error && cause.message ? cause.message : "[memorix] SQLite is unavailable (install a supported SQLite runtime)"
|
|
1709
|
-
);
|
|
1710
|
-
this.name = "SqliteUnavailableError";
|
|
1711
|
-
}
|
|
1712
|
-
};
|
|
1800
|
+
_dbLeases = /* @__PURE__ */ new Map();
|
|
1713
1801
|
}
|
|
1714
1802
|
});
|
|
1715
1803
|
|
|
@@ -2131,9 +2219,9 @@ var init_detector = __esm({
|
|
|
2131
2219
|
// src/config/legacy-loader.ts
|
|
2132
2220
|
import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
|
|
2133
2221
|
import { homedir as homedir3 } from "os";
|
|
2134
|
-
function loadFileConfig() {
|
|
2222
|
+
function loadFileConfig(homeDir = homedir3()) {
|
|
2135
2223
|
if (cachedConfig !== null) return cachedConfig;
|
|
2136
|
-
const configPath = getLegacyConfigJsonPath(
|
|
2224
|
+
const configPath = getLegacyConfigJsonPath(homeDir);
|
|
2137
2225
|
try {
|
|
2138
2226
|
if (existsSync5(configPath)) {
|
|
2139
2227
|
cachedConfig = JSON.parse(readFileSync5(configPath, "utf-8"));
|
|
@@ -2163,15 +2251,15 @@ import { homedir as homedir4 } from "os";
|
|
|
2163
2251
|
function loadTomlConfig(options = {}) {
|
|
2164
2252
|
const homeDir = options.homeDir ?? homedir4();
|
|
2165
2253
|
const projectRoot = options.projectRoot ?? null;
|
|
2166
|
-
const
|
|
2167
|
-
const cached = configCache2.get(
|
|
2254
|
+
const cacheKey3 = `${homeDir}\0${projectRoot ?? ""}`;
|
|
2255
|
+
const cached = configCache2.get(cacheKey3);
|
|
2168
2256
|
if (cached) return cached;
|
|
2169
2257
|
const userToml = getGlobalConfigTomlPath(homeDir);
|
|
2170
2258
|
const projectToml = projectRoot ? getProjectConfigTomlPath(projectRoot) : null;
|
|
2171
2259
|
const userConfig = existsSync6(userToml) ? parseTomlConfig(readFileSync6(userToml, "utf8"), userToml) : {};
|
|
2172
2260
|
const projectConfig = projectToml && existsSync6(projectToml) ? parseTomlConfig(readFileSync6(projectToml, "utf8"), projectToml) : {};
|
|
2173
2261
|
const merged = mergeTomlConfig(userConfig, projectConfig);
|
|
2174
|
-
configCache2.set(
|
|
2262
|
+
configCache2.set(cacheKey3, merged);
|
|
2175
2263
|
return merged;
|
|
2176
2264
|
}
|
|
2177
2265
|
function mergeTomlConfig(base, override) {
|
|
@@ -2292,8 +2380,8 @@ function getResolvedConfig(options = {}) {
|
|
|
2292
2380
|
const projectRoot = options.projectRoot === void 0 ? detectProject()?.rootPath ?? null : options.projectRoot;
|
|
2293
2381
|
loadDotenv(projectRoot === null ? void 0 : projectRoot ?? void 0, { userHomeDir: homeDir });
|
|
2294
2382
|
const toml = loadTomlConfig({ projectRoot: projectRoot ?? null, homeDir });
|
|
2295
|
-
const yaml = loadYamlConfig(projectRoot ?? null);
|
|
2296
|
-
const legacy = loadFileConfig();
|
|
2383
|
+
const yaml = loadYamlConfig(projectRoot ?? null, { homeDir });
|
|
2384
|
+
const legacy = loadFileConfig(homeDir);
|
|
2297
2385
|
const embeddingBaseUrl = first(process.env.MEMORIX_EMBEDDING_BASE_URL, toml.embedding?.base_url, yaml.embedding?.baseUrl, legacy.embeddingApi?.baseUrl);
|
|
2298
2386
|
const openRouterEmbeddingApiKey = isOpenRouterUrl(embeddingBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
|
|
2299
2387
|
const memoryLlmProvider = first(
|
|
@@ -2315,15 +2403,17 @@ function getResolvedConfig(options = {}) {
|
|
|
2315
2403
|
legacy.llm?.baseUrl
|
|
2316
2404
|
);
|
|
2317
2405
|
const openRouterMemoryLlmApiKey = isOpenRouterMemoryLane(memoryLlmProvider, memoryLlmBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
|
|
2406
|
+
const isAtlasCloud = memoryLlmProvider === "atlascloud";
|
|
2318
2407
|
const memoryLlmApiKey = first(
|
|
2319
2408
|
process.env.MEMORIX_LLM_API_KEY,
|
|
2320
2409
|
process.env.MEMORIX_API_KEY,
|
|
2321
2410
|
toml.memory?.llm?.api_key,
|
|
2322
2411
|
yaml.llm?.apiKey,
|
|
2323
2412
|
legacy.llm?.apiKey,
|
|
2324
|
-
|
|
2325
|
-
process.env.
|
|
2326
|
-
|
|
2413
|
+
// Never borrow another provider's credentials for the Atlas Cloud preset.
|
|
2414
|
+
isAtlasCloud ? process.env.ATLASCLOUD_API_KEY : process.env.OPENAI_API_KEY,
|
|
2415
|
+
isAtlasCloud ? void 0 : process.env.ANTHROPIC_API_KEY,
|
|
2416
|
+
isAtlasCloud ? void 0 : openRouterMemoryLlmApiKey
|
|
2327
2417
|
);
|
|
2328
2418
|
const resolved = {
|
|
2329
2419
|
agent: {
|
|
@@ -2502,7 +2592,8 @@ function getEnvSourceNames() {
|
|
|
2502
2592
|
"MEMORIX_CODEGRAPH_EXTERNAL_CONTEXT",
|
|
2503
2593
|
"MEMORIX_CODEGRAPH_EXTERNAL_COMMAND",
|
|
2504
2594
|
"MEMORIX_CODEGRAPH_EXTERNAL_TIMEOUT_MS",
|
|
2505
|
-
"OPENROUTER_API_KEY"
|
|
2595
|
+
"OPENROUTER_API_KEY",
|
|
2596
|
+
"ATLASCLOUD_API_KEY"
|
|
2506
2597
|
].filter((name) => process.env[name]);
|
|
2507
2598
|
}
|
|
2508
2599
|
function isOpenRouterUrl(value) {
|
|
@@ -2721,12 +2812,45 @@ function textHash(text2) {
|
|
|
2721
2812
|
async function loadDiskCache() {
|
|
2722
2813
|
try {
|
|
2723
2814
|
const raw = await readFile(CACHE_FILE, "utf-8");
|
|
2815
|
+
if (Buffer.byteLength(raw, "utf8") > MAX_CACHE_FILE_BYTES) {
|
|
2816
|
+
console.error("[memorix] FastEmbed cache exceeds the disk load limit; starting with an empty cache");
|
|
2817
|
+
return;
|
|
2818
|
+
}
|
|
2724
2819
|
const entries = JSON.parse(raw);
|
|
2725
|
-
|
|
2726
|
-
|
|
2820
|
+
if (!Array.isArray(entries)) return;
|
|
2821
|
+
for (const entry of entries) {
|
|
2822
|
+
if (!Array.isArray(entry) || typeof entry[0] !== "string" || !isVector(entry[1])) continue;
|
|
2823
|
+
cacheSet(entry[0], entry[1], false);
|
|
2824
|
+
}
|
|
2825
|
+
console.error(`[memorix] Loaded ${cache.size} cached embeddings from disk`);
|
|
2727
2826
|
} catch {
|
|
2728
2827
|
}
|
|
2729
2828
|
}
|
|
2829
|
+
function isVector(value) {
|
|
2830
|
+
return Array.isArray(value) && value.every((entry) => typeof entry === "number");
|
|
2831
|
+
}
|
|
2832
|
+
function maxCachePayloadBytes() {
|
|
2833
|
+
const raw = Number.parseInt(process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES ?? "", 10);
|
|
2834
|
+
return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_CACHE_PAYLOAD_BYTES;
|
|
2835
|
+
}
|
|
2836
|
+
function cacheSet(hash4, value, markDirty = true) {
|
|
2837
|
+
const incomingBytes = value.length * 8;
|
|
2838
|
+
if (incomingBytes > maxCachePayloadBytes()) return;
|
|
2839
|
+
const existing = cache.get(hash4);
|
|
2840
|
+
if (existing) cachePayloadBytes -= existing.length * 8;
|
|
2841
|
+
else {
|
|
2842
|
+
while (cache.size >= MAX_CACHE_SIZE || cachePayloadBytes + incomingBytes > maxCachePayloadBytes()) {
|
|
2843
|
+
const firstKey = cache.keys().next().value;
|
|
2844
|
+
if (firstKey === void 0) break;
|
|
2845
|
+
const old = cache.get(firstKey);
|
|
2846
|
+
cache.delete(firstKey);
|
|
2847
|
+
if (old) cachePayloadBytes -= old.length * 8;
|
|
2848
|
+
}
|
|
2849
|
+
}
|
|
2850
|
+
cache.set(hash4, value);
|
|
2851
|
+
cachePayloadBytes += incomingBytes;
|
|
2852
|
+
if (markDirty) diskCacheDirty = true;
|
|
2853
|
+
}
|
|
2730
2854
|
async function saveDiskCache() {
|
|
2731
2855
|
if (!diskCacheDirty) return;
|
|
2732
2856
|
try {
|
|
@@ -2737,7 +2861,7 @@ async function saveDiskCache() {
|
|
|
2737
2861
|
} catch {
|
|
2738
2862
|
}
|
|
2739
2863
|
}
|
|
2740
|
-
var CACHE_DIR, CACHE_FILE, cache, MAX_CACHE_SIZE, diskCacheDirty, FastEmbedProvider;
|
|
2864
|
+
var CACHE_DIR, CACHE_FILE, cache, MAX_CACHE_SIZE, DEFAULT_CACHE_PAYLOAD_BYTES, MAX_CACHE_FILE_BYTES, cachePayloadBytes, diskCacheDirty, FastEmbedProvider;
|
|
2741
2865
|
var init_fastembed_provider = __esm({
|
|
2742
2866
|
"src/embedding/fastembed-provider.ts"() {
|
|
2743
2867
|
"use strict";
|
|
@@ -2747,6 +2871,9 @@ var init_fastembed_provider = __esm({
|
|
|
2747
2871
|
CACHE_FILE = join2(CACHE_DIR, ".embedding-cache.json");
|
|
2748
2872
|
cache = /* @__PURE__ */ new Map();
|
|
2749
2873
|
MAX_CACHE_SIZE = 5e3;
|
|
2874
|
+
DEFAULT_CACHE_PAYLOAD_BYTES = 64 * 1024 * 1024;
|
|
2875
|
+
MAX_CACHE_FILE_BYTES = 128 * 1024 * 1024;
|
|
2876
|
+
cachePayloadBytes = 0;
|
|
2750
2877
|
diskCacheDirty = false;
|
|
2751
2878
|
FastEmbedProvider = class _FastEmbedProvider {
|
|
2752
2879
|
name = "fastembed-bge-small";
|
|
@@ -2788,7 +2915,7 @@ var init_fastembed_provider = __esm({
|
|
|
2788
2915
|
if (result.length !== this.dimensions) {
|
|
2789
2916
|
throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);
|
|
2790
2917
|
}
|
|
2791
|
-
|
|
2918
|
+
cacheSet(hash4, result);
|
|
2792
2919
|
return result;
|
|
2793
2920
|
}
|
|
2794
2921
|
async embedBatch(texts) {
|
|
@@ -2813,7 +2940,7 @@ var init_fastembed_provider = __esm({
|
|
|
2813
2940
|
const originalIdx = uncachedIndices[batchIdx];
|
|
2814
2941
|
const plain = Array.from(vec);
|
|
2815
2942
|
results[originalIdx] = plain;
|
|
2816
|
-
|
|
2943
|
+
cacheSet(textHash(uncachedTexts[batchIdx]), plain);
|
|
2817
2944
|
batchIdx++;
|
|
2818
2945
|
}
|
|
2819
2946
|
}
|
|
@@ -2821,14 +2948,6 @@ var init_fastembed_provider = __esm({
|
|
|
2821
2948
|
}
|
|
2822
2949
|
return results;
|
|
2823
2950
|
}
|
|
2824
|
-
cacheSet(hash4, value) {
|
|
2825
|
-
if (cache.size >= MAX_CACHE_SIZE) {
|
|
2826
|
-
const firstKey = cache.keys().next().value;
|
|
2827
|
-
if (firstKey !== void 0) cache.delete(firstKey);
|
|
2828
|
-
}
|
|
2829
|
-
cache.set(hash4, value);
|
|
2830
|
-
diskCacheDirty = true;
|
|
2831
|
-
}
|
|
2832
2951
|
};
|
|
2833
2952
|
}
|
|
2834
2953
|
});
|
|
@@ -2838,7 +2957,15 @@ var transformers_provider_exports = {};
|
|
|
2838
2957
|
__export(transformers_provider_exports, {
|
|
2839
2958
|
TransformersProvider: () => TransformersProvider
|
|
2840
2959
|
});
|
|
2841
|
-
|
|
2960
|
+
import { createHash as createHash2 } from "crypto";
|
|
2961
|
+
function cacheKey2(text2) {
|
|
2962
|
+
return createHash2("sha256").update(text2).digest("hex");
|
|
2963
|
+
}
|
|
2964
|
+
function maxCachePayloadBytes2() {
|
|
2965
|
+
const raw = Number.parseInt(process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES ?? "", 10);
|
|
2966
|
+
return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_CACHE_PAYLOAD_BYTES2;
|
|
2967
|
+
}
|
|
2968
|
+
var cache2, MAX_CACHE_SIZE2, DEFAULT_CACHE_PAYLOAD_BYTES2, cachePayloadBytes2, TransformersProvider;
|
|
2842
2969
|
var init_transformers_provider = __esm({
|
|
2843
2970
|
"src/embedding/transformers-provider.ts"() {
|
|
2844
2971
|
"use strict";
|
|
@@ -2846,6 +2973,8 @@ var init_transformers_provider = __esm({
|
|
|
2846
2973
|
init_provider();
|
|
2847
2974
|
cache2 = /* @__PURE__ */ new Map();
|
|
2848
2975
|
MAX_CACHE_SIZE2 = 5e3;
|
|
2976
|
+
DEFAULT_CACHE_PAYLOAD_BYTES2 = 64 * 1024 * 1024;
|
|
2977
|
+
cachePayloadBytes2 = 0;
|
|
2849
2978
|
TransformersProvider = class _TransformersProvider {
|
|
2850
2979
|
name = "transformers-minilm";
|
|
2851
2980
|
dimensions = 384;
|
|
@@ -2880,7 +3009,7 @@ var init_transformers_provider = __esm({
|
|
|
2880
3009
|
return Promise.all(inputs.map((input) => this.embedInput(input, options)));
|
|
2881
3010
|
}
|
|
2882
3011
|
async embed(text2) {
|
|
2883
|
-
const cached = cache2.get(text2);
|
|
3012
|
+
const cached = cache2.get(cacheKey2(text2));
|
|
2884
3013
|
if (cached) return cached;
|
|
2885
3014
|
const output = await this.extractor(text2, {
|
|
2886
3015
|
pooling: "mean",
|
|
@@ -2890,7 +3019,7 @@ var init_transformers_provider = __esm({
|
|
|
2890
3019
|
if (result.length !== this.dimensions) {
|
|
2891
3020
|
throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);
|
|
2892
3021
|
}
|
|
2893
|
-
this.cacheSet(text2, result);
|
|
3022
|
+
this.cacheSet(cacheKey2(text2), result);
|
|
2894
3023
|
return result;
|
|
2895
3024
|
}
|
|
2896
3025
|
async embedBatch(texts) {
|
|
@@ -2898,7 +3027,7 @@ var init_transformers_provider = __esm({
|
|
|
2898
3027
|
const uncachedIndices = [];
|
|
2899
3028
|
const uncachedTexts = [];
|
|
2900
3029
|
for (let i2 = 0; i2 < texts.length; i2++) {
|
|
2901
|
-
const cached = cache2.get(texts[i2]);
|
|
3030
|
+
const cached = cache2.get(cacheKey2(texts[i2]));
|
|
2902
3031
|
if (cached) {
|
|
2903
3032
|
results[i2] = cached;
|
|
2904
3033
|
} else {
|
|
@@ -2916,17 +3045,27 @@ var init_transformers_provider = __esm({
|
|
|
2916
3045
|
const vec = Array.from(allVecs[i2]);
|
|
2917
3046
|
const originalIdx = uncachedIndices[i2];
|
|
2918
3047
|
results[originalIdx] = vec;
|
|
2919
|
-
this.cacheSet(uncachedTexts[i2], vec);
|
|
3048
|
+
this.cacheSet(cacheKey2(uncachedTexts[i2]), vec);
|
|
2920
3049
|
}
|
|
2921
3050
|
}
|
|
2922
3051
|
return results;
|
|
2923
3052
|
}
|
|
2924
3053
|
cacheSet(key, value) {
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
3054
|
+
const incomingBytes = value.length * 8;
|
|
3055
|
+
if (incomingBytes > maxCachePayloadBytes2()) return;
|
|
3056
|
+
const existing = cache2.get(key);
|
|
3057
|
+
if (existing) cachePayloadBytes2 -= existing.length * 8;
|
|
3058
|
+
else {
|
|
3059
|
+
while (cache2.size >= MAX_CACHE_SIZE2 || cachePayloadBytes2 + incomingBytes > maxCachePayloadBytes2()) {
|
|
3060
|
+
const firstKey = cache2.keys().next().value;
|
|
3061
|
+
if (firstKey === void 0) break;
|
|
3062
|
+
const old = cache2.get(firstKey);
|
|
3063
|
+
cache2.delete(firstKey);
|
|
3064
|
+
if (old) cachePayloadBytes2 -= old.length * 8;
|
|
3065
|
+
}
|
|
2928
3066
|
}
|
|
2929
3067
|
cache2.set(key, value);
|
|
3068
|
+
cachePayloadBytes2 += incomingBytes;
|
|
2930
3069
|
}
|
|
2931
3070
|
};
|
|
2932
3071
|
}
|
|
@@ -2948,7 +3087,7 @@ __export(api_provider_exports, {
|
|
|
2948
3087
|
saveDiskCacheNow: () => saveDiskCacheNow,
|
|
2949
3088
|
seedApiEmbeddingCacheForTests: () => seedApiEmbeddingCacheForTests
|
|
2950
3089
|
});
|
|
2951
|
-
import { createHash as
|
|
3090
|
+
import { createHash as createHash3 } from "crypto";
|
|
2952
3091
|
import { createReadStream, createWriteStream, constants as fsConstants } from "fs";
|
|
2953
3092
|
import { access, readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, rename, stat, unlink } from "fs/promises";
|
|
2954
3093
|
import { join as join3 } from "path";
|
|
@@ -2975,7 +3114,7 @@ function cacheStatFile() {
|
|
|
2975
3114
|
function payloadBytes(vector) {
|
|
2976
3115
|
return vector.length * BYTES_PER_DIM;
|
|
2977
3116
|
}
|
|
2978
|
-
function
|
|
3117
|
+
function maxCachePayloadBytes3() {
|
|
2979
3118
|
const raw = process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES;
|
|
2980
3119
|
if (raw) {
|
|
2981
3120
|
const parsed = Number.parseInt(raw, 10);
|
|
@@ -2985,7 +3124,7 @@ function maxCachePayloadBytes() {
|
|
|
2985
3124
|
}
|
|
2986
3125
|
function maxEntriesForDimensions(dimensions) {
|
|
2987
3126
|
const dim = Math.max(1, Math.floor(dimensions));
|
|
2988
|
-
const byBytes = Math.floor(
|
|
3127
|
+
const byBytes = Math.floor(maxCachePayloadBytes3() / (dim * BYTES_PER_DIM));
|
|
2989
3128
|
return Math.max(1, Math.min(MAX_CACHE_ENTRIES, byBytes));
|
|
2990
3129
|
}
|
|
2991
3130
|
function rememberDimensions(vector) {
|
|
@@ -2998,13 +3137,15 @@ function evictOldest() {
|
|
|
2998
3137
|
if (firstKey === void 0) return;
|
|
2999
3138
|
const old = cache3.get(firstKey);
|
|
3000
3139
|
cache3.delete(firstKey);
|
|
3001
|
-
if (old)
|
|
3140
|
+
if (old) cachePayloadBytes3 -= payloadBytes(old);
|
|
3002
3141
|
}
|
|
3003
3142
|
function evictToFit(incomingBytes, incomingDims) {
|
|
3143
|
+
if (incomingBytes > maxCachePayloadBytes3()) return false;
|
|
3004
3144
|
const limit2 = maxEntriesForDimensions(incomingDims);
|
|
3005
|
-
while (cache3.size > 0 && (cache3.size >= limit2 ||
|
|
3145
|
+
while (cache3.size > 0 && (cache3.size >= limit2 || cachePayloadBytes3 + incomingBytes > maxCachePayloadBytes3())) {
|
|
3006
3146
|
evictOldest();
|
|
3007
3147
|
}
|
|
3148
|
+
return true;
|
|
3008
3149
|
}
|
|
3009
3150
|
function isNumberArray(value) {
|
|
3010
3151
|
return Array.isArray(value) && value.every((entry) => typeof entry === "number");
|
|
@@ -3031,12 +3172,12 @@ function cacheInsert(hash4, value, dirty) {
|
|
|
3031
3172
|
const incoming = payloadBytes(value);
|
|
3032
3173
|
const existing = cache3.get(hash4);
|
|
3033
3174
|
if (existing) {
|
|
3034
|
-
|
|
3175
|
+
cachePayloadBytes3 -= payloadBytes(existing);
|
|
3035
3176
|
cache3.delete(hash4);
|
|
3036
3177
|
}
|
|
3037
|
-
evictToFit(incoming, value.length || cacheDimensions || DEFAULT_ASSUMED_DIMENSIONS);
|
|
3178
|
+
if (!evictToFit(incoming, value.length || cacheDimensions || DEFAULT_ASSUMED_DIMENSIONS)) return;
|
|
3038
3179
|
cache3.set(hash4, value);
|
|
3039
|
-
|
|
3180
|
+
cachePayloadBytes3 += incoming;
|
|
3040
3181
|
if (dirty) diskCacheDirty2 = true;
|
|
3041
3182
|
}
|
|
3042
3183
|
async function readCacheStat() {
|
|
@@ -3072,7 +3213,7 @@ function cacheNamespace(config) {
|
|
|
3072
3213
|
].join("|");
|
|
3073
3214
|
}
|
|
3074
3215
|
function textHash2(text2, namespace) {
|
|
3075
|
-
return
|
|
3216
|
+
return createHash3("sha256").update(`${namespace}\0${text2}`).digest("hex").slice(0, 16);
|
|
3076
3217
|
}
|
|
3077
3218
|
function inputIdentity(input, options = {}) {
|
|
3078
3219
|
return JSON.stringify({
|
|
@@ -3414,7 +3555,7 @@ function getApiEmbeddingDiskCacheLoadCountForTests() {
|
|
|
3414
3555
|
}
|
|
3415
3556
|
function resetApiEmbeddingCacheForTests() {
|
|
3416
3557
|
cache3.clear();
|
|
3417
|
-
|
|
3558
|
+
cachePayloadBytes3 = 0;
|
|
3418
3559
|
cacheDimensions = null;
|
|
3419
3560
|
diskCacheEntryCount = 0;
|
|
3420
3561
|
diskCacheLoaded = false;
|
|
@@ -3425,14 +3566,14 @@ function resetApiEmbeddingCacheForTests() {
|
|
|
3425
3566
|
}
|
|
3426
3567
|
function seedApiEmbeddingCacheForTests(entries) {
|
|
3427
3568
|
cache3.clear();
|
|
3428
|
-
|
|
3569
|
+
cachePayloadBytes3 = 0;
|
|
3429
3570
|
cacheDimensions = null;
|
|
3430
3571
|
for (const [key, value] of entries) cacheInsert(key, value, true);
|
|
3431
3572
|
diskCacheLoaded = true;
|
|
3432
3573
|
diskCacheDirty2 = true;
|
|
3433
3574
|
}
|
|
3434
3575
|
function getApiEmbeddingCachePayloadBytesForTests() {
|
|
3435
|
-
return
|
|
3576
|
+
return cachePayloadBytes3;
|
|
3436
3577
|
}
|
|
3437
3578
|
function getApiEmbeddingJsonlLineCountCallsForTests() {
|
|
3438
3579
|
return jsonlLineCountCalls;
|
|
@@ -3606,7 +3747,7 @@ function scheduleDiskSave() {
|
|
|
3606
3747
|
diskSaveTimer = null;
|
|
3607
3748
|
}, DISK_SAVE_DEBOUNCE_MS);
|
|
3608
3749
|
}
|
|
3609
|
-
function
|
|
3750
|
+
function cacheSet2(hash4, value) {
|
|
3610
3751
|
cacheInsert(hash4, value, true);
|
|
3611
3752
|
}
|
|
3612
3753
|
function resolveEnvEmbeddingApiKey() {
|
|
@@ -3726,7 +3867,7 @@ async function waitForRetry(waitMs, signal) {
|
|
|
3726
3867
|
abortSignal.addEventListener("abort", onAbort, { once: true });
|
|
3727
3868
|
});
|
|
3728
3869
|
}
|
|
3729
|
-
var cache3, MAX_CACHE_ENTRIES, MAX_CACHE_PAYLOAD_BYTES, BYTES_PER_DIM, DEFAULT_ASSUMED_DIMENSIONS, MAX_MIGRATION_VALUE_BYTES,
|
|
3870
|
+
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;
|
|
3730
3871
|
var init_api_provider = __esm({
|
|
3731
3872
|
"src/embedding/api-provider.ts"() {
|
|
3732
3873
|
"use strict";
|
|
@@ -3738,7 +3879,7 @@ var init_api_provider = __esm({
|
|
|
3738
3879
|
BYTES_PER_DIM = 8;
|
|
3739
3880
|
DEFAULT_ASSUMED_DIMENSIONS = 4096;
|
|
3740
3881
|
MAX_MIGRATION_VALUE_BYTES = 16 * 1024 * 1024;
|
|
3741
|
-
|
|
3882
|
+
cachePayloadBytes3 = 0;
|
|
3742
3883
|
cacheDimensions = null;
|
|
3743
3884
|
diskCacheEntryCount = 0;
|
|
3744
3885
|
diskCacheDirty2 = false;
|
|
@@ -3923,7 +4064,7 @@ var init_api_provider = __esm({
|
|
|
3923
4064
|
} else {
|
|
3924
4065
|
embedding = await apiCall();
|
|
3925
4066
|
}
|
|
3926
|
-
|
|
4067
|
+
cacheSet2(hash4, embedding);
|
|
3927
4068
|
scheduleDiskSave();
|
|
3928
4069
|
return embedding;
|
|
3929
4070
|
}
|
|
@@ -3971,7 +4112,7 @@ var init_api_provider = __esm({
|
|
|
3971
4112
|
for (const item of response.data) {
|
|
3972
4113
|
const originalIdx = chunkIndices[item.index];
|
|
3973
4114
|
results[originalIdx] = item.embedding;
|
|
3974
|
-
|
|
4115
|
+
cacheSet2(textHash2(normalizedTexts[originalIdx], this.cacheKeyNamespace), item.embedding);
|
|
3975
4116
|
}
|
|
3976
4117
|
} catch (error) {
|
|
3977
4118
|
const providerLimit = parseBatchLimit(error);
|
|
@@ -4049,7 +4190,7 @@ var init_api_provider = __esm({
|
|
|
4049
4190
|
throw new Error(`Expected ${this.dimensions}d, got ${embedding.length}d; dimension mismatch`);
|
|
4050
4191
|
}
|
|
4051
4192
|
this.trackUsage(response);
|
|
4052
|
-
|
|
4193
|
+
cacheSet2(hash4, embedding);
|
|
4053
4194
|
scheduleDiskSave();
|
|
4054
4195
|
return embedding;
|
|
4055
4196
|
}
|
|
@@ -5432,6 +5573,7 @@ var init_provider2 = __esm({
|
|
|
5432
5573
|
openai: { baseUrl: "https://api.openai.com/v1", model: "gpt-4.1-nano" },
|
|
5433
5574
|
anthropic: { baseUrl: "https://api.anthropic.com/v1", model: "claude-3-5-haiku-latest" },
|
|
5434
5575
|
openrouter: { baseUrl: "https://openrouter.ai/api/v1", model: "openai/gpt-4.1-nano" },
|
|
5576
|
+
atlascloud: { baseUrl: "https://api.atlascloud.ai/v1", model: "deepseek-ai/deepseek-v3.2" },
|
|
5435
5577
|
custom: { baseUrl: "http://localhost:11434/v1", model: "llama3" }
|
|
5436
5578
|
};
|
|
5437
5579
|
currentConfig = null;
|
|
@@ -6195,7 +6337,7 @@ var init_obs_store = __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,
|
|
@@ -9252,13 +9404,13 @@ __export(workspace_exports, {
|
|
|
9252
9404
|
loadKnowledgeWorkspace: () => loadKnowledgeWorkspace,
|
|
9253
9405
|
resolveKnowledgeWorkspaceFile: () => resolveKnowledgeWorkspaceFile
|
|
9254
9406
|
});
|
|
9255
|
-
import { createHash as
|
|
9407
|
+
import { createHash as createHash6 } from "crypto";
|
|
9256
9408
|
import { execFile } from "child_process";
|
|
9257
9409
|
import { promises as fs6 } from "fs";
|
|
9258
9410
|
import path10 from "path";
|
|
9259
9411
|
import { promisify } from "util";
|
|
9260
9412
|
function hash(value) {
|
|
9261
|
-
return
|
|
9413
|
+
return createHash6("sha256").update(value).digest("hex");
|
|
9262
9414
|
}
|
|
9263
9415
|
function workspaceId(projectId, mode) {
|
|
9264
9416
|
return "workspace:" + hash(projectId + ":" + mode).slice(0, 24);
|
|
@@ -10393,14 +10545,14 @@ var init_types2 = __esm({
|
|
|
10393
10545
|
});
|
|
10394
10546
|
|
|
10395
10547
|
// src/media/asset-store.ts
|
|
10396
|
-
import { createHash as
|
|
10548
|
+
import { createHash as createHash7, randomUUID as randomUUID6 } from "crypto";
|
|
10397
10549
|
import { copyFile, lstat, mkdir as mkdir3, open, readFile as readFile3, readdir, rename as rename2, rm, stat as stat2, writeFile as writeFile3 } from "fs/promises";
|
|
10398
10550
|
import path11 from "path";
|
|
10399
10551
|
function mediaRoot(dataDir) {
|
|
10400
10552
|
return path11.resolve(dataDir, "media");
|
|
10401
10553
|
}
|
|
10402
10554
|
function projectStorageKey(projectId) {
|
|
10403
|
-
return
|
|
10555
|
+
return createHash7("sha256").update(projectId).digest("hex").slice(0, 16);
|
|
10404
10556
|
}
|
|
10405
10557
|
function validateUnderRoot(root, candidate) {
|
|
10406
10558
|
const resolved = path11.resolve(candidate);
|
|
@@ -10509,7 +10661,7 @@ async function importMediaBuffer(input) {
|
|
|
10509
10661
|
if (input.bytes.length === 0) throw new Error("Media import rejects empty payloads");
|
|
10510
10662
|
if (input.bytes.length > maxBytes) throw new Error(`Media payload is too large (${input.bytes.length} bytes; limit ${maxBytes})`);
|
|
10511
10663
|
const detected = detectMedia(input.bytes.subarray(0, 32));
|
|
10512
|
-
const sha256 =
|
|
10664
|
+
const sha256 = createHash7("sha256").update(input.bytes).digest("hex");
|
|
10513
10665
|
return importKnownMedia({
|
|
10514
10666
|
dataDir: input.dataDir,
|
|
10515
10667
|
projectId: input.projectId,
|
|
@@ -10527,7 +10679,7 @@ async function readMediaAsset(dataDir, asset, maxBytes = DEFAULT_MAX_MEDIA_BYTES
|
|
|
10527
10679
|
if (asset.byteSize > maxBytes) throw new Error(`Media asset exceeds read limit (${asset.byteSize} bytes; limit ${maxBytes})`);
|
|
10528
10680
|
const bytes = await readFile3(getMediaAssetPath(dataDir, asset));
|
|
10529
10681
|
if (bytes.length !== asset.byteSize) throw new Error(`Media asset size no longer matches metadata: ${asset.id}`);
|
|
10530
|
-
const sha256 =
|
|
10682
|
+
const sha256 = createHash7("sha256").update(bytes).digest("hex");
|
|
10531
10683
|
if (sha256 !== asset.sha256) throw new Error(`Media asset hash no longer matches metadata: ${asset.id}`);
|
|
10532
10684
|
return bytes;
|
|
10533
10685
|
}
|
|
@@ -69223,16 +69375,16 @@ var require_jwtaccess = __commonJS({
|
|
|
69223
69375
|
* @returns A string that returns the cached key.
|
|
69224
69376
|
*/
|
|
69225
69377
|
getCachedKey(url, scopes) {
|
|
69226
|
-
let
|
|
69378
|
+
let cacheKey3 = url;
|
|
69227
69379
|
if (scopes && Array.isArray(scopes) && scopes.length) {
|
|
69228
|
-
|
|
69380
|
+
cacheKey3 = url ? `${url}_${scopes.join("_")}` : `${scopes.join("_")}`;
|
|
69229
69381
|
} else if (typeof scopes === "string") {
|
|
69230
|
-
|
|
69382
|
+
cacheKey3 = url ? `${url}_${scopes}` : scopes;
|
|
69231
69383
|
}
|
|
69232
|
-
if (!
|
|
69384
|
+
if (!cacheKey3) {
|
|
69233
69385
|
throw Error("Scopes or url must be provided");
|
|
69234
69386
|
}
|
|
69235
|
-
return
|
|
69387
|
+
return cacheKey3;
|
|
69236
69388
|
}
|
|
69237
69389
|
/**
|
|
69238
69390
|
* Get a non-expired access token, after refreshing if necessary.
|
|
@@ -75778,7 +75930,7 @@ var require_websocket = __commonJS({
|
|
|
75778
75930
|
var http3 = __require("http");
|
|
75779
75931
|
var net = __require("net");
|
|
75780
75932
|
var tls = __require("tls");
|
|
75781
|
-
var { randomBytes, createHash:
|
|
75933
|
+
var { randomBytes, createHash: createHash17 } = __require("crypto");
|
|
75782
75934
|
var { Duplex, Readable: Readable2 } = __require("stream");
|
|
75783
75935
|
var { URL: URL2 } = __require("url");
|
|
75784
75936
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -76446,7 +76598,7 @@ var require_websocket = __commonJS({
|
|
|
76446
76598
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
76447
76599
|
return;
|
|
76448
76600
|
}
|
|
76449
|
-
const digest2 =
|
|
76601
|
+
const digest2 = createHash17("sha1").update(key + GUID).digest("base64");
|
|
76450
76602
|
if (res.headers["sec-websocket-accept"] !== digest2) {
|
|
76451
76603
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
76452
76604
|
return;
|
|
@@ -76818,7 +76970,7 @@ var require_websocket_server = __commonJS({
|
|
|
76818
76970
|
var EventEmitter = __require("events");
|
|
76819
76971
|
var http3 = __require("http");
|
|
76820
76972
|
var { Duplex } = __require("stream");
|
|
76821
|
-
var { createHash:
|
|
76973
|
+
var { createHash: createHash17 } = __require("crypto");
|
|
76822
76974
|
var extension3 = require_extension();
|
|
76823
76975
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
76824
76976
|
var subprotocol2 = require_subprotocol();
|
|
@@ -77125,7 +77277,7 @@ var require_websocket_server = __commonJS({
|
|
|
77125
77277
|
);
|
|
77126
77278
|
}
|
|
77127
77279
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
77128
|
-
const digest2 =
|
|
77280
|
+
const digest2 = createHash17("sha1").update(key + GUID).digest("base64");
|
|
77129
77281
|
const headers = [
|
|
77130
77282
|
"HTTP/1.1 101 Switching Protocols",
|
|
77131
77283
|
"Upgrade: websocket",
|
|
@@ -145704,9 +145856,9 @@ var init_long_term = __esm({
|
|
|
145704
145856
|
});
|
|
145705
145857
|
|
|
145706
145858
|
// src/codegraph/ids.ts
|
|
145707
|
-
import { createHash as
|
|
145859
|
+
import { createHash as createHash8 } from "crypto";
|
|
145708
145860
|
function digest(input) {
|
|
145709
|
-
return
|
|
145861
|
+
return createHash8("sha256").update(input).digest("hex").slice(0, 16);
|
|
145710
145862
|
}
|
|
145711
145863
|
function normalizeCodePath(path23) {
|
|
145712
145864
|
return path23.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+/g, "/");
|
|
@@ -146754,7 +146906,7 @@ var init_store = __esm({
|
|
|
146754
146906
|
|
|
146755
146907
|
// src/codegraph/code-state.ts
|
|
146756
146908
|
import { execFile as execFile2 } from "child_process";
|
|
146757
|
-
import { createHash as
|
|
146909
|
+
import { createHash as createHash9 } from "crypto";
|
|
146758
146910
|
import { promisify as promisify3 } from "util";
|
|
146759
146911
|
async function runGit(rootPath, args) {
|
|
146760
146912
|
try {
|
|
@@ -146783,7 +146935,7 @@ function changedPathCount(status) {
|
|
|
146783
146935
|
return count2;
|
|
146784
146936
|
}
|
|
146785
146937
|
function fingerprint(baseRevision, status) {
|
|
146786
|
-
return
|
|
146938
|
+
return createHash9("sha256").update(baseRevision ?? "").update("\0").update(status).digest("hex");
|
|
146787
146939
|
}
|
|
146788
146940
|
async function collectCodeStateSnapshot(input) {
|
|
146789
146941
|
const [revision, status] = await Promise.all([
|
|
@@ -146877,12 +147029,12 @@ var init_exclude3 = __esm({
|
|
|
146877
147029
|
});
|
|
146878
147030
|
|
|
146879
147031
|
// src/codegraph/semantic-provider.ts
|
|
146880
|
-
import { createHash as
|
|
147032
|
+
import { createHash as createHash10 } from "crypto";
|
|
146881
147033
|
import "fs";
|
|
146882
147034
|
import { resolve } from "path";
|
|
146883
147035
|
import ts from "typescript";
|
|
146884
147036
|
function hashText(value) {
|
|
146885
|
-
return
|
|
147037
|
+
return createHash10("sha256").update(value).digest("hex");
|
|
146886
147038
|
}
|
|
146887
147039
|
function canonicalPath(value) {
|
|
146888
147040
|
const normalized = resolve(value).replace(/\\/g, "/");
|
|
@@ -147227,11 +147379,11 @@ __export(lite_provider_exports, {
|
|
|
147227
147379
|
indexProjectLite: () => indexProjectLite,
|
|
147228
147380
|
refreshProjectLite: () => refreshProjectLite
|
|
147229
147381
|
});
|
|
147230
|
-
import { createHash as
|
|
147382
|
+
import { createHash as createHash11 } from "crypto";
|
|
147231
147383
|
import { existsSync as existsSync11, readdirSync as readdirSync2, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
|
|
147232
147384
|
import { join as join4, relative as relative2 } from "path";
|
|
147233
147385
|
function hashText2(text2) {
|
|
147234
|
-
return
|
|
147386
|
+
return createHash11("sha256").update(text2).digest("hex");
|
|
147235
147387
|
}
|
|
147236
147388
|
function extension2(path23) {
|
|
147237
147389
|
const index = path23.lastIndexOf(".");
|
|
@@ -147864,7 +148016,7 @@ var claim_store_exports = {};
|
|
|
147864
148016
|
__export(claim_store_exports, {
|
|
147865
148017
|
ClaimStore: () => ClaimStore
|
|
147866
148018
|
});
|
|
147867
|
-
import { createHash as
|
|
148019
|
+
import { createHash as createHash12, randomUUID as randomUUID12 } from "crypto";
|
|
147868
148020
|
function optionalText3(value) {
|
|
147869
148021
|
return typeof value === "string" && value ? value : void 0;
|
|
147870
148022
|
}
|
|
@@ -147917,7 +148069,7 @@ function rowToEvent3(row) {
|
|
|
147917
148069
|
};
|
|
147918
148070
|
}
|
|
147919
148071
|
function evidenceKey(input) {
|
|
147920
|
-
return
|
|
148072
|
+
return createHash12("sha256").update(JSON.stringify([
|
|
147921
148073
|
input.evidenceKind,
|
|
147922
148074
|
input.evidenceId,
|
|
147923
148075
|
input.relation,
|
|
@@ -148115,7 +148267,7 @@ __export(claims_exports, {
|
|
|
148115
148267
|
supersedeClaim: () => supersedeClaim,
|
|
148116
148268
|
writeClaim: () => writeClaim
|
|
148117
148269
|
});
|
|
148118
|
-
import { createHash as
|
|
148270
|
+
import { createHash as createHash13, randomUUID as randomUUID13 } from "crypto";
|
|
148119
148271
|
function compactText2(value, field) {
|
|
148120
148272
|
if (typeof value !== "string") throw new Error("Claim " + field + " must be text");
|
|
148121
148273
|
const sanitized = sanitizeCredentials(value).trim().replace(/\s+/g, " ");
|
|
@@ -148127,7 +148279,7 @@ function normalizedTerm(value) {
|
|
|
148127
148279
|
return compactText2(value, "identity").toLocaleLowerCase("en-US");
|
|
148128
148280
|
}
|
|
148129
148281
|
function hashIdentity(parts) {
|
|
148130
|
-
return
|
|
148282
|
+
return createHash13("sha256").update(parts.join(String.fromCharCode(31))).digest("hex");
|
|
148131
148283
|
}
|
|
148132
148284
|
function buildClaimIdentity(input) {
|
|
148133
148285
|
const subject = normalizedTerm(input.subject);
|
|
@@ -148368,7 +148520,7 @@ function supersedeClaim(store, input) {
|
|
|
148368
148520
|
});
|
|
148369
148521
|
}
|
|
148370
148522
|
function hashObservation(observation) {
|
|
148371
|
-
return
|
|
148523
|
+
return createHash13("sha256").update(JSON.stringify([
|
|
148372
148524
|
observation.title,
|
|
148373
148525
|
observation.narrative,
|
|
148374
148526
|
observation.facts,
|
|
@@ -148612,11 +148764,11 @@ var init_frontmatter = __esm({
|
|
|
148612
148764
|
});
|
|
148613
148765
|
|
|
148614
148766
|
// src/knowledge/markdown.ts
|
|
148615
|
-
import { createHash as
|
|
148767
|
+
import { createHash as createHash14 } from "crypto";
|
|
148616
148768
|
import { promises as fs10 } from "fs";
|
|
148617
148769
|
import path18 from "path";
|
|
148618
148770
|
function hashContent(content) {
|
|
148619
|
-
return
|
|
148771
|
+
return createHash14("sha256").update(content).digest("hex");
|
|
148620
148772
|
}
|
|
148621
148773
|
function stringField(data, key) {
|
|
148622
148774
|
const value = data[key];
|
|
@@ -148742,11 +148894,11 @@ __export(wiki_exports, {
|
|
|
148742
148894
|
lintKnowledgeWorkspace: () => lintKnowledgeWorkspace,
|
|
148743
148895
|
readKnowledgePage: () => readKnowledgePage
|
|
148744
148896
|
});
|
|
148745
|
-
import { createHash as
|
|
148897
|
+
import { createHash as createHash15 } from "crypto";
|
|
148746
148898
|
import { promises as fs11 } from "fs";
|
|
148747
148899
|
import path19 from "path";
|
|
148748
148900
|
function hash2(value) {
|
|
148749
|
-
return
|
|
148901
|
+
return createHash15("sha256").update(value).digest("hex");
|
|
148750
148902
|
}
|
|
148751
148903
|
function now() {
|
|
148752
148904
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -149603,11 +149755,11 @@ __export(workflows_exports, {
|
|
|
149603
149755
|
syncCanonicalWorkflows: () => syncCanonicalWorkflows,
|
|
149604
149756
|
writeCanonicalWorkflow: () => writeCanonicalWorkflow
|
|
149605
149757
|
});
|
|
149606
|
-
import { createHash as
|
|
149758
|
+
import { createHash as createHash16 } from "crypto";
|
|
149607
149759
|
import { promises as fs12 } from "fs";
|
|
149608
149760
|
import path20 from "path";
|
|
149609
149761
|
function hash3(value) {
|
|
149610
|
-
return
|
|
149762
|
+
return createHash16("sha256").update(value).digest("hex");
|
|
149611
149763
|
}
|
|
149612
149764
|
function now2() {
|
|
149613
149765
|
return (/* @__PURE__ */ new Date()).toISOString();
|