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
package/dist/sdk.js
CHANGED
|
@@ -294,6 +294,74 @@ var init_launch_root = __esm({
|
|
|
294
294
|
}
|
|
295
295
|
});
|
|
296
296
|
|
|
297
|
+
// src/store/sqlite-reliability.ts
|
|
298
|
+
function isTransientSqliteError(error) {
|
|
299
|
+
const code = error?.code;
|
|
300
|
+
if (typeof code === "string") {
|
|
301
|
+
return /^SQLITE_BUSY(?:_|$)/i.test(code);
|
|
302
|
+
}
|
|
303
|
+
return error instanceof Error && /\bdatabase is locked\b|\bdatabase is busy\b/i.test(error.message);
|
|
304
|
+
}
|
|
305
|
+
function isSqliteUnavailableError(error) {
|
|
306
|
+
return error instanceof SqliteUnavailableError || error instanceof Error && /SQLite is not available|better-sqlite3.*failed|node:sqlite.*failed|bun:sqlite.*failed/i.test(error.message);
|
|
307
|
+
}
|
|
308
|
+
function degradedReadError(storeName) {
|
|
309
|
+
return new Error(`[memorix] Cannot read ${storeName}: SQLite backend unavailable (memory is not loaded)`);
|
|
310
|
+
}
|
|
311
|
+
function degradedWriteError(storeName) {
|
|
312
|
+
return new Error(`[memorix] Cannot write ${storeName}: SQLite backend unavailable (degraded mode; read-only)`);
|
|
313
|
+
}
|
|
314
|
+
function formatSqliteFailure(error) {
|
|
315
|
+
return error instanceof Error && error.message ? error.message : String(error);
|
|
316
|
+
}
|
|
317
|
+
function delay(ms) {
|
|
318
|
+
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
319
|
+
}
|
|
320
|
+
async function retrySqliteBusy(operation, label) {
|
|
321
|
+
for (let attempt = 0; ; attempt++) {
|
|
322
|
+
try {
|
|
323
|
+
return await operation();
|
|
324
|
+
} catch (error) {
|
|
325
|
+
if (!isTransientSqliteError(error) || attempt >= SQLITE_BUSY_RETRY_DELAYS_MS.length) throw error;
|
|
326
|
+
const waitMs = SQLITE_BUSY_RETRY_DELAYS_MS[attempt];
|
|
327
|
+
console.error(
|
|
328
|
+
`[memorix] ${label} SQLite busy (attempt ${attempt + 1}/${SQLITE_BUSY_RETRY_DELAYS_MS.length + 1}), retrying in ${waitMs}ms`
|
|
329
|
+
);
|
|
330
|
+
await delay(waitMs);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
async function initializeSqliteStore(factory, dataDir, label) {
|
|
335
|
+
try {
|
|
336
|
+
loadBetterSqlite3();
|
|
337
|
+
} catch (error) {
|
|
338
|
+
throw new SqliteUnavailableError(error);
|
|
339
|
+
}
|
|
340
|
+
return retrySqliteBusy(async () => {
|
|
341
|
+
const store = factory();
|
|
342
|
+
await store.init(dataDir);
|
|
343
|
+
return store;
|
|
344
|
+
}, label);
|
|
345
|
+
}
|
|
346
|
+
var SQLITE_BUSY_RETRY_DELAYS_MS, SqliteUnavailableError;
|
|
347
|
+
var init_sqlite_reliability = __esm({
|
|
348
|
+
"src/store/sqlite-reliability.ts"() {
|
|
349
|
+
"use strict";
|
|
350
|
+
init_esm_shims();
|
|
351
|
+
init_sqlite_db();
|
|
352
|
+
SQLITE_BUSY_RETRY_DELAYS_MS = [50, 150, 400, 1e3, 2500];
|
|
353
|
+
SqliteUnavailableError = class extends Error {
|
|
354
|
+
code = "MEMORIX_SQLITE_UNAVAILABLE";
|
|
355
|
+
constructor(cause) {
|
|
356
|
+
super(
|
|
357
|
+
cause instanceof Error && cause.message ? cause.message : "[memorix] SQLite is unavailable (install a supported SQLite runtime)"
|
|
358
|
+
);
|
|
359
|
+
this.name = "SqliteUnavailableError";
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
|
|
297
365
|
// src/store/sqlite-fts.ts
|
|
298
366
|
function normalizeFtsToken(token) {
|
|
299
367
|
return token.replace(/"/g, '""');
|
|
@@ -307,22 +375,27 @@ function buildFtsQuery(query) {
|
|
|
307
375
|
function initializeObservationLexicalIndex(db2) {
|
|
308
376
|
const known = ftsAvailability.get(db2);
|
|
309
377
|
if (known !== void 0) return known;
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
db2.
|
|
378
|
+
let lastError;
|
|
379
|
+
for (let attempt = 1; attempt <= FTS_INIT_MAX_ATTEMPTS; attempt++) {
|
|
380
|
+
try {
|
|
381
|
+
db2.exec(CREATE_OBSERVATION_FTS);
|
|
382
|
+
const observationCount = Number(db2.prepare("SELECT COUNT(*) AS count FROM observations").get()?.count ?? 0);
|
|
383
|
+
const indexedCount = Number(db2.prepare(`SELECT COUNT(*) AS count FROM ${FTS_TABLE}`).get()?.count ?? 0);
|
|
384
|
+
if (observationCount !== indexedCount) {
|
|
385
|
+
db2.exec(`INSERT INTO ${FTS_TABLE}(${FTS_TABLE}) VALUES ('rebuild')`);
|
|
386
|
+
}
|
|
387
|
+
ftsAvailability.set(db2, true);
|
|
388
|
+
return true;
|
|
389
|
+
} catch (error) {
|
|
390
|
+
lastError = error;
|
|
391
|
+
if (!isTransientSqliteError(error) || attempt === FTS_INIT_MAX_ATTEMPTS) break;
|
|
316
392
|
}
|
|
317
|
-
ftsAvailability.set(db2, true);
|
|
318
|
-
return true;
|
|
319
|
-
} catch (error) {
|
|
320
|
-
ftsAvailability.set(db2, false);
|
|
321
|
-
console.warn(
|
|
322
|
-
`[memorix] SQLite FTS5 unavailable; using the existing search fallback: ${error instanceof Error ? error.message : String(error)}`
|
|
323
|
-
);
|
|
324
|
-
return false;
|
|
325
393
|
}
|
|
394
|
+
ftsAvailability.set(db2, false);
|
|
395
|
+
console.warn(
|
|
396
|
+
`[memorix] SQLite FTS5 unavailable; using the existing search fallback: ${lastError instanceof Error ? lastError.message : String(lastError)}`
|
|
397
|
+
);
|
|
398
|
+
return false;
|
|
326
399
|
}
|
|
327
400
|
function isObservationLexicalIndexEnabled(db2) {
|
|
328
401
|
return ftsAvailability.get(db2) === true;
|
|
@@ -376,11 +449,12 @@ function searchObservationLexically(db2, options) {
|
|
|
376
449
|
score: Math.max(0, Number(row.lexical_score ?? 0))
|
|
377
450
|
}));
|
|
378
451
|
}
|
|
379
|
-
var ftsAvailability, FTS_TABLE, CREATE_OBSERVATION_FTS;
|
|
452
|
+
var ftsAvailability, FTS_TABLE, CREATE_OBSERVATION_FTS, FTS_INIT_MAX_ATTEMPTS;
|
|
380
453
|
var init_sqlite_fts = __esm({
|
|
381
454
|
"src/store/sqlite-fts.ts"() {
|
|
382
455
|
"use strict";
|
|
383
456
|
init_esm_shims();
|
|
457
|
+
init_sqlite_reliability();
|
|
384
458
|
ftsAvailability = /* @__PURE__ */ new WeakMap();
|
|
385
459
|
FTS_TABLE = "observations_fts";
|
|
386
460
|
CREATE_OBSERVATION_FTS = `
|
|
@@ -414,15 +488,19 @@ CREATE TRIGGER IF NOT EXISTS observations_fts_au AFTER UPDATE ON observations BE
|
|
|
414
488
|
VALUES (new.id, new.entityName, new.title, new.narrative, new.facts, new.filesModified, new.concepts, new.attachments);
|
|
415
489
|
END;
|
|
416
490
|
`;
|
|
491
|
+
FTS_INIT_MAX_ATTEMPTS = 3;
|
|
417
492
|
}
|
|
418
493
|
});
|
|
419
494
|
|
|
420
495
|
// src/store/sqlite-db.ts
|
|
421
496
|
var sqlite_db_exports = {};
|
|
422
497
|
__export(sqlite_db_exports, {
|
|
498
|
+
acquireDatabase: () => acquireDatabase,
|
|
423
499
|
closeAllDatabases: () => closeAllDatabases,
|
|
424
500
|
closeDatabase: () => closeDatabase,
|
|
501
|
+
evictIdleDatabases: () => evictIdleDatabases,
|
|
425
502
|
getDatabase: () => getDatabase,
|
|
503
|
+
getDatabaseStats: () => getDatabaseStats,
|
|
426
504
|
isSqliteAvailable: () => isSqliteAvailable,
|
|
427
505
|
loadBetterSqlite3: () => loadBetterSqlite3
|
|
428
506
|
});
|
|
@@ -460,11 +538,21 @@ function applySchemaMigrations(db2) {
|
|
|
460
538
|
apply();
|
|
461
539
|
}
|
|
462
540
|
}
|
|
541
|
+
function normalizeDataDir(dataDir) {
|
|
542
|
+
return path3.resolve(dataDir);
|
|
543
|
+
}
|
|
544
|
+
function touchDatabase(normalized, db2) {
|
|
545
|
+
_dbCache.delete(normalized);
|
|
546
|
+
_dbCache.set(normalized, db2);
|
|
547
|
+
}
|
|
463
548
|
function getDatabase(dataDir) {
|
|
464
|
-
const normalized =
|
|
549
|
+
const normalized = normalizeDataDir(dataDir);
|
|
465
550
|
assertNotHomeDataDir(normalized);
|
|
466
551
|
const existing = _dbCache.get(normalized);
|
|
467
|
-
if (existing)
|
|
552
|
+
if (existing) {
|
|
553
|
+
touchDatabase(normalized, existing);
|
|
554
|
+
return existing;
|
|
555
|
+
}
|
|
468
556
|
loadBetterSqlite3();
|
|
469
557
|
fs.mkdirSync(dataDir, { recursive: true });
|
|
470
558
|
const dbPath = path3.join(dataDir, "memorix.db");
|
|
@@ -494,6 +582,8 @@ function getDatabase(dataDir) {
|
|
|
494
582
|
db2.exec(CREATE_MAINTENANCE_JOBS_TABLE);
|
|
495
583
|
db2.exec(CREATE_MAINTENANCE_TARGETS_TABLE);
|
|
496
584
|
db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
|
|
585
|
+
db2.exec(CREATE_TASK_CONTINUITY_EVENTS_TABLE);
|
|
586
|
+
db2.exec(CREATE_AGENT_EFFECTS_TABLE);
|
|
497
587
|
try {
|
|
498
588
|
db2.exec(`ALTER TABLE mini_skills ADD COLUMN sourceSnapshot TEXT NOT NULL DEFAULT ''`);
|
|
499
589
|
} catch {
|
|
@@ -532,7 +622,7 @@ function getDatabase(dataDir) {
|
|
|
532
622
|
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('storage_generation', '0')`).run();
|
|
533
623
|
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('next_id', '1')`).run();
|
|
534
624
|
db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('mini_skills_generation', '0')`).run();
|
|
535
|
-
|
|
625
|
+
touchDatabase(normalized, db2);
|
|
536
626
|
return db2;
|
|
537
627
|
} catch (error) {
|
|
538
628
|
try {
|
|
@@ -542,8 +632,46 @@ function getDatabase(dataDir) {
|
|
|
542
632
|
throw error;
|
|
543
633
|
}
|
|
544
634
|
}
|
|
635
|
+
function acquireDatabase(dataDir) {
|
|
636
|
+
const normalized = normalizeDataDir(dataDir);
|
|
637
|
+
const db2 = getDatabase(normalized);
|
|
638
|
+
_dbLeases.set(normalized, (_dbLeases.get(normalized) ?? 0) + 1);
|
|
639
|
+
let released = false;
|
|
640
|
+
return {
|
|
641
|
+
dataDir: normalized,
|
|
642
|
+
db: db2,
|
|
643
|
+
release: () => {
|
|
644
|
+
if (released) return;
|
|
645
|
+
released = true;
|
|
646
|
+
const count2 = (_dbLeases.get(normalized) ?? 0) - 1;
|
|
647
|
+
if (count2 > 0) _dbLeases.set(normalized, count2);
|
|
648
|
+
else _dbLeases.delete(normalized);
|
|
649
|
+
}
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
function getDatabaseStats() {
|
|
653
|
+
let leased = 0;
|
|
654
|
+
for (const count2 of _dbLeases.values()) leased += count2;
|
|
655
|
+
return { cached: _dbCache.size, leased, leasedDataDirs: _dbLeases.size };
|
|
656
|
+
}
|
|
657
|
+
function evictIdleDatabases(maxCached) {
|
|
658
|
+
const target = Math.max(0, Math.floor(maxCached));
|
|
659
|
+
let evicted = 0;
|
|
660
|
+
for (const [normalized, db2] of [..._dbCache]) {
|
|
661
|
+
if (_dbCache.size <= target) break;
|
|
662
|
+
if ((_dbLeases.get(normalized) ?? 0) > 0) continue;
|
|
663
|
+
try {
|
|
664
|
+
db2.close();
|
|
665
|
+
} catch {
|
|
666
|
+
}
|
|
667
|
+
_dbCache.delete(normalized);
|
|
668
|
+
evicted++;
|
|
669
|
+
}
|
|
670
|
+
return evicted;
|
|
671
|
+
}
|
|
545
672
|
function closeDatabase(dataDir) {
|
|
546
|
-
const normalized =
|
|
673
|
+
const normalized = normalizeDataDir(dataDir);
|
|
674
|
+
if ((_dbLeases.get(normalized) ?? 0) > 0) return;
|
|
547
675
|
const db2 = _dbCache.get(normalized);
|
|
548
676
|
if (db2) {
|
|
549
677
|
try {
|
|
@@ -561,6 +689,7 @@ function closeAllDatabases() {
|
|
|
561
689
|
}
|
|
562
690
|
_dbCache.delete(key);
|
|
563
691
|
}
|
|
692
|
+
_dbLeases.clear();
|
|
564
693
|
}
|
|
565
694
|
function isSqliteAvailable() {
|
|
566
695
|
try {
|
|
@@ -570,7 +699,7 @@ function isSqliteAvailable() {
|
|
|
570
699
|
return false;
|
|
571
700
|
}
|
|
572
701
|
}
|
|
573
|
-
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;
|
|
702
|
+
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;
|
|
574
703
|
var init_sqlite_db = __esm({
|
|
575
704
|
"src/store/sqlite-db.ts"() {
|
|
576
705
|
"use strict";
|
|
@@ -1287,6 +1416,43 @@ CREATE TABLE IF NOT EXISTS memory_feedback_events (
|
|
|
1287
1416
|
delta REAL NOT NULL DEFAULT 0,
|
|
1288
1417
|
observed_at TEXT NOT NULL
|
|
1289
1418
|
);
|
|
1419
|
+
`;
|
|
1420
|
+
CREATE_TASK_CONTINUITY_EVENTS_TABLE = `
|
|
1421
|
+
CREATE TABLE IF NOT EXISTS task_continuity_events (
|
|
1422
|
+
id TEXT PRIMARY KEY,
|
|
1423
|
+
project_id TEXT NOT NULL,
|
|
1424
|
+
task_id TEXT NOT NULL,
|
|
1425
|
+
task TEXT NOT NULL,
|
|
1426
|
+
kind TEXT NOT NULL,
|
|
1427
|
+
content TEXT NOT NULL,
|
|
1428
|
+
item_status TEXT,
|
|
1429
|
+
source_ref TEXT,
|
|
1430
|
+
evidence_json TEXT NOT NULL DEFAULT '[]',
|
|
1431
|
+
actor TEXT,
|
|
1432
|
+
created_at TEXT NOT NULL,
|
|
1433
|
+
event_key TEXT,
|
|
1434
|
+
item_key TEXT,
|
|
1435
|
+
supersedes_id TEXT
|
|
1436
|
+
);
|
|
1437
|
+
`;
|
|
1438
|
+
CREATE_AGENT_EFFECTS_TABLE = `
|
|
1439
|
+
CREATE TABLE IF NOT EXISTS agent_effects (
|
|
1440
|
+
id TEXT PRIMARY KEY,
|
|
1441
|
+
pipeline_id TEXT NOT NULL,
|
|
1442
|
+
task_id TEXT NOT NULL,
|
|
1443
|
+
attempt INTEGER NOT NULL,
|
|
1444
|
+
effect_key TEXT NOT NULL,
|
|
1445
|
+
tool TEXT NOT NULL,
|
|
1446
|
+
risk_tier TEXT NOT NULL,
|
|
1447
|
+
replay_policy TEXT NOT NULL,
|
|
1448
|
+
status TEXT NOT NULL,
|
|
1449
|
+
call_id TEXT,
|
|
1450
|
+
idempotency_key TEXT NOT NULL,
|
|
1451
|
+
input_fingerprint TEXT,
|
|
1452
|
+
detail TEXT,
|
|
1453
|
+
started_at INTEGER NOT NULL,
|
|
1454
|
+
finished_at INTEGER
|
|
1455
|
+
);
|
|
1290
1456
|
`;
|
|
1291
1457
|
CREATE_MCP_BINDINGS_TABLE = `
|
|
1292
1458
|
CREATE TABLE IF NOT EXISTS mcp_bindings (
|
|
@@ -1365,7 +1531,18 @@ CREATE INDEX IF NOT EXISTS idx_evidence_cards_candidate ON evidence_cards(projec
|
|
|
1365
1531
|
CREATE INDEX IF NOT EXISTS idx_evidence_card_events_card ON evidence_card_events(card_id, created_at);
|
|
1366
1532
|
CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC);
|
|
1367
1533
|
CREATE INDEX IF NOT EXISTS idx_memory_feedback_events_candidate ON memory_feedback_events(project_id, candidate_kind, candidate_id, observed_at DESC);
|
|
1534
|
+
CREATE INDEX IF NOT EXISTS idx_task_continuity_project_task ON task_continuity_events(project_id, task_id, created_at ASC);
|
|
1535
|
+
CREATE INDEX IF NOT EXISTS idx_task_continuity_project_recent ON task_continuity_events(project_id, created_at DESC);
|
|
1536
|
+
CREATE INDEX IF NOT EXISTS idx_task_continuity_item ON task_continuity_events(project_id, task_id, kind, item_key, created_at DESC);
|
|
1537
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_task_continuity_event_key
|
|
1538
|
+
ON task_continuity_events(project_id, task_id, event_key)
|
|
1539
|
+
WHERE event_key IS NOT NULL;
|
|
1540
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_effect_identity
|
|
1541
|
+
ON agent_effects(pipeline_id, task_id, attempt, effect_key);
|
|
1542
|
+
CREATE INDEX IF NOT EXISTS idx_agent_effect_pipeline ON agent_effects(pipeline_id, started_at ASC);
|
|
1368
1543
|
CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC);
|
|
1544
|
+
CREATE INDEX IF NOT EXISTS idx_mcp_bindings_root ON mcp_bindings(project_root, last_used_at DESC);
|
|
1545
|
+
CREATE INDEX IF NOT EXISTS idx_mcp_bindings_expiry ON mcp_bindings(expires_at);
|
|
1369
1546
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
|
|
1370
1547
|
ON maintenance_jobs(project_id, kind, dedupe_key)
|
|
1371
1548
|
WHERE status IN ('pending', 'running', 'retry');
|
|
@@ -1536,6 +1713,8 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
|
|
|
1536
1713
|
db2.exec("CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC)");
|
|
1537
1714
|
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)");
|
|
1538
1715
|
db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC)");
|
|
1716
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_root ON mcp_bindings(project_root, last_used_at DESC)");
|
|
1717
|
+
db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_expiry ON mcp_bindings(expires_at)");
|
|
1539
1718
|
}
|
|
1540
1719
|
},
|
|
1541
1720
|
{
|
|
@@ -1546,9 +1725,22 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
|
|
|
1546
1725
|
addColumnIfMissing(db2, "code_symbols", "source", "source TEXT");
|
|
1547
1726
|
addColumnIfMissing(db2, "code_edges", "source", "source TEXT");
|
|
1548
1727
|
}
|
|
1728
|
+
},
|
|
1729
|
+
{
|
|
1730
|
+
id: "1.9-continuity-v2",
|
|
1731
|
+
apply: (db2) => {
|
|
1732
|
+
addColumnIfMissing(db2, "task_continuity_events", "event_key", "event_key TEXT");
|
|
1733
|
+
addColumnIfMissing(db2, "task_continuity_events", "item_key", "item_key TEXT");
|
|
1734
|
+
addColumnIfMissing(db2, "task_continuity_events", "supersedes_id", "supersedes_id TEXT");
|
|
1735
|
+
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)");
|
|
1736
|
+
db2.exec(`CREATE UNIQUE INDEX IF NOT EXISTS idx_task_continuity_event_key
|
|
1737
|
+
ON task_continuity_events(project_id, task_id, event_key)
|
|
1738
|
+
WHERE event_key IS NOT NULL`);
|
|
1739
|
+
}
|
|
1549
1740
|
}
|
|
1550
1741
|
];
|
|
1551
1742
|
_dbCache = /* @__PURE__ */ new Map();
|
|
1743
|
+
_dbLeases = /* @__PURE__ */ new Map();
|
|
1552
1744
|
}
|
|
1553
1745
|
});
|
|
1554
1746
|
|
|
@@ -2521,74 +2713,6 @@ var init_types = __esm({
|
|
|
2521
2713
|
}
|
|
2522
2714
|
});
|
|
2523
2715
|
|
|
2524
|
-
// src/store/sqlite-reliability.ts
|
|
2525
|
-
function isTransientSqliteError(error) {
|
|
2526
|
-
const code = error?.code;
|
|
2527
|
-
if (typeof code === "string") {
|
|
2528
|
-
return /^SQLITE_BUSY(?:_|$)/i.test(code);
|
|
2529
|
-
}
|
|
2530
|
-
return error instanceof Error && /\bdatabase is locked\b|\bdatabase is busy\b/i.test(error.message);
|
|
2531
|
-
}
|
|
2532
|
-
function isSqliteUnavailableError(error) {
|
|
2533
|
-
return error instanceof SqliteUnavailableError || error instanceof Error && /SQLite is not available|better-sqlite3.*failed|node:sqlite.*failed|bun:sqlite.*failed/i.test(error.message);
|
|
2534
|
-
}
|
|
2535
|
-
function degradedReadError(storeName) {
|
|
2536
|
-
return new Error(`[memorix] Cannot read ${storeName}: SQLite backend unavailable (memory is not loaded)`);
|
|
2537
|
-
}
|
|
2538
|
-
function degradedWriteError(storeName) {
|
|
2539
|
-
return new Error(`[memorix] Cannot write ${storeName}: SQLite backend unavailable (degraded mode; read-only)`);
|
|
2540
|
-
}
|
|
2541
|
-
function formatSqliteFailure(error) {
|
|
2542
|
-
return error instanceof Error && error.message ? error.message : String(error);
|
|
2543
|
-
}
|
|
2544
|
-
function delay(ms) {
|
|
2545
|
-
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
2546
|
-
}
|
|
2547
|
-
async function retrySqliteBusy(operation, label) {
|
|
2548
|
-
for (let attempt = 0; ; attempt++) {
|
|
2549
|
-
try {
|
|
2550
|
-
return await operation();
|
|
2551
|
-
} catch (error) {
|
|
2552
|
-
if (!isTransientSqliteError(error) || attempt >= SQLITE_BUSY_RETRY_DELAYS_MS.length) throw error;
|
|
2553
|
-
const waitMs = SQLITE_BUSY_RETRY_DELAYS_MS[attempt];
|
|
2554
|
-
console.error(
|
|
2555
|
-
`[memorix] ${label} SQLite busy (attempt ${attempt + 1}/${SQLITE_BUSY_RETRY_DELAYS_MS.length + 1}), retrying in ${waitMs}ms`
|
|
2556
|
-
);
|
|
2557
|
-
await delay(waitMs);
|
|
2558
|
-
}
|
|
2559
|
-
}
|
|
2560
|
-
}
|
|
2561
|
-
async function initializeSqliteStore(factory, dataDir, label) {
|
|
2562
|
-
try {
|
|
2563
|
-
loadBetterSqlite3();
|
|
2564
|
-
} catch (error) {
|
|
2565
|
-
throw new SqliteUnavailableError(error);
|
|
2566
|
-
}
|
|
2567
|
-
return retrySqliteBusy(async () => {
|
|
2568
|
-
const store = factory();
|
|
2569
|
-
await store.init(dataDir);
|
|
2570
|
-
return store;
|
|
2571
|
-
}, label);
|
|
2572
|
-
}
|
|
2573
|
-
var SQLITE_BUSY_RETRY_DELAYS_MS, SqliteUnavailableError;
|
|
2574
|
-
var init_sqlite_reliability = __esm({
|
|
2575
|
-
"src/store/sqlite-reliability.ts"() {
|
|
2576
|
-
"use strict";
|
|
2577
|
-
init_esm_shims();
|
|
2578
|
-
init_sqlite_db();
|
|
2579
|
-
SQLITE_BUSY_RETRY_DELAYS_MS = [50, 150, 400, 1e3, 2500];
|
|
2580
|
-
SqliteUnavailableError = class extends Error {
|
|
2581
|
-
code = "MEMORIX_SQLITE_UNAVAILABLE";
|
|
2582
|
-
constructor(cause) {
|
|
2583
|
-
super(
|
|
2584
|
-
cause instanceof Error && cause.message ? cause.message : "[memorix] SQLite is unavailable (install a supported SQLite runtime)"
|
|
2585
|
-
);
|
|
2586
|
-
this.name = "SqliteUnavailableError";
|
|
2587
|
-
}
|
|
2588
|
-
};
|
|
2589
|
-
}
|
|
2590
|
-
});
|
|
2591
|
-
|
|
2592
2716
|
// src/store/mini-skill-store.ts
|
|
2593
2717
|
var mini_skill_store_exports = {};
|
|
2594
2718
|
__export(mini_skill_store_exports, {
|
|
@@ -3216,18 +3340,23 @@ __export(yaml_loader_exports, {
|
|
|
3216
3340
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
3217
3341
|
import { homedir } from "os";
|
|
3218
3342
|
import { parse as parseYamlDocument } from "yaml";
|
|
3343
|
+
function cacheKey(homeDir, projectRoot) {
|
|
3344
|
+
return `${homeDir}\0${projectRoot ?? ""}`;
|
|
3345
|
+
}
|
|
3219
3346
|
function initProjectRoot(root) {
|
|
3220
3347
|
globalProjectRoot = root;
|
|
3221
|
-
configCache.delete(root);
|
|
3348
|
+
configCache.delete(cacheKey(homedir(), root));
|
|
3222
3349
|
}
|
|
3223
3350
|
function clearProjectRoot() {
|
|
3224
3351
|
globalProjectRoot = null;
|
|
3225
3352
|
}
|
|
3226
|
-
function loadYamlConfig(projectRoot) {
|
|
3353
|
+
function loadYamlConfig(projectRoot, options = {}) {
|
|
3354
|
+
const homeDir = options.homeDir ?? homedir();
|
|
3227
3355
|
const resolvedRoot = projectRoot === null ? null : projectRoot ?? globalProjectRoot ?? null;
|
|
3228
|
-
const
|
|
3356
|
+
const key = cacheKey(homeDir, resolvedRoot);
|
|
3357
|
+
const cached = configCache.get(key);
|
|
3229
3358
|
if (cached) return cached;
|
|
3230
|
-
const userYaml = getGlobalYamlPath(
|
|
3359
|
+
const userYaml = getGlobalYamlPath(homeDir);
|
|
3231
3360
|
const projectYaml = resolvedRoot ? getProjectYamlPath(resolvedRoot) : null;
|
|
3232
3361
|
let userConfig = {};
|
|
3233
3362
|
let projectConfig = {};
|
|
@@ -3259,12 +3388,12 @@ function loadYamlConfig(projectRoot) {
|
|
|
3259
3388
|
server: { ...userConfig.server, ...projectConfig.server },
|
|
3260
3389
|
team: { ...userConfig.team, ...projectConfig.team }
|
|
3261
3390
|
};
|
|
3262
|
-
configCache.set(
|
|
3391
|
+
configCache.set(key, merged);
|
|
3263
3392
|
return merged;
|
|
3264
3393
|
}
|
|
3265
|
-
function resetYamlConfigCache(projectRoot) {
|
|
3394
|
+
function resetYamlConfigCache(projectRoot, homeDir = homedir()) {
|
|
3266
3395
|
if (projectRoot !== void 0) {
|
|
3267
|
-
configCache.delete(projectRoot ?? null);
|
|
3396
|
+
configCache.delete(cacheKey(homeDir, projectRoot ?? null));
|
|
3268
3397
|
} else {
|
|
3269
3398
|
configCache.clear();
|
|
3270
3399
|
}
|
|
@@ -3474,9 +3603,9 @@ var init_detector = __esm({
|
|
|
3474
3603
|
// src/config/legacy-loader.ts
|
|
3475
3604
|
import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
|
|
3476
3605
|
import { homedir as homedir2 } from "os";
|
|
3477
|
-
function loadFileConfig() {
|
|
3606
|
+
function loadFileConfig(homeDir = homedir2()) {
|
|
3478
3607
|
if (cachedConfig !== null) return cachedConfig;
|
|
3479
|
-
const configPath = getLegacyConfigJsonPath(
|
|
3608
|
+
const configPath = getLegacyConfigJsonPath(homeDir);
|
|
3480
3609
|
try {
|
|
3481
3610
|
if (existsSync4(configPath)) {
|
|
3482
3611
|
cachedConfig = JSON.parse(readFileSync4(configPath, "utf-8"));
|
|
@@ -3506,15 +3635,15 @@ import { homedir as homedir3 } from "os";
|
|
|
3506
3635
|
function loadTomlConfig(options = {}) {
|
|
3507
3636
|
const homeDir = options.homeDir ?? homedir3();
|
|
3508
3637
|
const projectRoot = options.projectRoot ?? null;
|
|
3509
|
-
const
|
|
3510
|
-
const cached = configCache2.get(
|
|
3638
|
+
const cacheKey3 = `${homeDir}\0${projectRoot ?? ""}`;
|
|
3639
|
+
const cached = configCache2.get(cacheKey3);
|
|
3511
3640
|
if (cached) return cached;
|
|
3512
3641
|
const userToml = getGlobalConfigTomlPath(homeDir);
|
|
3513
3642
|
const projectToml = projectRoot ? getProjectConfigTomlPath(projectRoot) : null;
|
|
3514
3643
|
const userConfig = existsSync5(userToml) ? parseTomlConfig(readFileSync5(userToml, "utf8"), userToml) : {};
|
|
3515
3644
|
const projectConfig = projectToml && existsSync5(projectToml) ? parseTomlConfig(readFileSync5(projectToml, "utf8"), projectToml) : {};
|
|
3516
3645
|
const merged = mergeTomlConfig(userConfig, projectConfig);
|
|
3517
|
-
configCache2.set(
|
|
3646
|
+
configCache2.set(cacheKey3, merged);
|
|
3518
3647
|
return merged;
|
|
3519
3648
|
}
|
|
3520
3649
|
function mergeTomlConfig(base, override) {
|
|
@@ -3714,8 +3843,8 @@ function getResolvedConfig(options = {}) {
|
|
|
3714
3843
|
const projectRoot = options.projectRoot === void 0 ? detectProject()?.rootPath ?? null : options.projectRoot;
|
|
3715
3844
|
loadDotenv(projectRoot === null ? void 0 : projectRoot ?? void 0, { userHomeDir: homeDir });
|
|
3716
3845
|
const toml = loadTomlConfig({ projectRoot: projectRoot ?? null, homeDir });
|
|
3717
|
-
const yaml = loadYamlConfig(projectRoot ?? null);
|
|
3718
|
-
const legacy = loadFileConfig();
|
|
3846
|
+
const yaml = loadYamlConfig(projectRoot ?? null, { homeDir });
|
|
3847
|
+
const legacy = loadFileConfig(homeDir);
|
|
3719
3848
|
const embeddingBaseUrl = first(process.env.MEMORIX_EMBEDDING_BASE_URL, toml.embedding?.base_url, yaml.embedding?.baseUrl, legacy.embeddingApi?.baseUrl);
|
|
3720
3849
|
const openRouterEmbeddingApiKey = isOpenRouterUrl(embeddingBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
|
|
3721
3850
|
const memoryLlmProvider = first(
|
|
@@ -3737,15 +3866,17 @@ function getResolvedConfig(options = {}) {
|
|
|
3737
3866
|
legacy.llm?.baseUrl
|
|
3738
3867
|
);
|
|
3739
3868
|
const openRouterMemoryLlmApiKey = isOpenRouterMemoryLane(memoryLlmProvider, memoryLlmBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
|
|
3869
|
+
const isAtlasCloud = memoryLlmProvider === "atlascloud";
|
|
3740
3870
|
const memoryLlmApiKey = first(
|
|
3741
3871
|
process.env.MEMORIX_LLM_API_KEY,
|
|
3742
3872
|
process.env.MEMORIX_API_KEY,
|
|
3743
3873
|
toml.memory?.llm?.api_key,
|
|
3744
3874
|
yaml.llm?.apiKey,
|
|
3745
3875
|
legacy.llm?.apiKey,
|
|
3746
|
-
|
|
3747
|
-
process.env.
|
|
3748
|
-
|
|
3876
|
+
// Never borrow another provider's credentials for the Atlas Cloud preset.
|
|
3877
|
+
isAtlasCloud ? process.env.ATLASCLOUD_API_KEY : process.env.OPENAI_API_KEY,
|
|
3878
|
+
isAtlasCloud ? void 0 : process.env.ANTHROPIC_API_KEY,
|
|
3879
|
+
isAtlasCloud ? void 0 : openRouterMemoryLlmApiKey
|
|
3749
3880
|
);
|
|
3750
3881
|
const resolved = {
|
|
3751
3882
|
agent: {
|
|
@@ -3924,7 +4055,8 @@ function getEnvSourceNames() {
|
|
|
3924
4055
|
"MEMORIX_CODEGRAPH_EXTERNAL_CONTEXT",
|
|
3925
4056
|
"MEMORIX_CODEGRAPH_EXTERNAL_COMMAND",
|
|
3926
4057
|
"MEMORIX_CODEGRAPH_EXTERNAL_TIMEOUT_MS",
|
|
3927
|
-
"OPENROUTER_API_KEY"
|
|
4058
|
+
"OPENROUTER_API_KEY",
|
|
4059
|
+
"ATLASCLOUD_API_KEY"
|
|
3928
4060
|
].filter((name) => process.env[name]);
|
|
3929
4061
|
}
|
|
3930
4062
|
function isOpenRouterUrl(value) {
|
|
@@ -4143,12 +4275,45 @@ function textHash(text3) {
|
|
|
4143
4275
|
async function loadDiskCache() {
|
|
4144
4276
|
try {
|
|
4145
4277
|
const raw = await readFile(CACHE_FILE, "utf-8");
|
|
4278
|
+
if (Buffer.byteLength(raw, "utf8") > MAX_CACHE_FILE_BYTES) {
|
|
4279
|
+
console.error("[memorix] FastEmbed cache exceeds the disk load limit; starting with an empty cache");
|
|
4280
|
+
return;
|
|
4281
|
+
}
|
|
4146
4282
|
const entries = JSON.parse(raw);
|
|
4147
|
-
|
|
4148
|
-
|
|
4283
|
+
if (!Array.isArray(entries)) return;
|
|
4284
|
+
for (const entry of entries) {
|
|
4285
|
+
if (!Array.isArray(entry) || typeof entry[0] !== "string" || !isVector(entry[1])) continue;
|
|
4286
|
+
cacheSet(entry[0], entry[1], false);
|
|
4287
|
+
}
|
|
4288
|
+
console.error(`[memorix] Loaded ${cache.size} cached embeddings from disk`);
|
|
4149
4289
|
} catch {
|
|
4150
4290
|
}
|
|
4151
4291
|
}
|
|
4292
|
+
function isVector(value) {
|
|
4293
|
+
return Array.isArray(value) && value.every((entry) => typeof entry === "number");
|
|
4294
|
+
}
|
|
4295
|
+
function maxCachePayloadBytes() {
|
|
4296
|
+
const raw = Number.parseInt(process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES ?? "", 10);
|
|
4297
|
+
return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_CACHE_PAYLOAD_BYTES;
|
|
4298
|
+
}
|
|
4299
|
+
function cacheSet(hash4, value, markDirty = true) {
|
|
4300
|
+
const incomingBytes = value.length * 8;
|
|
4301
|
+
if (incomingBytes > maxCachePayloadBytes()) return;
|
|
4302
|
+
const existing = cache.get(hash4);
|
|
4303
|
+
if (existing) cachePayloadBytes -= existing.length * 8;
|
|
4304
|
+
else {
|
|
4305
|
+
while (cache.size >= MAX_CACHE_SIZE || cachePayloadBytes + incomingBytes > maxCachePayloadBytes()) {
|
|
4306
|
+
const firstKey = cache.keys().next().value;
|
|
4307
|
+
if (firstKey === void 0) break;
|
|
4308
|
+
const old = cache.get(firstKey);
|
|
4309
|
+
cache.delete(firstKey);
|
|
4310
|
+
if (old) cachePayloadBytes -= old.length * 8;
|
|
4311
|
+
}
|
|
4312
|
+
}
|
|
4313
|
+
cache.set(hash4, value);
|
|
4314
|
+
cachePayloadBytes += incomingBytes;
|
|
4315
|
+
if (markDirty) diskCacheDirty = true;
|
|
4316
|
+
}
|
|
4152
4317
|
async function saveDiskCache() {
|
|
4153
4318
|
if (!diskCacheDirty) return;
|
|
4154
4319
|
try {
|
|
@@ -4159,7 +4324,7 @@ async function saveDiskCache() {
|
|
|
4159
4324
|
} catch {
|
|
4160
4325
|
}
|
|
4161
4326
|
}
|
|
4162
|
-
var CACHE_DIR, CACHE_FILE, cache, MAX_CACHE_SIZE, diskCacheDirty, FastEmbedProvider;
|
|
4327
|
+
var CACHE_DIR, CACHE_FILE, cache, MAX_CACHE_SIZE, DEFAULT_CACHE_PAYLOAD_BYTES, MAX_CACHE_FILE_BYTES, cachePayloadBytes, diskCacheDirty, FastEmbedProvider;
|
|
4163
4328
|
var init_fastembed_provider = __esm({
|
|
4164
4329
|
"src/embedding/fastembed-provider.ts"() {
|
|
4165
4330
|
"use strict";
|
|
@@ -4169,6 +4334,9 @@ var init_fastembed_provider = __esm({
|
|
|
4169
4334
|
CACHE_FILE = join2(CACHE_DIR, ".embedding-cache.json");
|
|
4170
4335
|
cache = /* @__PURE__ */ new Map();
|
|
4171
4336
|
MAX_CACHE_SIZE = 5e3;
|
|
4337
|
+
DEFAULT_CACHE_PAYLOAD_BYTES = 64 * 1024 * 1024;
|
|
4338
|
+
MAX_CACHE_FILE_BYTES = 128 * 1024 * 1024;
|
|
4339
|
+
cachePayloadBytes = 0;
|
|
4172
4340
|
diskCacheDirty = false;
|
|
4173
4341
|
FastEmbedProvider = class _FastEmbedProvider {
|
|
4174
4342
|
name = "fastembed-bge-small";
|
|
@@ -4210,7 +4378,7 @@ var init_fastembed_provider = __esm({
|
|
|
4210
4378
|
if (result.length !== this.dimensions) {
|
|
4211
4379
|
throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);
|
|
4212
4380
|
}
|
|
4213
|
-
|
|
4381
|
+
cacheSet(hash4, result);
|
|
4214
4382
|
return result;
|
|
4215
4383
|
}
|
|
4216
4384
|
async embedBatch(texts) {
|
|
@@ -4235,7 +4403,7 @@ var init_fastembed_provider = __esm({
|
|
|
4235
4403
|
const originalIdx = uncachedIndices[batchIdx];
|
|
4236
4404
|
const plain = Array.from(vec);
|
|
4237
4405
|
results[originalIdx] = plain;
|
|
4238
|
-
|
|
4406
|
+
cacheSet(textHash(uncachedTexts[batchIdx]), plain);
|
|
4239
4407
|
batchIdx++;
|
|
4240
4408
|
}
|
|
4241
4409
|
}
|
|
@@ -4243,14 +4411,6 @@ var init_fastembed_provider = __esm({
|
|
|
4243
4411
|
}
|
|
4244
4412
|
return results;
|
|
4245
4413
|
}
|
|
4246
|
-
cacheSet(hash4, value) {
|
|
4247
|
-
if (cache.size >= MAX_CACHE_SIZE) {
|
|
4248
|
-
const firstKey = cache.keys().next().value;
|
|
4249
|
-
if (firstKey !== void 0) cache.delete(firstKey);
|
|
4250
|
-
}
|
|
4251
|
-
cache.set(hash4, value);
|
|
4252
|
-
diskCacheDirty = true;
|
|
4253
|
-
}
|
|
4254
4414
|
};
|
|
4255
4415
|
}
|
|
4256
4416
|
});
|
|
@@ -4260,7 +4420,15 @@ var transformers_provider_exports = {};
|
|
|
4260
4420
|
__export(transformers_provider_exports, {
|
|
4261
4421
|
TransformersProvider: () => TransformersProvider
|
|
4262
4422
|
});
|
|
4263
|
-
|
|
4423
|
+
import { createHash as createHash2 } from "crypto";
|
|
4424
|
+
function cacheKey2(text3) {
|
|
4425
|
+
return createHash2("sha256").update(text3).digest("hex");
|
|
4426
|
+
}
|
|
4427
|
+
function maxCachePayloadBytes2() {
|
|
4428
|
+
const raw = Number.parseInt(process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES ?? "", 10);
|
|
4429
|
+
return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_CACHE_PAYLOAD_BYTES2;
|
|
4430
|
+
}
|
|
4431
|
+
var cache2, MAX_CACHE_SIZE2, DEFAULT_CACHE_PAYLOAD_BYTES2, cachePayloadBytes2, TransformersProvider;
|
|
4264
4432
|
var init_transformers_provider = __esm({
|
|
4265
4433
|
"src/embedding/transformers-provider.ts"() {
|
|
4266
4434
|
"use strict";
|
|
@@ -4268,6 +4436,8 @@ var init_transformers_provider = __esm({
|
|
|
4268
4436
|
init_provider();
|
|
4269
4437
|
cache2 = /* @__PURE__ */ new Map();
|
|
4270
4438
|
MAX_CACHE_SIZE2 = 5e3;
|
|
4439
|
+
DEFAULT_CACHE_PAYLOAD_BYTES2 = 64 * 1024 * 1024;
|
|
4440
|
+
cachePayloadBytes2 = 0;
|
|
4271
4441
|
TransformersProvider = class _TransformersProvider {
|
|
4272
4442
|
name = "transformers-minilm";
|
|
4273
4443
|
dimensions = 384;
|
|
@@ -4302,7 +4472,7 @@ var init_transformers_provider = __esm({
|
|
|
4302
4472
|
return Promise.all(inputs.map((input) => this.embedInput(input, options)));
|
|
4303
4473
|
}
|
|
4304
4474
|
async embed(text3) {
|
|
4305
|
-
const cached = cache2.get(text3);
|
|
4475
|
+
const cached = cache2.get(cacheKey2(text3));
|
|
4306
4476
|
if (cached) return cached;
|
|
4307
4477
|
const output = await this.extractor(text3, {
|
|
4308
4478
|
pooling: "mean",
|
|
@@ -4312,7 +4482,7 @@ var init_transformers_provider = __esm({
|
|
|
4312
4482
|
if (result.length !== this.dimensions) {
|
|
4313
4483
|
throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);
|
|
4314
4484
|
}
|
|
4315
|
-
this.cacheSet(text3, result);
|
|
4485
|
+
this.cacheSet(cacheKey2(text3), result);
|
|
4316
4486
|
return result;
|
|
4317
4487
|
}
|
|
4318
4488
|
async embedBatch(texts) {
|
|
@@ -4320,7 +4490,7 @@ var init_transformers_provider = __esm({
|
|
|
4320
4490
|
const uncachedIndices = [];
|
|
4321
4491
|
const uncachedTexts = [];
|
|
4322
4492
|
for (let i2 = 0; i2 < texts.length; i2++) {
|
|
4323
|
-
const cached = cache2.get(texts[i2]);
|
|
4493
|
+
const cached = cache2.get(cacheKey2(texts[i2]));
|
|
4324
4494
|
if (cached) {
|
|
4325
4495
|
results[i2] = cached;
|
|
4326
4496
|
} else {
|
|
@@ -4338,17 +4508,27 @@ var init_transformers_provider = __esm({
|
|
|
4338
4508
|
const vec = Array.from(allVecs[i2]);
|
|
4339
4509
|
const originalIdx = uncachedIndices[i2];
|
|
4340
4510
|
results[originalIdx] = vec;
|
|
4341
|
-
this.cacheSet(uncachedTexts[i2], vec);
|
|
4511
|
+
this.cacheSet(cacheKey2(uncachedTexts[i2]), vec);
|
|
4342
4512
|
}
|
|
4343
4513
|
}
|
|
4344
4514
|
return results;
|
|
4345
4515
|
}
|
|
4346
4516
|
cacheSet(key, value) {
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4517
|
+
const incomingBytes = value.length * 8;
|
|
4518
|
+
if (incomingBytes > maxCachePayloadBytes2()) return;
|
|
4519
|
+
const existing = cache2.get(key);
|
|
4520
|
+
if (existing) cachePayloadBytes2 -= existing.length * 8;
|
|
4521
|
+
else {
|
|
4522
|
+
while (cache2.size >= MAX_CACHE_SIZE2 || cachePayloadBytes2 + incomingBytes > maxCachePayloadBytes2()) {
|
|
4523
|
+
const firstKey = cache2.keys().next().value;
|
|
4524
|
+
if (firstKey === void 0) break;
|
|
4525
|
+
const old = cache2.get(firstKey);
|
|
4526
|
+
cache2.delete(firstKey);
|
|
4527
|
+
if (old) cachePayloadBytes2 -= old.length * 8;
|
|
4528
|
+
}
|
|
4350
4529
|
}
|
|
4351
4530
|
cache2.set(key, value);
|
|
4531
|
+
cachePayloadBytes2 += incomingBytes;
|
|
4352
4532
|
}
|
|
4353
4533
|
};
|
|
4354
4534
|
}
|
|
@@ -4370,7 +4550,7 @@ __export(api_provider_exports, {
|
|
|
4370
4550
|
saveDiskCacheNow: () => saveDiskCacheNow,
|
|
4371
4551
|
seedApiEmbeddingCacheForTests: () => seedApiEmbeddingCacheForTests
|
|
4372
4552
|
});
|
|
4373
|
-
import { createHash as
|
|
4553
|
+
import { createHash as createHash3 } from "crypto";
|
|
4374
4554
|
import { createReadStream, createWriteStream, constants as fsConstants } from "fs";
|
|
4375
4555
|
import { access, readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, rename, stat, unlink } from "fs/promises";
|
|
4376
4556
|
import { join as join3 } from "path";
|
|
@@ -4397,7 +4577,7 @@ function cacheStatFile() {
|
|
|
4397
4577
|
function payloadBytes(vector) {
|
|
4398
4578
|
return vector.length * BYTES_PER_DIM;
|
|
4399
4579
|
}
|
|
4400
|
-
function
|
|
4580
|
+
function maxCachePayloadBytes3() {
|
|
4401
4581
|
const raw = process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES;
|
|
4402
4582
|
if (raw) {
|
|
4403
4583
|
const parsed = Number.parseInt(raw, 10);
|
|
@@ -4407,7 +4587,7 @@ function maxCachePayloadBytes() {
|
|
|
4407
4587
|
}
|
|
4408
4588
|
function maxEntriesForDimensions(dimensions) {
|
|
4409
4589
|
const dim = Math.max(1, Math.floor(dimensions));
|
|
4410
|
-
const byBytes = Math.floor(
|
|
4590
|
+
const byBytes = Math.floor(maxCachePayloadBytes3() / (dim * BYTES_PER_DIM));
|
|
4411
4591
|
return Math.max(1, Math.min(MAX_CACHE_ENTRIES, byBytes));
|
|
4412
4592
|
}
|
|
4413
4593
|
function rememberDimensions(vector) {
|
|
@@ -4420,13 +4600,15 @@ function evictOldest() {
|
|
|
4420
4600
|
if (firstKey === void 0) return;
|
|
4421
4601
|
const old = cache3.get(firstKey);
|
|
4422
4602
|
cache3.delete(firstKey);
|
|
4423
|
-
if (old)
|
|
4603
|
+
if (old) cachePayloadBytes3 -= payloadBytes(old);
|
|
4424
4604
|
}
|
|
4425
4605
|
function evictToFit(incomingBytes, incomingDims) {
|
|
4606
|
+
if (incomingBytes > maxCachePayloadBytes3()) return false;
|
|
4426
4607
|
const limit2 = maxEntriesForDimensions(incomingDims);
|
|
4427
|
-
while (cache3.size > 0 && (cache3.size >= limit2 ||
|
|
4608
|
+
while (cache3.size > 0 && (cache3.size >= limit2 || cachePayloadBytes3 + incomingBytes > maxCachePayloadBytes3())) {
|
|
4428
4609
|
evictOldest();
|
|
4429
4610
|
}
|
|
4611
|
+
return true;
|
|
4430
4612
|
}
|
|
4431
4613
|
function isNumberArray(value) {
|
|
4432
4614
|
return Array.isArray(value) && value.every((entry) => typeof entry === "number");
|
|
@@ -4453,12 +4635,12 @@ function cacheInsert(hash4, value, dirty) {
|
|
|
4453
4635
|
const incoming = payloadBytes(value);
|
|
4454
4636
|
const existing = cache3.get(hash4);
|
|
4455
4637
|
if (existing) {
|
|
4456
|
-
|
|
4638
|
+
cachePayloadBytes3 -= payloadBytes(existing);
|
|
4457
4639
|
cache3.delete(hash4);
|
|
4458
4640
|
}
|
|
4459
|
-
evictToFit(incoming, value.length || cacheDimensions || DEFAULT_ASSUMED_DIMENSIONS);
|
|
4641
|
+
if (!evictToFit(incoming, value.length || cacheDimensions || DEFAULT_ASSUMED_DIMENSIONS)) return;
|
|
4460
4642
|
cache3.set(hash4, value);
|
|
4461
|
-
|
|
4643
|
+
cachePayloadBytes3 += incoming;
|
|
4462
4644
|
if (dirty) diskCacheDirty2 = true;
|
|
4463
4645
|
}
|
|
4464
4646
|
async function readCacheStat() {
|
|
@@ -4494,7 +4676,7 @@ function cacheNamespace(config) {
|
|
|
4494
4676
|
].join("|");
|
|
4495
4677
|
}
|
|
4496
4678
|
function textHash2(text3, namespace) {
|
|
4497
|
-
return
|
|
4679
|
+
return createHash3("sha256").update(`${namespace}\0${text3}`).digest("hex").slice(0, 16);
|
|
4498
4680
|
}
|
|
4499
4681
|
function inputIdentity(input, options = {}) {
|
|
4500
4682
|
return JSON.stringify({
|
|
@@ -4836,7 +5018,7 @@ function getApiEmbeddingDiskCacheLoadCountForTests() {
|
|
|
4836
5018
|
}
|
|
4837
5019
|
function resetApiEmbeddingCacheForTests() {
|
|
4838
5020
|
cache3.clear();
|
|
4839
|
-
|
|
5021
|
+
cachePayloadBytes3 = 0;
|
|
4840
5022
|
cacheDimensions = null;
|
|
4841
5023
|
diskCacheEntryCount = 0;
|
|
4842
5024
|
diskCacheLoaded = false;
|
|
@@ -4847,14 +5029,14 @@ function resetApiEmbeddingCacheForTests() {
|
|
|
4847
5029
|
}
|
|
4848
5030
|
function seedApiEmbeddingCacheForTests(entries) {
|
|
4849
5031
|
cache3.clear();
|
|
4850
|
-
|
|
5032
|
+
cachePayloadBytes3 = 0;
|
|
4851
5033
|
cacheDimensions = null;
|
|
4852
5034
|
for (const [key, value] of entries) cacheInsert(key, value, true);
|
|
4853
5035
|
diskCacheLoaded = true;
|
|
4854
5036
|
diskCacheDirty2 = true;
|
|
4855
5037
|
}
|
|
4856
5038
|
function getApiEmbeddingCachePayloadBytesForTests() {
|
|
4857
|
-
return
|
|
5039
|
+
return cachePayloadBytes3;
|
|
4858
5040
|
}
|
|
4859
5041
|
function getApiEmbeddingJsonlLineCountCallsForTests() {
|
|
4860
5042
|
return jsonlLineCountCalls;
|
|
@@ -5028,7 +5210,7 @@ function scheduleDiskSave() {
|
|
|
5028
5210
|
diskSaveTimer = null;
|
|
5029
5211
|
}, DISK_SAVE_DEBOUNCE_MS);
|
|
5030
5212
|
}
|
|
5031
|
-
function
|
|
5213
|
+
function cacheSet2(hash4, value) {
|
|
5032
5214
|
cacheInsert(hash4, value, true);
|
|
5033
5215
|
}
|
|
5034
5216
|
function resolveEnvEmbeddingApiKey() {
|
|
@@ -5148,7 +5330,7 @@ async function waitForRetry(waitMs, signal) {
|
|
|
5148
5330
|
abortSignal.addEventListener("abort", onAbort, { once: true });
|
|
5149
5331
|
});
|
|
5150
5332
|
}
|
|
5151
|
-
var cache3, MAX_CACHE_ENTRIES, MAX_CACHE_PAYLOAD_BYTES, BYTES_PER_DIM, DEFAULT_ASSUMED_DIMENSIONS, MAX_MIGRATION_VALUE_BYTES,
|
|
5333
|
+
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;
|
|
5152
5334
|
var init_api_provider = __esm({
|
|
5153
5335
|
"src/embedding/api-provider.ts"() {
|
|
5154
5336
|
"use strict";
|
|
@@ -5160,7 +5342,7 @@ var init_api_provider = __esm({
|
|
|
5160
5342
|
BYTES_PER_DIM = 8;
|
|
5161
5343
|
DEFAULT_ASSUMED_DIMENSIONS = 4096;
|
|
5162
5344
|
MAX_MIGRATION_VALUE_BYTES = 16 * 1024 * 1024;
|
|
5163
|
-
|
|
5345
|
+
cachePayloadBytes3 = 0;
|
|
5164
5346
|
cacheDimensions = null;
|
|
5165
5347
|
diskCacheEntryCount = 0;
|
|
5166
5348
|
diskCacheDirty2 = false;
|
|
@@ -5345,7 +5527,7 @@ var init_api_provider = __esm({
|
|
|
5345
5527
|
} else {
|
|
5346
5528
|
embedding = await apiCall();
|
|
5347
5529
|
}
|
|
5348
|
-
|
|
5530
|
+
cacheSet2(hash4, embedding);
|
|
5349
5531
|
scheduleDiskSave();
|
|
5350
5532
|
return embedding;
|
|
5351
5533
|
}
|
|
@@ -5393,7 +5575,7 @@ var init_api_provider = __esm({
|
|
|
5393
5575
|
for (const item of response.data) {
|
|
5394
5576
|
const originalIdx = chunkIndices[item.index];
|
|
5395
5577
|
results[originalIdx] = item.embedding;
|
|
5396
|
-
|
|
5578
|
+
cacheSet2(textHash2(normalizedTexts[originalIdx], this.cacheKeyNamespace), item.embedding);
|
|
5397
5579
|
}
|
|
5398
5580
|
} catch (error) {
|
|
5399
5581
|
const providerLimit = parseBatchLimit(error);
|
|
@@ -5471,7 +5653,7 @@ var init_api_provider = __esm({
|
|
|
5471
5653
|
throw new Error(`Expected ${this.dimensions}d, got ${embedding.length}d; dimension mismatch`);
|
|
5472
5654
|
}
|
|
5473
5655
|
this.trackUsage(response);
|
|
5474
|
-
|
|
5656
|
+
cacheSet2(hash4, embedding);
|
|
5475
5657
|
scheduleDiskSave();
|
|
5476
5658
|
return embedding;
|
|
5477
5659
|
}
|
|
@@ -6854,6 +7036,7 @@ var init_provider2 = __esm({
|
|
|
6854
7036
|
openai: { baseUrl: "https://api.openai.com/v1", model: "gpt-4.1-nano" },
|
|
6855
7037
|
anthropic: { baseUrl: "https://api.anthropic.com/v1", model: "claude-3-5-haiku-latest" },
|
|
6856
7038
|
openrouter: { baseUrl: "https://openrouter.ai/api/v1", model: "openai/gpt-4.1-nano" },
|
|
7039
|
+
atlascloud: { baseUrl: "https://api.atlascloud.ai/v1", model: "deepseek-ai/deepseek-v3.2" },
|
|
6857
7040
|
custom: { baseUrl: "http://localhost:11434/v1", model: "llama3" }
|
|
6858
7041
|
};
|
|
6859
7042
|
currentConfig = null;
|
|
@@ -7630,7 +7813,7 @@ __export(semantic_index_exports, {
|
|
|
7630
7813
|
upsertSemanticVector: () => upsertSemanticVector,
|
|
7631
7814
|
upsertSemanticVectors: () => upsertSemanticVectors
|
|
7632
7815
|
});
|
|
7633
|
-
import { createHash as
|
|
7816
|
+
import { createHash as createHash4 } from "crypto";
|
|
7634
7817
|
import { createRequire as createRequire3 } from "module";
|
|
7635
7818
|
import path11 from "path";
|
|
7636
7819
|
function createSemanticIndexProfile(provider2) {
|
|
@@ -7644,7 +7827,7 @@ function stateKey(dataDir, profile) {
|
|
|
7644
7827
|
return `${path11.resolve(dataDir)}::${profile.key}`;
|
|
7645
7828
|
}
|
|
7646
7829
|
function tableName(profile) {
|
|
7647
|
-
const digest2 =
|
|
7830
|
+
const digest2 = createHash4("sha256").update(profile.key).digest("hex").slice(0, 20);
|
|
7648
7831
|
return `${TABLE_PREFIX}${digest2}`;
|
|
7649
7832
|
}
|
|
7650
7833
|
function indexRoot(dataDir) {
|
|
@@ -9031,6 +9214,7 @@ async function searchObservations(options) {
|
|
|
9031
9214
|
};
|
|
9032
9215
|
let queryVector = null;
|
|
9033
9216
|
let embeddingProviderForSearch = null;
|
|
9217
|
+
let embeddingUnavailable = false;
|
|
9034
9218
|
if (quality !== "fast" && embeddingEnabled && hasQuery && tier !== "fast") {
|
|
9035
9219
|
try {
|
|
9036
9220
|
const provider2 = await getEmbeddingProvider();
|
|
@@ -9038,6 +9222,7 @@ async function searchObservations(options) {
|
|
|
9038
9222
|
embeddingProviderForSearch = provider2;
|
|
9039
9223
|
const activeVectorDimensions = getVectorDimensions();
|
|
9040
9224
|
if (activeVectorDimensions !== null && provider2.dimensions !== activeVectorDimensions) {
|
|
9225
|
+
embeddingUnavailable = true;
|
|
9041
9226
|
rememberSearchMode(
|
|
9042
9227
|
modeKey,
|
|
9043
9228
|
`fulltext (embedding dimension mismatch: provider ${provider2.dimensions}d vs index ${activeVectorDimensions}d)`
|
|
@@ -9077,8 +9262,11 @@ async function searchObservations(options) {
|
|
|
9077
9262
|
hybridWeights: isCJKHeavy ? { text: 0.2, vector: 0.8 } : { text: 0.6, vector: 0.4 }
|
|
9078
9263
|
};
|
|
9079
9264
|
}
|
|
9265
|
+
} else {
|
|
9266
|
+
embeddingUnavailable = true;
|
|
9080
9267
|
}
|
|
9081
9268
|
} catch (error) {
|
|
9269
|
+
embeddingUnavailable = true;
|
|
9082
9270
|
rememberSearchMode(modeKey, "fulltext (embedding unavailable)");
|
|
9083
9271
|
console.error("[memorix] Embedding failed or timed out, falling back to fulltext search");
|
|
9084
9272
|
}
|
|
@@ -9086,7 +9274,7 @@ async function searchObservations(options) {
|
|
|
9086
9274
|
mark("preSearch");
|
|
9087
9275
|
let results;
|
|
9088
9276
|
const persistentCorpusEligible = await shouldUsePersistentSearch(projectIds, options.projectId);
|
|
9089
|
-
const canUsePersistentLexical = persistentCorpusEligible && Boolean(hasQuery) && !queryVector && (quality === "fast" || tier === "fast" || !embeddingEnabled);
|
|
9277
|
+
const canUsePersistentLexical = persistentCorpusEligible && Boolean(hasQuery) && !queryVector && (quality === "fast" || tier === "fast" || !embeddingEnabled || embeddingUnavailable);
|
|
9090
9278
|
let persistent = persistentCorpusEligible && queryVector && embeddingProviderForSearch ? await searchPersistentSemantically(options, projectIds, requestLimit, queryVector, embeddingProviderForSearch) : canUsePersistentLexical ? await searchPersistentLexically(options, projectIds, requestLimit) : null;
|
|
9091
9279
|
const durableStore = getOptionalObservationStore();
|
|
9092
9280
|
if (!persistent && queryVector && durableStore?.hasLexicalIndex?.() && count(database) === 0) {
|
|
@@ -9732,6 +9920,7 @@ var init_secret_filter = __esm({
|
|
|
9732
9920
|
// src/runtime/maintenance-jobs.ts
|
|
9733
9921
|
var maintenance_jobs_exports = {};
|
|
9734
9922
|
__export(maintenance_jobs_exports, {
|
|
9923
|
+
DEFAULT_FAILED_HISTORY_RETENTION_MS: () => DEFAULT_FAILED_HISTORY_RETENTION_MS,
|
|
9735
9924
|
MAINTENANCE_JOB_KINDS: () => MAINTENANCE_JOB_KINDS,
|
|
9736
9925
|
MaintenanceJobStore: () => MaintenanceJobStore,
|
|
9737
9926
|
MaintenanceJobWorker: () => MaintenanceJobWorker,
|
|
@@ -9781,7 +9970,7 @@ function normalizedKinds(kinds) {
|
|
|
9781
9970
|
function getMaintenanceRetryDelayMs(attempts) {
|
|
9782
9971
|
return Math.min(6e4, 1e3 * 2 ** Math.max(0, attempts - 1));
|
|
9783
9972
|
}
|
|
9784
|
-
var MAINTENANCE_JOB_KINDS, DEFAULT_MAX_ATTEMPTS, DEFAULT_LEASE_MS, DEFAULT_POLL_INTERVAL_MS, MAX_ERROR_LENGTH, DEFAULT_COMPLETED_HISTORY_RETENTION_MS, MaintenanceJobStore, MaintenanceJobWorker;
|
|
9973
|
+
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;
|
|
9785
9974
|
var init_maintenance_jobs = __esm({
|
|
9786
9975
|
"src/runtime/maintenance-jobs.ts"() {
|
|
9787
9976
|
"use strict";
|
|
@@ -9808,6 +9997,7 @@ var init_maintenance_jobs = __esm({
|
|
|
9808
9997
|
DEFAULT_POLL_INTERVAL_MS = 2e3;
|
|
9809
9998
|
MAX_ERROR_LENGTH = 1e3;
|
|
9810
9999
|
DEFAULT_COMPLETED_HISTORY_RETENTION_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
10000
|
+
DEFAULT_FAILED_HISTORY_RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
9811
10001
|
MaintenanceJobStore = class {
|
|
9812
10002
|
db;
|
|
9813
10003
|
constructor(dataDir) {
|
|
@@ -9934,18 +10124,21 @@ var init_maintenance_jobs = __esm({
|
|
|
9934
10124
|
}
|
|
9935
10125
|
/**
|
|
9936
10126
|
* Completed jobs are useful recent operator history, not permanent data.
|
|
9937
|
-
* Failed
|
|
9938
|
-
*
|
|
10127
|
+
* Failed diagnostics are retained longer, but are still bounded so a
|
|
10128
|
+
* permanently failing job kind cannot grow the database forever.
|
|
9939
10129
|
*/
|
|
9940
10130
|
pruneCompletedHistory(options = {}) {
|
|
9941
10131
|
const now3 = options.now ?? Date.now();
|
|
9942
10132
|
const maxAgeMs = Number.isFinite(options.maxAgeMs) ? Math.max(0, Math.floor(options.maxAgeMs)) : DEFAULT_COMPLETED_HISTORY_RETENTION_MS;
|
|
10133
|
+
const failedMaxAgeMs = Number.isFinite(options.failedMaxAgeMs) ? Math.max(0, Math.floor(options.failedMaxAgeMs)) : DEFAULT_FAILED_HISTORY_RETENTION_MS;
|
|
9943
10134
|
const result = this.db.prepare(`
|
|
9944
10135
|
DELETE FROM maintenance_jobs
|
|
9945
|
-
WHERE status = 'completed'
|
|
10136
|
+
WHERE (status = 'completed'
|
|
9946
10137
|
AND completed_at IS NOT NULL
|
|
9947
|
-
AND completed_at < ?
|
|
9948
|
-
|
|
10138
|
+
AND completed_at < ?)
|
|
10139
|
+
OR (status = 'failed'
|
|
10140
|
+
AND updated_at < ?)
|
|
10141
|
+
`).run(now3 - maxAgeMs, now3 - failedMaxAgeMs);
|
|
9949
10142
|
return Number(result.changes ?? 0);
|
|
9950
10143
|
}
|
|
9951
10144
|
claimNext(options) {
|
|
@@ -10299,7 +10492,7 @@ var init_lifecycle = __esm({
|
|
|
10299
10492
|
});
|
|
10300
10493
|
|
|
10301
10494
|
// src/store/evidence-store.ts
|
|
10302
|
-
import { createHash as
|
|
10495
|
+
import { createHash as createHash5, randomUUID as randomUUID3 } from "crypto";
|
|
10303
10496
|
function safeJson(value, fallback) {
|
|
10304
10497
|
if (typeof value !== "string" || value.length === 0) return fallback;
|
|
10305
10498
|
try {
|
|
@@ -10333,7 +10526,7 @@ function rowToCard(row) {
|
|
|
10333
10526
|
};
|
|
10334
10527
|
}
|
|
10335
10528
|
function observationHash(observation) {
|
|
10336
|
-
return
|
|
10529
|
+
return createHash5("sha256").update(JSON.stringify({
|
|
10337
10530
|
projectId: observation.projectId,
|
|
10338
10531
|
id: observation.id,
|
|
10339
10532
|
title: observation.title,
|
|
@@ -10927,13 +11120,13 @@ __export(workspace_exports, {
|
|
|
10927
11120
|
loadKnowledgeWorkspace: () => loadKnowledgeWorkspace,
|
|
10928
11121
|
resolveKnowledgeWorkspaceFile: () => resolveKnowledgeWorkspaceFile
|
|
10929
11122
|
});
|
|
10930
|
-
import { createHash as
|
|
11123
|
+
import { createHash as createHash6 } from "crypto";
|
|
10931
11124
|
import { execFile } from "child_process";
|
|
10932
11125
|
import { promises as fs9 } from "fs";
|
|
10933
11126
|
import path14 from "path";
|
|
10934
11127
|
import { promisify } from "util";
|
|
10935
11128
|
function hash(value) {
|
|
10936
|
-
return
|
|
11129
|
+
return createHash6("sha256").update(value).digest("hex");
|
|
10937
11130
|
}
|
|
10938
11131
|
function workspaceId(projectId, mode) {
|
|
10939
11132
|
return "workspace:" + hash(projectId + ":" + mode).slice(0, 24);
|
|
@@ -12086,14 +12279,14 @@ __export(asset_store_exports, {
|
|
|
12086
12279
|
readMediaAsset: () => readMediaAsset,
|
|
12087
12280
|
removeMediaAsset: () => removeMediaAsset
|
|
12088
12281
|
});
|
|
12089
|
-
import { createHash as
|
|
12282
|
+
import { createHash as createHash7, randomUUID as randomUUID6 } from "crypto";
|
|
12090
12283
|
import { copyFile, lstat, mkdir as mkdir3, open, readFile as readFile3, readdir, rename as rename2, rm, stat as stat2, writeFile as writeFile3 } from "fs/promises";
|
|
12091
12284
|
import path15 from "path";
|
|
12092
12285
|
function mediaRoot(dataDir) {
|
|
12093
12286
|
return path15.resolve(dataDir, "media");
|
|
12094
12287
|
}
|
|
12095
12288
|
function projectStorageKey(projectId) {
|
|
12096
|
-
return
|
|
12289
|
+
return createHash7("sha256").update(projectId).digest("hex").slice(0, 16);
|
|
12097
12290
|
}
|
|
12098
12291
|
function validateUnderRoot(root, candidate) {
|
|
12099
12292
|
const resolved = path15.resolve(candidate);
|
|
@@ -12153,7 +12346,7 @@ async function readHeader(filePath, bytes = 32) {
|
|
|
12153
12346
|
}
|
|
12154
12347
|
async function sha256File(filePath) {
|
|
12155
12348
|
const bytes = await readFile3(filePath);
|
|
12156
|
-
return
|
|
12349
|
+
return createHash7("sha256").update(bytes).digest("hex");
|
|
12157
12350
|
}
|
|
12158
12351
|
function destinationFor(root, projectId, sha256, extension3) {
|
|
12159
12352
|
const relative5 = path15.join("assets", projectStorageKey(projectId), sha256.slice(0, 2), `${sha256}${extension3}`);
|
|
@@ -12259,7 +12452,7 @@ async function importMediaBuffer(input) {
|
|
|
12259
12452
|
if (input.bytes.length === 0) throw new Error("Media import rejects empty payloads");
|
|
12260
12453
|
if (input.bytes.length > maxBytes) throw new Error(`Media payload is too large (${input.bytes.length} bytes; limit ${maxBytes})`);
|
|
12261
12454
|
const detected = detectMedia(input.bytes.subarray(0, 32));
|
|
12262
|
-
const sha256 =
|
|
12455
|
+
const sha256 = createHash7("sha256").update(input.bytes).digest("hex");
|
|
12263
12456
|
return importKnownMedia({
|
|
12264
12457
|
dataDir: input.dataDir,
|
|
12265
12458
|
projectId: input.projectId,
|
|
@@ -12277,7 +12470,7 @@ async function readMediaAsset(dataDir, asset, maxBytes = DEFAULT_MAX_MEDIA_BYTES
|
|
|
12277
12470
|
if (asset.byteSize > maxBytes) throw new Error(`Media asset exceeds read limit (${asset.byteSize} bytes; limit ${maxBytes})`);
|
|
12278
12471
|
const bytes = await readFile3(getMediaAssetPath(dataDir, asset));
|
|
12279
12472
|
if (bytes.length !== asset.byteSize) throw new Error(`Media asset size no longer matches metadata: ${asset.id}`);
|
|
12280
|
-
const sha256 =
|
|
12473
|
+
const sha256 = createHash7("sha256").update(bytes).digest("hex");
|
|
12281
12474
|
if (sha256 !== asset.sha256) throw new Error(`Media asset hash no longer matches metadata: ${asset.id}`);
|
|
12282
12475
|
return bytes;
|
|
12283
12476
|
}
|
|
@@ -65147,7 +65340,7 @@ var require_gaxios = __commonJS({
|
|
|
65147
65340
|
var retry_js_1 = require_retry3();
|
|
65148
65341
|
var stream_1 = __require("stream");
|
|
65149
65342
|
var interceptor_js_1 = require_interceptor();
|
|
65150
|
-
var
|
|
65343
|
+
var randomUUID20 = async () => globalThis.crypto?.randomUUID() || (await import("crypto")).randomUUID();
|
|
65151
65344
|
var HTTP_STATUS_NO_CONTENT = 204;
|
|
65152
65345
|
var Gaxios = class {
|
|
65153
65346
|
agentCache = /* @__PURE__ */ new Map();
|
|
@@ -65420,7 +65613,7 @@ var require_gaxios = __commonJS({
|
|
|
65420
65613
|
*/
|
|
65421
65614
|
["Blob", "File", "FormData"].includes(opts.data?.constructor?.name || "");
|
|
65422
65615
|
if (opts.multipart?.length) {
|
|
65423
|
-
const boundary = await
|
|
65616
|
+
const boundary = await randomUUID20();
|
|
65424
65617
|
preparedHeaders.set("content-type", `multipart/related; boundary=${boundary}`);
|
|
65425
65618
|
opts.body = stream_1.Readable.from(this.getMultipartRequest(opts.multipart, boundary));
|
|
65426
65619
|
} else if (shouldDirectlyPassData) {
|
|
@@ -71092,16 +71285,16 @@ var require_jwtaccess = __commonJS({
|
|
|
71092
71285
|
* @returns A string that returns the cached key.
|
|
71093
71286
|
*/
|
|
71094
71287
|
getCachedKey(url, scopes) {
|
|
71095
|
-
let
|
|
71288
|
+
let cacheKey3 = url;
|
|
71096
71289
|
if (scopes && Array.isArray(scopes) && scopes.length) {
|
|
71097
|
-
|
|
71290
|
+
cacheKey3 = url ? `${url}_${scopes.join("_")}` : `${scopes.join("_")}`;
|
|
71098
71291
|
} else if (typeof scopes === "string") {
|
|
71099
|
-
|
|
71292
|
+
cacheKey3 = url ? `${url}_${scopes}` : scopes;
|
|
71100
71293
|
}
|
|
71101
|
-
if (!
|
|
71294
|
+
if (!cacheKey3) {
|
|
71102
71295
|
throw Error("Scopes or url must be provided");
|
|
71103
71296
|
}
|
|
71104
|
-
return
|
|
71297
|
+
return cacheKey3;
|
|
71105
71298
|
}
|
|
71106
71299
|
/**
|
|
71107
71300
|
* Get a non-expired access token, after refreshing if necessary.
|
|
@@ -77647,7 +77840,7 @@ var require_websocket = __commonJS({
|
|
|
77647
77840
|
var http3 = __require("http");
|
|
77648
77841
|
var net = __require("net");
|
|
77649
77842
|
var tls = __require("tls");
|
|
77650
|
-
var { randomBytes: randomBytes2, createHash:
|
|
77843
|
+
var { randomBytes: randomBytes2, createHash: createHash20 } = __require("crypto");
|
|
77651
77844
|
var { Duplex, Readable: Readable2 } = __require("stream");
|
|
77652
77845
|
var { URL: URL2 } = __require("url");
|
|
77653
77846
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -78315,7 +78508,7 @@ var require_websocket = __commonJS({
|
|
|
78315
78508
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
78316
78509
|
return;
|
|
78317
78510
|
}
|
|
78318
|
-
const digest2 =
|
|
78511
|
+
const digest2 = createHash20("sha1").update(key + GUID).digest("base64");
|
|
78319
78512
|
if (res.headers["sec-websocket-accept"] !== digest2) {
|
|
78320
78513
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
78321
78514
|
return;
|
|
@@ -78687,7 +78880,7 @@ var require_websocket_server = __commonJS({
|
|
|
78687
78880
|
var EventEmitter2 = __require("events");
|
|
78688
78881
|
var http3 = __require("http");
|
|
78689
78882
|
var { Duplex } = __require("stream");
|
|
78690
|
-
var { createHash:
|
|
78883
|
+
var { createHash: createHash20 } = __require("crypto");
|
|
78691
78884
|
var extension3 = require_extension();
|
|
78692
78885
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
78693
78886
|
var subprotocol2 = require_subprotocol();
|
|
@@ -78994,7 +79187,7 @@ var require_websocket_server = __commonJS({
|
|
|
78994
79187
|
);
|
|
78995
79188
|
}
|
|
78996
79189
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
78997
|
-
const digest2 =
|
|
79190
|
+
const digest2 = createHash20("sha1").update(key + GUID).digest("base64");
|
|
78998
79191
|
const headers = [
|
|
78999
79192
|
"HTTP/1.1 101 Switching Protocols",
|
|
79000
79193
|
"Upgrade: websocket",
|
|
@@ -143053,9 +143246,9 @@ var init_union_priority_sort = __esm({
|
|
|
143053
143246
|
// node_modules/typebox/build/value/clean/from_union.mjs
|
|
143054
143247
|
function FromUnion9(context, type, value) {
|
|
143055
143248
|
for (const schema of UnionPrioritySort(type.anyOf)) {
|
|
143056
|
-
const
|
|
143057
|
-
if (Check2(context, schema,
|
|
143058
|
-
return
|
|
143249
|
+
const clean2 = FromType19(context, schema, Clone2(value));
|
|
143250
|
+
if (Check2(context, schema, clean2))
|
|
143251
|
+
return clean2;
|
|
143059
143252
|
}
|
|
143060
143253
|
return value;
|
|
143061
143254
|
}
|
|
@@ -147693,9 +147886,9 @@ var init_long_term = __esm({
|
|
|
147693
147886
|
});
|
|
147694
147887
|
|
|
147695
147888
|
// src/codegraph/ids.ts
|
|
147696
|
-
import { createHash as
|
|
147889
|
+
import { createHash as createHash8 } from "crypto";
|
|
147697
147890
|
function digest(input) {
|
|
147698
|
-
return
|
|
147891
|
+
return createHash8("sha256").update(input).digest("hex").slice(0, 16);
|
|
147699
147892
|
}
|
|
147700
147893
|
function normalizeCodePath(path37) {
|
|
147701
147894
|
return path37.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+/g, "/");
|
|
@@ -148743,7 +148936,7 @@ var init_store = __esm({
|
|
|
148743
148936
|
|
|
148744
148937
|
// src/codegraph/code-state.ts
|
|
148745
148938
|
import { execFile as execFile2 } from "child_process";
|
|
148746
|
-
import { createHash as
|
|
148939
|
+
import { createHash as createHash9 } from "crypto";
|
|
148747
148940
|
import { promisify as promisify3 } from "util";
|
|
148748
148941
|
async function runGit(rootPath, args) {
|
|
148749
148942
|
try {
|
|
@@ -148772,7 +148965,7 @@ function changedPathCount(status) {
|
|
|
148772
148965
|
return count2;
|
|
148773
148966
|
}
|
|
148774
148967
|
function fingerprint(baseRevision, status) {
|
|
148775
|
-
return
|
|
148968
|
+
return createHash9("sha256").update(baseRevision ?? "").update("\0").update(status).digest("hex");
|
|
148776
148969
|
}
|
|
148777
148970
|
async function collectCodeStateSnapshot(input) {
|
|
148778
148971
|
const [revision, status] = await Promise.all([
|
|
@@ -148866,12 +149059,12 @@ var init_exclude3 = __esm({
|
|
|
148866
149059
|
});
|
|
148867
149060
|
|
|
148868
149061
|
// src/codegraph/semantic-provider.ts
|
|
148869
|
-
import { createHash as
|
|
149062
|
+
import { createHash as createHash10 } from "crypto";
|
|
148870
149063
|
import "fs";
|
|
148871
149064
|
import { resolve } from "path";
|
|
148872
149065
|
import ts from "typescript";
|
|
148873
149066
|
function hashText(value) {
|
|
148874
|
-
return
|
|
149067
|
+
return createHash10("sha256").update(value).digest("hex");
|
|
148875
149068
|
}
|
|
148876
149069
|
function canonicalPath(value) {
|
|
148877
149070
|
const normalized = resolve(value).replace(/\\/g, "/");
|
|
@@ -149216,11 +149409,11 @@ __export(lite_provider_exports, {
|
|
|
149216
149409
|
indexProjectLite: () => indexProjectLite,
|
|
149217
149410
|
refreshProjectLite: () => refreshProjectLite
|
|
149218
149411
|
});
|
|
149219
|
-
import { createHash as
|
|
149412
|
+
import { createHash as createHash11 } from "crypto";
|
|
149220
149413
|
import { existsSync as existsSync12, readdirSync as readdirSync2, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
|
|
149221
149414
|
import { join as join4, relative as relative2 } from "path";
|
|
149222
149415
|
function hashText2(text3) {
|
|
149223
|
-
return
|
|
149416
|
+
return createHash11("sha256").update(text3).digest("hex");
|
|
149224
149417
|
}
|
|
149225
149418
|
function extension2(path37) {
|
|
149226
149419
|
const index = path37.lastIndexOf(".");
|
|
@@ -149853,7 +150046,7 @@ var claim_store_exports = {};
|
|
|
149853
150046
|
__export(claim_store_exports, {
|
|
149854
150047
|
ClaimStore: () => ClaimStore
|
|
149855
150048
|
});
|
|
149856
|
-
import { createHash as
|
|
150049
|
+
import { createHash as createHash12, randomUUID as randomUUID12 } from "crypto";
|
|
149857
150050
|
function optionalText3(value) {
|
|
149858
150051
|
return typeof value === "string" && value ? value : void 0;
|
|
149859
150052
|
}
|
|
@@ -149906,7 +150099,7 @@ function rowToEvent3(row) {
|
|
|
149906
150099
|
};
|
|
149907
150100
|
}
|
|
149908
150101
|
function evidenceKey(input) {
|
|
149909
|
-
return
|
|
150102
|
+
return createHash12("sha256").update(JSON.stringify([
|
|
149910
150103
|
input.evidenceKind,
|
|
149911
150104
|
input.evidenceId,
|
|
149912
150105
|
input.relation,
|
|
@@ -150104,7 +150297,7 @@ __export(claims_exports, {
|
|
|
150104
150297
|
supersedeClaim: () => supersedeClaim,
|
|
150105
150298
|
writeClaim: () => writeClaim
|
|
150106
150299
|
});
|
|
150107
|
-
import { createHash as
|
|
150300
|
+
import { createHash as createHash13, randomUUID as randomUUID13 } from "crypto";
|
|
150108
150301
|
function compactText2(value, field) {
|
|
150109
150302
|
if (typeof value !== "string") throw new Error("Claim " + field + " must be text");
|
|
150110
150303
|
const sanitized = sanitizeCredentials(value).trim().replace(/\s+/g, " ");
|
|
@@ -150116,7 +150309,7 @@ function normalizedTerm(value) {
|
|
|
150116
150309
|
return compactText2(value, "identity").toLocaleLowerCase("en-US");
|
|
150117
150310
|
}
|
|
150118
150311
|
function hashIdentity(parts) {
|
|
150119
|
-
return
|
|
150312
|
+
return createHash13("sha256").update(parts.join(String.fromCharCode(31))).digest("hex");
|
|
150120
150313
|
}
|
|
150121
150314
|
function buildClaimIdentity(input) {
|
|
150122
150315
|
const subject = normalizedTerm(input.subject);
|
|
@@ -150357,7 +150550,7 @@ function supersedeClaim(store, input) {
|
|
|
150357
150550
|
});
|
|
150358
150551
|
}
|
|
150359
150552
|
function hashObservation(observation) {
|
|
150360
|
-
return
|
|
150553
|
+
return createHash13("sha256").update(JSON.stringify([
|
|
150361
150554
|
observation.title,
|
|
150362
150555
|
observation.narrative,
|
|
150363
150556
|
observation.facts,
|
|
@@ -150601,11 +150794,11 @@ var init_frontmatter = __esm({
|
|
|
150601
150794
|
});
|
|
150602
150795
|
|
|
150603
150796
|
// src/knowledge/markdown.ts
|
|
150604
|
-
import { createHash as
|
|
150797
|
+
import { createHash as createHash14 } from "crypto";
|
|
150605
150798
|
import { promises as fs13 } from "fs";
|
|
150606
150799
|
import path22 from "path";
|
|
150607
150800
|
function hashContent(content) {
|
|
150608
|
-
return
|
|
150801
|
+
return createHash14("sha256").update(content).digest("hex");
|
|
150609
150802
|
}
|
|
150610
150803
|
function stringField(data, key) {
|
|
150611
150804
|
const value = data[key];
|
|
@@ -150731,11 +150924,11 @@ __export(wiki_exports, {
|
|
|
150731
150924
|
lintKnowledgeWorkspace: () => lintKnowledgeWorkspace,
|
|
150732
150925
|
readKnowledgePage: () => readKnowledgePage
|
|
150733
150926
|
});
|
|
150734
|
-
import { createHash as
|
|
150927
|
+
import { createHash as createHash15 } from "crypto";
|
|
150735
150928
|
import { promises as fs14 } from "fs";
|
|
150736
150929
|
import path23 from "path";
|
|
150737
150930
|
function hash2(value) {
|
|
150738
|
-
return
|
|
150931
|
+
return createHash15("sha256").update(value).digest("hex");
|
|
150739
150932
|
}
|
|
150740
150933
|
function now() {
|
|
150741
150934
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -151954,11 +152147,11 @@ __export(workflows_exports, {
|
|
|
151954
152147
|
syncCanonicalWorkflows: () => syncCanonicalWorkflows,
|
|
151955
152148
|
writeCanonicalWorkflow: () => writeCanonicalWorkflow
|
|
151956
152149
|
});
|
|
151957
|
-
import { createHash as
|
|
152150
|
+
import { createHash as createHash16 } from "crypto";
|
|
151958
152151
|
import { promises as fs15 } from "fs";
|
|
151959
152152
|
import path24 from "path";
|
|
151960
152153
|
function hash3(value) {
|
|
151961
|
-
return
|
|
152154
|
+
return createHash16("sha256").update(value).digest("hex");
|
|
151962
152155
|
}
|
|
151963
152156
|
function now2() {
|
|
151964
152157
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -155993,8 +156186,8 @@ function legacyBehavior(homeDir) {
|
|
|
155993
156186
|
function getBehaviorConfig(options = {}) {
|
|
155994
156187
|
const homeDir = options.homeDir ?? homedir22();
|
|
155995
156188
|
const projectRoot = options.projectRoot === void 0 ? detectProject()?.rootPath ?? null : options.projectRoot;
|
|
155996
|
-
const
|
|
155997
|
-
const cached = cache4.get(
|
|
156189
|
+
const cacheKey3 = `${homeDir}\0${projectRoot ?? ""}`;
|
|
156190
|
+
const cached = cache4.get(cacheKey3);
|
|
155998
156191
|
if (cached) return cached;
|
|
155999
156192
|
const legacy = legacyBehavior(homeDir);
|
|
156000
156193
|
let resolved = {};
|
|
@@ -156008,7 +156201,7 @@ function getBehaviorConfig(options = {}) {
|
|
|
156008
156201
|
autoCleanup: typeof resolved.autoCleanup === "boolean" ? resolved.autoCleanup : typeof legacy.autoCleanup === "boolean" ? legacy.autoCleanup : DEFAULTS.autoCleanup,
|
|
156009
156202
|
formationMode: isFormationMode(resolved.formation) ? resolved.formation : isFormationMode(legacy.formationMode) ? legacy.formationMode : DEFAULTS.formationMode
|
|
156010
156203
|
};
|
|
156011
|
-
cache4.set(
|
|
156204
|
+
cache4.set(cacheKey3, config);
|
|
156012
156205
|
return config;
|
|
156013
156206
|
}
|
|
156014
156207
|
function resetBehaviorConfigCache() {
|
|
@@ -156613,6 +156806,7 @@ function freshnessForMemory(status) {
|
|
|
156613
156806
|
return "unknown";
|
|
156614
156807
|
}
|
|
156615
156808
|
function receiptOmissionKind(raw) {
|
|
156809
|
+
if (raw.includes("continuity")) return "continuity";
|
|
156616
156810
|
if (raw.includes("continuation")) return "continuation";
|
|
156617
156811
|
if (raw.includes("task")) return "task";
|
|
156618
156812
|
if (raw.includes("fact")) return "current-fact";
|
|
@@ -156723,6 +156917,77 @@ function renderTaskWorksetPrompt(input) {
|
|
|
156723
156917
|
trust: "source-backed"
|
|
156724
156918
|
});
|
|
156725
156919
|
appendLine(lines, "Task lens: " + input.lens, maxTokens, omitted, "lens");
|
|
156920
|
+
if (input.continuity) {
|
|
156921
|
+
const continuity = input.continuity;
|
|
156922
|
+
appendLine(lines, "", maxTokens, omitted, "continuity-heading");
|
|
156923
|
+
appendLine(lines, "Task continuity", maxTokens, omitted, "continuity-heading", selected, {
|
|
156924
|
+
kind: "continuity",
|
|
156925
|
+
id: "continuity:" + continuity.taskId,
|
|
156926
|
+
reason: "explicit task continuity ledger",
|
|
156927
|
+
trust: "source-backed"
|
|
156928
|
+
});
|
|
156929
|
+
appendLine(
|
|
156930
|
+
lines,
|
|
156931
|
+
"- Status: " + continuity.status + " | " + short(continuity.task, 30),
|
|
156932
|
+
maxTokens,
|
|
156933
|
+
omitted,
|
|
156934
|
+
"continuity-task"
|
|
156935
|
+
);
|
|
156936
|
+
appendLine(
|
|
156937
|
+
lines,
|
|
156938
|
+
"- Outcome: " + continuity.outcome.state,
|
|
156939
|
+
maxTokens,
|
|
156940
|
+
omitted,
|
|
156941
|
+
"continuity-outcome",
|
|
156942
|
+
selected,
|
|
156943
|
+
{
|
|
156944
|
+
kind: "continuity",
|
|
156945
|
+
id: "continuity:" + continuity.taskId,
|
|
156946
|
+
reason: "deterministic task outcome projection",
|
|
156947
|
+
trust: "derived"
|
|
156948
|
+
}
|
|
156949
|
+
);
|
|
156950
|
+
for (const requirement of continuity.requirements.slice(0, 3)) {
|
|
156951
|
+
appendLine(lines, "- Requirement: " + short(requirement, 24), maxTokens, omitted, "continuity-requirement", selected, {
|
|
156952
|
+
kind: "continuity",
|
|
156953
|
+
id: "continuity:" + continuity.taskId,
|
|
156954
|
+
reason: "explicit task requirement",
|
|
156955
|
+
trust: "source-backed"
|
|
156956
|
+
});
|
|
156957
|
+
}
|
|
156958
|
+
for (const decision of continuity.decisions.slice(0, 2)) {
|
|
156959
|
+
appendLine(lines, "- Decision: " + short(decision, 24), maxTokens, omitted, "continuity-decision", selected, {
|
|
156960
|
+
kind: "continuity",
|
|
156961
|
+
id: "continuity:" + continuity.taskId,
|
|
156962
|
+
reason: "explicit task decision",
|
|
156963
|
+
trust: "source-backed"
|
|
156964
|
+
});
|
|
156965
|
+
}
|
|
156966
|
+
for (const verification of continuity.verification.slice(-3)) {
|
|
156967
|
+
appendLine(
|
|
156968
|
+
lines,
|
|
156969
|
+
"- Verify [" + verification.status + "]: " + short(verification.content, 22),
|
|
156970
|
+
maxTokens,
|
|
156971
|
+
omitted,
|
|
156972
|
+
"continuity-verification",
|
|
156973
|
+
selected,
|
|
156974
|
+
{
|
|
156975
|
+
kind: "continuity",
|
|
156976
|
+
id: "continuity:" + continuity.taskId,
|
|
156977
|
+
reason: "task verification state",
|
|
156978
|
+
trust: "source-backed"
|
|
156979
|
+
}
|
|
156980
|
+
);
|
|
156981
|
+
}
|
|
156982
|
+
for (const risk of continuity.risks.slice(0, 2)) {
|
|
156983
|
+
appendLine(lines, "- Risk: " + short(risk, 22), maxTokens, omitted, "continuity-risk", selected, {
|
|
156984
|
+
kind: "continuity",
|
|
156985
|
+
id: "continuity:" + continuity.taskId,
|
|
156986
|
+
reason: "open task risk",
|
|
156987
|
+
trust: "source-backed"
|
|
156988
|
+
});
|
|
156989
|
+
}
|
|
156990
|
+
}
|
|
156726
156991
|
if (input.alwaysOn) {
|
|
156727
156992
|
const hasAlwaysOn = input.alwaysOn.profile.length > 0 || Boolean(input.alwaysOn.state) || input.alwaysOn.durable.length > 0;
|
|
156728
156993
|
if (hasAlwaysOn) {
|
|
@@ -157246,6 +157511,7 @@ async function buildTaskWorkset(input) {
|
|
|
157246
157511
|
version: "1.3",
|
|
157247
157512
|
task,
|
|
157248
157513
|
lens: input.lens,
|
|
157514
|
+
...input.continuity ? { continuity: input.continuity } : {},
|
|
157249
157515
|
...input.alwaysOn && (input.alwaysOn.profile.length > 0 || input.alwaysOn.state || input.alwaysOn.durable.length > 0) ? { alwaysOn: input.alwaysOn } : {},
|
|
157250
157516
|
currentFacts: input.currentFacts?.map((fact) => fact.startsWith("Historical note:") ? short(fact, 48) : short(fact, 28)).slice(0, 4) ?? [],
|
|
157251
157517
|
...continuation ? { continuation } : {},
|
|
@@ -158630,7 +158896,7 @@ var compaction_checkpoint_store_exports = {};
|
|
|
158630
158896
|
__export(compaction_checkpoint_store_exports, {
|
|
158631
158897
|
CompactionCheckpointStore: () => CompactionCheckpointStore
|
|
158632
158898
|
});
|
|
158633
|
-
import { createHash as
|
|
158899
|
+
import { createHash as createHash18, randomUUID as randomUUID16 } from "crypto";
|
|
158634
158900
|
function optionalText7(value) {
|
|
158635
158901
|
return typeof value === "string" && value ? value : void 0;
|
|
158636
158902
|
}
|
|
@@ -158672,7 +158938,7 @@ function sourceKeyFor(input, summary) {
|
|
|
158672
158938
|
input.tokensBefore ?? "",
|
|
158673
158939
|
input.firstKeptEntryId ?? ""
|
|
158674
158940
|
].join("\0");
|
|
158675
|
-
return `derived:${
|
|
158941
|
+
return `derived:${createHash18("sha256").update(material).digest("hex").slice(0, 32)}`;
|
|
158676
158942
|
}
|
|
158677
158943
|
function rowToCheckpoint(row) {
|
|
158678
158944
|
return {
|
|
@@ -158930,6 +159196,305 @@ var init_compaction_checkpoint_store = __esm({
|
|
|
158930
159196
|
}
|
|
158931
159197
|
});
|
|
158932
159198
|
|
|
159199
|
+
// src/knowledge/task-continuity.ts
|
|
159200
|
+
var task_continuity_exports = {};
|
|
159201
|
+
__export(task_continuity_exports, {
|
|
159202
|
+
TASK_CONTINUITY_EVENT_KINDS: () => TASK_CONTINUITY_EVENT_KINDS,
|
|
159203
|
+
TaskContinuityStore: () => TaskContinuityStore,
|
|
159204
|
+
evaluateTaskContinuity: () => evaluateTaskContinuity
|
|
159205
|
+
});
|
|
159206
|
+
import { randomUUID as randomUUID17 } from "crypto";
|
|
159207
|
+
function clean(value, maxLength = MAX_TEXT_LENGTH2) {
|
|
159208
|
+
return sanitizeCredentials(value).replace(/\s+/g, " ").trim().slice(0, maxLength);
|
|
159209
|
+
}
|
|
159210
|
+
function cleanList(values, maxLength = MAX_TEXT_LENGTH2) {
|
|
159211
|
+
return [...new Set((values ?? []).map((value) => clean(value, maxLength)).filter(Boolean))].slice(0, MAX_LIST_ITEMS2);
|
|
159212
|
+
}
|
|
159213
|
+
function parseRefs(value) {
|
|
159214
|
+
if (typeof value !== "string") return [];
|
|
159215
|
+
try {
|
|
159216
|
+
const parsed = JSON.parse(value);
|
|
159217
|
+
return Array.isArray(parsed) ? cleanList(parsed.filter((item) => typeof item === "string"), 500).slice(0, MAX_EVIDENCE_REFS) : [];
|
|
159218
|
+
} catch {
|
|
159219
|
+
return [];
|
|
159220
|
+
}
|
|
159221
|
+
}
|
|
159222
|
+
function evaluateTaskContinuity(ledger) {
|
|
159223
|
+
const verification = {
|
|
159224
|
+
passed: ledger.verification.filter((item) => item.status === "passed").length,
|
|
159225
|
+
failed: ledger.verification.filter((item) => item.status === "failed").length,
|
|
159226
|
+
pending: ledger.verification.filter((item) => item.status === "pending").length,
|
|
159227
|
+
skipped: ledger.verification.filter((item) => item.status === "skipped").length
|
|
159228
|
+
};
|
|
159229
|
+
const reasons = [];
|
|
159230
|
+
if (verification.failed > 0) reasons.push("verification-failed");
|
|
159231
|
+
if (verification.pending > 0) reasons.push("verification-pending");
|
|
159232
|
+
if (ledger.risks.length > 0) reasons.push("open-risks");
|
|
159233
|
+
if (ledger.status === "blocked") reasons.push("task-blocked");
|
|
159234
|
+
if (ledger.status === "abandoned") reasons.push("task-abandoned");
|
|
159235
|
+
if (ledger.status === "blocked" || ledger.status === "abandoned" || verification.failed > 0) {
|
|
159236
|
+
return {
|
|
159237
|
+
state: "at-risk",
|
|
159238
|
+
score: verification.passed > verification.failed ? 0.55 : 0.2,
|
|
159239
|
+
verification,
|
|
159240
|
+
reasons
|
|
159241
|
+
};
|
|
159242
|
+
}
|
|
159243
|
+
if (ledger.status === "completed") {
|
|
159244
|
+
if (verification.passed > 0 && verification.pending === 0 && verification.skipped === 0) {
|
|
159245
|
+
return {
|
|
159246
|
+
state: ledger.risks.length > 0 ? "validated-with-risks" : "validated",
|
|
159247
|
+
score: ledger.risks.length > 0 ? 0.8 : 1,
|
|
159248
|
+
verification,
|
|
159249
|
+
reasons: reasons.length > 0 ? reasons : ["verification-passed"]
|
|
159250
|
+
};
|
|
159251
|
+
}
|
|
159252
|
+
return {
|
|
159253
|
+
state: "unverified",
|
|
159254
|
+
score: 0.4,
|
|
159255
|
+
verification,
|
|
159256
|
+
reasons: reasons.length > 0 ? reasons : ["no-passing-verification"]
|
|
159257
|
+
};
|
|
159258
|
+
}
|
|
159259
|
+
return {
|
|
159260
|
+
state: "in-progress",
|
|
159261
|
+
score: verification.passed > 0 && verification.pending === 0 ? 0.75 : 0.5,
|
|
159262
|
+
verification,
|
|
159263
|
+
reasons: reasons.length > 0 ? reasons : ["task-open"]
|
|
159264
|
+
};
|
|
159265
|
+
}
|
|
159266
|
+
function rowToEvent4(row) {
|
|
159267
|
+
const status = row.item_status ? String(row.item_status) : void 0;
|
|
159268
|
+
return {
|
|
159269
|
+
id: String(row.id),
|
|
159270
|
+
projectId: String(row.project_id),
|
|
159271
|
+
taskId: String(row.task_id),
|
|
159272
|
+
task: clean(String(row.task), MAX_TASK_LENGTH),
|
|
159273
|
+
kind: row.kind,
|
|
159274
|
+
content: clean(String(row.content)),
|
|
159275
|
+
...status ? { status } : {},
|
|
159276
|
+
...row.source_ref ? { sourceRef: clean(String(row.source_ref), 500) } : {},
|
|
159277
|
+
evidenceRefs: parseRefs(row.evidence_json),
|
|
159278
|
+
...row.actor ? { actor: clean(String(row.actor), 200) } : {},
|
|
159279
|
+
at: String(row.created_at),
|
|
159280
|
+
...row.event_key ? { eventKey: clean(String(row.event_key), 200) } : {},
|
|
159281
|
+
...row.item_key ? { itemKey: clean(String(row.item_key), 120) } : {},
|
|
159282
|
+
...row.supersedes_id ? { supersedesId: clean(String(row.supersedes_id), 120) } : {}
|
|
159283
|
+
};
|
|
159284
|
+
}
|
|
159285
|
+
function aggregate(events) {
|
|
159286
|
+
const first2 = events.find((event) => event.kind === "task") ?? events[0];
|
|
159287
|
+
const latestOutcome = [...events].reverse().find((event) => event.kind === "outcome");
|
|
159288
|
+
const verificationByKey = /* @__PURE__ */ new Map();
|
|
159289
|
+
for (const event of events.filter((event2) => event2.kind === "verification")) {
|
|
159290
|
+
verificationByKey.set(event.itemKey ?? `event:${event.id}`, event);
|
|
159291
|
+
}
|
|
159292
|
+
const ledger = {
|
|
159293
|
+
taskId: first2.taskId,
|
|
159294
|
+
projectId: first2.projectId,
|
|
159295
|
+
task: first2.task,
|
|
159296
|
+
status: latestOutcome?.status ?? "open",
|
|
159297
|
+
requirements: events.filter((event) => event.kind === "requirement").map((event) => event.content),
|
|
159298
|
+
decisions: events.filter((event) => event.kind === "decision").map((event) => event.content),
|
|
159299
|
+
verification: [...verificationByKey.values()].map((event) => ({
|
|
159300
|
+
id: event.itemKey ?? event.id,
|
|
159301
|
+
content: event.content,
|
|
159302
|
+
status: event.status ?? "pending",
|
|
159303
|
+
...event.sourceRef ? { sourceRef: event.sourceRef } : {},
|
|
159304
|
+
evidenceRefs: event.evidenceRefs
|
|
159305
|
+
})),
|
|
159306
|
+
risks: events.filter((event) => event.kind === "risk").map((event) => event.content),
|
|
159307
|
+
outcomes: events.filter((event) => event.kind === "outcome").map((event) => event.content),
|
|
159308
|
+
updatedAt: events[events.length - 1].at,
|
|
159309
|
+
events
|
|
159310
|
+
};
|
|
159311
|
+
return { ...ledger, outcome: evaluateTaskContinuity(ledger) };
|
|
159312
|
+
}
|
|
159313
|
+
var TASK_CONTINUITY_EVENT_KINDS, MAX_TEXT_LENGTH2, MAX_TASK_LENGTH, MAX_LIST_ITEMS2, MAX_EVIDENCE_REFS, MAX_EVENTS_PER_TASK, TaskContinuityStore;
|
|
159314
|
+
var init_task_continuity = __esm({
|
|
159315
|
+
"src/knowledge/task-continuity.ts"() {
|
|
159316
|
+
"use strict";
|
|
159317
|
+
init_esm_shims();
|
|
159318
|
+
init_secret_filter();
|
|
159319
|
+
init_sqlite_db();
|
|
159320
|
+
TASK_CONTINUITY_EVENT_KINDS = [
|
|
159321
|
+
"task",
|
|
159322
|
+
"requirement",
|
|
159323
|
+
"decision",
|
|
159324
|
+
"verification",
|
|
159325
|
+
"risk",
|
|
159326
|
+
"outcome"
|
|
159327
|
+
];
|
|
159328
|
+
MAX_TEXT_LENGTH2 = 2e3;
|
|
159329
|
+
MAX_TASK_LENGTH = 1e3;
|
|
159330
|
+
MAX_LIST_ITEMS2 = 8;
|
|
159331
|
+
MAX_EVIDENCE_REFS = 8;
|
|
159332
|
+
MAX_EVENTS_PER_TASK = 200;
|
|
159333
|
+
TaskContinuityStore = class {
|
|
159334
|
+
db = null;
|
|
159335
|
+
async init(dataDir) {
|
|
159336
|
+
this.db = getDatabase(dataDir);
|
|
159337
|
+
}
|
|
159338
|
+
requireDb() {
|
|
159339
|
+
if (!this.db) throw new Error("TaskContinuityStore is not initialized.");
|
|
159340
|
+
return this.db;
|
|
159341
|
+
}
|
|
159342
|
+
insert(input) {
|
|
159343
|
+
const db2 = this.requireDb();
|
|
159344
|
+
const projectId = clean(input.projectId, 500);
|
|
159345
|
+
const taskId = clean(input.taskId, 120);
|
|
159346
|
+
const eventKey = input.eventKey ? clean(input.eventKey, 200) : void 0;
|
|
159347
|
+
if (eventKey) {
|
|
159348
|
+
const existing = db2.prepare(
|
|
159349
|
+
"SELECT * FROM task_continuity_events WHERE project_id = ? AND task_id = ? AND event_key = ?"
|
|
159350
|
+
).get(projectId, taskId, eventKey);
|
|
159351
|
+
if (existing) return rowToEvent4(existing);
|
|
159352
|
+
}
|
|
159353
|
+
const existingCount = db2.prepare(
|
|
159354
|
+
"SELECT COUNT(*) AS count FROM task_continuity_events WHERE project_id = ? AND task_id = ?"
|
|
159355
|
+
).get(projectId, taskId);
|
|
159356
|
+
if (Number(existingCount?.count ?? 0) >= MAX_EVENTS_PER_TASK) {
|
|
159357
|
+
throw new Error("Task continuity ledger reached its 200-event limit.");
|
|
159358
|
+
}
|
|
159359
|
+
const event = {
|
|
159360
|
+
id: randomUUID17(),
|
|
159361
|
+
projectId,
|
|
159362
|
+
taskId,
|
|
159363
|
+
task: clean(input.task, MAX_TASK_LENGTH),
|
|
159364
|
+
kind: input.kind,
|
|
159365
|
+
content: clean(input.content),
|
|
159366
|
+
...input.status ? { status: input.status } : {},
|
|
159367
|
+
...input.sourceRef ? { sourceRef: clean(input.sourceRef, 500) } : {},
|
|
159368
|
+
evidenceRefs: cleanList(input.evidenceRefs, 500).slice(0, MAX_EVIDENCE_REFS),
|
|
159369
|
+
...input.actor ? { actor: clean(input.actor, 200) } : {},
|
|
159370
|
+
at: input.at ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
159371
|
+
...eventKey ? { eventKey } : {},
|
|
159372
|
+
...input.itemKey ? { itemKey: clean(input.itemKey, 120) } : {},
|
|
159373
|
+
...input.supersedesId ? { supersedesId: clean(input.supersedesId, 120) } : {}
|
|
159374
|
+
};
|
|
159375
|
+
db2.prepare(`
|
|
159376
|
+
INSERT INTO task_continuity_events (
|
|
159377
|
+
id, project_id, task_id, task, kind, content, item_status,
|
|
159378
|
+
source_ref, evidence_json, actor, created_at, event_key, item_key, supersedes_id
|
|
159379
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
159380
|
+
`).run(
|
|
159381
|
+
event.id,
|
|
159382
|
+
event.projectId,
|
|
159383
|
+
event.taskId,
|
|
159384
|
+
event.task,
|
|
159385
|
+
event.kind,
|
|
159386
|
+
event.content,
|
|
159387
|
+
event.status ?? null,
|
|
159388
|
+
event.sourceRef ?? null,
|
|
159389
|
+
JSON.stringify(event.evidenceRefs),
|
|
159390
|
+
event.actor ?? null,
|
|
159391
|
+
event.at,
|
|
159392
|
+
event.eventKey ?? null,
|
|
159393
|
+
event.itemKey ?? null,
|
|
159394
|
+
event.supersedesId ?? null
|
|
159395
|
+
);
|
|
159396
|
+
return event;
|
|
159397
|
+
}
|
|
159398
|
+
start(input) {
|
|
159399
|
+
const task = clean(input.task, MAX_TASK_LENGTH);
|
|
159400
|
+
if (!task) throw new Error("A non-empty task is required.");
|
|
159401
|
+
const idempotencyKey = input.idempotencyKey ? clean(input.idempotencyKey, 200) : void 0;
|
|
159402
|
+
const taskId = clean(input.taskId ?? idempotencyKey ?? "", 120) || randomUUID17();
|
|
159403
|
+
const requirements = cleanList(input.requirements);
|
|
159404
|
+
const transaction = this.requireDb().transaction(() => {
|
|
159405
|
+
this.insert({
|
|
159406
|
+
projectId: input.projectId,
|
|
159407
|
+
taskId,
|
|
159408
|
+
task,
|
|
159409
|
+
kind: "task",
|
|
159410
|
+
content: task,
|
|
159411
|
+
status: "open",
|
|
159412
|
+
actor: input.actor,
|
|
159413
|
+
...idempotencyKey ? { eventKey: `start:${idempotencyKey}` } : {}
|
|
159414
|
+
});
|
|
159415
|
+
for (const requirement of requirements) {
|
|
159416
|
+
this.insert({
|
|
159417
|
+
projectId: input.projectId,
|
|
159418
|
+
taskId,
|
|
159419
|
+
task,
|
|
159420
|
+
kind: "requirement",
|
|
159421
|
+
content: requirement,
|
|
159422
|
+
actor: input.actor
|
|
159423
|
+
});
|
|
159424
|
+
}
|
|
159425
|
+
});
|
|
159426
|
+
transaction.immediate();
|
|
159427
|
+
return { taskId, ledger: this.get(input.projectId, taskId) };
|
|
159428
|
+
}
|
|
159429
|
+
record(input) {
|
|
159430
|
+
const projectId = clean(input.projectId, 500);
|
|
159431
|
+
const taskId = clean(input.taskId, 120);
|
|
159432
|
+
const existing = this.get(projectId, taskId);
|
|
159433
|
+
if (!existing) throw new Error("Task continuity ledger not found: " + taskId);
|
|
159434
|
+
const transaction = this.requireDb().transaction(() => this.insert({
|
|
159435
|
+
projectId,
|
|
159436
|
+
taskId,
|
|
159437
|
+
task: existing.task,
|
|
159438
|
+
kind: input.kind,
|
|
159439
|
+
content: input.content,
|
|
159440
|
+
...input.kind === "verification" && input.verificationStatus ? { status: input.verificationStatus } : {},
|
|
159441
|
+
sourceRef: input.sourceRef,
|
|
159442
|
+
evidenceRefs: input.evidenceRefs,
|
|
159443
|
+
actor: input.actor,
|
|
159444
|
+
at: input.at,
|
|
159445
|
+
...input.idempotencyKey ? { eventKey: input.idempotencyKey } : {},
|
|
159446
|
+
...input.verificationId ? { itemKey: input.verificationId } : {}
|
|
159447
|
+
}));
|
|
159448
|
+
const event = transaction.immediate();
|
|
159449
|
+
return { event, ledger: this.get(projectId, taskId) };
|
|
159450
|
+
}
|
|
159451
|
+
close(input) {
|
|
159452
|
+
const projectId = clean(input.projectId, 500);
|
|
159453
|
+
const taskId = clean(input.taskId, 120);
|
|
159454
|
+
const existing = this.get(projectId, taskId);
|
|
159455
|
+
if (!existing) throw new Error("Task continuity ledger not found: " + taskId);
|
|
159456
|
+
const transaction = this.requireDb().transaction(() => this.insert({
|
|
159457
|
+
projectId,
|
|
159458
|
+
taskId,
|
|
159459
|
+
task: existing.task,
|
|
159460
|
+
kind: "outcome",
|
|
159461
|
+
content: input.content,
|
|
159462
|
+
status: input.status,
|
|
159463
|
+
sourceRef: input.sourceRef,
|
|
159464
|
+
evidenceRefs: input.evidenceRefs,
|
|
159465
|
+
actor: input.actor,
|
|
159466
|
+
at: input.at,
|
|
159467
|
+
...input.idempotencyKey ? { eventKey: input.idempotencyKey } : {}
|
|
159468
|
+
}));
|
|
159469
|
+
const event = transaction.immediate();
|
|
159470
|
+
return { event, ledger: this.get(projectId, taskId) };
|
|
159471
|
+
}
|
|
159472
|
+
get(projectId, taskId) {
|
|
159473
|
+
const normalizedProjectId = clean(projectId, 500);
|
|
159474
|
+
const normalizedTaskId = clean(taskId, 120);
|
|
159475
|
+
const rows = this.requireDb().prepare(`
|
|
159476
|
+
SELECT * FROM task_continuity_events
|
|
159477
|
+
WHERE project_id = ? AND task_id = ?
|
|
159478
|
+
ORDER BY created_at ASC, rowid ASC
|
|
159479
|
+
`).all(normalizedProjectId, normalizedTaskId);
|
|
159480
|
+
if (rows.length === 0) return void 0;
|
|
159481
|
+
return aggregate(rows.map(rowToEvent4));
|
|
159482
|
+
}
|
|
159483
|
+
list(projectId, limit2 = 20) {
|
|
159484
|
+
const rows = this.requireDb().prepare(`
|
|
159485
|
+
SELECT task_id
|
|
159486
|
+
FROM task_continuity_events
|
|
159487
|
+
WHERE project_id = ?
|
|
159488
|
+
GROUP BY task_id
|
|
159489
|
+
ORDER BY MAX(created_at) DESC
|
|
159490
|
+
LIMIT ?
|
|
159491
|
+
`).all(projectId, Math.min(100, Math.max(1, Math.floor(limit2))));
|
|
159492
|
+
return rows.map((row) => this.get(projectId, String(row.task_id))).filter((ledger) => Boolean(ledger));
|
|
159493
|
+
}
|
|
159494
|
+
};
|
|
159495
|
+
}
|
|
159496
|
+
});
|
|
159497
|
+
|
|
158933
159498
|
// src/codegraph/auto-context.ts
|
|
158934
159499
|
var auto_context_exports = {};
|
|
158935
159500
|
__export(auto_context_exports, {
|
|
@@ -159186,6 +159751,16 @@ async function buildAutoProjectContext(input) {
|
|
|
159186
159751
|
};
|
|
159187
159752
|
}
|
|
159188
159753
|
}
|
|
159754
|
+
let continuity = input.continuity;
|
|
159755
|
+
if (!continuity && input.taskId) {
|
|
159756
|
+
try {
|
|
159757
|
+
const { TaskContinuityStore: TaskContinuityStore2 } = await Promise.resolve().then(() => (init_task_continuity(), task_continuity_exports));
|
|
159758
|
+
const continuityStore = new TaskContinuityStore2();
|
|
159759
|
+
await continuityStore.init(input.dataDir);
|
|
159760
|
+
continuity = continuityStore.get(input.project.id, input.taskId);
|
|
159761
|
+
} catch {
|
|
159762
|
+
}
|
|
159763
|
+
}
|
|
159189
159764
|
const alwaysOn = await buildAlwaysOnBlock({
|
|
159190
159765
|
dataDir: input.dataDir,
|
|
159191
159766
|
projectId: input.project.id,
|
|
@@ -159204,6 +159779,7 @@ async function buildAutoProjectContext(input) {
|
|
|
159204
159779
|
providerQuality: providerQuality2,
|
|
159205
159780
|
currentFacts: worksetFactLines(currentFacts),
|
|
159206
159781
|
...continuation ? { continuation } : {},
|
|
159782
|
+
...continuity ? { continuity } : {},
|
|
159207
159783
|
codeState: codeStateLine(overview),
|
|
159208
159784
|
...codeEvolution ? { codeEvolution } : {},
|
|
159209
159785
|
reliableMemory: sourceSets.reliableSources.slice(0, lens.sourceLimit).map((source) => ({
|
|
@@ -159251,6 +159827,7 @@ async function buildAutoProjectContext(input) {
|
|
|
159251
159827
|
refresh,
|
|
159252
159828
|
providerQuality: providerQuality2,
|
|
159253
159829
|
...continuationRequested && workset.continuation ? { continuation: workset.continuation } : {},
|
|
159830
|
+
...workset.continuity ? { continuity: workset.continuity } : {},
|
|
159254
159831
|
workset
|
|
159255
159832
|
};
|
|
159256
159833
|
}
|
|
@@ -159552,7 +160129,14 @@ function buildBoundedContextReceipt(input) {
|
|
|
159552
160129
|
externalState: provider2?.external.state ?? "not-detected",
|
|
159553
160130
|
...input.workset.provenance.snapshotId ? { snapshotId: input.workset.provenance.snapshotId } : {}
|
|
159554
160131
|
},
|
|
159555
|
-
...input.workset.agentLoadout ? { loadout: input.workset.agentLoadout } : {}
|
|
160132
|
+
...input.workset.agentLoadout ? { loadout: input.workset.agentLoadout } : {},
|
|
160133
|
+
...input.workset.continuity ? {
|
|
160134
|
+
continuity: {
|
|
160135
|
+
taskId: input.workset.continuity.taskId,
|
|
160136
|
+
status: input.workset.continuity.status,
|
|
160137
|
+
outcome: input.workset.continuity.outcome
|
|
160138
|
+
}
|
|
160139
|
+
} : {}
|
|
159556
160140
|
};
|
|
159557
160141
|
}
|
|
159558
160142
|
var init_context_receipt = __esm({
|
|
@@ -160184,15 +160768,21 @@ var team_store_exports = {};
|
|
|
160184
160768
|
__export(team_store_exports, {
|
|
160185
160769
|
AGENT_TYPE_ROLE_MAP: () => AGENT_TYPE_ROLE_MAP,
|
|
160186
160770
|
DEFAULT_ROLES: () => DEFAULT_ROLES,
|
|
160771
|
+
DEFAULT_TEAM_QUERY_LIMIT: () => DEFAULT_TEAM_QUERY_LIMIT,
|
|
160772
|
+
MAX_TEAM_QUERY_LIMIT: () => MAX_TEAM_QUERY_LIMIT,
|
|
160187
160773
|
TeamStore: () => TeamStore,
|
|
160188
160774
|
getTeamStore: () => getTeamStore,
|
|
160189
160775
|
initTeamStore: () => initTeamStore,
|
|
160190
160776
|
isTeamStoreInitialized: () => isTeamStoreInitialized,
|
|
160191
160777
|
resetTeamStore: () => resetTeamStore
|
|
160192
160778
|
});
|
|
160193
|
-
import { randomUUID as
|
|
160779
|
+
import { randomUUID as randomUUID18 } from "crypto";
|
|
160194
160780
|
import path31 from "path";
|
|
160195
160781
|
import fs18 from "fs";
|
|
160782
|
+
function clampTeamQueryLimit(limit2) {
|
|
160783
|
+
if (!Number.isFinite(limit2) || limit2 == null) return DEFAULT_TEAM_QUERY_LIMIT;
|
|
160784
|
+
return Math.min(MAX_TEAM_QUERY_LIMIT, Math.max(1, Math.floor(limit2)));
|
|
160785
|
+
}
|
|
160196
160786
|
function getTeamStore() {
|
|
160197
160787
|
if (!_teamStore) {
|
|
160198
160788
|
throw new Error("[memorix] TeamStore not initialized \u2014 call initTeamStore() first");
|
|
@@ -160216,12 +160806,14 @@ function resetTeamStore() {
|
|
|
160216
160806
|
_teamStore = null;
|
|
160217
160807
|
_teamStoreDataDir = null;
|
|
160218
160808
|
}
|
|
160219
|
-
var DEFAULT_ROLES, AGENT_TYPE_ROLE_MAP, TeamStore, _teamStore, _teamStoreDataDir;
|
|
160809
|
+
var DEFAULT_TEAM_QUERY_LIMIT, MAX_TEAM_QUERY_LIMIT, DEFAULT_ROLES, AGENT_TYPE_ROLE_MAP, TeamStore, _teamStore, _teamStoreDataDir;
|
|
160220
160810
|
var init_team_store = __esm({
|
|
160221
160811
|
"src/team/team-store.ts"() {
|
|
160222
160812
|
"use strict";
|
|
160223
160813
|
init_esm_shims();
|
|
160224
160814
|
init_sqlite_db();
|
|
160815
|
+
DEFAULT_TEAM_QUERY_LIMIT = 100;
|
|
160816
|
+
MAX_TEAM_QUERY_LIMIT = 500;
|
|
160225
160817
|
DEFAULT_ROLES = [
|
|
160226
160818
|
{ roleId: "planner", label: "Planner", description: "Breaks down requirements, creates tasks, defines dependencies", preferredAgentTypes: ["claude-code", "cursor", "codex"], maxConcurrent: 2 },
|
|
160227
160819
|
{ roleId: "researcher", label: "Researcher", description: "Investigates codebase, gathers context, answers questions", preferredAgentTypes: ["claude-code", "cursor", "gemini-cli"], maxConcurrent: 2 },
|
|
@@ -160479,7 +161071,7 @@ var init_team_store = __esm({
|
|
|
160479
161071
|
* reactivate it (preserving agent_id). Otherwise create a new one.
|
|
160480
161072
|
*/
|
|
160481
161073
|
registerAgent(input) {
|
|
160482
|
-
const instanceId = input.instanceId ||
|
|
161074
|
+
const instanceId = input.instanceId || randomUUID18();
|
|
160483
161075
|
const now3 = Date.now();
|
|
160484
161076
|
const existing = this.stmtAgentFindByInstance.get(
|
|
160485
161077
|
input.projectId,
|
|
@@ -160505,7 +161097,7 @@ var init_team_store = __esm({
|
|
|
160505
161097
|
this.eventBus?.emit("agent:joined", { agentId: row2.agent_id, projectId: input.projectId, agentType: input.agentType });
|
|
160506
161098
|
return row2;
|
|
160507
161099
|
}
|
|
160508
|
-
const agentId =
|
|
161100
|
+
const agentId = randomUUID18();
|
|
160509
161101
|
this.stmtAgentUpsert.run({
|
|
160510
161102
|
agent_id: agentId,
|
|
160511
161103
|
project_id: input.projectId,
|
|
@@ -160531,32 +161123,37 @@ var init_team_store = __esm({
|
|
|
160531
161123
|
return this.stmtAgentFindByInstance.get(projectId, agentType, instanceId);
|
|
160532
161124
|
}
|
|
160533
161125
|
listAgents(projectId, filter) {
|
|
160534
|
-
const
|
|
161126
|
+
const limit2 = clampTeamQueryLimit(filter?.limit);
|
|
160535
161127
|
if (filter?.status) {
|
|
160536
|
-
return
|
|
161128
|
+
return this.db.prepare(
|
|
161129
|
+
`SELECT * FROM team_agents WHERE project_id = ? AND status = ? ORDER BY joined_at DESC LIMIT ?`
|
|
161130
|
+
).all(projectId, filter.status, limit2);
|
|
160537
161131
|
}
|
|
160538
|
-
return
|
|
161132
|
+
return this.db.prepare(
|
|
161133
|
+
`SELECT * FROM team_agents WHERE project_id = ? ORDER BY joined_at DESC LIMIT ?`
|
|
161134
|
+
).all(projectId, limit2);
|
|
160539
161135
|
}
|
|
160540
161136
|
/** List agents across all projects (for global scope) */
|
|
160541
|
-
listAllAgents() {
|
|
161137
|
+
listAllAgents(limit2) {
|
|
160542
161138
|
if (!this.db) return [];
|
|
160543
|
-
return this.db.prepare("SELECT * FROM team_agents ORDER BY last_heartbeat DESC").all();
|
|
161139
|
+
return this.db.prepare("SELECT * FROM team_agents ORDER BY last_heartbeat DESC LIMIT ?").all(clampTeamQueryLimit(limit2));
|
|
160544
161140
|
}
|
|
160545
161141
|
/** List locks across all projects (for global scope) */
|
|
160546
|
-
listAllLocks() {
|
|
161142
|
+
listAllLocks(limit2) {
|
|
160547
161143
|
if (!this.db) return [];
|
|
160548
161144
|
this.db.prepare("DELETE FROM team_locks WHERE expires_at <= ?").run(Date.now());
|
|
160549
|
-
return this.db.prepare("SELECT * FROM team_locks WHERE expires_at > ? ORDER BY locked_at DESC").all(Date.now());
|
|
161145
|
+
return this.db.prepare("SELECT * FROM team_locks WHERE expires_at > ? ORDER BY locked_at DESC LIMIT ?").all(Date.now(), clampTeamQueryLimit(limit2));
|
|
160550
161146
|
}
|
|
160551
161147
|
/** List tasks across all projects (for global scope) */
|
|
160552
161148
|
listAllTasks(filter) {
|
|
160553
161149
|
if (!this.db) return [];
|
|
161150
|
+
const limit2 = clampTeamQueryLimit(filter?.limit);
|
|
160554
161151
|
if (filter?.available) {
|
|
160555
161152
|
return this.db.prepare(
|
|
160556
|
-
`SELECT t.* FROM team_tasks t WHERE t.status = 'pending' AND t.assignee_agent_id IS NULL ORDER BY t.created_at DESC
|
|
160557
|
-
).all();
|
|
161153
|
+
`SELECT t.* FROM team_tasks t WHERE t.status = 'pending' AND t.assignee_agent_id IS NULL ORDER BY t.created_at DESC LIMIT ?`
|
|
161154
|
+
).all(limit2);
|
|
160558
161155
|
}
|
|
160559
|
-
return this.db.prepare("SELECT * FROM team_tasks ORDER BY created_at DESC").all();
|
|
161156
|
+
return this.db.prepare("SELECT * FROM team_tasks ORDER BY created_at DESC LIMIT ?").all(limit2);
|
|
160560
161157
|
}
|
|
160561
161158
|
heartbeat(agentId) {
|
|
160562
161159
|
const info = this.stmtAgentUpdateHeartbeat.run(Date.now(), agentId);
|
|
@@ -160591,7 +161188,10 @@ var init_team_store = __esm({
|
|
|
160591
161188
|
return staleIds;
|
|
160592
161189
|
}
|
|
160593
161190
|
getActiveCount(projectId) {
|
|
160594
|
-
|
|
161191
|
+
const row = this.db.prepare(
|
|
161192
|
+
`SELECT COUNT(*) AS count FROM team_agents WHERE project_id = ? AND status = 'active'`
|
|
161193
|
+
).get(projectId);
|
|
161194
|
+
return Number(row?.count ?? 0);
|
|
160595
161195
|
}
|
|
160596
161196
|
// ═══════════════════════════════════════════════════════════════════
|
|
160597
161197
|
// Message Operations
|
|
@@ -160607,7 +161207,7 @@ var init_team_store = __esm({
|
|
|
160607
161207
|
return { error: `Recipient agent '${input.recipientAgentId}' not found \u2014 cannot send to unknown agent` };
|
|
160608
161208
|
}
|
|
160609
161209
|
}
|
|
160610
|
-
const id =
|
|
161210
|
+
const id = randomUUID18();
|
|
160611
161211
|
const now3 = Date.now();
|
|
160612
161212
|
const row = {
|
|
160613
161213
|
id,
|
|
@@ -160626,8 +161226,14 @@ var init_team_store = __esm({
|
|
|
160626
161226
|
this.stmtMsgInsert.run(row);
|
|
160627
161227
|
return row;
|
|
160628
161228
|
}
|
|
160629
|
-
getInbox(projectId, agentId) {
|
|
160630
|
-
return this.
|
|
161229
|
+
getInbox(projectId, agentId, limit2) {
|
|
161230
|
+
return this.db.prepare(`
|
|
161231
|
+
SELECT * FROM team_messages
|
|
161232
|
+
WHERE project_id = ?
|
|
161233
|
+
AND (recipient_agent_id = ? OR recipient_agent_id IS NULL)
|
|
161234
|
+
ORDER BY created_at ASC
|
|
161235
|
+
LIMIT ?
|
|
161236
|
+
`).all(projectId, agentId, clampTeamQueryLimit(limit2));
|
|
160631
161237
|
}
|
|
160632
161238
|
getUnreadCount(projectId, agentId) {
|
|
160633
161239
|
const row = this.stmtMsgUnreadCount.get(projectId, agentId);
|
|
@@ -160657,7 +161263,7 @@ var init_team_store = __esm({
|
|
|
160657
161263
|
// Task Operations (with atomic claim semantics)
|
|
160658
161264
|
// ═══════════════════════════════════════════════════════════════════
|
|
160659
161265
|
createTask(input) {
|
|
160660
|
-
const taskId =
|
|
161266
|
+
const taskId = randomUUID18();
|
|
160661
161267
|
const now3 = Date.now();
|
|
160662
161268
|
const row = {
|
|
160663
161269
|
task_id: taskId,
|
|
@@ -160784,17 +161390,22 @@ var init_team_store = __esm({
|
|
|
160784
161390
|
return info.changes;
|
|
160785
161391
|
}
|
|
160786
161392
|
listTasks(projectId, filter) {
|
|
160787
|
-
|
|
160788
|
-
|
|
160789
|
-
|
|
160790
|
-
const all = this.stmtTaskListByProject.all(projectId);
|
|
161393
|
+
const clauses = ["project_id = ?"];
|
|
161394
|
+
const values = [projectId];
|
|
161395
|
+
if (filter?.available) clauses.push("status = 'pending'", "assignee_agent_id IS NULL");
|
|
160791
161396
|
if (filter?.status) {
|
|
160792
|
-
|
|
161397
|
+
clauses.push("status = ?");
|
|
161398
|
+
values.push(filter.status);
|
|
160793
161399
|
}
|
|
160794
161400
|
if (filter?.assignee) {
|
|
160795
|
-
|
|
161401
|
+
clauses.push("assignee_agent_id = ?");
|
|
161402
|
+
values.push(filter.assignee);
|
|
160796
161403
|
}
|
|
160797
|
-
|
|
161404
|
+
values.push(clampTeamQueryLimit(filter?.limit));
|
|
161405
|
+
const orderBy = filter?.available ? "created_at ASC, rowid ASC" : "created_at DESC, rowid DESC";
|
|
161406
|
+
return this.db.prepare(
|
|
161407
|
+
`SELECT * FROM team_tasks WHERE ${clauses.join(" AND ")} ORDER BY ${orderBy} LIMIT ?`
|
|
161408
|
+
).all(...values);
|
|
160798
161409
|
}
|
|
160799
161410
|
/**
|
|
160800
161411
|
* List available tasks for a specific agent, sorted by role affinity.
|
|
@@ -160806,7 +161417,7 @@ var init_team_store = __esm({
|
|
|
160806
161417
|
const agent = this.stmtAgentFindById.get(agentId);
|
|
160807
161418
|
if (!agent) return [];
|
|
160808
161419
|
const agentRole = agent.role;
|
|
160809
|
-
const available = this.
|
|
161420
|
+
const available = this.listTasks(projectId, { available: true, limit: MAX_TEAM_QUERY_LIMIT });
|
|
160810
161421
|
const eligible = available.filter((t2) => !t2.required_role || t2.required_role === agentRole);
|
|
160811
161422
|
const score = (t2) => {
|
|
160812
161423
|
if (t2.preferred_role === agentRole) return 0;
|
|
@@ -160860,12 +161471,16 @@ var init_team_store = __esm({
|
|
|
160860
161471
|
const row = this.stmtLockGet.get(file, projectId);
|
|
160861
161472
|
return row ?? null;
|
|
160862
161473
|
}
|
|
160863
|
-
listLocks(projectId, agentId) {
|
|
161474
|
+
listLocks(projectId, agentId, limit2) {
|
|
160864
161475
|
this.stmtLockDeleteExpired.run(projectId, Date.now());
|
|
160865
161476
|
if (agentId) {
|
|
160866
|
-
return this.
|
|
161477
|
+
return this.db.prepare(
|
|
161478
|
+
`SELECT * FROM team_locks WHERE project_id = ? AND locked_by = ? ORDER BY locked_at DESC LIMIT ?`
|
|
161479
|
+
).all(projectId, agentId, clampTeamQueryLimit(limit2));
|
|
160867
161480
|
}
|
|
160868
|
-
return this.
|
|
161481
|
+
return this.db.prepare(
|
|
161482
|
+
`SELECT * FROM team_locks WHERE project_id = ? ORDER BY locked_at DESC LIMIT ?`
|
|
161483
|
+
).all(projectId, clampTeamQueryLimit(limit2));
|
|
160869
161484
|
}
|
|
160870
161485
|
releaseAllLocks(agentId) {
|
|
160871
161486
|
const info = this.stmtLockDeleteByAgent.run(agentId);
|
|
@@ -160929,7 +161544,7 @@ var init_team_store = __esm({
|
|
|
160929
161544
|
for (const [agentId, msgs] of Object.entries(snap.messages.inboxes)) {
|
|
160930
161545
|
for (const msg of msgs) {
|
|
160931
161546
|
this.stmtMsgInsert.run({
|
|
160932
|
-
id: msg.id ??
|
|
161547
|
+
id: msg.id ?? randomUUID18(),
|
|
160933
161548
|
project_id: "migrated",
|
|
160934
161549
|
sender_agent_id: msg.from ?? "unknown",
|
|
160935
161550
|
recipient_agent_id: msg.to === "__broadcast__" ? null : msg.to ?? agentId,
|
|
@@ -163887,7 +164502,7 @@ __export(planner_exports, {
|
|
|
163887
164502
|
materializeTaskGraph: () => materializeTaskGraph,
|
|
163888
164503
|
seedAutonomousPipeline: () => seedAutonomousPipeline
|
|
163889
164504
|
});
|
|
163890
|
-
import { randomUUID as
|
|
164505
|
+
import { randomUUID as randomUUID19 } from "crypto";
|
|
163891
164506
|
function isPlannerTask(metadata) {
|
|
163892
164507
|
if (!metadata) return null;
|
|
163893
164508
|
try {
|
|
@@ -163945,7 +164560,7 @@ function seedAutonomousPipeline(teamStore, projectId, config, opts) {
|
|
|
163945
164560
|
const maxIterations = config.maxIterations ?? 3;
|
|
163946
164561
|
const taskBudget = config.taskBudget ?? 15;
|
|
163947
164562
|
const structuredPlan = opts?.structuredPlan ?? true;
|
|
163948
|
-
const pipelineId =
|
|
164563
|
+
const pipelineId = randomUUID19();
|
|
163949
164564
|
const meta = {
|
|
163950
164565
|
plannerType: "plan",
|
|
163951
164566
|
pipelineId,
|
|
@@ -164626,6 +165241,7 @@ var init_official_skills = __esm({
|
|
|
164626
165241
|
"| Need the sequence around one memory | `memorix_timeline` | `memorix memory timeline --id <id>` |",
|
|
164627
165242
|
"| Check source and freshness for a memory | `memorix_evidence` | `memorix evidence list|get|events` |",
|
|
164628
165243
|
"| Record whether a memory helped, conflicted, or was corrected | `memorix_feedback` | `memorix feedback record|show|audit` |",
|
|
165244
|
+
"| Track task requirements, decisions, verification, and outcome | `memorix_continuity` | `memorix continuity start|record|show|close` |",
|
|
164629
165245
|
"| Inspect or import controlled media | `memorix_media` | `memorix media import|attach|list|show|status` |",
|
|
164630
165246
|
'| Learned reusable project knowledge | `memorix_store` | `memorix memory store --type <type> --entity <name> --title "<title>" "<text>"` |',
|
|
164631
165247
|
"| Task or bug is complete/outdated | `memorix_resolve` | `memorix memory resolve --ids <ids>` |",
|
|
@@ -164649,6 +165265,7 @@ var init_official_skills = __esm({
|
|
|
164649
165265
|
"3. Use stale or unbound memory only as a warning or search lead.",
|
|
164650
165266
|
"4. Store durable decisions, fixes, and gotchas after the project state changes.",
|
|
164651
165267
|
"5. Resolve completed or obsolete memories so future briefs stay small.",
|
|
165268
|
+
"6. For multi-step work, start a continuity ledger and pass its taskId back to memorix_project_context.",
|
|
164652
165269
|
"",
|
|
164653
165270
|
"## Store Rules",
|
|
164654
165271
|
"",
|
|
@@ -166376,7 +166993,7 @@ init_freshness();
|
|
|
166376
166993
|
init_obs_store();
|
|
166377
166994
|
init_mini_skill_store();
|
|
166378
166995
|
init_session_store();
|
|
166379
|
-
import { createHash as
|
|
166996
|
+
import { createHash as createHash19 } from "crypto";
|
|
166380
166997
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
166381
166998
|
import { z as z627 } from "zod";
|
|
166382
166999
|
|
|
@@ -167768,9 +168385,9 @@ init_frontmatter();
|
|
|
167768
168385
|
|
|
167769
168386
|
// src/rules/utils.ts
|
|
167770
168387
|
init_esm_shims();
|
|
167771
|
-
import { createHash as
|
|
168388
|
+
import { createHash as createHash17 } from "crypto";
|
|
167772
168389
|
function hashContent2(content) {
|
|
167773
|
-
return
|
|
168390
|
+
return createHash17("sha256").update(content.trim()).digest("hex").substring(0, 16);
|
|
167774
168391
|
}
|
|
167775
168392
|
function generateRuleId(source, filePath) {
|
|
167776
168393
|
const sanitized = filePath.replace(/[\/\\]/g, "-").replace(/^\./, "");
|
|
@@ -169976,6 +170593,7 @@ var TOOL_PROFILES = Object.freeze({
|
|
|
169976
170593
|
// keep the default micro profile at its nine-tool token budget.
|
|
169977
170594
|
memorix_evidence: ["lite", "team", "full"],
|
|
169978
170595
|
memorix_feedback: ["lite", "team", "full"],
|
|
170596
|
+
memorix_continuity: ["lite", "team", "full"],
|
|
169979
170597
|
// ── lite: extended solo memory surface ────────────────────────────
|
|
169980
170598
|
memorix_graph_context: ["lite", "team", "full"],
|
|
169981
170599
|
memorix_timeline: ["lite", "team", "full"],
|
|
@@ -170198,7 +170816,7 @@ var MCP_SERVER_INFO_META_KEY = "io.modelcontextprotocol/serverInfo";
|
|
|
170198
170816
|
function getMcpServerInfo() {
|
|
170199
170817
|
return {
|
|
170200
170818
|
name: "memorix",
|
|
170201
|
-
version: true ? "1.9.
|
|
170819
|
+
version: true ? "1.9.7" : "1.0.1"
|
|
170202
170820
|
};
|
|
170203
170821
|
}
|
|
170204
170822
|
function createMcpDiscoverResult(capabilities, serverInfo) {
|
|
@@ -170333,7 +170951,7 @@ function coerceObjectArray(val) {
|
|
|
170333
170951
|
return [];
|
|
170334
170952
|
}
|
|
170335
170953
|
function createDeterministicInstanceId(projectId, agentType, agentName) {
|
|
170336
|
-
const digest2 =
|
|
170954
|
+
const digest2 = createHash19("sha256").update(projectId).update("\n").update(agentType).update("\n").update(agentName ?? "").digest("hex").slice(0, 24);
|
|
170337
170955
|
return `auto-${digest2}`;
|
|
170338
170956
|
}
|
|
170339
170957
|
var BOOTSTRAP_SAFE_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
@@ -170549,6 +171167,22 @@ async function createMemorixServer(cwd, existingServer, sharedTeam, options = {}
|
|
|
170549
171167
|
}
|
|
170550
171168
|
await projectRuntimeInitPromise;
|
|
170551
171169
|
};
|
|
171170
|
+
const activateProjectRuntime = async () => {
|
|
171171
|
+
if (!projectResolved) return;
|
|
171172
|
+
await initObservationStore(projectDir2);
|
|
171173
|
+
await initMiniSkillStore(projectDir2);
|
|
171174
|
+
await initSessionStore(projectDir2);
|
|
171175
|
+
await initObservations(projectDir2, { skipCorpusLoad: true });
|
|
171176
|
+
try {
|
|
171177
|
+
const { initProjectRoot: initProjectRoot2 } = await Promise.resolve().then(() => (init_yaml_loader(), yaml_loader_exports));
|
|
171178
|
+
const { resetDotenv: resetDotenv2, loadDotenv: loadDotenv2 } = await Promise.resolve().then(() => (init_dotenv_loader(), dotenv_loader_exports));
|
|
171179
|
+
initProjectRoot2(project.rootPath);
|
|
171180
|
+
resetDotenv2();
|
|
171181
|
+
loadDotenv2(project.rootPath);
|
|
171182
|
+
} catch {
|
|
171183
|
+
}
|
|
171184
|
+
initLLM({ projectRoot: project.rootPath });
|
|
171185
|
+
};
|
|
170552
171186
|
let maintenanceWorker = null;
|
|
170553
171187
|
const startProjectMaintenanceWorker = async (autoCleanup = false) => {
|
|
170554
171188
|
maintenanceWorker?.stop();
|
|
@@ -171464,6 +172098,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
|
|
|
171464
172098
|
description: "Build a compact Memory Autopilot brief for the current coding task. Schedules Code Memory refresh when needed, includes Start here files, reliable code-bound memories, stale/suspect cautions, and verification hints. Use this at the start of a new coding turn or after switching tasks.",
|
|
171465
172099
|
inputSchema: {
|
|
171466
172100
|
task: z627.string().optional().describe("Current coding task or question"),
|
|
172101
|
+
taskId: z627.string().max(120).optional().describe("Optional task continuity ledger id to include in the brief"),
|
|
171467
172102
|
refresh: z627.enum(["auto", "always", "never"]).optional().default("auto").describe(
|
|
171468
172103
|
"Code Memory refresh policy. auto refreshes only when missing or stale."
|
|
171469
172104
|
),
|
|
@@ -171488,7 +172123,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
|
|
|
171488
172123
|
limit: z627.number().optional().describe("Reserved for future source limits; current prompt stays compact by default.")
|
|
171489
172124
|
}
|
|
171490
172125
|
},
|
|
171491
|
-
async ({ task, refresh, format, agent }) => {
|
|
172126
|
+
async ({ task, taskId, refresh, format, agent }) => {
|
|
171492
172127
|
const unresolved = requireResolvedProject("build project context for the current project");
|
|
171493
172128
|
if (unresolved) return unresolved;
|
|
171494
172129
|
const [
|
|
@@ -171518,6 +172153,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
|
|
|
171518
172153
|
dataDir: projectDir2,
|
|
171519
172154
|
observations: observations2,
|
|
171520
172155
|
task,
|
|
172156
|
+
taskId,
|
|
171521
172157
|
agent,
|
|
171522
172158
|
refresh: refresh ?? "auto",
|
|
171523
172159
|
reader: getObservationReader(),
|
|
@@ -173943,6 +174579,94 @@ ${json2}
|
|
|
173943
174579
|
}
|
|
173944
174580
|
}
|
|
173945
174581
|
);
|
|
174582
|
+
server.registerTool(
|
|
174583
|
+
"memorix_continuity",
|
|
174584
|
+
{
|
|
174585
|
+
title: "Task Continuity Ledger",
|
|
174586
|
+
description: "Maintain a bounded, append-only continuity ledger for a coding task. Use start for requirements, record for decisions/verification/risks, show or list to inspect, and close for the final outcome. Pass the returned taskId to memorix_project_context so the current brief includes this ledger.",
|
|
174587
|
+
inputSchema: {
|
|
174588
|
+
action: z627.enum(["start", "record", "show", "list", "close"]).describe("Continuity operation"),
|
|
174589
|
+
taskId: z627.string().max(120).optional().describe("Continuity task id"),
|
|
174590
|
+
task: z627.string().max(1e3).optional().describe("Task description for start"),
|
|
174591
|
+
requirements: z627.array(z627.string().max(2e3)).max(8).optional().describe("Requirements for start"),
|
|
174592
|
+
kind: z627.enum(["requirement", "decision", "verification", "risk"]).optional().describe("Entry kind for record"),
|
|
174593
|
+
content: z627.string().max(2e3).optional().describe("Requirement, decision, verification, risk, or outcome text"),
|
|
174594
|
+
verificationStatus: z627.enum(["pending", "passed", "failed", "skipped"]).optional(),
|
|
174595
|
+
verificationId: z627.string().max(120).optional().describe("Stable verification obligation id; reuse it to move pending to passed/failed"),
|
|
174596
|
+
idempotencyKey: z627.string().max(200).optional().describe("Stable retry key; repeating the same operation returns the original event"),
|
|
174597
|
+
status: z627.enum(["completed", "blocked", "abandoned"]).optional().describe("Outcome status for close"),
|
|
174598
|
+
sourceRef: z627.string().max(500).optional().describe("Evidence or source reference"),
|
|
174599
|
+
evidenceRefs: z627.array(z627.string().max(500)).max(8).optional(),
|
|
174600
|
+
actor: z627.string().max(200).optional(),
|
|
174601
|
+
limit: z627.number().int().positive().max(100).optional().default(20)
|
|
174602
|
+
}
|
|
174603
|
+
},
|
|
174604
|
+
async ({ action, taskId, task, requirements, kind, content, verificationStatus, verificationId, idempotencyKey, status, sourceRef, evidenceRefs: evidenceRefs2, actor, limit: limit2 }) => {
|
|
174605
|
+
const unresolved = requireResolvedProject("manage task continuity for the current project");
|
|
174606
|
+
if (unresolved) return unresolved;
|
|
174607
|
+
const { TaskContinuityStore: TaskContinuityStore2 } = await Promise.resolve().then(() => (init_task_continuity(), task_continuity_exports));
|
|
174608
|
+
const continuity = new TaskContinuityStore2();
|
|
174609
|
+
await continuity.init(projectDir2);
|
|
174610
|
+
const effectiveActor = actor ?? currentAgentId;
|
|
174611
|
+
try {
|
|
174612
|
+
if (action === "start") {
|
|
174613
|
+
if (!task?.trim()) return { content: [{ type: "text", text: "task is required for continuity start." }], isError: true };
|
|
174614
|
+
const result2 = continuity.start({
|
|
174615
|
+
projectId: project.id,
|
|
174616
|
+
task,
|
|
174617
|
+
...taskId ? { taskId } : {},
|
|
174618
|
+
requirements,
|
|
174619
|
+
...effectiveActor ? { actor: effectiveActor } : {},
|
|
174620
|
+
...idempotencyKey ? { idempotencyKey } : {}
|
|
174621
|
+
});
|
|
174622
|
+
return { content: [{ type: "text", text: JSON.stringify({ projectId: project.id, ...result2 }, null, 2) }] };
|
|
174623
|
+
}
|
|
174624
|
+
if (action === "list") {
|
|
174625
|
+
return { content: [{ type: "text", text: JSON.stringify({ projectId: project.id, ledgers: continuity.list(project.id, limit2) }, null, 2) }] };
|
|
174626
|
+
}
|
|
174627
|
+
if (!taskId?.trim()) return { content: [{ type: "text", text: "taskId is required for this continuity action." }], isError: true };
|
|
174628
|
+
if (action === "show") {
|
|
174629
|
+
const ledger = continuity.get(project.id, taskId);
|
|
174630
|
+
if (!ledger) return { content: [{ type: "text", text: "Task continuity ledger not found." }], isError: true };
|
|
174631
|
+
return { content: [{ type: "text", text: JSON.stringify({ projectId: project.id, ledger }, null, 2) }] };
|
|
174632
|
+
}
|
|
174633
|
+
if (action === "record") {
|
|
174634
|
+
if (!kind || !content?.trim()) {
|
|
174635
|
+
return { content: [{ type: "text", text: "record requires kind and content." }], isError: true };
|
|
174636
|
+
}
|
|
174637
|
+
const result2 = continuity.record({
|
|
174638
|
+
projectId: project.id,
|
|
174639
|
+
taskId,
|
|
174640
|
+
kind,
|
|
174641
|
+
content,
|
|
174642
|
+
...verificationStatus ? { verificationStatus } : {},
|
|
174643
|
+
...sourceRef ? { sourceRef } : {},
|
|
174644
|
+
...evidenceRefs2 ? { evidenceRefs: evidenceRefs2 } : {},
|
|
174645
|
+
...effectiveActor ? { actor: effectiveActor } : {},
|
|
174646
|
+
...verificationId ? { verificationId } : {},
|
|
174647
|
+
...idempotencyKey ? { idempotencyKey } : {}
|
|
174648
|
+
});
|
|
174649
|
+
return { content: [{ type: "text", text: JSON.stringify({ projectId: project.id, ...result2 }, null, 2) }] };
|
|
174650
|
+
}
|
|
174651
|
+
if (!status || !content?.trim()) {
|
|
174652
|
+
return { content: [{ type: "text", text: "close requires status and content." }], isError: true };
|
|
174653
|
+
}
|
|
174654
|
+
const result = continuity.close({
|
|
174655
|
+
projectId: project.id,
|
|
174656
|
+
taskId,
|
|
174657
|
+
status,
|
|
174658
|
+
content,
|
|
174659
|
+
...sourceRef ? { sourceRef } : {},
|
|
174660
|
+
...evidenceRefs2 ? { evidenceRefs: evidenceRefs2 } : {},
|
|
174661
|
+
...effectiveActor ? { actor: effectiveActor } : {},
|
|
174662
|
+
...idempotencyKey ? { idempotencyKey } : {}
|
|
174663
|
+
});
|
|
174664
|
+
return { content: [{ type: "text", text: JSON.stringify({ projectId: project.id, ...result }, null, 2) }] };
|
|
174665
|
+
} catch (error) {
|
|
174666
|
+
return { content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }], isError: true };
|
|
174667
|
+
}
|
|
174668
|
+
}
|
|
174669
|
+
);
|
|
173946
174670
|
if (teamFeaturesEnabled) {
|
|
173947
174671
|
const { initTeamStore: initTeamStore2 } = await Promise.resolve().then(() => (init_team_store(), team_store_exports));
|
|
173948
174672
|
initTeamStoreForProject = initTeamStore2;
|
|
@@ -174970,7 +175694,9 @@ fi
|
|
|
174970
175694
|
graphManager,
|
|
174971
175695
|
projectId: project.id,
|
|
174972
175696
|
deferredInit,
|
|
175697
|
+
activateProjectRuntime,
|
|
174973
175698
|
switchProject,
|
|
175699
|
+
getProjectDataDir: () => projectDir2,
|
|
174974
175700
|
isExplicitlyBound: () => projectBinding.isExplicit(),
|
|
174975
175701
|
getRequestContext,
|
|
174976
175702
|
handleTransportClose
|