memorix 1.9.4 → 1.9.6
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 +75 -1
- package/README.md +12 -6
- package/README.zh-CN.md +12 -6
- package/dist/cli/index.js +2533 -585
- package/dist/index.d.ts +15 -8
- package/dist/index.js +1201 -284
- package/dist/maintenance-runner.js +387 -216
- package/dist/media-audio-runner.js +300 -129
- package/dist/media-video-runner.js +300 -129
- package/dist/memcode-runtime/CHANGELOG.md +75 -1
- package/dist/sdk.d.ts +1 -0
- package/dist/sdk.js +1882 -998
- package/dist/types.d.ts +1 -1
- package/dist/vector-backfill-runner.js +300 -129
- package/docs/AGENT_OPERATOR_PLAYBOOK.md +47 -3
- package/docs/API_REFERENCE.md +39 -1
- package/docs/CONFIGURATION.md +58 -1
- package/docs/DEVELOPMENT.md +1 -1
- package/docs/DOCKER.md +23 -3
- package/docs/INTEGRATIONS.md +1 -1
- package/docs/KNOWN_ISSUES_AND_ROADMAP.md +61 -1
- package/docs/MULTI-DEVICE-SYNC-RESEARCH.md +4 -0
- package/docs/PERFORMANCE.md +46 -2
- package/docs/README.md +2 -1
- package/docs/SETUP.md +56 -1
- package/package.json +3 -2
- 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 +15 -3
- package/src/cli/commands/agent-integrations.ts +57 -0
- package/src/cli/commands/background.ts +11 -2
- 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 +435 -84
- package/src/cli/commands/setup.ts +77 -10
- package/src/cli/commands/sync-store.ts +47 -12
- package/src/cli/commands/sync.ts +26 -0
- 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/dashboard/server.ts +10 -12
- 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/integrations/registry.ts +1 -1
- 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/memory/graph.ts +10 -8
- package/src/memory/session.ts +1 -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/sdk.ts +24 -0
- package/src/server/mcp-binding-store.ts +14 -3
- package/src/server/modern-mcp-bridge.ts +153 -27
- package/src/server/tool-profile.ts +3 -2
- package/src/server.ts +131 -7
- package/src/store/file-lock.ts +28 -3
- package/src/store/graph-store.ts +178 -46
- package/src/store/persistence.ts +14 -9
- package/src/store/sqlite-db.ts +150 -7
- package/src/store/sqlite-store.ts +32 -27
- package/src/sync/engine.ts +9 -7
- package/src/sync/namespace.ts +23 -0
- package/src/sync/policy.ts +19 -4
- package/src/sync/store-port.ts +43 -13
- package/src/sync/types.ts +2 -0
- package/src/team/team-store.ts +62 -27
- package/src/types.ts +1 -1
- package/src/workspace/mcp-adapters/grok.ts +32 -0
|
@@ -380,11 +380,21 @@ function applySchemaMigrations(db2) {
|
|
|
380
380
|
apply();
|
|
381
381
|
}
|
|
382
382
|
}
|
|
383
|
+
function normalizeDataDir(dataDir) {
|
|
384
|
+
return path3.resolve(dataDir);
|
|
385
|
+
}
|
|
386
|
+
function touchDatabase(normalized, db2) {
|
|
387
|
+
_dbCache.delete(normalized);
|
|
388
|
+
_dbCache.set(normalized, db2);
|
|
389
|
+
}
|
|
383
390
|
function getDatabase(dataDir) {
|
|
384
|
-
const normalized =
|
|
391
|
+
const normalized = normalizeDataDir(dataDir);
|
|
385
392
|
assertNotHomeDataDir(normalized);
|
|
386
393
|
const existing = _dbCache.get(normalized);
|
|
387
|
-
if (existing)
|
|
394
|
+
if (existing) {
|
|
395
|
+
touchDatabase(normalized, existing);
|
|
396
|
+
return existing;
|
|
397
|
+
}
|
|
388
398
|
loadBetterSqlite3();
|
|
389
399
|
fs.mkdirSync(dataDir, { recursive: true });
|
|
390
400
|
const dbPath = path3.join(dataDir, "memorix.db");
|
|
@@ -414,6 +424,8 @@ function getDatabase(dataDir) {
|
|
|
414
424
|
db2.exec(CREATE_MAINTENANCE_JOBS_TABLE);
|
|
415
425
|
db2.exec(CREATE_MAINTENANCE_TARGETS_TABLE);
|
|
416
426
|
db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
|
|
427
|
+
db2.exec(CREATE_TASK_CONTINUITY_EVENTS_TABLE);
|
|
428
|
+
db2.exec(CREATE_AGENT_EFFECTS_TABLE);
|
|
417
429
|
try {
|
|
418
430
|
db2.exec(`ALTER TABLE mini_skills ADD COLUMN sourceSnapshot TEXT NOT NULL DEFAULT ''`);
|
|
419
431
|
} catch {
|
|
@@ -452,7 +464,7 @@ function getDatabase(dataDir) {
|
|
|
452
464
|
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('storage_generation', '0')`).run();
|
|
453
465
|
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('next_id', '1')`).run();
|
|
454
466
|
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('mini_skills_generation', '0')`).run();
|
|
455
|
-
|
|
467
|
+
touchDatabase(normalized, db2);
|
|
456
468
|
return db2;
|
|
457
469
|
} catch (error) {
|
|
458
470
|
try {
|
|
@@ -470,8 +482,9 @@ function closeAllDatabases() {
|
|
|
470
482
|
}
|
|
471
483
|
_dbCache.delete(key);
|
|
472
484
|
}
|
|
485
|
+
_dbLeases.clear();
|
|
473
486
|
}
|
|
474
|
-
var BetterSqlite3, CREATE_OBSERVATIONS_TABLE, CREATE_MINI_SKILLS_TABLE, CREATE_SESSIONS_TABLE, CREATE_META_TABLE, CREATE_TEAM_AGENTS_TABLE, CREATE_TEAM_MESSAGES_TABLE, CREATE_TEAM_TASKS_TABLE, CREATE_TEAM_TASK_DEPS_TABLE, CREATE_TEAM_LOCKS_TABLE, CREATE_TEAM_ROLES_TABLE, CREATE_CHAT_TRANSCRIPT_TABLE, CREATE_GRAPH_ENTITIES_TABLE, CREATE_GRAPH_RELATIONS_TABLE, CREATE_CODE_FILES_TABLE, CREATE_CODE_SYMBOLS_TABLE, CREATE_CODE_EDGES_TABLE, CREATE_OBSERVATION_CODE_REFS_TABLE, CREATE_SCHEMA_MIGRATIONS_TABLE, CREATE_CODE_STATE_SNAPSHOTS_TABLE, CREATE_CODE_STATE_SNAPSHOT_FILES_TABLE, CREATE_KNOWLEDGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_CLAIM_EVIDENCE_TABLE, CREATE_KNOWLEDGE_CLAIM_EVENTS_TABLE, CREATE_KNOWLEDGE_WORKSPACES_TABLE, CREATE_KNOWLEDGE_PAGES_TABLE, CREATE_KNOWLEDGE_PAGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_PAGE_LINKS_TABLE, CREATE_KNOWLEDGE_PROPOSALS_TABLE, CREATE_KNOWLEDGE_WORKFLOWS_TABLE, CREATE_KNOWLEDGE_WORKFLOW_RUNS_TABLE, CREATE_LONG_TERM_MEMORIES_TABLE, CREATE_LONG_TERM_MEMORY_EVIDENCE_TABLE, CREATE_LONG_TERM_MEMORY_EVENTS_TABLE, CREATE_MEMORY_OUTCOME_SIGNALS_TABLE, CREATE_MEDIA_ASSETS_TABLE, CREATE_MEDIA_ASSET_LINKS_TABLE, CREATE_MEDIA_DERIVATIONS_TABLE, CREATE_MEDIA_EMBEDDING_PROFILES_TABLE, CREATE_MEDIA_EMBEDDINGS_TABLE, CREATE_MEDIA_JOBS_TABLE, CREATE_MAINTENANCE_JOBS_TABLE, CREATE_MAINTENANCE_TARGETS_TABLE, CREATE_COMPACTION_CHECKPOINTS_TABLE, CREATE_EVIDENCE_CARDS_TABLE, CREATE_EVIDENCE_CARD_EVENTS_TABLE, CREATE_MEMORY_FEEDBACK_STATES_TABLE, CREATE_MEMORY_FEEDBACK_EVENTS_TABLE, CREATE_MCP_BINDINGS_TABLE, CREATE_INDEXES, SCHEMA_MIGRATIONS, _dbCache;
|
|
487
|
+
var BetterSqlite3, CREATE_OBSERVATIONS_TABLE, CREATE_MINI_SKILLS_TABLE, CREATE_SESSIONS_TABLE, CREATE_META_TABLE, CREATE_TEAM_AGENTS_TABLE, CREATE_TEAM_MESSAGES_TABLE, CREATE_TEAM_TASKS_TABLE, CREATE_TEAM_TASK_DEPS_TABLE, CREATE_TEAM_LOCKS_TABLE, CREATE_TEAM_ROLES_TABLE, CREATE_CHAT_TRANSCRIPT_TABLE, CREATE_GRAPH_ENTITIES_TABLE, CREATE_GRAPH_RELATIONS_TABLE, CREATE_CODE_FILES_TABLE, CREATE_CODE_SYMBOLS_TABLE, CREATE_CODE_EDGES_TABLE, CREATE_OBSERVATION_CODE_REFS_TABLE, CREATE_SCHEMA_MIGRATIONS_TABLE, CREATE_CODE_STATE_SNAPSHOTS_TABLE, CREATE_CODE_STATE_SNAPSHOT_FILES_TABLE, CREATE_KNOWLEDGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_CLAIM_EVIDENCE_TABLE, CREATE_KNOWLEDGE_CLAIM_EVENTS_TABLE, CREATE_KNOWLEDGE_WORKSPACES_TABLE, CREATE_KNOWLEDGE_PAGES_TABLE, CREATE_KNOWLEDGE_PAGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_PAGE_LINKS_TABLE, CREATE_KNOWLEDGE_PROPOSALS_TABLE, CREATE_KNOWLEDGE_WORKFLOWS_TABLE, CREATE_KNOWLEDGE_WORKFLOW_RUNS_TABLE, CREATE_LONG_TERM_MEMORIES_TABLE, CREATE_LONG_TERM_MEMORY_EVIDENCE_TABLE, CREATE_LONG_TERM_MEMORY_EVENTS_TABLE, CREATE_MEMORY_OUTCOME_SIGNALS_TABLE, CREATE_MEDIA_ASSETS_TABLE, CREATE_MEDIA_ASSET_LINKS_TABLE, CREATE_MEDIA_DERIVATIONS_TABLE, CREATE_MEDIA_EMBEDDING_PROFILES_TABLE, CREATE_MEDIA_EMBEDDINGS_TABLE, CREATE_MEDIA_JOBS_TABLE, CREATE_MAINTENANCE_JOBS_TABLE, CREATE_MAINTENANCE_TARGETS_TABLE, CREATE_COMPACTION_CHECKPOINTS_TABLE, CREATE_EVIDENCE_CARDS_TABLE, CREATE_EVIDENCE_CARD_EVENTS_TABLE, CREATE_MEMORY_FEEDBACK_STATES_TABLE, CREATE_MEMORY_FEEDBACK_EVENTS_TABLE, CREATE_TASK_CONTINUITY_EVENTS_TABLE, CREATE_AGENT_EFFECTS_TABLE, CREATE_MCP_BINDINGS_TABLE, CREATE_INDEXES, SCHEMA_MIGRATIONS, _dbCache, _dbLeases;
|
|
475
488
|
var init_sqlite_db = __esm({
|
|
476
489
|
"src/store/sqlite-db.ts"() {
|
|
477
490
|
"use strict";
|
|
@@ -643,18 +656,21 @@ CREATE TABLE IF NOT EXISTS chat_transcript (
|
|
|
643
656
|
`;
|
|
644
657
|
CREATE_GRAPH_ENTITIES_TABLE = `
|
|
645
658
|
CREATE TABLE IF NOT EXISTS graph_entities (
|
|
646
|
-
|
|
659
|
+
projectId TEXT NOT NULL,
|
|
660
|
+
name TEXT NOT NULL,
|
|
647
661
|
entityType TEXT NOT NULL DEFAULT '',
|
|
648
|
-
observations TEXT NOT NULL DEFAULT '[]'
|
|
662
|
+
observations TEXT NOT NULL DEFAULT '[]',
|
|
663
|
+
PRIMARY KEY (projectId, name)
|
|
649
664
|
);
|
|
650
665
|
`;
|
|
651
666
|
CREATE_GRAPH_RELATIONS_TABLE = `
|
|
652
667
|
CREATE TABLE IF NOT EXISTS graph_relations (
|
|
653
668
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
669
|
+
projectId TEXT NOT NULL,
|
|
654
670
|
from_entity TEXT NOT NULL,
|
|
655
671
|
to_entity TEXT NOT NULL,
|
|
656
672
|
relationType TEXT NOT NULL DEFAULT '',
|
|
657
|
-
UNIQUE(from_entity, to_entity, relationType)
|
|
673
|
+
UNIQUE(projectId, from_entity, to_entity, relationType)
|
|
658
674
|
);
|
|
659
675
|
`;
|
|
660
676
|
CREATE_CODE_FILES_TABLE = `
|
|
@@ -1185,6 +1201,43 @@ CREATE TABLE IF NOT EXISTS memory_feedback_events (
|
|
|
1185
1201
|
delta REAL NOT NULL DEFAULT 0,
|
|
1186
1202
|
observed_at TEXT NOT NULL
|
|
1187
1203
|
);
|
|
1204
|
+
`;
|
|
1205
|
+
CREATE_TASK_CONTINUITY_EVENTS_TABLE = `
|
|
1206
|
+
CREATE TABLE IF NOT EXISTS task_continuity_events (
|
|
1207
|
+
id TEXT PRIMARY KEY,
|
|
1208
|
+
project_id TEXT NOT NULL,
|
|
1209
|
+
task_id TEXT NOT NULL,
|
|
1210
|
+
task TEXT NOT NULL,
|
|
1211
|
+
kind TEXT NOT NULL,
|
|
1212
|
+
content TEXT NOT NULL,
|
|
1213
|
+
item_status TEXT,
|
|
1214
|
+
source_ref TEXT,
|
|
1215
|
+
evidence_json TEXT NOT NULL DEFAULT '[]',
|
|
1216
|
+
actor TEXT,
|
|
1217
|
+
created_at TEXT NOT NULL,
|
|
1218
|
+
event_key TEXT,
|
|
1219
|
+
item_key TEXT,
|
|
1220
|
+
supersedes_id TEXT
|
|
1221
|
+
);
|
|
1222
|
+
`;
|
|
1223
|
+
CREATE_AGENT_EFFECTS_TABLE = `
|
|
1224
|
+
CREATE TABLE IF NOT EXISTS agent_effects (
|
|
1225
|
+
id TEXT PRIMARY KEY,
|
|
1226
|
+
pipeline_id TEXT NOT NULL,
|
|
1227
|
+
task_id TEXT NOT NULL,
|
|
1228
|
+
attempt INTEGER NOT NULL,
|
|
1229
|
+
effect_key TEXT NOT NULL,
|
|
1230
|
+
tool TEXT NOT NULL,
|
|
1231
|
+
risk_tier TEXT NOT NULL,
|
|
1232
|
+
replay_policy TEXT NOT NULL,
|
|
1233
|
+
status TEXT NOT NULL,
|
|
1234
|
+
call_id TEXT,
|
|
1235
|
+
idempotency_key TEXT NOT NULL,
|
|
1236
|
+
input_fingerprint TEXT,
|
|
1237
|
+
detail TEXT,
|
|
1238
|
+
started_at INTEGER NOT NULL,
|
|
1239
|
+
finished_at INTEGER
|
|
1240
|
+
);
|
|
1188
1241
|
`;
|
|
1189
1242
|
CREATE_MCP_BINDINGS_TABLE = `
|
|
1190
1243
|
CREATE TABLE IF NOT EXISTS mcp_bindings (
|
|
@@ -1263,7 +1316,18 @@ CREATE INDEX IF NOT EXISTS idx_evidence_cards_candidate ON evidence_cards(projec
|
|
|
1263
1316
|
CREATE INDEX IF NOT EXISTS idx_evidence_card_events_card ON evidence_card_events(card_id, created_at);
|
|
1264
1317
|
CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC);
|
|
1265
1318
|
CREATE INDEX IF NOT EXISTS idx_memory_feedback_events_candidate ON memory_feedback_events(project_id, candidate_kind, candidate_id, observed_at DESC);
|
|
1319
|
+
CREATE INDEX IF NOT EXISTS idx_task_continuity_project_task ON task_continuity_events(project_id, task_id, created_at ASC);
|
|
1320
|
+
CREATE INDEX IF NOT EXISTS idx_task_continuity_project_recent ON task_continuity_events(project_id, created_at DESC);
|
|
1321
|
+
CREATE INDEX IF NOT EXISTS idx_task_continuity_item ON task_continuity_events(project_id, task_id, kind, item_key, created_at DESC);
|
|
1322
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_task_continuity_event_key
|
|
1323
|
+
ON task_continuity_events(project_id, task_id, event_key)
|
|
1324
|
+
WHERE event_key IS NOT NULL;
|
|
1325
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_effect_identity
|
|
1326
|
+
ON agent_effects(pipeline_id, task_id, attempt, effect_key);
|
|
1327
|
+
CREATE INDEX IF NOT EXISTS idx_agent_effect_pipeline ON agent_effects(pipeline_id, started_at ASC);
|
|
1266
1328
|
CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC);
|
|
1329
|
+
CREATE INDEX IF NOT EXISTS idx_mcp_bindings_root ON mcp_bindings(project_root, last_used_at DESC);
|
|
1330
|
+
CREATE INDEX IF NOT EXISTS idx_mcp_bindings_expiry ON mcp_bindings(expires_at);
|
|
1267
1331
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
|
|
1268
1332
|
ON maintenance_jobs(project_id, kind, dedupe_key)
|
|
1269
1333
|
WHERE status IN ('pending', 'running', 'retry');
|
|
@@ -1434,6 +1498,8 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
|
|
|
1434
1498
|
db2.exec("CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC)");
|
|
1435
1499
|
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)");
|
|
1436
1500
|
db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC)");
|
|
1501
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_root ON mcp_bindings(project_root, last_used_at DESC)");
|
|
1502
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_expiry ON mcp_bindings(expires_at)");
|
|
1437
1503
|
}
|
|
1438
1504
|
},
|
|
1439
1505
|
{
|
|
@@ -1444,9 +1510,22 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
|
|
|
1444
1510
|
addColumnIfMissing(db2, "code_symbols", "source", "source TEXT");
|
|
1445
1511
|
addColumnIfMissing(db2, "code_edges", "source", "source TEXT");
|
|
1446
1512
|
}
|
|
1513
|
+
},
|
|
1514
|
+
{
|
|
1515
|
+
id: "1.9-continuity-v2",
|
|
1516
|
+
apply: (db2) => {
|
|
1517
|
+
addColumnIfMissing(db2, "task_continuity_events", "event_key", "event_key TEXT");
|
|
1518
|
+
addColumnIfMissing(db2, "task_continuity_events", "item_key", "item_key TEXT");
|
|
1519
|
+
addColumnIfMissing(db2, "task_continuity_events", "supersedes_id", "supersedes_id TEXT");
|
|
1520
|
+
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)");
|
|
1521
|
+
db2.exec(`CREATE UNIQUE INDEX IF NOT EXISTS idx_task_continuity_event_key
|
|
1522
|
+
ON task_continuity_events(project_id, task_id, event_key)
|
|
1523
|
+
WHERE event_key IS NOT NULL`);
|
|
1524
|
+
}
|
|
1447
1525
|
}
|
|
1448
1526
|
];
|
|
1449
1527
|
_dbCache = /* @__PURE__ */ new Map();
|
|
1528
|
+
_dbLeases = /* @__PURE__ */ new Map();
|
|
1450
1529
|
}
|
|
1451
1530
|
});
|
|
1452
1531
|
|
|
@@ -1549,15 +1628,20 @@ var init_dotenv_loader = __esm({
|
|
|
1549
1628
|
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
|
|
1550
1629
|
import { homedir as homedir2 } from "os";
|
|
1551
1630
|
import { parse as parseYamlDocument } from "yaml";
|
|
1631
|
+
function cacheKey(homeDir, projectRoot) {
|
|
1632
|
+
return `${homeDir}\0${projectRoot ?? ""}`;
|
|
1633
|
+
}
|
|
1552
1634
|
function initProjectRoot(root) {
|
|
1553
1635
|
globalProjectRoot = root;
|
|
1554
|
-
configCache.delete(root);
|
|
1636
|
+
configCache.delete(cacheKey(homedir2(), root));
|
|
1555
1637
|
}
|
|
1556
|
-
function loadYamlConfig(projectRoot) {
|
|
1638
|
+
function loadYamlConfig(projectRoot, options = {}) {
|
|
1639
|
+
const homeDir = options.homeDir ?? homedir2();
|
|
1557
1640
|
const resolvedRoot = projectRoot === null ? null : projectRoot ?? globalProjectRoot ?? null;
|
|
1558
|
-
const
|
|
1641
|
+
const key = cacheKey(homeDir, resolvedRoot);
|
|
1642
|
+
const cached = configCache.get(key);
|
|
1559
1643
|
if (cached) return cached;
|
|
1560
|
-
const userYaml = getGlobalYamlPath(
|
|
1644
|
+
const userYaml = getGlobalYamlPath(homeDir);
|
|
1561
1645
|
const projectYaml = resolvedRoot ? getProjectYamlPath(resolvedRoot) : null;
|
|
1562
1646
|
let userConfig = {};
|
|
1563
1647
|
let projectConfig = {};
|
|
@@ -1589,7 +1673,7 @@ function loadYamlConfig(projectRoot) {
|
|
|
1589
1673
|
server: { ...userConfig.server, ...projectConfig.server },
|
|
1590
1674
|
team: { ...userConfig.team, ...projectConfig.team }
|
|
1591
1675
|
};
|
|
1592
|
-
configCache.set(
|
|
1676
|
+
configCache.set(key, merged);
|
|
1593
1677
|
return merged;
|
|
1594
1678
|
}
|
|
1595
1679
|
function parseYaml(content) {
|
|
@@ -1765,9 +1849,9 @@ var init_detector = __esm({
|
|
|
1765
1849
|
// src/config/legacy-loader.ts
|
|
1766
1850
|
import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
|
|
1767
1851
|
import { homedir as homedir3 } from "os";
|
|
1768
|
-
function loadFileConfig() {
|
|
1852
|
+
function loadFileConfig(homeDir = homedir3()) {
|
|
1769
1853
|
if (cachedConfig !== null) return cachedConfig;
|
|
1770
|
-
const configPath = getLegacyConfigJsonPath(
|
|
1854
|
+
const configPath = getLegacyConfigJsonPath(homeDir);
|
|
1771
1855
|
try {
|
|
1772
1856
|
if (existsSync5(configPath)) {
|
|
1773
1857
|
cachedConfig = JSON.parse(readFileSync5(configPath, "utf-8"));
|
|
@@ -1797,15 +1881,15 @@ import { homedir as homedir4 } from "os";
|
|
|
1797
1881
|
function loadTomlConfig(options = {}) {
|
|
1798
1882
|
const homeDir = options.homeDir ?? homedir4();
|
|
1799
1883
|
const projectRoot = options.projectRoot ?? null;
|
|
1800
|
-
const
|
|
1801
|
-
const cached = configCache2.get(
|
|
1884
|
+
const cacheKey3 = `${homeDir}\0${projectRoot ?? ""}`;
|
|
1885
|
+
const cached = configCache2.get(cacheKey3);
|
|
1802
1886
|
if (cached) return cached;
|
|
1803
1887
|
const userToml = getGlobalConfigTomlPath(homeDir);
|
|
1804
1888
|
const projectToml = projectRoot ? getProjectConfigTomlPath(projectRoot) : null;
|
|
1805
1889
|
const userConfig = existsSync6(userToml) ? parseTomlConfig(readFileSync6(userToml, "utf8"), userToml) : {};
|
|
1806
1890
|
const projectConfig = projectToml && existsSync6(projectToml) ? parseTomlConfig(readFileSync6(projectToml, "utf8"), projectToml) : {};
|
|
1807
1891
|
const merged = mergeTomlConfig(userConfig, projectConfig);
|
|
1808
|
-
configCache2.set(
|
|
1892
|
+
configCache2.set(cacheKey3, merged);
|
|
1809
1893
|
return merged;
|
|
1810
1894
|
}
|
|
1811
1895
|
function mergeTomlConfig(base, override) {
|
|
@@ -1926,8 +2010,8 @@ function getResolvedConfig(options = {}) {
|
|
|
1926
2010
|
const projectRoot = options.projectRoot === void 0 ? detectProject()?.rootPath ?? null : options.projectRoot;
|
|
1927
2011
|
loadDotenv(projectRoot === null ? void 0 : projectRoot ?? void 0, { userHomeDir: homeDir });
|
|
1928
2012
|
const toml = loadTomlConfig({ projectRoot: projectRoot ?? null, homeDir });
|
|
1929
|
-
const yaml = loadYamlConfig(projectRoot ?? null);
|
|
1930
|
-
const legacy = loadFileConfig();
|
|
2013
|
+
const yaml = loadYamlConfig(projectRoot ?? null, { homeDir });
|
|
2014
|
+
const legacy = loadFileConfig(homeDir);
|
|
1931
2015
|
const embeddingBaseUrl = first(process.env.MEMORIX_EMBEDDING_BASE_URL, toml.embedding?.base_url, yaml.embedding?.baseUrl, legacy.embeddingApi?.baseUrl);
|
|
1932
2016
|
const openRouterEmbeddingApiKey = isOpenRouterUrl(embeddingBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
|
|
1933
2017
|
const memoryLlmProvider = first(
|
|
@@ -1949,15 +2033,17 @@ function getResolvedConfig(options = {}) {
|
|
|
1949
2033
|
legacy.llm?.baseUrl
|
|
1950
2034
|
);
|
|
1951
2035
|
const openRouterMemoryLlmApiKey = isOpenRouterMemoryLane(memoryLlmProvider, memoryLlmBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
|
|
2036
|
+
const isAtlasCloud = memoryLlmProvider === "atlascloud";
|
|
1952
2037
|
const memoryLlmApiKey = first(
|
|
1953
2038
|
process.env.MEMORIX_LLM_API_KEY,
|
|
1954
2039
|
process.env.MEMORIX_API_KEY,
|
|
1955
2040
|
toml.memory?.llm?.api_key,
|
|
1956
2041
|
yaml.llm?.apiKey,
|
|
1957
2042
|
legacy.llm?.apiKey,
|
|
1958
|
-
|
|
1959
|
-
process.env.
|
|
1960
|
-
|
|
2043
|
+
// Never borrow another provider's credentials for the Atlas Cloud preset.
|
|
2044
|
+
isAtlasCloud ? process.env.ATLASCLOUD_API_KEY : process.env.OPENAI_API_KEY,
|
|
2045
|
+
isAtlasCloud ? void 0 : process.env.ANTHROPIC_API_KEY,
|
|
2046
|
+
isAtlasCloud ? void 0 : openRouterMemoryLlmApiKey
|
|
1961
2047
|
);
|
|
1962
2048
|
const resolved = {
|
|
1963
2049
|
agent: {
|
|
@@ -2136,7 +2222,8 @@ function getEnvSourceNames() {
|
|
|
2136
2222
|
"MEMORIX_CODEGRAPH_EXTERNAL_CONTEXT",
|
|
2137
2223
|
"MEMORIX_CODEGRAPH_EXTERNAL_COMMAND",
|
|
2138
2224
|
"MEMORIX_CODEGRAPH_EXTERNAL_TIMEOUT_MS",
|
|
2139
|
-
"OPENROUTER_API_KEY"
|
|
2225
|
+
"OPENROUTER_API_KEY",
|
|
2226
|
+
"ATLASCLOUD_API_KEY"
|
|
2140
2227
|
].filter((name) => process.env[name]);
|
|
2141
2228
|
}
|
|
2142
2229
|
function isOpenRouterUrl(value) {
|
|
@@ -2967,6 +3054,7 @@ var init_provider = __esm({
|
|
|
2967
3054
|
openai: { baseUrl: "https://api.openai.com/v1", model: "gpt-4.1-nano" },
|
|
2968
3055
|
anthropic: { baseUrl: "https://api.anthropic.com/v1", model: "claude-3-5-haiku-latest" },
|
|
2969
3056
|
openrouter: { baseUrl: "https://openrouter.ai/api/v1", model: "openai/gpt-4.1-nano" },
|
|
3057
|
+
atlascloud: { baseUrl: "https://api.atlascloud.ai/v1", model: "deepseek-ai/deepseek-v3.2" },
|
|
2970
3058
|
custom: { baseUrl: "http://localhost:11434/v1", model: "llama3" }
|
|
2971
3059
|
};
|
|
2972
3060
|
currentConfig = null;
|
|
@@ -3041,13 +3129,120 @@ var init_sqlite_reliability = __esm({
|
|
|
3041
3129
|
}
|
|
3042
3130
|
});
|
|
3043
3131
|
|
|
3132
|
+
// src/store/file-lock.ts
|
|
3133
|
+
import { promises as fs2 } from "fs";
|
|
3134
|
+
import { randomUUID } from "crypto";
|
|
3135
|
+
import path5 from "path";
|
|
3136
|
+
function canReclaimStaleLock(raw) {
|
|
3137
|
+
try {
|
|
3138
|
+
const parsed = JSON.parse(raw);
|
|
3139
|
+
const pid = Number(parsed.pid);
|
|
3140
|
+
if (!Number.isSafeInteger(pid) || pid < 1) return true;
|
|
3141
|
+
try {
|
|
3142
|
+
process.kill(pid, 0);
|
|
3143
|
+
return false;
|
|
3144
|
+
} catch (error) {
|
|
3145
|
+
return error.code !== "EPERM";
|
|
3146
|
+
}
|
|
3147
|
+
} catch {
|
|
3148
|
+
return true;
|
|
3149
|
+
}
|
|
3150
|
+
}
|
|
3151
|
+
async function acquireLock(lockPath) {
|
|
3152
|
+
for (let i2 = 0; i2 < MAX_RETRIES; i2++) {
|
|
3153
|
+
try {
|
|
3154
|
+
const fd = await fs2.open(lockPath, "wx");
|
|
3155
|
+
await fd.writeFile(JSON.stringify({ pid: process.pid, time: Date.now() }));
|
|
3156
|
+
await fd.close();
|
|
3157
|
+
return;
|
|
3158
|
+
} catch (err) {
|
|
3159
|
+
const code = err instanceof Error && "code" in err ? err.code : void 0;
|
|
3160
|
+
if (code === "EEXIST" || code === "EPERM") {
|
|
3161
|
+
try {
|
|
3162
|
+
const stat5 = await fs2.stat(lockPath);
|
|
3163
|
+
if (Date.now() - stat5.mtimeMs > LOCK_STALE_MS) {
|
|
3164
|
+
const raw2 = await fs2.readFile(lockPath, "utf8").catch(() => "");
|
|
3165
|
+
if (canReclaimStaleLock(raw2)) {
|
|
3166
|
+
await fs2.unlink(lockPath).catch(() => {
|
|
3167
|
+
});
|
|
3168
|
+
continue;
|
|
3169
|
+
}
|
|
3170
|
+
}
|
|
3171
|
+
} catch {
|
|
3172
|
+
continue;
|
|
3173
|
+
}
|
|
3174
|
+
await new Promise((r2) => setTimeout(r2, RETRY_INTERVAL_MS));
|
|
3175
|
+
} else {
|
|
3176
|
+
throw err;
|
|
3177
|
+
}
|
|
3178
|
+
}
|
|
3179
|
+
}
|
|
3180
|
+
const raw = await fs2.readFile(lockPath, "utf8").catch(() => "");
|
|
3181
|
+
if (!canReclaimStaleLock(raw)) {
|
|
3182
|
+
throw new Error(`Failed to acquire lock: ${lockPath} (owner is still running)`);
|
|
3183
|
+
}
|
|
3184
|
+
await fs2.unlink(lockPath).catch(() => {
|
|
3185
|
+
});
|
|
3186
|
+
try {
|
|
3187
|
+
const fd = await fs2.open(lockPath, "wx");
|
|
3188
|
+
await fd.writeFile(JSON.stringify({ pid: process.pid, time: Date.now() }));
|
|
3189
|
+
await fd.close();
|
|
3190
|
+
return;
|
|
3191
|
+
} catch {
|
|
3192
|
+
throw new Error(`Failed to acquire lock: ${lockPath} (timeout after ${MAX_RETRIES * RETRY_INTERVAL_MS}ms)`);
|
|
3193
|
+
}
|
|
3194
|
+
}
|
|
3195
|
+
async function releaseLock(lockPath) {
|
|
3196
|
+
await fs2.unlink(lockPath).catch(() => {
|
|
3197
|
+
});
|
|
3198
|
+
}
|
|
3199
|
+
async function withFileLock(projectDir2, fn) {
|
|
3200
|
+
const lockPath = path5.join(projectDir2, ".memorix.lock");
|
|
3201
|
+
await acquireLock(lockPath);
|
|
3202
|
+
try {
|
|
3203
|
+
return await fn();
|
|
3204
|
+
} finally {
|
|
3205
|
+
await releaseLock(lockPath);
|
|
3206
|
+
}
|
|
3207
|
+
}
|
|
3208
|
+
async function atomicWriteFileOnce(filePath, data) {
|
|
3209
|
+
const tmpPath = filePath + `.tmp.${process.pid}.${randomUUID()}`;
|
|
3210
|
+
try {
|
|
3211
|
+
await fs2.writeFile(tmpPath, data, "utf-8");
|
|
3212
|
+
await fs2.rename(tmpPath, filePath);
|
|
3213
|
+
} catch (error) {
|
|
3214
|
+
await fs2.unlink(tmpPath).catch(() => {
|
|
3215
|
+
});
|
|
3216
|
+
throw error;
|
|
3217
|
+
}
|
|
3218
|
+
}
|
|
3219
|
+
function atomicWriteFile(filePath, data) {
|
|
3220
|
+
const previous = atomicWriteTails.get(filePath) ?? Promise.resolve();
|
|
3221
|
+
const next = previous.catch(() => void 0).then(() => atomicWriteFileOnce(filePath, data));
|
|
3222
|
+
atomicWriteTails.set(filePath, next);
|
|
3223
|
+
return next.finally(() => {
|
|
3224
|
+
if (atomicWriteTails.get(filePath) === next) atomicWriteTails.delete(filePath);
|
|
3225
|
+
});
|
|
3226
|
+
}
|
|
3227
|
+
var LOCK_STALE_MS, RETRY_INTERVAL_MS, MAX_RETRIES, atomicWriteTails;
|
|
3228
|
+
var init_file_lock = __esm({
|
|
3229
|
+
"src/store/file-lock.ts"() {
|
|
3230
|
+
"use strict";
|
|
3231
|
+
init_esm_shims();
|
|
3232
|
+
LOCK_STALE_MS = 1e4;
|
|
3233
|
+
RETRY_INTERVAL_MS = 50;
|
|
3234
|
+
MAX_RETRIES = 60;
|
|
3235
|
+
atomicWriteTails = /* @__PURE__ */ new Map();
|
|
3236
|
+
}
|
|
3237
|
+
});
|
|
3238
|
+
|
|
3044
3239
|
// src/store/sqlite-store.ts
|
|
3045
3240
|
var sqlite_store_exports = {};
|
|
3046
3241
|
__export(sqlite_store_exports, {
|
|
3047
3242
|
SqliteBackend: () => SqliteBackend
|
|
3048
3243
|
});
|
|
3049
|
-
import
|
|
3050
|
-
import
|
|
3244
|
+
import path6 from "path";
|
|
3245
|
+
import fs3 from "fs";
|
|
3051
3246
|
function obsToRow(obs) {
|
|
3052
3247
|
return {
|
|
3053
3248
|
id: obs.id,
|
|
@@ -3134,6 +3329,7 @@ var init_sqlite_store = __esm({
|
|
|
3134
3329
|
init_sqlite_db();
|
|
3135
3330
|
init_sqlite_reliability();
|
|
3136
3331
|
init_sqlite_fts();
|
|
3332
|
+
init_file_lock();
|
|
3137
3333
|
SqliteBackend = class {
|
|
3138
3334
|
db = null;
|
|
3139
3335
|
dataDir = "";
|
|
@@ -3297,38 +3493,43 @@ var init_sqlite_store = __esm({
|
|
|
3297
3493
|
}
|
|
3298
3494
|
// ── Migration ────────────────────────────────────────────────────
|
|
3299
3495
|
async migrateFromJsonIfNeeded() {
|
|
3300
|
-
const
|
|
3301
|
-
if (
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
const raw =
|
|
3306
|
-
const
|
|
3496
|
+
const jsonPath = path6.join(this.dataDir, "observations.json");
|
|
3497
|
+
if (!fs3.existsSync(jsonPath)) return;
|
|
3498
|
+
await withFileLock(this.dataDir, async () => {
|
|
3499
|
+
const count2 = this.db.prepare(`SELECT COUNT(*) AS cnt FROM observations`).get();
|
|
3500
|
+
if (count2.cnt > 0) return;
|
|
3501
|
+
const raw = fs3.readFileSync(jsonPath, "utf-8");
|
|
3502
|
+
const parsed = JSON.parse(raw);
|
|
3503
|
+
if (!Array.isArray(parsed)) {
|
|
3504
|
+
throw new Error("[memorix] observations.json migration refused: expected a JSON array");
|
|
3505
|
+
}
|
|
3506
|
+
const observations2 = parsed;
|
|
3307
3507
|
if (observations2.length === 0) return;
|
|
3508
|
+
if (observations2.some((obs) => !obs || !Number.isSafeInteger(obs.id) || obs.id < 1 || typeof obs.projectId !== "string")) {
|
|
3509
|
+
throw new Error("[memorix] observations.json migration refused: invalid observation record");
|
|
3510
|
+
}
|
|
3308
3511
|
console.error(`[memorix] Migrating ${observations2.length} observations from JSON to SQLite...`);
|
|
3309
3512
|
const insertMany = this.db.transaction((obsList) => {
|
|
3310
3513
|
for (const obs of obsList) {
|
|
3311
3514
|
this.stmtInsert.run(obsToRow(obs));
|
|
3312
3515
|
}
|
|
3516
|
+
const counterPath = path6.join(this.dataDir, "counter.json");
|
|
3517
|
+
let counterNextId;
|
|
3518
|
+
if (fs3.existsSync(counterPath)) {
|
|
3519
|
+
const counterData = JSON.parse(fs3.readFileSync(counterPath, "utf-8"));
|
|
3520
|
+
const candidate = counterData.nextId ?? counterData.next_id;
|
|
3521
|
+
if (candidate !== void 0 && (!Number.isSafeInteger(candidate) || Number(candidate) < 1)) {
|
|
3522
|
+
throw new Error("[memorix] counter.json migration refused: nextId must be a positive integer");
|
|
3523
|
+
}
|
|
3524
|
+
counterNextId = candidate === void 0 ? void 0 : Number(candidate);
|
|
3525
|
+
}
|
|
3526
|
+
const maxId = Math.max(...obsList.map((obs) => obs.id));
|
|
3527
|
+
this.rawSaveIdCounter(Math.max(counterNextId ?? 1, maxId + 1));
|
|
3528
|
+
this.bumpGeneration();
|
|
3313
3529
|
});
|
|
3314
3530
|
insertMany(observations2);
|
|
3315
|
-
const counterPath = path5.join(this.dataDir, "counter.json");
|
|
3316
|
-
if (fs2.existsSync(counterPath)) {
|
|
3317
|
-
try {
|
|
3318
|
-
const counterData = JSON.parse(fs2.readFileSync(counterPath, "utf-8"));
|
|
3319
|
-
const nextId2 = counterData.nextId ?? counterData.next_id ?? Math.max(...observations2.map((o) => o.id)) + 1;
|
|
3320
|
-
this.rawSaveIdCounter(nextId2);
|
|
3321
|
-
} catch {
|
|
3322
|
-
this.rawSaveIdCounter(Math.max(...observations2.map((o) => o.id)) + 1);
|
|
3323
|
-
}
|
|
3324
|
-
} else {
|
|
3325
|
-
this.rawSaveIdCounter(Math.max(...observations2.map((o) => o.id)) + 1);
|
|
3326
|
-
}
|
|
3327
|
-
this.bumpGeneration();
|
|
3328
3531
|
console.error(`[memorix] Migration complete. ${observations2.length} observations now in SQLite.`);
|
|
3329
|
-
}
|
|
3330
|
-
console.error(`[memorix] JSON\u2192SQLite migration failed (non-fatal, data preserved in JSON): ${err}`);
|
|
3331
|
-
}
|
|
3532
|
+
});
|
|
3332
3533
|
}
|
|
3333
3534
|
// ── Public read ──────────────────────────────────────────────────
|
|
3334
3535
|
async loadAll() {
|
|
@@ -3657,91 +3858,6 @@ var init_types = __esm({
|
|
|
3657
3858
|
}
|
|
3658
3859
|
});
|
|
3659
3860
|
|
|
3660
|
-
// src/store/file-lock.ts
|
|
3661
|
-
import { promises as fs3 } from "fs";
|
|
3662
|
-
import { randomUUID } from "crypto";
|
|
3663
|
-
import path6 from "path";
|
|
3664
|
-
async function acquireLock(lockPath) {
|
|
3665
|
-
for (let i2 = 0; i2 < MAX_RETRIES; i2++) {
|
|
3666
|
-
try {
|
|
3667
|
-
const fd = await fs3.open(lockPath, "wx");
|
|
3668
|
-
await fd.writeFile(JSON.stringify({ pid: process.pid, time: Date.now() }));
|
|
3669
|
-
await fd.close();
|
|
3670
|
-
return;
|
|
3671
|
-
} catch (err) {
|
|
3672
|
-
const code = err instanceof Error && "code" in err ? err.code : void 0;
|
|
3673
|
-
if (code === "EEXIST" || code === "EPERM") {
|
|
3674
|
-
try {
|
|
3675
|
-
const stat5 = await fs3.stat(lockPath);
|
|
3676
|
-
if (Date.now() - stat5.mtimeMs > LOCK_STALE_MS) {
|
|
3677
|
-
await fs3.unlink(lockPath).catch(() => {
|
|
3678
|
-
});
|
|
3679
|
-
continue;
|
|
3680
|
-
}
|
|
3681
|
-
} catch {
|
|
3682
|
-
continue;
|
|
3683
|
-
}
|
|
3684
|
-
await new Promise((r2) => setTimeout(r2, RETRY_INTERVAL_MS));
|
|
3685
|
-
} else {
|
|
3686
|
-
throw err;
|
|
3687
|
-
}
|
|
3688
|
-
}
|
|
3689
|
-
}
|
|
3690
|
-
await fs3.unlink(lockPath).catch(() => {
|
|
3691
|
-
});
|
|
3692
|
-
try {
|
|
3693
|
-
const fd = await fs3.open(lockPath, "wx");
|
|
3694
|
-
await fd.writeFile(JSON.stringify({ pid: process.pid, time: Date.now() }));
|
|
3695
|
-
await fd.close();
|
|
3696
|
-
return;
|
|
3697
|
-
} catch {
|
|
3698
|
-
throw new Error(`Failed to acquire lock: ${lockPath} (timeout after ${MAX_RETRIES * RETRY_INTERVAL_MS}ms)`);
|
|
3699
|
-
}
|
|
3700
|
-
}
|
|
3701
|
-
async function releaseLock(lockPath) {
|
|
3702
|
-
await fs3.unlink(lockPath).catch(() => {
|
|
3703
|
-
});
|
|
3704
|
-
}
|
|
3705
|
-
async function withFileLock(projectDir2, fn) {
|
|
3706
|
-
const lockPath = path6.join(projectDir2, ".memorix.lock");
|
|
3707
|
-
await acquireLock(lockPath);
|
|
3708
|
-
try {
|
|
3709
|
-
return await fn();
|
|
3710
|
-
} finally {
|
|
3711
|
-
await releaseLock(lockPath);
|
|
3712
|
-
}
|
|
3713
|
-
}
|
|
3714
|
-
async function atomicWriteFileOnce(filePath, data) {
|
|
3715
|
-
const tmpPath = filePath + `.tmp.${process.pid}.${randomUUID()}`;
|
|
3716
|
-
try {
|
|
3717
|
-
await fs3.writeFile(tmpPath, data, "utf-8");
|
|
3718
|
-
await fs3.rename(tmpPath, filePath);
|
|
3719
|
-
} catch (error) {
|
|
3720
|
-
await fs3.unlink(tmpPath).catch(() => {
|
|
3721
|
-
});
|
|
3722
|
-
throw error;
|
|
3723
|
-
}
|
|
3724
|
-
}
|
|
3725
|
-
function atomicWriteFile(filePath, data) {
|
|
3726
|
-
const previous = atomicWriteTails.get(filePath) ?? Promise.resolve();
|
|
3727
|
-
const next = previous.catch(() => void 0).then(() => atomicWriteFileOnce(filePath, data));
|
|
3728
|
-
atomicWriteTails.set(filePath, next);
|
|
3729
|
-
return next.finally(() => {
|
|
3730
|
-
if (atomicWriteTails.get(filePath) === next) atomicWriteTails.delete(filePath);
|
|
3731
|
-
});
|
|
3732
|
-
}
|
|
3733
|
-
var LOCK_STALE_MS, RETRY_INTERVAL_MS, MAX_RETRIES, atomicWriteTails;
|
|
3734
|
-
var init_file_lock = __esm({
|
|
3735
|
-
"src/store/file-lock.ts"() {
|
|
3736
|
-
"use strict";
|
|
3737
|
-
init_esm_shims();
|
|
3738
|
-
LOCK_STALE_MS = 1e4;
|
|
3739
|
-
RETRY_INTERVAL_MS = 50;
|
|
3740
|
-
MAX_RETRIES = 60;
|
|
3741
|
-
atomicWriteTails = /* @__PURE__ */ new Map();
|
|
3742
|
-
}
|
|
3743
|
-
});
|
|
3744
|
-
|
|
3745
3861
|
// src/store/mini-skill-store.ts
|
|
3746
3862
|
import path7 from "path";
|
|
3747
3863
|
import fs4 from "fs";
|
|
@@ -3915,12 +4031,45 @@ function textHash(text2) {
|
|
|
3915
4031
|
async function loadDiskCache() {
|
|
3916
4032
|
try {
|
|
3917
4033
|
const raw = await readFile(CACHE_FILE, "utf-8");
|
|
4034
|
+
if (Buffer.byteLength(raw, "utf8") > MAX_CACHE_FILE_BYTES) {
|
|
4035
|
+
console.error("[memorix] FastEmbed cache exceeds the disk load limit; starting with an empty cache");
|
|
4036
|
+
return;
|
|
4037
|
+
}
|
|
3918
4038
|
const entries = JSON.parse(raw);
|
|
3919
|
-
|
|
3920
|
-
|
|
4039
|
+
if (!Array.isArray(entries)) return;
|
|
4040
|
+
for (const entry of entries) {
|
|
4041
|
+
if (!Array.isArray(entry) || typeof entry[0] !== "string" || !isVector(entry[1])) continue;
|
|
4042
|
+
cacheSet(entry[0], entry[1], false);
|
|
4043
|
+
}
|
|
4044
|
+
console.error(`[memorix] Loaded ${cache.size} cached embeddings from disk`);
|
|
3921
4045
|
} catch {
|
|
3922
4046
|
}
|
|
3923
4047
|
}
|
|
4048
|
+
function isVector(value) {
|
|
4049
|
+
return Array.isArray(value) && value.every((entry) => typeof entry === "number");
|
|
4050
|
+
}
|
|
4051
|
+
function maxCachePayloadBytes() {
|
|
4052
|
+
const raw = Number.parseInt(process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES ?? "", 10);
|
|
4053
|
+
return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_CACHE_PAYLOAD_BYTES;
|
|
4054
|
+
}
|
|
4055
|
+
function cacheSet(hash4, value, markDirty = true) {
|
|
4056
|
+
const incomingBytes = value.length * 8;
|
|
4057
|
+
if (incomingBytes > maxCachePayloadBytes()) return;
|
|
4058
|
+
const existing = cache.get(hash4);
|
|
4059
|
+
if (existing) cachePayloadBytes -= existing.length * 8;
|
|
4060
|
+
else {
|
|
4061
|
+
while (cache.size >= MAX_CACHE_SIZE || cachePayloadBytes + incomingBytes > maxCachePayloadBytes()) {
|
|
4062
|
+
const firstKey = cache.keys().next().value;
|
|
4063
|
+
if (firstKey === void 0) break;
|
|
4064
|
+
const old = cache.get(firstKey);
|
|
4065
|
+
cache.delete(firstKey);
|
|
4066
|
+
if (old) cachePayloadBytes -= old.length * 8;
|
|
4067
|
+
}
|
|
4068
|
+
}
|
|
4069
|
+
cache.set(hash4, value);
|
|
4070
|
+
cachePayloadBytes += incomingBytes;
|
|
4071
|
+
if (markDirty) diskCacheDirty = true;
|
|
4072
|
+
}
|
|
3924
4073
|
async function saveDiskCache() {
|
|
3925
4074
|
if (!diskCacheDirty) return;
|
|
3926
4075
|
try {
|
|
@@ -3931,7 +4080,7 @@ async function saveDiskCache() {
|
|
|
3931
4080
|
} catch {
|
|
3932
4081
|
}
|
|
3933
4082
|
}
|
|
3934
|
-
var CACHE_DIR, CACHE_FILE, cache, MAX_CACHE_SIZE, diskCacheDirty, FastEmbedProvider;
|
|
4083
|
+
var CACHE_DIR, CACHE_FILE, cache, MAX_CACHE_SIZE, DEFAULT_CACHE_PAYLOAD_BYTES, MAX_CACHE_FILE_BYTES, cachePayloadBytes, diskCacheDirty, FastEmbedProvider;
|
|
3935
4084
|
var init_fastembed_provider = __esm({
|
|
3936
4085
|
"src/embedding/fastembed-provider.ts"() {
|
|
3937
4086
|
"use strict";
|
|
@@ -3941,6 +4090,9 @@ var init_fastembed_provider = __esm({
|
|
|
3941
4090
|
CACHE_FILE = join2(CACHE_DIR, ".embedding-cache.json");
|
|
3942
4091
|
cache = /* @__PURE__ */ new Map();
|
|
3943
4092
|
MAX_CACHE_SIZE = 5e3;
|
|
4093
|
+
DEFAULT_CACHE_PAYLOAD_BYTES = 64 * 1024 * 1024;
|
|
4094
|
+
MAX_CACHE_FILE_BYTES = 128 * 1024 * 1024;
|
|
4095
|
+
cachePayloadBytes = 0;
|
|
3944
4096
|
diskCacheDirty = false;
|
|
3945
4097
|
FastEmbedProvider = class _FastEmbedProvider {
|
|
3946
4098
|
name = "fastembed-bge-small";
|
|
@@ -3982,7 +4134,7 @@ var init_fastembed_provider = __esm({
|
|
|
3982
4134
|
if (result.length !== this.dimensions) {
|
|
3983
4135
|
throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);
|
|
3984
4136
|
}
|
|
3985
|
-
|
|
4137
|
+
cacheSet(hash4, result);
|
|
3986
4138
|
return result;
|
|
3987
4139
|
}
|
|
3988
4140
|
async embedBatch(texts) {
|
|
@@ -4007,7 +4159,7 @@ var init_fastembed_provider = __esm({
|
|
|
4007
4159
|
const originalIdx = uncachedIndices[batchIdx];
|
|
4008
4160
|
const plain = Array.from(vec);
|
|
4009
4161
|
results[originalIdx] = plain;
|
|
4010
|
-
|
|
4162
|
+
cacheSet(textHash(uncachedTexts[batchIdx]), plain);
|
|
4011
4163
|
batchIdx++;
|
|
4012
4164
|
}
|
|
4013
4165
|
}
|
|
@@ -4015,14 +4167,6 @@ var init_fastembed_provider = __esm({
|
|
|
4015
4167
|
}
|
|
4016
4168
|
return results;
|
|
4017
4169
|
}
|
|
4018
|
-
cacheSet(hash4, value) {
|
|
4019
|
-
if (cache.size >= MAX_CACHE_SIZE) {
|
|
4020
|
-
const firstKey = cache.keys().next().value;
|
|
4021
|
-
if (firstKey !== void 0) cache.delete(firstKey);
|
|
4022
|
-
}
|
|
4023
|
-
cache.set(hash4, value);
|
|
4024
|
-
diskCacheDirty = true;
|
|
4025
|
-
}
|
|
4026
4170
|
};
|
|
4027
4171
|
}
|
|
4028
4172
|
});
|
|
@@ -4032,7 +4176,15 @@ var transformers_provider_exports = {};
|
|
|
4032
4176
|
__export(transformers_provider_exports, {
|
|
4033
4177
|
TransformersProvider: () => TransformersProvider
|
|
4034
4178
|
});
|
|
4035
|
-
|
|
4179
|
+
import { createHash as createHash2 } from "crypto";
|
|
4180
|
+
function cacheKey2(text2) {
|
|
4181
|
+
return createHash2("sha256").update(text2).digest("hex");
|
|
4182
|
+
}
|
|
4183
|
+
function maxCachePayloadBytes2() {
|
|
4184
|
+
const raw = Number.parseInt(process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES ?? "", 10);
|
|
4185
|
+
return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_CACHE_PAYLOAD_BYTES2;
|
|
4186
|
+
}
|
|
4187
|
+
var cache2, MAX_CACHE_SIZE2, DEFAULT_CACHE_PAYLOAD_BYTES2, cachePayloadBytes2, TransformersProvider;
|
|
4036
4188
|
var init_transformers_provider = __esm({
|
|
4037
4189
|
"src/embedding/transformers-provider.ts"() {
|
|
4038
4190
|
"use strict";
|
|
@@ -4040,6 +4192,8 @@ var init_transformers_provider = __esm({
|
|
|
4040
4192
|
init_provider2();
|
|
4041
4193
|
cache2 = /* @__PURE__ */ new Map();
|
|
4042
4194
|
MAX_CACHE_SIZE2 = 5e3;
|
|
4195
|
+
DEFAULT_CACHE_PAYLOAD_BYTES2 = 64 * 1024 * 1024;
|
|
4196
|
+
cachePayloadBytes2 = 0;
|
|
4043
4197
|
TransformersProvider = class _TransformersProvider {
|
|
4044
4198
|
name = "transformers-minilm";
|
|
4045
4199
|
dimensions = 384;
|
|
@@ -4074,7 +4228,7 @@ var init_transformers_provider = __esm({
|
|
|
4074
4228
|
return Promise.all(inputs.map((input) => this.embedInput(input, options)));
|
|
4075
4229
|
}
|
|
4076
4230
|
async embed(text2) {
|
|
4077
|
-
const cached = cache2.get(text2);
|
|
4231
|
+
const cached = cache2.get(cacheKey2(text2));
|
|
4078
4232
|
if (cached) return cached;
|
|
4079
4233
|
const output = await this.extractor(text2, {
|
|
4080
4234
|
pooling: "mean",
|
|
@@ -4084,7 +4238,7 @@ var init_transformers_provider = __esm({
|
|
|
4084
4238
|
if (result.length !== this.dimensions) {
|
|
4085
4239
|
throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);
|
|
4086
4240
|
}
|
|
4087
|
-
this.cacheSet(text2, result);
|
|
4241
|
+
this.cacheSet(cacheKey2(text2), result);
|
|
4088
4242
|
return result;
|
|
4089
4243
|
}
|
|
4090
4244
|
async embedBatch(texts) {
|
|
@@ -4092,7 +4246,7 @@ var init_transformers_provider = __esm({
|
|
|
4092
4246
|
const uncachedIndices = [];
|
|
4093
4247
|
const uncachedTexts = [];
|
|
4094
4248
|
for (let i2 = 0; i2 < texts.length; i2++) {
|
|
4095
|
-
const cached = cache2.get(texts[i2]);
|
|
4249
|
+
const cached = cache2.get(cacheKey2(texts[i2]));
|
|
4096
4250
|
if (cached) {
|
|
4097
4251
|
results[i2] = cached;
|
|
4098
4252
|
} else {
|
|
@@ -4110,17 +4264,27 @@ var init_transformers_provider = __esm({
|
|
|
4110
4264
|
const vec = Array.from(allVecs[i2]);
|
|
4111
4265
|
const originalIdx = uncachedIndices[i2];
|
|
4112
4266
|
results[originalIdx] = vec;
|
|
4113
|
-
this.cacheSet(uncachedTexts[i2], vec);
|
|
4267
|
+
this.cacheSet(cacheKey2(uncachedTexts[i2]), vec);
|
|
4114
4268
|
}
|
|
4115
4269
|
}
|
|
4116
4270
|
return results;
|
|
4117
4271
|
}
|
|
4118
4272
|
cacheSet(key, value) {
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4273
|
+
const incomingBytes = value.length * 8;
|
|
4274
|
+
if (incomingBytes > maxCachePayloadBytes2()) return;
|
|
4275
|
+
const existing = cache2.get(key);
|
|
4276
|
+
if (existing) cachePayloadBytes2 -= existing.length * 8;
|
|
4277
|
+
else {
|
|
4278
|
+
while (cache2.size >= MAX_CACHE_SIZE2 || cachePayloadBytes2 + incomingBytes > maxCachePayloadBytes2()) {
|
|
4279
|
+
const firstKey = cache2.keys().next().value;
|
|
4280
|
+
if (firstKey === void 0) break;
|
|
4281
|
+
const old = cache2.get(firstKey);
|
|
4282
|
+
cache2.delete(firstKey);
|
|
4283
|
+
if (old) cachePayloadBytes2 -= old.length * 8;
|
|
4284
|
+
}
|
|
4122
4285
|
}
|
|
4123
4286
|
cache2.set(key, value);
|
|
4287
|
+
cachePayloadBytes2 += incomingBytes;
|
|
4124
4288
|
}
|
|
4125
4289
|
};
|
|
4126
4290
|
}
|
|
@@ -4142,7 +4306,7 @@ __export(api_provider_exports, {
|
|
|
4142
4306
|
saveDiskCacheNow: () => saveDiskCacheNow,
|
|
4143
4307
|
seedApiEmbeddingCacheForTests: () => seedApiEmbeddingCacheForTests
|
|
4144
4308
|
});
|
|
4145
|
-
import { createHash as
|
|
4309
|
+
import { createHash as createHash3 } from "crypto";
|
|
4146
4310
|
import { createReadStream, createWriteStream, constants as fsConstants } from "fs";
|
|
4147
4311
|
import { access, readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, rename, stat, unlink } from "fs/promises";
|
|
4148
4312
|
import { join as join3 } from "path";
|
|
@@ -4169,7 +4333,7 @@ function cacheStatFile() {
|
|
|
4169
4333
|
function payloadBytes(vector) {
|
|
4170
4334
|
return vector.length * BYTES_PER_DIM;
|
|
4171
4335
|
}
|
|
4172
|
-
function
|
|
4336
|
+
function maxCachePayloadBytes3() {
|
|
4173
4337
|
const raw = process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES;
|
|
4174
4338
|
if (raw) {
|
|
4175
4339
|
const parsed = Number.parseInt(raw, 10);
|
|
@@ -4179,7 +4343,7 @@ function maxCachePayloadBytes() {
|
|
|
4179
4343
|
}
|
|
4180
4344
|
function maxEntriesForDimensions(dimensions) {
|
|
4181
4345
|
const dim = Math.max(1, Math.floor(dimensions));
|
|
4182
|
-
const byBytes = Math.floor(
|
|
4346
|
+
const byBytes = Math.floor(maxCachePayloadBytes3() / (dim * BYTES_PER_DIM));
|
|
4183
4347
|
return Math.max(1, Math.min(MAX_CACHE_ENTRIES, byBytes));
|
|
4184
4348
|
}
|
|
4185
4349
|
function rememberDimensions(vector) {
|
|
@@ -4192,13 +4356,15 @@ function evictOldest() {
|
|
|
4192
4356
|
if (firstKey === void 0) return;
|
|
4193
4357
|
const old = cache3.get(firstKey);
|
|
4194
4358
|
cache3.delete(firstKey);
|
|
4195
|
-
if (old)
|
|
4359
|
+
if (old) cachePayloadBytes3 -= payloadBytes(old);
|
|
4196
4360
|
}
|
|
4197
4361
|
function evictToFit(incomingBytes, incomingDims) {
|
|
4362
|
+
if (incomingBytes > maxCachePayloadBytes3()) return false;
|
|
4198
4363
|
const limit2 = maxEntriesForDimensions(incomingDims);
|
|
4199
|
-
while (cache3.size > 0 && (cache3.size >= limit2 ||
|
|
4364
|
+
while (cache3.size > 0 && (cache3.size >= limit2 || cachePayloadBytes3 + incomingBytes > maxCachePayloadBytes3())) {
|
|
4200
4365
|
evictOldest();
|
|
4201
4366
|
}
|
|
4367
|
+
return true;
|
|
4202
4368
|
}
|
|
4203
4369
|
function isNumberArray(value) {
|
|
4204
4370
|
return Array.isArray(value) && value.every((entry) => typeof entry === "number");
|
|
@@ -4225,12 +4391,12 @@ function cacheInsert(hash4, value, dirty) {
|
|
|
4225
4391
|
const incoming = payloadBytes(value);
|
|
4226
4392
|
const existing = cache3.get(hash4);
|
|
4227
4393
|
if (existing) {
|
|
4228
|
-
|
|
4394
|
+
cachePayloadBytes3 -= payloadBytes(existing);
|
|
4229
4395
|
cache3.delete(hash4);
|
|
4230
4396
|
}
|
|
4231
|
-
evictToFit(incoming, value.length || cacheDimensions || DEFAULT_ASSUMED_DIMENSIONS);
|
|
4397
|
+
if (!evictToFit(incoming, value.length || cacheDimensions || DEFAULT_ASSUMED_DIMENSIONS)) return;
|
|
4232
4398
|
cache3.set(hash4, value);
|
|
4233
|
-
|
|
4399
|
+
cachePayloadBytes3 += incoming;
|
|
4234
4400
|
if (dirty) diskCacheDirty2 = true;
|
|
4235
4401
|
}
|
|
4236
4402
|
async function readCacheStat() {
|
|
@@ -4266,7 +4432,7 @@ function cacheNamespace(config) {
|
|
|
4266
4432
|
].join("|");
|
|
4267
4433
|
}
|
|
4268
4434
|
function textHash2(text2, namespace) {
|
|
4269
|
-
return
|
|
4435
|
+
return createHash3("sha256").update(`${namespace}\0${text2}`).digest("hex").slice(0, 16);
|
|
4270
4436
|
}
|
|
4271
4437
|
function inputIdentity(input, options = {}) {
|
|
4272
4438
|
return JSON.stringify({
|
|
@@ -4608,7 +4774,7 @@ function getApiEmbeddingDiskCacheLoadCountForTests() {
|
|
|
4608
4774
|
}
|
|
4609
4775
|
function resetApiEmbeddingCacheForTests() {
|
|
4610
4776
|
cache3.clear();
|
|
4611
|
-
|
|
4777
|
+
cachePayloadBytes3 = 0;
|
|
4612
4778
|
cacheDimensions = null;
|
|
4613
4779
|
diskCacheEntryCount = 0;
|
|
4614
4780
|
diskCacheLoaded = false;
|
|
@@ -4619,14 +4785,14 @@ function resetApiEmbeddingCacheForTests() {
|
|
|
4619
4785
|
}
|
|
4620
4786
|
function seedApiEmbeddingCacheForTests(entries) {
|
|
4621
4787
|
cache3.clear();
|
|
4622
|
-
|
|
4788
|
+
cachePayloadBytes3 = 0;
|
|
4623
4789
|
cacheDimensions = null;
|
|
4624
4790
|
for (const [key, value] of entries) cacheInsert(key, value, true);
|
|
4625
4791
|
diskCacheLoaded = true;
|
|
4626
4792
|
diskCacheDirty2 = true;
|
|
4627
4793
|
}
|
|
4628
4794
|
function getApiEmbeddingCachePayloadBytesForTests() {
|
|
4629
|
-
return
|
|
4795
|
+
return cachePayloadBytes3;
|
|
4630
4796
|
}
|
|
4631
4797
|
function getApiEmbeddingJsonlLineCountCallsForTests() {
|
|
4632
4798
|
return jsonlLineCountCalls;
|
|
@@ -4800,7 +4966,7 @@ function scheduleDiskSave() {
|
|
|
4800
4966
|
diskSaveTimer = null;
|
|
4801
4967
|
}, DISK_SAVE_DEBOUNCE_MS);
|
|
4802
4968
|
}
|
|
4803
|
-
function
|
|
4969
|
+
function cacheSet2(hash4, value) {
|
|
4804
4970
|
cacheInsert(hash4, value, true);
|
|
4805
4971
|
}
|
|
4806
4972
|
function resolveEnvEmbeddingApiKey() {
|
|
@@ -4920,7 +5086,7 @@ async function waitForRetry(waitMs, signal) {
|
|
|
4920
5086
|
abortSignal.addEventListener("abort", onAbort, { once: true });
|
|
4921
5087
|
});
|
|
4922
5088
|
}
|
|
4923
|
-
var cache3, MAX_CACHE_ENTRIES, MAX_CACHE_PAYLOAD_BYTES, BYTES_PER_DIM, DEFAULT_ASSUMED_DIMENSIONS, MAX_MIGRATION_VALUE_BYTES,
|
|
5089
|
+
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;
|
|
4924
5090
|
var init_api_provider = __esm({
|
|
4925
5091
|
"src/embedding/api-provider.ts"() {
|
|
4926
5092
|
"use strict";
|
|
@@ -4932,7 +5098,7 @@ var init_api_provider = __esm({
|
|
|
4932
5098
|
BYTES_PER_DIM = 8;
|
|
4933
5099
|
DEFAULT_ASSUMED_DIMENSIONS = 4096;
|
|
4934
5100
|
MAX_MIGRATION_VALUE_BYTES = 16 * 1024 * 1024;
|
|
4935
|
-
|
|
5101
|
+
cachePayloadBytes3 = 0;
|
|
4936
5102
|
cacheDimensions = null;
|
|
4937
5103
|
diskCacheEntryCount = 0;
|
|
4938
5104
|
diskCacheDirty2 = false;
|
|
@@ -5117,7 +5283,7 @@ var init_api_provider = __esm({
|
|
|
5117
5283
|
} else {
|
|
5118
5284
|
embedding = await apiCall();
|
|
5119
5285
|
}
|
|
5120
|
-
|
|
5286
|
+
cacheSet2(hash4, embedding);
|
|
5121
5287
|
scheduleDiskSave();
|
|
5122
5288
|
return embedding;
|
|
5123
5289
|
}
|
|
@@ -5165,7 +5331,7 @@ var init_api_provider = __esm({
|
|
|
5165
5331
|
for (const item of response.data) {
|
|
5166
5332
|
const originalIdx = chunkIndices[item.index];
|
|
5167
5333
|
results[originalIdx] = item.embedding;
|
|
5168
|
-
|
|
5334
|
+
cacheSet2(textHash2(normalizedTexts[originalIdx], this.cacheKeyNamespace), item.embedding);
|
|
5169
5335
|
}
|
|
5170
5336
|
} catch (error) {
|
|
5171
5337
|
const providerLimit = parseBatchLimit(error);
|
|
@@ -5243,7 +5409,7 @@ var init_api_provider = __esm({
|
|
|
5243
5409
|
throw new Error(`Expected ${this.dimensions}d, got ${embedding.length}d; dimension mismatch`);
|
|
5244
5410
|
}
|
|
5245
5411
|
this.trackUsage(response);
|
|
5246
|
-
|
|
5412
|
+
cacheSet2(hash4, embedding);
|
|
5247
5413
|
scheduleDiskSave();
|
|
5248
5414
|
return embedding;
|
|
5249
5415
|
}
|
|
@@ -6164,7 +6330,7 @@ var init_timeout = __esm({
|
|
|
6164
6330
|
});
|
|
6165
6331
|
|
|
6166
6332
|
// src/search/semantic-index.ts
|
|
6167
|
-
import { createHash as
|
|
6333
|
+
import { createHash as createHash4 } from "crypto";
|
|
6168
6334
|
import { createRequire as createRequire3 } from "module";
|
|
6169
6335
|
import path8 from "path";
|
|
6170
6336
|
function createSemanticIndexProfile(provider2) {
|
|
@@ -6178,7 +6344,7 @@ function stateKey(dataDir, profile) {
|
|
|
6178
6344
|
return `${path8.resolve(dataDir)}::${profile.key}`;
|
|
6179
6345
|
}
|
|
6180
6346
|
function tableName(profile) {
|
|
6181
|
-
const digest2 =
|
|
6347
|
+
const digest2 = createHash4("sha256").update(profile.key).digest("hex").slice(0, 20);
|
|
6182
6348
|
return `${TABLE_PREFIX}${digest2}`;
|
|
6183
6349
|
}
|
|
6184
6350
|
function indexRoot(dataDir) {
|
|
@@ -8218,6 +8384,7 @@ var init_secret_filter = __esm({
|
|
|
8218
8384
|
// src/runtime/maintenance-jobs.ts
|
|
8219
8385
|
var maintenance_jobs_exports = {};
|
|
8220
8386
|
__export(maintenance_jobs_exports, {
|
|
8387
|
+
DEFAULT_FAILED_HISTORY_RETENTION_MS: () => DEFAULT_FAILED_HISTORY_RETENTION_MS,
|
|
8221
8388
|
MAINTENANCE_JOB_KINDS: () => MAINTENANCE_JOB_KINDS,
|
|
8222
8389
|
MaintenanceJobStore: () => MaintenanceJobStore,
|
|
8223
8390
|
MaintenanceJobWorker: () => MaintenanceJobWorker,
|
|
@@ -8267,7 +8434,7 @@ function normalizedKinds(kinds) {
|
|
|
8267
8434
|
function getMaintenanceRetryDelayMs(attempts) {
|
|
8268
8435
|
return Math.min(6e4, 1e3 * 2 ** Math.max(0, attempts - 1));
|
|
8269
8436
|
}
|
|
8270
|
-
var MAINTENANCE_JOB_KINDS, DEFAULT_MAX_ATTEMPTS, DEFAULT_LEASE_MS, DEFAULT_POLL_INTERVAL_MS, MAX_ERROR_LENGTH, DEFAULT_COMPLETED_HISTORY_RETENTION_MS, MaintenanceJobStore, MaintenanceJobWorker;
|
|
8437
|
+
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;
|
|
8271
8438
|
var init_maintenance_jobs = __esm({
|
|
8272
8439
|
"src/runtime/maintenance-jobs.ts"() {
|
|
8273
8440
|
"use strict";
|
|
@@ -8294,6 +8461,7 @@ var init_maintenance_jobs = __esm({
|
|
|
8294
8461
|
DEFAULT_POLL_INTERVAL_MS = 2e3;
|
|
8295
8462
|
MAX_ERROR_LENGTH = 1e3;
|
|
8296
8463
|
DEFAULT_COMPLETED_HISTORY_RETENTION_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
8464
|
+
DEFAULT_FAILED_HISTORY_RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
8297
8465
|
MaintenanceJobStore = class {
|
|
8298
8466
|
db;
|
|
8299
8467
|
constructor(dataDir) {
|
|
@@ -8420,18 +8588,21 @@ var init_maintenance_jobs = __esm({
|
|
|
8420
8588
|
}
|
|
8421
8589
|
/**
|
|
8422
8590
|
* Completed jobs are useful recent operator history, not permanent data.
|
|
8423
|
-
* Failed
|
|
8424
|
-
*
|
|
8591
|
+
* Failed diagnostics are retained longer, but are still bounded so a
|
|
8592
|
+
* permanently failing job kind cannot grow the database forever.
|
|
8425
8593
|
*/
|
|
8426
8594
|
pruneCompletedHistory(options = {}) {
|
|
8427
8595
|
const now3 = options.now ?? Date.now();
|
|
8428
8596
|
const maxAgeMs = Number.isFinite(options.maxAgeMs) ? Math.max(0, Math.floor(options.maxAgeMs)) : DEFAULT_COMPLETED_HISTORY_RETENTION_MS;
|
|
8597
|
+
const failedMaxAgeMs = Number.isFinite(options.failedMaxAgeMs) ? Math.max(0, Math.floor(options.failedMaxAgeMs)) : DEFAULT_FAILED_HISTORY_RETENTION_MS;
|
|
8429
8598
|
const result = this.db.prepare(`
|
|
8430
8599
|
DELETE FROM maintenance_jobs
|
|
8431
|
-
WHERE status = 'completed'
|
|
8600
|
+
WHERE (status = 'completed'
|
|
8432
8601
|
AND completed_at IS NOT NULL
|
|
8433
|
-
AND completed_at < ?
|
|
8434
|
-
|
|
8602
|
+
AND completed_at < ?)
|
|
8603
|
+
OR (status = 'failed'
|
|
8604
|
+
AND updated_at < ?)
|
|
8605
|
+
`).run(now3 - maxAgeMs, now3 - failedMaxAgeMs);
|
|
8435
8606
|
return Number(result.changes ?? 0);
|
|
8436
8607
|
}
|
|
8437
8608
|
claimNext(options) {
|
|
@@ -8757,7 +8928,7 @@ var init_lifecycle = __esm({
|
|
|
8757
8928
|
});
|
|
8758
8929
|
|
|
8759
8930
|
// src/store/evidence-store.ts
|
|
8760
|
-
import { createHash as
|
|
8931
|
+
import { createHash as createHash5, randomUUID as randomUUID3 } from "crypto";
|
|
8761
8932
|
function safeJson(value, fallback) {
|
|
8762
8933
|
if (typeof value !== "string" || value.length === 0) return fallback;
|
|
8763
8934
|
try {
|
|
@@ -8791,7 +8962,7 @@ function rowToCard(row) {
|
|
|
8791
8962
|
};
|
|
8792
8963
|
}
|
|
8793
8964
|
function observationHash(observation) {
|
|
8794
|
-
return
|
|
8965
|
+
return createHash5("sha256").update(JSON.stringify({
|
|
8795
8966
|
projectId: observation.projectId,
|
|
8796
8967
|
id: observation.id,
|
|
8797
8968
|
title: observation.title,
|
|
@@ -9251,13 +9422,13 @@ __export(workspace_exports, {
|
|
|
9251
9422
|
loadKnowledgeWorkspace: () => loadKnowledgeWorkspace,
|
|
9252
9423
|
resolveKnowledgeWorkspaceFile: () => resolveKnowledgeWorkspaceFile
|
|
9253
9424
|
});
|
|
9254
|
-
import { createHash as
|
|
9425
|
+
import { createHash as createHash6 } from "crypto";
|
|
9255
9426
|
import { execFile } from "child_process";
|
|
9256
9427
|
import { promises as fs6 } from "fs";
|
|
9257
9428
|
import path11 from "path";
|
|
9258
9429
|
import { promisify } from "util";
|
|
9259
9430
|
function hash(value) {
|
|
9260
|
-
return
|
|
9431
|
+
return createHash6("sha256").update(value).digest("hex");
|
|
9261
9432
|
}
|
|
9262
9433
|
function workspaceId(projectId, mode) {
|
|
9263
9434
|
return "workspace:" + hash(projectId + ":" + mode).slice(0, 24);
|
|
@@ -10392,14 +10563,14 @@ var init_types2 = __esm({
|
|
|
10392
10563
|
});
|
|
10393
10564
|
|
|
10394
10565
|
// src/media/asset-store.ts
|
|
10395
|
-
import { createHash as
|
|
10566
|
+
import { createHash as createHash7, randomUUID as randomUUID6 } from "crypto";
|
|
10396
10567
|
import { copyFile, lstat, mkdir as mkdir3, open, readFile as readFile3, readdir, rename as rename2, rm, stat as stat2, writeFile as writeFile3 } from "fs/promises";
|
|
10397
10568
|
import path12 from "path";
|
|
10398
10569
|
function mediaRoot(dataDir) {
|
|
10399
10570
|
return path12.resolve(dataDir, "media");
|
|
10400
10571
|
}
|
|
10401
10572
|
function projectStorageKey(projectId) {
|
|
10402
|
-
return
|
|
10573
|
+
return createHash7("sha256").update(projectId).digest("hex").slice(0, 16);
|
|
10403
10574
|
}
|
|
10404
10575
|
function validateUnderRoot(root, candidate) {
|
|
10405
10576
|
const resolved = path12.resolve(candidate);
|
|
@@ -10508,7 +10679,7 @@ async function importMediaBuffer(input) {
|
|
|
10508
10679
|
if (input.bytes.length === 0) throw new Error("Media import rejects empty payloads");
|
|
10509
10680
|
if (input.bytes.length > maxBytes) throw new Error(`Media payload is too large (${input.bytes.length} bytes; limit ${maxBytes})`);
|
|
10510
10681
|
const detected = detectMedia(input.bytes.subarray(0, 32));
|
|
10511
|
-
const sha256 =
|
|
10682
|
+
const sha256 = createHash7("sha256").update(input.bytes).digest("hex");
|
|
10512
10683
|
return importKnownMedia({
|
|
10513
10684
|
dataDir: input.dataDir,
|
|
10514
10685
|
projectId: input.projectId,
|
|
@@ -10526,7 +10697,7 @@ async function readMediaAsset(dataDir, asset, maxBytes = DEFAULT_MAX_MEDIA_BYTES
|
|
|
10526
10697
|
if (asset.byteSize > maxBytes) throw new Error(`Media asset exceeds read limit (${asset.byteSize} bytes; limit ${maxBytes})`);
|
|
10527
10698
|
const bytes = await readFile3(getMediaAssetPath(dataDir, asset));
|
|
10528
10699
|
if (bytes.length !== asset.byteSize) throw new Error(`Media asset size no longer matches metadata: ${asset.id}`);
|
|
10529
|
-
const sha256 =
|
|
10700
|
+
const sha256 = createHash7("sha256").update(bytes).digest("hex");
|
|
10530
10701
|
if (sha256 !== asset.sha256) throw new Error(`Media asset hash no longer matches metadata: ${asset.id}`);
|
|
10531
10702
|
return bytes;
|
|
10532
10703
|
}
|
|
@@ -69222,16 +69393,16 @@ var require_jwtaccess = __commonJS({
|
|
|
69222
69393
|
* @returns A string that returns the cached key.
|
|
69223
69394
|
*/
|
|
69224
69395
|
getCachedKey(url, scopes) {
|
|
69225
|
-
let
|
|
69396
|
+
let cacheKey3 = url;
|
|
69226
69397
|
if (scopes && Array.isArray(scopes) && scopes.length) {
|
|
69227
|
-
|
|
69398
|
+
cacheKey3 = url ? `${url}_${scopes.join("_")}` : `${scopes.join("_")}`;
|
|
69228
69399
|
} else if (typeof scopes === "string") {
|
|
69229
|
-
|
|
69400
|
+
cacheKey3 = url ? `${url}_${scopes}` : scopes;
|
|
69230
69401
|
}
|
|
69231
|
-
if (!
|
|
69402
|
+
if (!cacheKey3) {
|
|
69232
69403
|
throw Error("Scopes or url must be provided");
|
|
69233
69404
|
}
|
|
69234
|
-
return
|
|
69405
|
+
return cacheKey3;
|
|
69235
69406
|
}
|
|
69236
69407
|
/**
|
|
69237
69408
|
* Get a non-expired access token, after refreshing if necessary.
|
|
@@ -75777,7 +75948,7 @@ var require_websocket = __commonJS({
|
|
|
75777
75948
|
var http3 = __require("http");
|
|
75778
75949
|
var net = __require("net");
|
|
75779
75950
|
var tls = __require("tls");
|
|
75780
|
-
var { randomBytes, createHash:
|
|
75951
|
+
var { randomBytes, createHash: createHash17 } = __require("crypto");
|
|
75781
75952
|
var { Duplex, Readable: Readable2 } = __require("stream");
|
|
75782
75953
|
var { URL: URL2 } = __require("url");
|
|
75783
75954
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -76445,7 +76616,7 @@ var require_websocket = __commonJS({
|
|
|
76445
76616
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
76446
76617
|
return;
|
|
76447
76618
|
}
|
|
76448
|
-
const digest2 =
|
|
76619
|
+
const digest2 = createHash17("sha1").update(key + GUID).digest("base64");
|
|
76449
76620
|
if (res.headers["sec-websocket-accept"] !== digest2) {
|
|
76450
76621
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
76451
76622
|
return;
|
|
@@ -76817,7 +76988,7 @@ var require_websocket_server = __commonJS({
|
|
|
76817
76988
|
var EventEmitter = __require("events");
|
|
76818
76989
|
var http3 = __require("http");
|
|
76819
76990
|
var { Duplex } = __require("stream");
|
|
76820
|
-
var { createHash:
|
|
76991
|
+
var { createHash: createHash17 } = __require("crypto");
|
|
76821
76992
|
var extension3 = require_extension();
|
|
76822
76993
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
76823
76994
|
var subprotocol2 = require_subprotocol();
|
|
@@ -77124,7 +77295,7 @@ var require_websocket_server = __commonJS({
|
|
|
77124
77295
|
);
|
|
77125
77296
|
}
|
|
77126
77297
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
77127
|
-
const digest2 =
|
|
77298
|
+
const digest2 = createHash17("sha1").update(key + GUID).digest("base64");
|
|
77128
77299
|
const headers = [
|
|
77129
77300
|
"HTTP/1.1 101 Switching Protocols",
|
|
77130
77301
|
"Upgrade: websocket",
|
|
@@ -145703,9 +145874,9 @@ var init_long_term = __esm({
|
|
|
145703
145874
|
});
|
|
145704
145875
|
|
|
145705
145876
|
// src/codegraph/ids.ts
|
|
145706
|
-
import { createHash as
|
|
145877
|
+
import { createHash as createHash8 } from "crypto";
|
|
145707
145878
|
function digest(input) {
|
|
145708
|
-
return
|
|
145879
|
+
return createHash8("sha256").update(input).digest("hex").slice(0, 16);
|
|
145709
145880
|
}
|
|
145710
145881
|
function normalizeCodePath(path23) {
|
|
145711
145882
|
return path23.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+/g, "/");
|
|
@@ -146753,7 +146924,7 @@ var init_store = __esm({
|
|
|
146753
146924
|
|
|
146754
146925
|
// src/codegraph/code-state.ts
|
|
146755
146926
|
import { execFile as execFile2 } from "child_process";
|
|
146756
|
-
import { createHash as
|
|
146927
|
+
import { createHash as createHash9 } from "crypto";
|
|
146757
146928
|
import { promisify as promisify3 } from "util";
|
|
146758
146929
|
async function runGit(rootPath, args) {
|
|
146759
146930
|
try {
|
|
@@ -146782,7 +146953,7 @@ function changedPathCount(status) {
|
|
|
146782
146953
|
return count2;
|
|
146783
146954
|
}
|
|
146784
146955
|
function fingerprint(baseRevision, status) {
|
|
146785
|
-
return
|
|
146956
|
+
return createHash9("sha256").update(baseRevision ?? "").update("\0").update(status).digest("hex");
|
|
146786
146957
|
}
|
|
146787
146958
|
async function collectCodeStateSnapshot(input) {
|
|
146788
146959
|
const [revision, status] = await Promise.all([
|
|
@@ -146876,12 +147047,12 @@ var init_exclude3 = __esm({
|
|
|
146876
147047
|
});
|
|
146877
147048
|
|
|
146878
147049
|
// src/codegraph/semantic-provider.ts
|
|
146879
|
-
import { createHash as
|
|
147050
|
+
import { createHash as createHash10 } from "crypto";
|
|
146880
147051
|
import "fs";
|
|
146881
147052
|
import { resolve } from "path";
|
|
146882
147053
|
import ts from "typescript";
|
|
146883
147054
|
function hashText(value) {
|
|
146884
|
-
return
|
|
147055
|
+
return createHash10("sha256").update(value).digest("hex");
|
|
146885
147056
|
}
|
|
146886
147057
|
function canonicalPath(value) {
|
|
146887
147058
|
const normalized = resolve(value).replace(/\\/g, "/");
|
|
@@ -147226,11 +147397,11 @@ __export(lite_provider_exports, {
|
|
|
147226
147397
|
indexProjectLite: () => indexProjectLite,
|
|
147227
147398
|
refreshProjectLite: () => refreshProjectLite
|
|
147228
147399
|
});
|
|
147229
|
-
import { createHash as
|
|
147400
|
+
import { createHash as createHash11 } from "crypto";
|
|
147230
147401
|
import { existsSync as existsSync12, readdirSync as readdirSync2, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
|
|
147231
147402
|
import { join as join4, relative as relative2 } from "path";
|
|
147232
147403
|
function hashText2(text2) {
|
|
147233
|
-
return
|
|
147404
|
+
return createHash11("sha256").update(text2).digest("hex");
|
|
147234
147405
|
}
|
|
147235
147406
|
function extension2(path23) {
|
|
147236
147407
|
const index = path23.lastIndexOf(".");
|
|
@@ -147863,7 +148034,7 @@ var claim_store_exports = {};
|
|
|
147863
148034
|
__export(claim_store_exports, {
|
|
147864
148035
|
ClaimStore: () => ClaimStore
|
|
147865
148036
|
});
|
|
147866
|
-
import { createHash as
|
|
148037
|
+
import { createHash as createHash12, randomUUID as randomUUID12 } from "crypto";
|
|
147867
148038
|
function optionalText3(value) {
|
|
147868
148039
|
return typeof value === "string" && value ? value : void 0;
|
|
147869
148040
|
}
|
|
@@ -147916,7 +148087,7 @@ function rowToEvent3(row) {
|
|
|
147916
148087
|
};
|
|
147917
148088
|
}
|
|
147918
148089
|
function evidenceKey(input) {
|
|
147919
|
-
return
|
|
148090
|
+
return createHash12("sha256").update(JSON.stringify([
|
|
147920
148091
|
input.evidenceKind,
|
|
147921
148092
|
input.evidenceId,
|
|
147922
148093
|
input.relation,
|
|
@@ -148114,7 +148285,7 @@ __export(claims_exports, {
|
|
|
148114
148285
|
supersedeClaim: () => supersedeClaim,
|
|
148115
148286
|
writeClaim: () => writeClaim
|
|
148116
148287
|
});
|
|
148117
|
-
import { createHash as
|
|
148288
|
+
import { createHash as createHash13, randomUUID as randomUUID13 } from "crypto";
|
|
148118
148289
|
function compactText2(value, field) {
|
|
148119
148290
|
if (typeof value !== "string") throw new Error("Claim " + field + " must be text");
|
|
148120
148291
|
const sanitized = sanitizeCredentials(value).trim().replace(/\s+/g, " ");
|
|
@@ -148126,7 +148297,7 @@ function normalizedTerm(value) {
|
|
|
148126
148297
|
return compactText2(value, "identity").toLocaleLowerCase("en-US");
|
|
148127
148298
|
}
|
|
148128
148299
|
function hashIdentity(parts) {
|
|
148129
|
-
return
|
|
148300
|
+
return createHash13("sha256").update(parts.join(String.fromCharCode(31))).digest("hex");
|
|
148130
148301
|
}
|
|
148131
148302
|
function buildClaimIdentity(input) {
|
|
148132
148303
|
const subject = normalizedTerm(input.subject);
|
|
@@ -148367,7 +148538,7 @@ function supersedeClaim(store, input) {
|
|
|
148367
148538
|
});
|
|
148368
148539
|
}
|
|
148369
148540
|
function hashObservation(observation) {
|
|
148370
|
-
return
|
|
148541
|
+
return createHash13("sha256").update(JSON.stringify([
|
|
148371
148542
|
observation.title,
|
|
148372
148543
|
observation.narrative,
|
|
148373
148544
|
observation.facts,
|
|
@@ -148611,11 +148782,11 @@ var init_frontmatter = __esm({
|
|
|
148611
148782
|
});
|
|
148612
148783
|
|
|
148613
148784
|
// src/knowledge/markdown.ts
|
|
148614
|
-
import { createHash as
|
|
148785
|
+
import { createHash as createHash14 } from "crypto";
|
|
148615
148786
|
import { promises as fs10 } from "fs";
|
|
148616
148787
|
import path19 from "path";
|
|
148617
148788
|
function hashContent(content) {
|
|
148618
|
-
return
|
|
148789
|
+
return createHash14("sha256").update(content).digest("hex");
|
|
148619
148790
|
}
|
|
148620
148791
|
function stringField(data, key) {
|
|
148621
148792
|
const value = data[key];
|
|
@@ -148741,11 +148912,11 @@ __export(wiki_exports, {
|
|
|
148741
148912
|
lintKnowledgeWorkspace: () => lintKnowledgeWorkspace,
|
|
148742
148913
|
readKnowledgePage: () => readKnowledgePage
|
|
148743
148914
|
});
|
|
148744
|
-
import { createHash as
|
|
148915
|
+
import { createHash as createHash15 } from "crypto";
|
|
148745
148916
|
import { promises as fs11 } from "fs";
|
|
148746
148917
|
import path20 from "path";
|
|
148747
148918
|
function hash2(value) {
|
|
148748
|
-
return
|
|
148919
|
+
return createHash15("sha256").update(value).digest("hex");
|
|
148749
148920
|
}
|
|
148750
148921
|
function now() {
|
|
148751
148922
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -149602,11 +149773,11 @@ __export(workflows_exports, {
|
|
|
149602
149773
|
syncCanonicalWorkflows: () => syncCanonicalWorkflows,
|
|
149603
149774
|
writeCanonicalWorkflow: () => writeCanonicalWorkflow
|
|
149604
149775
|
});
|
|
149605
|
-
import { createHash as
|
|
149776
|
+
import { createHash as createHash16 } from "crypto";
|
|
149606
149777
|
import { promises as fs12 } from "fs";
|
|
149607
149778
|
import path21 from "path";
|
|
149608
149779
|
function hash3(value) {
|
|
149609
|
-
return
|
|
149780
|
+
return createHash16("sha256").update(value).digest("hex");
|
|
149610
149781
|
}
|
|
149611
149782
|
function now2() {
|
|
149612
149783
|
return (/* @__PURE__ */ new Date()).toISOString();
|