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,
|
|
@@ -9008,9 +9160,9 @@ var init_evidence_store = __esm({
|
|
|
9008
9160
|
});
|
|
9009
9161
|
|
|
9010
9162
|
// src/codegraph/ids.ts
|
|
9011
|
-
import { createHash as
|
|
9163
|
+
import { createHash as createHash6 } from "crypto";
|
|
9012
9164
|
function digest(input) {
|
|
9013
|
-
return
|
|
9165
|
+
return createHash6("sha256").update(input).digest("hex").slice(0, 16);
|
|
9014
9166
|
}
|
|
9015
9167
|
function normalizeCodePath(path22) {
|
|
9016
9168
|
return path22.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+/g, "/");
|
|
@@ -11580,13 +11732,13 @@ __export(workspace_exports, {
|
|
|
11580
11732
|
loadKnowledgeWorkspace: () => loadKnowledgeWorkspace,
|
|
11581
11733
|
resolveKnowledgeWorkspaceFile: () => resolveKnowledgeWorkspaceFile
|
|
11582
11734
|
});
|
|
11583
|
-
import { createHash as
|
|
11735
|
+
import { createHash as createHash7 } from "crypto";
|
|
11584
11736
|
import { execFile } from "child_process";
|
|
11585
11737
|
import { promises as fs6 } from "fs";
|
|
11586
11738
|
import path10 from "path";
|
|
11587
11739
|
import { promisify } from "util";
|
|
11588
11740
|
function hash(value) {
|
|
11589
|
-
return
|
|
11741
|
+
return createHash7("sha256").update(value).digest("hex");
|
|
11590
11742
|
}
|
|
11591
11743
|
function workspaceId(projectId, mode) {
|
|
11592
11744
|
return "workspace:" + hash(projectId + ":" + mode).slice(0, 24);
|
|
@@ -12721,14 +12873,14 @@ var init_types2 = __esm({
|
|
|
12721
12873
|
});
|
|
12722
12874
|
|
|
12723
12875
|
// src/media/asset-store.ts
|
|
12724
|
-
import { createHash as
|
|
12876
|
+
import { createHash as createHash8, randomUUID as randomUUID7 } from "crypto";
|
|
12725
12877
|
import { copyFile, lstat, mkdir as mkdir3, open, readFile as readFile3, readdir, rename as rename2, rm, stat as stat2, writeFile as writeFile3 } from "fs/promises";
|
|
12726
12878
|
import path11 from "path";
|
|
12727
12879
|
function mediaRoot(dataDir) {
|
|
12728
12880
|
return path11.resolve(dataDir, "media");
|
|
12729
12881
|
}
|
|
12730
12882
|
function projectStorageKey(projectId) {
|
|
12731
|
-
return
|
|
12883
|
+
return createHash8("sha256").update(projectId).digest("hex").slice(0, 16);
|
|
12732
12884
|
}
|
|
12733
12885
|
function validateUnderRoot(root, candidate) {
|
|
12734
12886
|
const resolved = path11.resolve(candidate);
|
|
@@ -12837,7 +12989,7 @@ async function importMediaBuffer(input) {
|
|
|
12837
12989
|
if (input.bytes.length === 0) throw new Error("Media import rejects empty payloads");
|
|
12838
12990
|
if (input.bytes.length > maxBytes) throw new Error(`Media payload is too large (${input.bytes.length} bytes; limit ${maxBytes})`);
|
|
12839
12991
|
const detected = detectMedia(input.bytes.subarray(0, 32));
|
|
12840
|
-
const sha256 =
|
|
12992
|
+
const sha256 = createHash8("sha256").update(input.bytes).digest("hex");
|
|
12841
12993
|
return importKnownMedia({
|
|
12842
12994
|
dataDir: input.dataDir,
|
|
12843
12995
|
projectId: input.projectId,
|
|
@@ -12855,7 +13007,7 @@ async function readMediaAsset(dataDir, asset, maxBytes = DEFAULT_MAX_MEDIA_BYTES
|
|
|
12855
13007
|
if (asset.byteSize > maxBytes) throw new Error(`Media asset exceeds read limit (${asset.byteSize} bytes; limit ${maxBytes})`);
|
|
12856
13008
|
const bytes = await readFile3(getMediaAssetPath(dataDir, asset));
|
|
12857
13009
|
if (bytes.length !== asset.byteSize) throw new Error(`Media asset size no longer matches metadata: ${asset.id}`);
|
|
12858
|
-
const sha256 =
|
|
13010
|
+
const sha256 = createHash8("sha256").update(bytes).digest("hex");
|
|
12859
13011
|
if (sha256 !== asset.sha256) throw new Error(`Media asset hash no longer matches metadata: ${asset.id}`);
|
|
12860
13012
|
return bytes;
|
|
12861
13013
|
}
|
|
@@ -71551,16 +71703,16 @@ var require_jwtaccess = __commonJS({
|
|
|
71551
71703
|
* @returns A string that returns the cached key.
|
|
71552
71704
|
*/
|
|
71553
71705
|
getCachedKey(url, scopes) {
|
|
71554
|
-
let
|
|
71706
|
+
let cacheKey3 = url;
|
|
71555
71707
|
if (scopes && Array.isArray(scopes) && scopes.length) {
|
|
71556
|
-
|
|
71708
|
+
cacheKey3 = url ? `${url}_${scopes.join("_")}` : `${scopes.join("_")}`;
|
|
71557
71709
|
} else if (typeof scopes === "string") {
|
|
71558
|
-
|
|
71710
|
+
cacheKey3 = url ? `${url}_${scopes}` : scopes;
|
|
71559
71711
|
}
|
|
71560
|
-
if (!
|
|
71712
|
+
if (!cacheKey3) {
|
|
71561
71713
|
throw Error("Scopes or url must be provided");
|
|
71562
71714
|
}
|
|
71563
|
-
return
|
|
71715
|
+
return cacheKey3;
|
|
71564
71716
|
}
|
|
71565
71717
|
/**
|
|
71566
71718
|
* Get a non-expired access token, after refreshing if necessary.
|
|
@@ -78106,7 +78258,7 @@ var require_websocket = __commonJS({
|
|
|
78106
78258
|
var http3 = __require("http");
|
|
78107
78259
|
var net = __require("net");
|
|
78108
78260
|
var tls = __require("tls");
|
|
78109
|
-
var { randomBytes, createHash:
|
|
78261
|
+
var { randomBytes, createHash: createHash17 } = __require("crypto");
|
|
78110
78262
|
var { Duplex, Readable: Readable2 } = __require("stream");
|
|
78111
78263
|
var { URL: URL2 } = __require("url");
|
|
78112
78264
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -78774,7 +78926,7 @@ var require_websocket = __commonJS({
|
|
|
78774
78926
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
78775
78927
|
return;
|
|
78776
78928
|
}
|
|
78777
|
-
const digest2 =
|
|
78929
|
+
const digest2 = createHash17("sha1").update(key + GUID).digest("base64");
|
|
78778
78930
|
if (res.headers["sec-websocket-accept"] !== digest2) {
|
|
78779
78931
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
78780
78932
|
return;
|
|
@@ -79146,7 +79298,7 @@ var require_websocket_server = __commonJS({
|
|
|
79146
79298
|
var EventEmitter = __require("events");
|
|
79147
79299
|
var http3 = __require("http");
|
|
79148
79300
|
var { Duplex } = __require("stream");
|
|
79149
|
-
var { createHash:
|
|
79301
|
+
var { createHash: createHash17 } = __require("crypto");
|
|
79150
79302
|
var extension3 = require_extension();
|
|
79151
79303
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
79152
79304
|
var subprotocol2 = require_subprotocol();
|
|
@@ -79453,7 +79605,7 @@ var require_websocket_server = __commonJS({
|
|
|
79453
79605
|
);
|
|
79454
79606
|
}
|
|
79455
79607
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
79456
|
-
const digest2 =
|
|
79608
|
+
const digest2 = createHash17("sha1").update(key + GUID).digest("base64");
|
|
79457
79609
|
const headers = [
|
|
79458
79610
|
"HTTP/1.1 101 Switching Protocols",
|
|
79459
79611
|
"Upgrade: websocket",
|
|
@@ -148033,7 +148185,7 @@ var init_long_term = __esm({
|
|
|
148033
148185
|
|
|
148034
148186
|
// src/codegraph/code-state.ts
|
|
148035
148187
|
import { execFile as execFile2 } from "child_process";
|
|
148036
|
-
import { createHash as
|
|
148188
|
+
import { createHash as createHash9 } from "crypto";
|
|
148037
148189
|
import { promisify as promisify3 } from "util";
|
|
148038
148190
|
async function runGit(rootPath, args) {
|
|
148039
148191
|
try {
|
|
@@ -148062,7 +148214,7 @@ function changedPathCount(status) {
|
|
|
148062
148214
|
return count2;
|
|
148063
148215
|
}
|
|
148064
148216
|
function fingerprint(baseRevision, status) {
|
|
148065
|
-
return
|
|
148217
|
+
return createHash9("sha256").update(baseRevision ?? "").update("\0").update(status).digest("hex");
|
|
148066
148218
|
}
|
|
148067
148219
|
async function collectCodeStateSnapshot(input) {
|
|
148068
148220
|
const [revision, status] = await Promise.all([
|
|
@@ -148156,12 +148308,12 @@ var init_exclude3 = __esm({
|
|
|
148156
148308
|
});
|
|
148157
148309
|
|
|
148158
148310
|
// src/codegraph/semantic-provider.ts
|
|
148159
|
-
import { createHash as
|
|
148311
|
+
import { createHash as createHash10 } from "crypto";
|
|
148160
148312
|
import "fs";
|
|
148161
148313
|
import { resolve } from "path";
|
|
148162
148314
|
import ts from "typescript";
|
|
148163
148315
|
function hashText(value) {
|
|
148164
|
-
return
|
|
148316
|
+
return createHash10("sha256").update(value).digest("hex");
|
|
148165
148317
|
}
|
|
148166
148318
|
function canonicalPath(value) {
|
|
148167
148319
|
const normalized = resolve(value).replace(/\\/g, "/");
|
|
@@ -148506,11 +148658,11 @@ __export(lite_provider_exports, {
|
|
|
148506
148658
|
indexProjectLite: () => indexProjectLite,
|
|
148507
148659
|
refreshProjectLite: () => refreshProjectLite
|
|
148508
148660
|
});
|
|
148509
|
-
import { createHash as
|
|
148661
|
+
import { createHash as createHash11 } from "crypto";
|
|
148510
148662
|
import { existsSync as existsSync11, readdirSync as readdirSync2, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
|
|
148511
148663
|
import { join as join4, relative as relative2 } from "path";
|
|
148512
148664
|
function hashText2(text2) {
|
|
148513
|
-
return
|
|
148665
|
+
return createHash11("sha256").update(text2).digest("hex");
|
|
148514
148666
|
}
|
|
148515
148667
|
function extension2(path22) {
|
|
148516
148668
|
const index = path22.lastIndexOf(".");
|
|
@@ -148986,7 +149138,7 @@ var claim_store_exports = {};
|
|
|
148986
149138
|
__export(claim_store_exports, {
|
|
148987
149139
|
ClaimStore: () => ClaimStore
|
|
148988
149140
|
});
|
|
148989
|
-
import { createHash as
|
|
149141
|
+
import { createHash as createHash12, randomUUID as randomUUID12 } from "crypto";
|
|
148990
149142
|
function optionalText3(value) {
|
|
148991
149143
|
return typeof value === "string" && value ? value : void 0;
|
|
148992
149144
|
}
|
|
@@ -149039,7 +149191,7 @@ function rowToEvent3(row) {
|
|
|
149039
149191
|
};
|
|
149040
149192
|
}
|
|
149041
149193
|
function evidenceKey(input) {
|
|
149042
|
-
return
|
|
149194
|
+
return createHash12("sha256").update(JSON.stringify([
|
|
149043
149195
|
input.evidenceKind,
|
|
149044
149196
|
input.evidenceId,
|
|
149045
149197
|
input.relation,
|
|
@@ -149237,7 +149389,7 @@ __export(claims_exports, {
|
|
|
149237
149389
|
supersedeClaim: () => supersedeClaim,
|
|
149238
149390
|
writeClaim: () => writeClaim
|
|
149239
149391
|
});
|
|
149240
|
-
import { createHash as
|
|
149392
|
+
import { createHash as createHash13, randomUUID as randomUUID13 } from "crypto";
|
|
149241
149393
|
function compactText2(value, field) {
|
|
149242
149394
|
if (typeof value !== "string") throw new Error("Claim " + field + " must be text");
|
|
149243
149395
|
const sanitized = sanitizeCredentials(value).trim().replace(/\s+/g, " ");
|
|
@@ -149249,7 +149401,7 @@ function normalizedTerm(value) {
|
|
|
149249
149401
|
return compactText2(value, "identity").toLocaleLowerCase("en-US");
|
|
149250
149402
|
}
|
|
149251
149403
|
function hashIdentity(parts) {
|
|
149252
|
-
return
|
|
149404
|
+
return createHash13("sha256").update(parts.join(String.fromCharCode(31))).digest("hex");
|
|
149253
149405
|
}
|
|
149254
149406
|
function buildClaimIdentity(input) {
|
|
149255
149407
|
const subject = normalizedTerm(input.subject);
|
|
@@ -149490,7 +149642,7 @@ function supersedeClaim(store, input) {
|
|
|
149490
149642
|
});
|
|
149491
149643
|
}
|
|
149492
149644
|
function hashObservation(observation) {
|
|
149493
|
-
return
|
|
149645
|
+
return createHash13("sha256").update(JSON.stringify([
|
|
149494
149646
|
observation.title,
|
|
149495
149647
|
observation.narrative,
|
|
149496
149648
|
observation.facts,
|
|
@@ -149734,11 +149886,11 @@ var init_frontmatter = __esm({
|
|
|
149734
149886
|
});
|
|
149735
149887
|
|
|
149736
149888
|
// src/knowledge/markdown.ts
|
|
149737
|
-
import { createHash as
|
|
149889
|
+
import { createHash as createHash14 } from "crypto";
|
|
149738
149890
|
import { promises as fs10 } from "fs";
|
|
149739
149891
|
import path18 from "path";
|
|
149740
149892
|
function hashContent(content) {
|
|
149741
|
-
return
|
|
149893
|
+
return createHash14("sha256").update(content).digest("hex");
|
|
149742
149894
|
}
|
|
149743
149895
|
function stringField(data, key) {
|
|
149744
149896
|
const value = data[key];
|
|
@@ -149864,11 +150016,11 @@ __export(wiki_exports, {
|
|
|
149864
150016
|
lintKnowledgeWorkspace: () => lintKnowledgeWorkspace,
|
|
149865
150017
|
readKnowledgePage: () => readKnowledgePage
|
|
149866
150018
|
});
|
|
149867
|
-
import { createHash as
|
|
150019
|
+
import { createHash as createHash15 } from "crypto";
|
|
149868
150020
|
import { promises as fs11 } from "fs";
|
|
149869
150021
|
import path19 from "path";
|
|
149870
150022
|
function hash2(value) {
|
|
149871
|
-
return
|
|
150023
|
+
return createHash15("sha256").update(value).digest("hex");
|
|
149872
150024
|
}
|
|
149873
150025
|
function now() {
|
|
149874
150026
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -150725,11 +150877,11 @@ __export(workflows_exports, {
|
|
|
150725
150877
|
syncCanonicalWorkflows: () => syncCanonicalWorkflows,
|
|
150726
150878
|
writeCanonicalWorkflow: () => writeCanonicalWorkflow
|
|
150727
150879
|
});
|
|
150728
|
-
import { createHash as
|
|
150880
|
+
import { createHash as createHash16 } from "crypto";
|
|
150729
150881
|
import { promises as fs12 } from "fs";
|
|
150730
150882
|
import path20 from "path";
|
|
150731
150883
|
function hash3(value) {
|
|
150732
|
-
return
|
|
150884
|
+
return createHash16("sha256").update(value).digest("hex");
|
|
150733
150885
|
}
|
|
150734
150886
|
function now2() {
|
|
150735
150887
|
return (/* @__PURE__ */ new Date()).toISOString();
|