memorix 1.8.9 → 1.9.0
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 +18 -0
- package/README.md +7 -0
- package/README.zh-CN.md +6 -0
- package/dist/cli/index.js +3261 -1348
- package/dist/index.js +324 -187
- package/dist/maintenance-runner.js +285 -103
- package/dist/media-audio-runner.js +285 -103
- package/dist/media-video-runner.js +285 -103
- package/dist/memcode-runtime/CHANGELOG.md +18 -0
- package/dist/sdk.js +323 -186
- package/dist/vector-backfill-runner.d.ts +4 -1
- package/dist/vector-backfill-runner.js +288 -104
- package/docs/API_REFERENCE.md +14 -0
- package/docs/CONFIGURATION.md +46 -0
- package/docs/DEVELOPMENT.md +2 -2
- package/docs/MULTI-DEVICE-SYNC-RESEARCH.md +344 -0
- package/docs/PERFORMANCE.md +32 -0
- package/docs/README.md +4 -2
- package/llms-full.txt +1 -0
- package/llms.txt +1 -0
- package/package.json +1 -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/command-guide.ts +9 -1
- package/src/cli/commands/serve-http.ts +11 -0
- package/src/cli/commands/sync-store.ts +191 -0
- package/src/cli/commands/sync.ts +8 -0
- package/src/memory/observations.ts +15 -2
- package/src/runtime/maintenance-targets.ts +6 -0
- package/src/runtime/vector-backfill-runner.ts +185 -7
- package/src/store/orama-store.ts +85 -102
- package/src/sync/adapters/fs.ts +179 -0
- package/src/sync/adapters/github.ts +258 -0
- package/src/sync/adapters/object-store.ts +267 -0
- package/src/sync/adapters/postgres.ts +269 -0
- package/src/sync/engine.ts +353 -0
- package/src/sync/journal.ts +162 -0
- package/src/sync/merge.ts +116 -0
- package/src/sync/namespace.ts +15 -0
- package/src/sync/paging.ts +45 -0
- package/src/sync/policy.ts +37 -0
- package/src/sync/remote-factory.ts +49 -0
- package/src/sync/store-port.ts +288 -0
- package/src/sync/types.ts +183 -0
|
@@ -10,11 +10,14 @@ interface VectorBackfillLauncherOptions {
|
|
|
10
10
|
runnerPath?: string;
|
|
11
11
|
exists?: (path: string) => boolean;
|
|
12
12
|
spawn?: typeof spawn;
|
|
13
|
+
lockPath?: string;
|
|
13
14
|
}
|
|
14
15
|
/** Resolve the standalone worker next to either the library or CLI bundle. */
|
|
15
16
|
declare function resolveVectorBackfillRunnerPath(moduleUrl?: string): string;
|
|
16
17
|
/** Parse the internal request passed from a short-lived CLI process. */
|
|
17
18
|
declare function parseVectorBackfillRequest(raw: string): VectorBackfillRequest;
|
|
19
|
+
declare function vectorBackfillLockPath(dataDir: string): string;
|
|
20
|
+
declare function releaseVectorBackfillLock(lockPath?: string | undefined): void;
|
|
18
21
|
/**
|
|
19
22
|
* Start a detached one-shot worker. The caller has already persisted the
|
|
20
23
|
* observation and durable vector job, so failure to start is recoverable by a
|
|
@@ -28,4 +31,4 @@ declare function executeVectorBackfill(request: VectorBackfillRequest): Promise<
|
|
|
28
31
|
}>;
|
|
29
32
|
declare function main(): Promise<void>;
|
|
30
33
|
|
|
31
|
-
export { type VectorBackfillLauncherOptions, type VectorBackfillRequest, executeVectorBackfill, launchDetachedVectorBackfill, main, parseVectorBackfillRequest, resolveVectorBackfillRunnerPath };
|
|
34
|
+
export { type VectorBackfillLauncherOptions, type VectorBackfillRequest, executeVectorBackfill, launchDetachedVectorBackfill, main, parseVectorBackfillRequest, releaseVectorBackfillLock, resolveVectorBackfillRunnerPath, vectorBackfillLockPath };
|
|
@@ -5993,6 +5993,14 @@ __export(orama_store_exports, {
|
|
|
5993
5993
|
updateObservationMetadata: () => updateObservationMetadata
|
|
5994
5994
|
});
|
|
5995
5995
|
import { create, insert as insert2, insertMultiple, search, remove as remove2, update, count, getByID } from "@orama/orama";
|
|
5996
|
+
function rememberSearchMode(key, value) {
|
|
5997
|
+
if (!lastSearchModeByProject.has(key) && lastSearchModeByProject.size >= MAX_SEARCH_MODE_KEYS) {
|
|
5998
|
+
const oldest = lastSearchModeByProject.keys().next().value;
|
|
5999
|
+
if (oldest !== void 0) lastSearchModeByProject.delete(oldest);
|
|
6000
|
+
}
|
|
6001
|
+
lastSearchModeByProject.delete(key);
|
|
6002
|
+
lastSearchModeByProject.set(key, value);
|
|
6003
|
+
}
|
|
5996
6004
|
function getLastSearchMode(projectId) {
|
|
5997
6005
|
return lastSearchModeByProject.get(projectId ?? SEARCH_MODE_DEFAULT_KEY) ?? "fulltext";
|
|
5998
6006
|
}
|
|
@@ -6005,9 +6013,6 @@ function makeEntryKey(projectId, observationId2) {
|
|
|
6005
6013
|
function rememberObservationDoc(doc) {
|
|
6006
6014
|
const publicDoc = { ...doc };
|
|
6007
6015
|
delete publicDoc.embedding;
|
|
6008
|
-
if (doc.projectId && typeof doc.observationId === "number") {
|
|
6009
|
-
docByObservationKey.set(makeEntryKey(doc.projectId, doc.observationId), publicDoc);
|
|
6010
|
-
}
|
|
6011
6016
|
return publicDoc;
|
|
6012
6017
|
}
|
|
6013
6018
|
function isCommandLikeQuery(query) {
|
|
@@ -6111,7 +6116,6 @@ async function resetDb() {
|
|
|
6111
6116
|
indexEmbeddingProvider = null;
|
|
6112
6117
|
deferredCachedVectorHydration = null;
|
|
6113
6118
|
lastSearchModeByProject.clear();
|
|
6114
|
-
docByObservationKey.clear();
|
|
6115
6119
|
}
|
|
6116
6120
|
function isEmbeddingEnabled() {
|
|
6117
6121
|
return embeddingEnabled;
|
|
@@ -6174,78 +6178,72 @@ function isCompatibleCachedVector(vector) {
|
|
|
6174
6178
|
vector && embeddingDimensions !== null && vector.length === embeddingDimensions && vector.every(Number.isFinite)
|
|
6175
6179
|
);
|
|
6176
6180
|
}
|
|
6177
|
-
async function attachCachedVectors(database,
|
|
6178
|
-
const
|
|
6179
|
-
|
|
6180
|
-
|
|
6181
|
-
|
|
6182
|
-
|
|
6183
|
-
|
|
6184
|
-
|
|
6185
|
-
|
|
6186
|
-
|
|
6187
|
-
|
|
6188
|
-
|
|
6189
|
-
|
|
6190
|
-
|
|
6191
|
-
|
|
6192
|
-
|
|
6181
|
+
async function attachCachedVectors(database, observations2) {
|
|
6182
|
+
const batchSize = 200;
|
|
6183
|
+
for (let start = 0; start < observations2.length; start += batchSize) {
|
|
6184
|
+
const batch = observations2.slice(start, start + batchSize);
|
|
6185
|
+
const cachedVectors = await getCachedEmbeddings(batch.map(observationEmbeddingText));
|
|
6186
|
+
if (db !== database) return;
|
|
6187
|
+
for (let index = 0; index < batch.length; index++) {
|
|
6188
|
+
const vector = cachedVectors[index];
|
|
6189
|
+
if (!isCompatibleCachedVector(vector)) continue;
|
|
6190
|
+
const id = makeOramaObservationId(batch[index].projectId, batch[index].id);
|
|
6191
|
+
const existing = getByID(database, id);
|
|
6192
|
+
if (!existing || documentEmbeddingText(existing) !== observationEmbeddingText(batch[index])) continue;
|
|
6193
|
+
try {
|
|
6194
|
+
await update(database, id, { ...existing, embedding: vector });
|
|
6195
|
+
} catch {
|
|
6196
|
+
}
|
|
6193
6197
|
}
|
|
6198
|
+
await new Promise((resolve2) => setImmediate(resolve2));
|
|
6194
6199
|
}
|
|
6195
6200
|
}
|
|
6196
6201
|
async function hydrateIndex(observations2, options = {}) {
|
|
6197
6202
|
const database = await getDb({ allowNetworkProbe: options.allowNetworkProbe });
|
|
6198
|
-
const candidates = [];
|
|
6199
|
-
for (const observation of observations2) {
|
|
6200
|
-
if (!observation || !observation.id || !observation.projectId) continue;
|
|
6201
|
-
const id = makeOramaObservationId(observation.projectId, observation.id);
|
|
6202
|
-
if (getByID(database, id)) continue;
|
|
6203
|
-
candidates.push({ observation, id });
|
|
6204
|
-
}
|
|
6205
6203
|
const deferCachedVectors = options.deferCachedVectors === true && Boolean(indexEmbeddingProvider?.getCachedEmbeddings);
|
|
6206
|
-
const cachedVectors = deferCachedVectors ? candidates.map(() => null) : await getCachedEmbeddings(candidates.map(({ observation }) => observationEmbeddingText(observation)));
|
|
6207
|
-
const documents = [];
|
|
6208
|
-
for (let index = 0; index < candidates.length; index++) {
|
|
6209
|
-
const { observation: obs, id } = candidates[index];
|
|
6210
|
-
try {
|
|
6211
|
-
const vector = cachedVectors[index];
|
|
6212
|
-
const compatibleVector = isCompatibleCachedVector(vector) ? vector : null;
|
|
6213
|
-
const doc = {
|
|
6214
|
-
id,
|
|
6215
|
-
observationId: obs.id,
|
|
6216
|
-
entityName: obs.entityName || "",
|
|
6217
|
-
type: obs.type || "discovery",
|
|
6218
|
-
title: obs.title || "",
|
|
6219
|
-
narrative: obs.narrative || "",
|
|
6220
|
-
facts: Array.isArray(obs.facts) ? obs.facts.join(" ") : "",
|
|
6221
|
-
filesModified: Array.isArray(obs.filesModified) ? obs.filesModified.join(" ") : "",
|
|
6222
|
-
concepts: Array.isArray(obs.concepts) ? obs.concepts.join(" ") : "",
|
|
6223
|
-
tokens: obs.tokens ?? 0,
|
|
6224
|
-
createdAt: obs.createdAt || "",
|
|
6225
|
-
projectId: obs.projectId,
|
|
6226
|
-
accessCount: obs.accessCount ?? 0,
|
|
6227
|
-
lastAccessedAt: obs.lastAccessedAt || "",
|
|
6228
|
-
status: obs.status ?? "active",
|
|
6229
|
-
source: obs.source || "agent",
|
|
6230
|
-
sourceDetail: obs.sourceDetail ?? "",
|
|
6231
|
-
valueCategory: obs.valueCategory ?? "",
|
|
6232
|
-
admissionState: obs.admissionState ?? "",
|
|
6233
|
-
admissionReason: obs.admissionReason ?? "",
|
|
6234
|
-
visibility: obs.visibility ?? "project",
|
|
6235
|
-
createdByAgentId: obs.createdByAgentId ?? "",
|
|
6236
|
-
sharedWithAgentIds: JSON.stringify(obs.sharedWithAgentIds ?? []),
|
|
6237
|
-
documentType: "observation",
|
|
6238
|
-
knowledgeLayer: resolveKnowledgeLayer("observation", obs.sourceDetail, obs.source),
|
|
6239
|
-
...compatibleVector ? { embedding: compatibleVector } : {}
|
|
6240
|
-
};
|
|
6241
|
-
documents.push(doc);
|
|
6242
|
-
} catch {
|
|
6243
|
-
}
|
|
6244
|
-
}
|
|
6245
6204
|
let inserted = 0;
|
|
6246
6205
|
const hydrationBatchSize = 200;
|
|
6247
|
-
for (let start = 0; start <
|
|
6248
|
-
const
|
|
6206
|
+
for (let start = 0; start < observations2.length; start += hydrationBatchSize) {
|
|
6207
|
+
const batchObservations = observations2.slice(start, start + hydrationBatchSize).filter((observation) => observation && observation.id && observation.projectId).filter((observation) => !getByID(database, makeOramaObservationId(observation.projectId, observation.id)));
|
|
6208
|
+
if (batchObservations.length === 0) continue;
|
|
6209
|
+
const cachedVectors = deferCachedVectors || options.skipCachedVectors ? batchObservations.map(() => null) : await getCachedEmbeddings(batchObservations.map(observationEmbeddingText));
|
|
6210
|
+
const batch = [];
|
|
6211
|
+
for (let index = 0; index < batchObservations.length; index++) {
|
|
6212
|
+
const obs = batchObservations[index];
|
|
6213
|
+
try {
|
|
6214
|
+
const compatibleVector = isCompatibleCachedVector(cachedVectors[index]) ? cachedVectors[index] : null;
|
|
6215
|
+
batch.push({
|
|
6216
|
+
id: makeOramaObservationId(obs.projectId, obs.id),
|
|
6217
|
+
observationId: obs.id,
|
|
6218
|
+
entityName: obs.entityName || "",
|
|
6219
|
+
type: obs.type || "discovery",
|
|
6220
|
+
title: obs.title || "",
|
|
6221
|
+
narrative: obs.narrative || "",
|
|
6222
|
+
facts: Array.isArray(obs.facts) ? obs.facts.join(" ") : "",
|
|
6223
|
+
filesModified: Array.isArray(obs.filesModified) ? obs.filesModified.join(" ") : "",
|
|
6224
|
+
concepts: Array.isArray(obs.concepts) ? obs.concepts.join(" ") : "",
|
|
6225
|
+
tokens: obs.tokens ?? 0,
|
|
6226
|
+
createdAt: obs.createdAt || "",
|
|
6227
|
+
projectId: obs.projectId,
|
|
6228
|
+
accessCount: obs.accessCount ?? 0,
|
|
6229
|
+
lastAccessedAt: obs.lastAccessedAt || "",
|
|
6230
|
+
status: obs.status ?? "active",
|
|
6231
|
+
source: obs.source || "agent",
|
|
6232
|
+
sourceDetail: obs.sourceDetail ?? "",
|
|
6233
|
+
valueCategory: obs.valueCategory ?? "",
|
|
6234
|
+
admissionState: obs.admissionState ?? "",
|
|
6235
|
+
admissionReason: obs.admissionReason ?? "",
|
|
6236
|
+
visibility: obs.visibility ?? "project",
|
|
6237
|
+
createdByAgentId: obs.createdByAgentId ?? "",
|
|
6238
|
+
sharedWithAgentIds: JSON.stringify(obs.sharedWithAgentIds ?? []),
|
|
6239
|
+
documentType: "observation",
|
|
6240
|
+
knowledgeLayer: resolveKnowledgeLayer("observation", obs.sourceDetail, obs.source),
|
|
6241
|
+
...compatibleVector ? { embedding: compatibleVector } : {}
|
|
6242
|
+
});
|
|
6243
|
+
} catch {
|
|
6244
|
+
}
|
|
6245
|
+
}
|
|
6246
|
+
if (batch.length === 0) continue;
|
|
6249
6247
|
try {
|
|
6250
6248
|
await insertMultiple(database, batch, batch.length);
|
|
6251
6249
|
for (const doc of batch) rememberObservationDoc(doc);
|
|
@@ -6267,7 +6265,7 @@ async function hydrateIndex(observations2, options = {}) {
|
|
|
6267
6265
|
}
|
|
6268
6266
|
await new Promise((resolve2) => setImmediate(resolve2));
|
|
6269
6267
|
}
|
|
6270
|
-
deferredCachedVectorHydration = options.skipCachedVectors ? null : deferCachedVectors ? attachCachedVectors(database,
|
|
6268
|
+
deferredCachedVectorHydration = options.skipCachedVectors ? null : deferCachedVectors ? attachCachedVectors(database, observations2).catch(() => {
|
|
6271
6269
|
}) : null;
|
|
6272
6270
|
return inserted;
|
|
6273
6271
|
}
|
|
@@ -6304,12 +6302,6 @@ async function updateObservationMetadata(projectId, observationId2, patch) {
|
|
|
6304
6302
|
async function removeObservation(oramaId) {
|
|
6305
6303
|
const database = await getDb();
|
|
6306
6304
|
await remove2(database, oramaId);
|
|
6307
|
-
for (const [key, doc] of docByObservationKey.entries()) {
|
|
6308
|
-
if (doc.id === oramaId) {
|
|
6309
|
-
docByObservationKey.delete(key);
|
|
6310
|
-
break;
|
|
6311
|
-
}
|
|
6312
|
-
}
|
|
6313
6305
|
}
|
|
6314
6306
|
async function searchObservations(options) {
|
|
6315
6307
|
const perf = !!process.env.MEMORIX_PERF;
|
|
@@ -6324,7 +6316,7 @@ async function searchObservations(options) {
|
|
|
6324
6316
|
const modeKey = options.projectId ?? SEARCH_MODE_DEFAULT_KEY;
|
|
6325
6317
|
const quality = options.quality ?? "balanced";
|
|
6326
6318
|
const database = await getDb();
|
|
6327
|
-
|
|
6319
|
+
rememberSearchMode(
|
|
6328
6320
|
modeKey,
|
|
6329
6321
|
quality === "fast" ? "fulltext (fast profile)" : embeddingEnabled ? "hybrid" : "fulltext"
|
|
6330
6322
|
);
|
|
@@ -6391,7 +6383,7 @@ async function searchObservations(options) {
|
|
|
6391
6383
|
if (provider2) {
|
|
6392
6384
|
const activeVectorDimensions = getVectorDimensions();
|
|
6393
6385
|
if (activeVectorDimensions !== null && provider2.dimensions !== activeVectorDimensions) {
|
|
6394
|
-
|
|
6386
|
+
rememberSearchMode(
|
|
6395
6387
|
modeKey,
|
|
6396
6388
|
`fulltext (embedding dimension mismatch: provider ${provider2.dimensions}d vs index ${activeVectorDimensions}d)`
|
|
6397
6389
|
);
|
|
@@ -6416,7 +6408,7 @@ async function searchObservations(options) {
|
|
|
6416
6408
|
mark("embedding");
|
|
6417
6409
|
const cjkRatio = (originalQuery.match(/[\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af]/g) || []).length / originalQuery.length;
|
|
6418
6410
|
const isCJKHeavy = cjkRatio > 0.3;
|
|
6419
|
-
|
|
6411
|
+
rememberSearchMode(modeKey, "hybrid");
|
|
6420
6412
|
searchParams = {
|
|
6421
6413
|
...searchParams,
|
|
6422
6414
|
mode: "hybrid",
|
|
@@ -6432,7 +6424,7 @@ async function searchObservations(options) {
|
|
|
6432
6424
|
}
|
|
6433
6425
|
}
|
|
6434
6426
|
} catch (error) {
|
|
6435
|
-
|
|
6427
|
+
rememberSearchMode(modeKey, "fulltext (embedding unavailable)");
|
|
6436
6428
|
console.error("[memorix] Embedding failed or timed out, falling back to fulltext search");
|
|
6437
6429
|
}
|
|
6438
6430
|
}
|
|
@@ -6442,7 +6434,7 @@ async function searchObservations(options) {
|
|
|
6442
6434
|
results = await search(database, searchParams);
|
|
6443
6435
|
} catch (error) {
|
|
6444
6436
|
if (queryVector && isVectorDimensionMismatchError(error)) {
|
|
6445
|
-
|
|
6437
|
+
rememberSearchMode(modeKey, "fulltext (embedding dimension mismatch)");
|
|
6446
6438
|
console.error("[memorix] Vector search dimension mismatch detected, retrying without embeddings");
|
|
6447
6439
|
results = await search(database, stripVectorSearchParams(searchParams));
|
|
6448
6440
|
} else {
|
|
@@ -6464,7 +6456,7 @@ async function searchObservations(options) {
|
|
|
6464
6456
|
},
|
|
6465
6457
|
similarity: 0.25
|
|
6466
6458
|
};
|
|
6467
|
-
|
|
6459
|
+
rememberSearchMode(modeKey, "vector-only (hybrid empty fallback)");
|
|
6468
6460
|
results = await search(database, vectorOnlyParams);
|
|
6469
6461
|
} catch {
|
|
6470
6462
|
}
|
|
@@ -6705,7 +6697,7 @@ async function searchObservations(options) {
|
|
|
6705
6697
|
const rerankedTop = neural.map((row) => candidateMap.get(row.id)).filter((entry) => entry != null);
|
|
6706
6698
|
if (rerankedTop.length > 0) {
|
|
6707
6699
|
intermediate = [...rerankedTop, ...intermediate.slice(RERANK_TOP_K)];
|
|
6708
|
-
|
|
6700
|
+
rememberSearchMode(modeKey, (lastSearchModeByProject.get(modeKey) ?? "fulltext") + " + neural rerank");
|
|
6709
6701
|
mark("rerank(usedNeural=true)");
|
|
6710
6702
|
}
|
|
6711
6703
|
}
|
|
@@ -6722,7 +6714,7 @@ async function searchObservations(options) {
|
|
|
6722
6714
|
);
|
|
6723
6715
|
mark(`rerank(usedLLM=${usedLLM})`);
|
|
6724
6716
|
if (usedLLM) {
|
|
6725
|
-
|
|
6717
|
+
rememberSearchMode(modeKey, (lastSearchModeByProject.get(modeKey) ?? "fulltext") + " + LLM rerank");
|
|
6726
6718
|
const rerankedTop = reranked.map((row) => candidateMap.get(row.id)).filter((entry) => entry != null);
|
|
6727
6719
|
if (rerankedTop.length > 0) {
|
|
6728
6720
|
intermediate = [...rerankedTop, ...intermediate.slice(RERANK_TOP_K)];
|
|
@@ -6795,13 +6787,6 @@ async function getObservationsByIds(ids, projectId) {
|
|
|
6795
6787
|
const database = await getDb();
|
|
6796
6788
|
const results = [];
|
|
6797
6789
|
for (const id of ids) {
|
|
6798
|
-
if (projectId) {
|
|
6799
|
-
const cached = docByObservationKey.get(makeEntryKey(projectId, id));
|
|
6800
|
-
if (cached) {
|
|
6801
|
-
results.push(cached);
|
|
6802
|
-
continue;
|
|
6803
|
-
}
|
|
6804
|
-
}
|
|
6805
6790
|
const searchResult = await search(database, {
|
|
6806
6791
|
term: "",
|
|
6807
6792
|
includeVectors: true,
|
|
@@ -6901,7 +6886,7 @@ function formatTime(isoDate) {
|
|
|
6901
6886
|
return isoDate;
|
|
6902
6887
|
}
|
|
6903
6888
|
}
|
|
6904
|
-
var db, dbInitPromise, dbGeneration, embeddingEnabled, embeddingDimensions, indexEmbeddingProvider, deferredCachedVectorHydration,
|
|
6889
|
+
var db, dbInitPromise, dbGeneration, embeddingEnabled, embeddingDimensions, indexEmbeddingProvider, deferredCachedVectorHydration, NON_CJK_HYBRID_SIMILARITY, lastSearchModeByProject, SEARCH_MODE_DEFAULT_KEY, MAX_SEARCH_MODE_KEYS, COMMAND_LOG_TITLE, COMMAND_STYLE_TITLE, COMMAND_LIKE_QUERY2, COMMAND_INTENT_QUERY, NATURAL_LANGUAGE_MARKERS;
|
|
6905
6890
|
var init_orama_store = __esm({
|
|
6906
6891
|
"src/store/orama-store.ts"() {
|
|
6907
6892
|
"use strict";
|
|
@@ -6922,10 +6907,10 @@ var init_orama_store = __esm({
|
|
|
6922
6907
|
embeddingDimensions = null;
|
|
6923
6908
|
indexEmbeddingProvider = null;
|
|
6924
6909
|
deferredCachedVectorHydration = null;
|
|
6925
|
-
docByObservationKey = /* @__PURE__ */ new Map();
|
|
6926
6910
|
NON_CJK_HYBRID_SIMILARITY = 0.45;
|
|
6927
6911
|
lastSearchModeByProject = /* @__PURE__ */ new Map();
|
|
6928
6912
|
SEARCH_MODE_DEFAULT_KEY = "__global__";
|
|
6913
|
+
MAX_SEARCH_MODE_KEYS = 4096;
|
|
6929
6914
|
COMMAND_LOG_TITLE = /^(Ran:|Command:|Executed:)\s/i;
|
|
6930
6915
|
COMMAND_STYLE_TITLE = /(\bfindstr\b|\bSelect-String\b|\bGet-Content\b|\bnpx\s+vitest\b|\bnpx\s+tsc\b|\b2>&1\b)/i;
|
|
6931
6916
|
COMMAND_LIKE_QUERY2 = /\b(git|npm|npx|pnpm|yarn|node|bash|powershell|curl|memorix)\b/i;
|
|
@@ -9563,11 +9548,17 @@ function resetObservationRuntime() {
|
|
|
9563
9548
|
embeddingWorkerProjectRoot = void 0;
|
|
9564
9549
|
vectorMissingIds.clear();
|
|
9565
9550
|
vectorSchemaUpgradePromise = null;
|
|
9551
|
+
embeddingFailureLogTimestamps.clear();
|
|
9566
9552
|
}
|
|
9567
9553
|
function logEmbeddingFailureOnce(key, message) {
|
|
9568
9554
|
const now3 = Date.now();
|
|
9569
9555
|
const last = embeddingFailureLogTimestamps.get(key) ?? 0;
|
|
9570
9556
|
if (now3 - last < EMBEDDING_FAILURE_LOG_COOLDOWN_MS) return;
|
|
9557
|
+
if (!embeddingFailureLogTimestamps.has(key) && embeddingFailureLogTimestamps.size >= MAX_EMBEDDING_FAILURE_KEYS) {
|
|
9558
|
+
const oldest = embeddingFailureLogTimestamps.keys().next().value;
|
|
9559
|
+
if (oldest !== void 0) embeddingFailureLogTimestamps.delete(oldest);
|
|
9560
|
+
}
|
|
9561
|
+
embeddingFailureLogTimestamps.delete(key);
|
|
9571
9562
|
embeddingFailureLogTimestamps.set(key, now3);
|
|
9572
9563
|
console.error(message);
|
|
9573
9564
|
}
|
|
@@ -9597,13 +9588,14 @@ function queueVectorBackfill(projectId, options = {}) {
|
|
|
9597
9588
|
const dataDir = projectDir;
|
|
9598
9589
|
if (!dataDir) return;
|
|
9599
9590
|
void Promise.resolve().then(() => (init_maintenance_jobs(), maintenance_jobs_exports)).then(({ MaintenanceJobStore: MaintenanceJobStore2 }) => {
|
|
9600
|
-
new MaintenanceJobStore2(dataDir).enqueue({
|
|
9591
|
+
const job = new MaintenanceJobStore2(dataDir).enqueue({
|
|
9601
9592
|
projectId,
|
|
9602
9593
|
kind: "vector-backfill",
|
|
9603
9594
|
dedupeKey: "vector-backfill",
|
|
9604
9595
|
payload: { limit: 12 }
|
|
9605
9596
|
});
|
|
9606
|
-
|
|
9597
|
+
const due = !job || job.status === "pending" && job.runAfter <= Date.now();
|
|
9598
|
+
if (due && options.detachedWorker && options.projectRoot) {
|
|
9607
9599
|
void Promise.resolve().then(() => (init_vector_backfill_runner(), vector_backfill_runner_exports)).then(({ launchDetachedVectorBackfill: launchDetachedVectorBackfill2 }) => {
|
|
9608
9600
|
launchDetachedVectorBackfill2({
|
|
9609
9601
|
projectId,
|
|
@@ -10534,7 +10526,7 @@ async function backfillVectorEmbeddings(options = {}) {
|
|
|
10534
10526
|
...lastFailure ? { lastError: lastFailure } : {}
|
|
10535
10527
|
};
|
|
10536
10528
|
}
|
|
10537
|
-
var observations, nextId, projectDir, searchIndexPrepared, embeddingWriteMode, embeddingWorkerProjectRoot, corpusLoaded, loadedObservationStore, vectorMissingIds, vectorBackfillRunning, vectorSchemaUpgradePromise, lastVectorBackfill, embeddingFailureLogTimestamps, EMBEDDING_FAILURE_LOG_COOLDOWN_MS;
|
|
10529
|
+
var observations, nextId, projectDir, searchIndexPrepared, embeddingWriteMode, embeddingWorkerProjectRoot, corpusLoaded, loadedObservationStore, vectorMissingIds, vectorBackfillRunning, vectorSchemaUpgradePromise, lastVectorBackfill, embeddingFailureLogTimestamps, EMBEDDING_FAILURE_LOG_COOLDOWN_MS, MAX_EMBEDDING_FAILURE_KEYS;
|
|
10538
10530
|
var init_observations = __esm({
|
|
10539
10531
|
"src/memory/observations.ts"() {
|
|
10540
10532
|
"use strict";
|
|
@@ -10562,6 +10554,57 @@ var init_observations = __esm({
|
|
|
10562
10554
|
lastVectorBackfill = null;
|
|
10563
10555
|
embeddingFailureLogTimestamps = /* @__PURE__ */ new Map();
|
|
10564
10556
|
EMBEDDING_FAILURE_LOG_COOLDOWN_MS = 3e4;
|
|
10557
|
+
MAX_EMBEDDING_FAILURE_KEYS = 1024;
|
|
10558
|
+
}
|
|
10559
|
+
});
|
|
10560
|
+
|
|
10561
|
+
// src/runtime/maintenance-targets.ts
|
|
10562
|
+
function rowToTarget(row) {
|
|
10563
|
+
return {
|
|
10564
|
+
projectId: row.project_id,
|
|
10565
|
+
projectRoot: row.project_root,
|
|
10566
|
+
dataDir: row.data_dir,
|
|
10567
|
+
updatedAt: Number(row.updated_at)
|
|
10568
|
+
};
|
|
10569
|
+
}
|
|
10570
|
+
var MaintenanceTargetStore;
|
|
10571
|
+
var init_maintenance_targets = __esm({
|
|
10572
|
+
"src/runtime/maintenance-targets.ts"() {
|
|
10573
|
+
"use strict";
|
|
10574
|
+
init_esm_shims();
|
|
10575
|
+
init_sqlite_db();
|
|
10576
|
+
MaintenanceTargetStore = class {
|
|
10577
|
+
db;
|
|
10578
|
+
constructor(dataDir) {
|
|
10579
|
+
this.db = getDatabase(dataDir);
|
|
10580
|
+
}
|
|
10581
|
+
register(input) {
|
|
10582
|
+
if (!input.projectId.trim()) throw new Error("Maintenance target requires a project ID");
|
|
10583
|
+
if (!input.projectRoot.trim()) throw new Error("Maintenance target requires a project root");
|
|
10584
|
+
if (!input.dataDir.trim()) throw new Error("Maintenance target requires a data directory");
|
|
10585
|
+
const now3 = input.now ?? Date.now();
|
|
10586
|
+
this.db.prepare(`
|
|
10587
|
+
INSERT INTO maintenance_targets (project_id, project_root, data_dir, updated_at)
|
|
10588
|
+
VALUES (?, ?, ?, ?)
|
|
10589
|
+
ON CONFLICT(project_id) DO UPDATE SET
|
|
10590
|
+
project_root = excluded.project_root,
|
|
10591
|
+
data_dir = excluded.data_dir,
|
|
10592
|
+
updated_at = excluded.updated_at
|
|
10593
|
+
`).run(input.projectId, input.projectRoot, input.dataDir, now3);
|
|
10594
|
+
return this.get(input.projectId);
|
|
10595
|
+
}
|
|
10596
|
+
get(projectId) {
|
|
10597
|
+
const row = this.db.prepare(`
|
|
10598
|
+
SELECT * FROM maintenance_targets WHERE project_id = ?
|
|
10599
|
+
`).get(projectId);
|
|
10600
|
+
return row ? rowToTarget(row) : void 0;
|
|
10601
|
+
}
|
|
10602
|
+
list() {
|
|
10603
|
+
return this.db.prepare(`
|
|
10604
|
+
SELECT * FROM maintenance_targets ORDER BY updated_at DESC
|
|
10605
|
+
`).all().map(rowToTarget);
|
|
10606
|
+
}
|
|
10607
|
+
};
|
|
10565
10608
|
}
|
|
10566
10609
|
});
|
|
10567
10610
|
|
|
@@ -151044,10 +151087,21 @@ __export(vector_backfill_runner_exports, {
|
|
|
151044
151087
|
launchDetachedVectorBackfill: () => launchDetachedVectorBackfill,
|
|
151045
151088
|
main: () => main,
|
|
151046
151089
|
parseVectorBackfillRequest: () => parseVectorBackfillRequest,
|
|
151047
|
-
|
|
151090
|
+
releaseVectorBackfillLock: () => releaseVectorBackfillLock,
|
|
151091
|
+
resolveVectorBackfillRunnerPath: () => resolveVectorBackfillRunnerPath,
|
|
151092
|
+
vectorBackfillLockPath: () => vectorBackfillLockPath
|
|
151048
151093
|
});
|
|
151049
151094
|
import { spawn as spawn3 } from "child_process";
|
|
151050
|
-
import {
|
|
151095
|
+
import {
|
|
151096
|
+
closeSync,
|
|
151097
|
+
existsSync as existsSync11,
|
|
151098
|
+
mkdirSync as mkdirSync2,
|
|
151099
|
+
openSync,
|
|
151100
|
+
readFileSync as readFileSync9,
|
|
151101
|
+
statSync as statSync4,
|
|
151102
|
+
unlinkSync,
|
|
151103
|
+
writeFileSync as writeFileSync2
|
|
151104
|
+
} from "fs";
|
|
151051
151105
|
import path20 from "path";
|
|
151052
151106
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
151053
151107
|
function isNonEmptyString(value) {
|
|
@@ -151074,10 +151128,104 @@ function parseVectorBackfillRequest(raw) {
|
|
|
151074
151128
|
dataDir: value.dataDir
|
|
151075
151129
|
};
|
|
151076
151130
|
}
|
|
151131
|
+
function vectorBackfillLockPath(dataDir) {
|
|
151132
|
+
return path20.join(dataDir, VECTOR_BACKFILL_LOCK_FILE);
|
|
151133
|
+
}
|
|
151134
|
+
function processIsAlive(pid) {
|
|
151135
|
+
if (!Number.isSafeInteger(pid) || pid == null || pid <= 0) return false;
|
|
151136
|
+
try {
|
|
151137
|
+
process.kill(pid, 0);
|
|
151138
|
+
return true;
|
|
151139
|
+
} catch (error) {
|
|
151140
|
+
return error.code === "EPERM";
|
|
151141
|
+
}
|
|
151142
|
+
}
|
|
151143
|
+
function readVectorBackfillLock(lockPath) {
|
|
151144
|
+
try {
|
|
151145
|
+
const value = JSON.parse(readFileSync9(lockPath, "utf8"));
|
|
151146
|
+
if (typeof value.parentPid !== "number" || !Number.isSafeInteger(value.parentPid) || typeof value.startedAt !== "number" || !Number.isFinite(value.startedAt) || typeof value.projectId !== "string") return void 0;
|
|
151147
|
+
return {
|
|
151148
|
+
parentPid: value.parentPid,
|
|
151149
|
+
...typeof value.childPid === "number" ? { childPid: value.childPid } : {},
|
|
151150
|
+
startedAt: value.startedAt,
|
|
151151
|
+
projectId: value.projectId
|
|
151152
|
+
};
|
|
151153
|
+
} catch {
|
|
151154
|
+
return void 0;
|
|
151155
|
+
}
|
|
151156
|
+
}
|
|
151157
|
+
function writeVectorBackfillLock(lockPath, value) {
|
|
151158
|
+
writeFileSync2(lockPath, `${JSON.stringify(value)}
|
|
151159
|
+
`, "utf8");
|
|
151160
|
+
}
|
|
151161
|
+
function acquireVectorBackfillLock(dataDir, projectId, preferredPath) {
|
|
151162
|
+
const lockPath = preferredPath ?? vectorBackfillLockPath(dataDir);
|
|
151163
|
+
mkdirSync2(path20.dirname(lockPath), { recursive: true });
|
|
151164
|
+
const initial = {
|
|
151165
|
+
parentPid: process.pid,
|
|
151166
|
+
startedAt: Date.now(),
|
|
151167
|
+
projectId
|
|
151168
|
+
};
|
|
151169
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
151170
|
+
try {
|
|
151171
|
+
const fd = openSync(lockPath, "wx");
|
|
151172
|
+
try {
|
|
151173
|
+
writeFileSync2(fd, `${JSON.stringify(initial)}
|
|
151174
|
+
`, "utf8");
|
|
151175
|
+
} finally {
|
|
151176
|
+
closeSync(fd);
|
|
151177
|
+
}
|
|
151178
|
+
return {
|
|
151179
|
+
path: lockPath,
|
|
151180
|
+
setChildPid(pid) {
|
|
151181
|
+
try {
|
|
151182
|
+
writeVectorBackfillLock(lockPath, { ...initial, childPid: pid });
|
|
151183
|
+
} catch {
|
|
151184
|
+
}
|
|
151185
|
+
},
|
|
151186
|
+
release() {
|
|
151187
|
+
try {
|
|
151188
|
+
unlinkSync(lockPath);
|
|
151189
|
+
} catch {
|
|
151190
|
+
}
|
|
151191
|
+
}
|
|
151192
|
+
};
|
|
151193
|
+
} catch (error) {
|
|
151194
|
+
if (error.code !== "EEXIST") return void 0;
|
|
151195
|
+
const existing = readVectorBackfillLock(lockPath);
|
|
151196
|
+
const ownerAlive = existing && (processIsAlive(existing.childPid) || processIsAlive(existing.parentPid));
|
|
151197
|
+
if (ownerAlive) return void 0;
|
|
151198
|
+
let stale = false;
|
|
151199
|
+
try {
|
|
151200
|
+
stale = Date.now() - statSync4(lockPath).mtimeMs >= STALE_LOCK_RECOVERY_MS;
|
|
151201
|
+
} catch {
|
|
151202
|
+
stale = false;
|
|
151203
|
+
}
|
|
151204
|
+
if (!existing && !stale) return void 0;
|
|
151205
|
+
try {
|
|
151206
|
+
unlinkSync(lockPath);
|
|
151207
|
+
} catch {
|
|
151208
|
+
return void 0;
|
|
151209
|
+
}
|
|
151210
|
+
}
|
|
151211
|
+
}
|
|
151212
|
+
return void 0;
|
|
151213
|
+
}
|
|
151214
|
+
function releaseVectorBackfillLock(lockPath = process.env.MEMORIX_VECTOR_BACKFILL_LOCK) {
|
|
151215
|
+
if (!lockPath) return;
|
|
151216
|
+
const lock = readVectorBackfillLock(lockPath);
|
|
151217
|
+
if (lock && lock.childPid !== process.pid) return;
|
|
151218
|
+
try {
|
|
151219
|
+
unlinkSync(lockPath);
|
|
151220
|
+
} catch {
|
|
151221
|
+
}
|
|
151222
|
+
}
|
|
151077
151223
|
function launchDetachedVectorBackfill(request, options = {}) {
|
|
151078
151224
|
const runnerPath = options.runnerPath ?? resolveVectorBackfillRunnerPath();
|
|
151079
151225
|
const exists = options.exists ?? existsSync11;
|
|
151080
151226
|
if (!exists(runnerPath)) return false;
|
|
151227
|
+
const lock = acquireVectorBackfillLock(request.dataDir, request.projectId, options.lockPath);
|
|
151228
|
+
if (!lock) return false;
|
|
151081
151229
|
try {
|
|
151082
151230
|
const child = (options.spawn ?? spawn3)(process.execPath, [runnerPath], {
|
|
151083
151231
|
cwd: request.projectRoot,
|
|
@@ -151087,14 +151235,23 @@ function launchDetachedVectorBackfill(request, options = {}) {
|
|
|
151087
151235
|
stdio: "ignore",
|
|
151088
151236
|
// The request contains only local project metadata, never credentials.
|
|
151089
151237
|
// Environment transport avoids a live stdin pipe keeping the CLI alive.
|
|
151090
|
-
env: {
|
|
151238
|
+
env: {
|
|
151239
|
+
...process.env,
|
|
151240
|
+
MEMORIX_VECTOR_BACKFILL_REQUEST: JSON.stringify(request),
|
|
151241
|
+
MEMORIX_VECTOR_BACKFILL_LOCK: lock.path
|
|
151242
|
+
},
|
|
151091
151243
|
windowsHide: true
|
|
151092
151244
|
});
|
|
151245
|
+
if (child.pid) lock.setChildPid(child.pid);
|
|
151246
|
+
else lock.release();
|
|
151093
151247
|
child.once?.("error", () => {
|
|
151094
151248
|
});
|
|
151249
|
+
child.once?.("close", () => lock.release());
|
|
151250
|
+
if (typeof child.once !== "function") lock.release();
|
|
151095
151251
|
child.unref();
|
|
151096
|
-
return
|
|
151252
|
+
return Boolean(child.pid);
|
|
151097
151253
|
} catch {
|
|
151254
|
+
lock.release();
|
|
151098
151255
|
return false;
|
|
151099
151256
|
}
|
|
151100
151257
|
}
|
|
@@ -151106,12 +151263,32 @@ async function executeVectorBackfill(request) {
|
|
|
151106
151263
|
await prepareSearchIndex();
|
|
151107
151264
|
await getDeferredCachedVectorHydration()?.catch(() => {
|
|
151108
151265
|
});
|
|
151266
|
+
const queue = new MaintenanceJobStore(request.dataDir);
|
|
151267
|
+
const targets = new MaintenanceTargetStore(request.dataDir);
|
|
151268
|
+
let preparedRoot = request.projectRoot;
|
|
151269
|
+
const prepareTarget = async (target) => {
|
|
151270
|
+
if (target.projectRoot === preparedRoot) return;
|
|
151271
|
+
initProjectRoot(target.projectRoot);
|
|
151272
|
+
loadDotenv(target.projectRoot);
|
|
151273
|
+
preparedRoot = target.projectRoot;
|
|
151274
|
+
};
|
|
151275
|
+
const handler = async (job) => {
|
|
151276
|
+
const target = targets.get(job.projectId) ?? (job.projectId === request.projectId ? { projectId: request.projectId, projectRoot: request.projectRoot, dataDir: request.dataDir, updatedAt: Date.now() } : void 0);
|
|
151277
|
+
if (!target) return { action: "reschedule", delayMs: 3e4 };
|
|
151278
|
+
await prepareTarget(target);
|
|
151279
|
+
return createProjectMaintenanceHandler(job.projectId, target.dataDir, target.projectRoot)(job);
|
|
151280
|
+
};
|
|
151109
151281
|
const worker = new MaintenanceJobWorker(
|
|
151110
|
-
|
|
151111
|
-
|
|
151112
|
-
{
|
|
151282
|
+
queue,
|
|
151283
|
+
handler,
|
|
151284
|
+
{ kinds: ["vector-backfill"] }
|
|
151113
151285
|
);
|
|
151114
|
-
|
|
151286
|
+
let result = { state: "idle" };
|
|
151287
|
+
while (true) {
|
|
151288
|
+
result = await worker.runOnce();
|
|
151289
|
+
if (result.state === "idle") break;
|
|
151290
|
+
}
|
|
151291
|
+
return result;
|
|
151115
151292
|
}
|
|
151116
151293
|
async function readStdin() {
|
|
151117
151294
|
return new Promise((resolve2, reject) => {
|
|
@@ -151134,9 +151311,11 @@ async function main() {
|
|
|
151134
151311
|
`);
|
|
151135
151312
|
process.exitCode = 1;
|
|
151136
151313
|
} finally {
|
|
151314
|
+
releaseVectorBackfillLock();
|
|
151137
151315
|
closeAllDatabases();
|
|
151138
151316
|
}
|
|
151139
151317
|
}
|
|
151318
|
+
var VECTOR_BACKFILL_LOCK_FILE, STALE_LOCK_RECOVERY_MS;
|
|
151140
151319
|
var init_vector_backfill_runner = __esm({
|
|
151141
151320
|
"src/runtime/vector-backfill-runner.ts"() {
|
|
151142
151321
|
init_esm_shims();
|
|
@@ -151148,7 +151327,10 @@ var init_vector_backfill_runner = __esm({
|
|
|
151148
151327
|
init_orama_store();
|
|
151149
151328
|
init_sqlite_db();
|
|
151150
151329
|
init_maintenance_jobs();
|
|
151330
|
+
init_maintenance_targets();
|
|
151151
151331
|
init_project_maintenance();
|
|
151332
|
+
VECTOR_BACKFILL_LOCK_FILE = ".memorix-vector-backfill.lock";
|
|
151333
|
+
STALE_LOCK_RECOVERY_MS = 24 * 60 * 60 * 1e3;
|
|
151152
151334
|
if (process.argv[1] && process.argv[1].endsWith("vector-backfill-runner.js")) {
|
|
151153
151335
|
void main();
|
|
151154
151336
|
}
|
|
@@ -151160,7 +151342,9 @@ export {
|
|
|
151160
151342
|
launchDetachedVectorBackfill,
|
|
151161
151343
|
main,
|
|
151162
151344
|
parseVectorBackfillRequest,
|
|
151163
|
-
|
|
151345
|
+
releaseVectorBackfillLock,
|
|
151346
|
+
resolveVectorBackfillRunnerPath,
|
|
151347
|
+
vectorBackfillLockPath
|
|
151164
151348
|
};
|
|
151165
151349
|
/*! Bundled license information:
|
|
151166
151350
|
|
package/docs/API_REFERENCE.md
CHANGED
|
@@ -78,6 +78,10 @@ memorix audit project
|
|
|
78
78
|
memorix transfer export --format markdown --out ./memorix-export.md
|
|
79
79
|
memorix skills show --name auth-pattern
|
|
80
80
|
memorix sync workspace --action scan
|
|
81
|
+
memorix sync store status --json
|
|
82
|
+
memorix sync store push
|
|
83
|
+
memorix sync store pull
|
|
84
|
+
memorix sync store device rotate
|
|
81
85
|
memorix ingest image --path ./diagram.png
|
|
82
86
|
memorix media import --path ./architecture.png
|
|
83
87
|
memorix media attach --asset <asset-id> --title "Architecture diagram"
|
|
@@ -87,6 +91,16 @@ memorix receipt --json --probe "release blocker"
|
|
|
87
91
|
|
|
88
92
|
The CLI is for direct terminal use, not a 1:1 mirror of MCP tool names. It does not require an MCP connection. `--cwd` selects a Git project from any shell; an unbound terminal has project-visible access only, including transfer exports. `memorix identity join|use|clear` makes personal/team access and coordination explicit, while `--as <agent-id>` is the one-command equivalent for scripts. The only MCP-only area is the optional graph-compatibility tools (`create_entities`, `read_graph`, and related tools) for workflows that expect the official memory-server style graph API.
|
|
89
93
|
|
|
94
|
+
`memorix sync store` is an explicit, opt-in multi-device observation relay. It
|
|
95
|
+
uses the current Git project as its namespace, excludes personal/agent-targeted
|
|
96
|
+
and unqualified records, keeps a local retry outbox, and stores cursors locally.
|
|
97
|
+
The default `status` action is preview-only. GitHub stores immutable JSONL event
|
|
98
|
+
blobs; it does not receive `memorix.db`, `memorix.db-wal`, or `memorix.db-shm`.
|
|
99
|
+
Use `memorix sync store compact --dry --through device=sequence` to preview
|
|
100
|
+
remote log cleanup; add `--yes` only when the acknowledged cutoffs are correct.
|
|
101
|
+
The S3 adapter supports an optional `MEMORIX_SYNC_S3_PREFIX` so several
|
|
102
|
+
independent stores can share one bucket without crossing key spaces.
|
|
103
|
+
|
|
90
104
|
### Memory Autopilot, Code State, and Context Packs
|
|
91
105
|
|
|
92
106
|
Memory Autopilot is the default agent-facing path for coding context. It builds a bounded task Workset instead of dumping old chat text: current project facts, Code State, selected observations, source-backed claims, matching knowledge/workflow starts, cautions, and verification hints. Code State stores versioned local file, symbol, import-edge, and memory-to-code reference facts beside project memory. It is not a replacement for normal file reads. Its job is to help agents decide which memories still point at current code, which ones are stale, and which files/symbols deserve inspection next.
|