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
package/dist/index.js
CHANGED
|
@@ -7292,6 +7292,14 @@ __export(orama_store_exports, {
|
|
|
7292
7292
|
updateObservationMetadata: () => updateObservationMetadata
|
|
7293
7293
|
});
|
|
7294
7294
|
import { create, insert as insert2, insertMultiple, search, remove as remove2, update, count, getByID } from "@orama/orama";
|
|
7295
|
+
function rememberSearchMode(key, value) {
|
|
7296
|
+
if (!lastSearchModeByProject.has(key) && lastSearchModeByProject.size >= MAX_SEARCH_MODE_KEYS) {
|
|
7297
|
+
const oldest = lastSearchModeByProject.keys().next().value;
|
|
7298
|
+
if (oldest !== void 0) lastSearchModeByProject.delete(oldest);
|
|
7299
|
+
}
|
|
7300
|
+
lastSearchModeByProject.delete(key);
|
|
7301
|
+
lastSearchModeByProject.set(key, value);
|
|
7302
|
+
}
|
|
7295
7303
|
function getLastSearchMode(projectId) {
|
|
7296
7304
|
return lastSearchModeByProject.get(projectId ?? SEARCH_MODE_DEFAULT_KEY) ?? "fulltext";
|
|
7297
7305
|
}
|
|
@@ -7304,9 +7312,6 @@ function makeEntryKey(projectId, observationId2) {
|
|
|
7304
7312
|
function rememberObservationDoc(doc) {
|
|
7305
7313
|
const publicDoc = { ...doc };
|
|
7306
7314
|
delete publicDoc.embedding;
|
|
7307
|
-
if (doc.projectId && typeof doc.observationId === "number") {
|
|
7308
|
-
docByObservationKey.set(makeEntryKey(doc.projectId, doc.observationId), publicDoc);
|
|
7309
|
-
}
|
|
7310
7315
|
return publicDoc;
|
|
7311
7316
|
}
|
|
7312
7317
|
function isCommandLikeQuery(query) {
|
|
@@ -7410,7 +7415,6 @@ async function resetDb() {
|
|
|
7410
7415
|
indexEmbeddingProvider = null;
|
|
7411
7416
|
deferredCachedVectorHydration = null;
|
|
7412
7417
|
lastSearchModeByProject.clear();
|
|
7413
|
-
docByObservationKey.clear();
|
|
7414
7418
|
}
|
|
7415
7419
|
function isEmbeddingEnabled() {
|
|
7416
7420
|
return embeddingEnabled;
|
|
@@ -7473,78 +7477,72 @@ function isCompatibleCachedVector(vector) {
|
|
|
7473
7477
|
vector && embeddingDimensions !== null && vector.length === embeddingDimensions && vector.every(Number.isFinite)
|
|
7474
7478
|
);
|
|
7475
7479
|
}
|
|
7476
|
-
async function attachCachedVectors(database,
|
|
7477
|
-
const
|
|
7478
|
-
|
|
7479
|
-
|
|
7480
|
-
|
|
7481
|
-
|
|
7482
|
-
|
|
7483
|
-
|
|
7484
|
-
|
|
7485
|
-
|
|
7486
|
-
|
|
7487
|
-
|
|
7488
|
-
|
|
7489
|
-
|
|
7490
|
-
|
|
7491
|
-
|
|
7480
|
+
async function attachCachedVectors(database, observations2) {
|
|
7481
|
+
const batchSize = 200;
|
|
7482
|
+
for (let start = 0; start < observations2.length; start += batchSize) {
|
|
7483
|
+
const batch = observations2.slice(start, start + batchSize);
|
|
7484
|
+
const cachedVectors = await getCachedEmbeddings(batch.map(observationEmbeddingText));
|
|
7485
|
+
if (db !== database) return;
|
|
7486
|
+
for (let index = 0; index < batch.length; index++) {
|
|
7487
|
+
const vector = cachedVectors[index];
|
|
7488
|
+
if (!isCompatibleCachedVector(vector)) continue;
|
|
7489
|
+
const id = makeOramaObservationId(batch[index].projectId, batch[index].id);
|
|
7490
|
+
const existing = getByID(database, id);
|
|
7491
|
+
if (!existing || documentEmbeddingText(existing) !== observationEmbeddingText(batch[index])) continue;
|
|
7492
|
+
try {
|
|
7493
|
+
await update(database, id, { ...existing, embedding: vector });
|
|
7494
|
+
} catch {
|
|
7495
|
+
}
|
|
7492
7496
|
}
|
|
7497
|
+
await new Promise((resolve5) => setImmediate(resolve5));
|
|
7493
7498
|
}
|
|
7494
7499
|
}
|
|
7495
7500
|
async function hydrateIndex(observations2, options = {}) {
|
|
7496
7501
|
const database = await getDb({ allowNetworkProbe: options.allowNetworkProbe });
|
|
7497
|
-
const candidates = [];
|
|
7498
|
-
for (const observation of observations2) {
|
|
7499
|
-
if (!observation || !observation.id || !observation.projectId) continue;
|
|
7500
|
-
const id = makeOramaObservationId(observation.projectId, observation.id);
|
|
7501
|
-
if (getByID(database, id)) continue;
|
|
7502
|
-
candidates.push({ observation, id });
|
|
7503
|
-
}
|
|
7504
7502
|
const deferCachedVectors = options.deferCachedVectors === true && Boolean(indexEmbeddingProvider?.getCachedEmbeddings);
|
|
7505
|
-
const cachedVectors = deferCachedVectors ? candidates.map(() => null) : await getCachedEmbeddings(candidates.map(({ observation }) => observationEmbeddingText(observation)));
|
|
7506
|
-
const documents = [];
|
|
7507
|
-
for (let index = 0; index < candidates.length; index++) {
|
|
7508
|
-
const { observation: obs, id } = candidates[index];
|
|
7509
|
-
try {
|
|
7510
|
-
const vector = cachedVectors[index];
|
|
7511
|
-
const compatibleVector = isCompatibleCachedVector(vector) ? vector : null;
|
|
7512
|
-
const doc = {
|
|
7513
|
-
id,
|
|
7514
|
-
observationId: obs.id,
|
|
7515
|
-
entityName: obs.entityName || "",
|
|
7516
|
-
type: obs.type || "discovery",
|
|
7517
|
-
title: obs.title || "",
|
|
7518
|
-
narrative: obs.narrative || "",
|
|
7519
|
-
facts: Array.isArray(obs.facts) ? obs.facts.join(" ") : "",
|
|
7520
|
-
filesModified: Array.isArray(obs.filesModified) ? obs.filesModified.join(" ") : "",
|
|
7521
|
-
concepts: Array.isArray(obs.concepts) ? obs.concepts.join(" ") : "",
|
|
7522
|
-
tokens: obs.tokens ?? 0,
|
|
7523
|
-
createdAt: obs.createdAt || "",
|
|
7524
|
-
projectId: obs.projectId,
|
|
7525
|
-
accessCount: obs.accessCount ?? 0,
|
|
7526
|
-
lastAccessedAt: obs.lastAccessedAt || "",
|
|
7527
|
-
status: obs.status ?? "active",
|
|
7528
|
-
source: obs.source || "agent",
|
|
7529
|
-
sourceDetail: obs.sourceDetail ?? "",
|
|
7530
|
-
valueCategory: obs.valueCategory ?? "",
|
|
7531
|
-
admissionState: obs.admissionState ?? "",
|
|
7532
|
-
admissionReason: obs.admissionReason ?? "",
|
|
7533
|
-
visibility: obs.visibility ?? "project",
|
|
7534
|
-
createdByAgentId: obs.createdByAgentId ?? "",
|
|
7535
|
-
sharedWithAgentIds: JSON.stringify(obs.sharedWithAgentIds ?? []),
|
|
7536
|
-
documentType: "observation",
|
|
7537
|
-
knowledgeLayer: resolveKnowledgeLayer("observation", obs.sourceDetail, obs.source),
|
|
7538
|
-
...compatibleVector ? { embedding: compatibleVector } : {}
|
|
7539
|
-
};
|
|
7540
|
-
documents.push(doc);
|
|
7541
|
-
} catch {
|
|
7542
|
-
}
|
|
7543
|
-
}
|
|
7544
7503
|
let inserted = 0;
|
|
7545
7504
|
const hydrationBatchSize = 200;
|
|
7546
|
-
for (let start = 0; start <
|
|
7547
|
-
const
|
|
7505
|
+
for (let start = 0; start < observations2.length; start += hydrationBatchSize) {
|
|
7506
|
+
const batchObservations = observations2.slice(start, start + hydrationBatchSize).filter((observation) => observation && observation.id && observation.projectId).filter((observation) => !getByID(database, makeOramaObservationId(observation.projectId, observation.id)));
|
|
7507
|
+
if (batchObservations.length === 0) continue;
|
|
7508
|
+
const cachedVectors = deferCachedVectors || options.skipCachedVectors ? batchObservations.map(() => null) : await getCachedEmbeddings(batchObservations.map(observationEmbeddingText));
|
|
7509
|
+
const batch = [];
|
|
7510
|
+
for (let index = 0; index < batchObservations.length; index++) {
|
|
7511
|
+
const obs = batchObservations[index];
|
|
7512
|
+
try {
|
|
7513
|
+
const compatibleVector = isCompatibleCachedVector(cachedVectors[index]) ? cachedVectors[index] : null;
|
|
7514
|
+
batch.push({
|
|
7515
|
+
id: makeOramaObservationId(obs.projectId, obs.id),
|
|
7516
|
+
observationId: obs.id,
|
|
7517
|
+
entityName: obs.entityName || "",
|
|
7518
|
+
type: obs.type || "discovery",
|
|
7519
|
+
title: obs.title || "",
|
|
7520
|
+
narrative: obs.narrative || "",
|
|
7521
|
+
facts: Array.isArray(obs.facts) ? obs.facts.join(" ") : "",
|
|
7522
|
+
filesModified: Array.isArray(obs.filesModified) ? obs.filesModified.join(" ") : "",
|
|
7523
|
+
concepts: Array.isArray(obs.concepts) ? obs.concepts.join(" ") : "",
|
|
7524
|
+
tokens: obs.tokens ?? 0,
|
|
7525
|
+
createdAt: obs.createdAt || "",
|
|
7526
|
+
projectId: obs.projectId,
|
|
7527
|
+
accessCount: obs.accessCount ?? 0,
|
|
7528
|
+
lastAccessedAt: obs.lastAccessedAt || "",
|
|
7529
|
+
status: obs.status ?? "active",
|
|
7530
|
+
source: obs.source || "agent",
|
|
7531
|
+
sourceDetail: obs.sourceDetail ?? "",
|
|
7532
|
+
valueCategory: obs.valueCategory ?? "",
|
|
7533
|
+
admissionState: obs.admissionState ?? "",
|
|
7534
|
+
admissionReason: obs.admissionReason ?? "",
|
|
7535
|
+
visibility: obs.visibility ?? "project",
|
|
7536
|
+
createdByAgentId: obs.createdByAgentId ?? "",
|
|
7537
|
+
sharedWithAgentIds: JSON.stringify(obs.sharedWithAgentIds ?? []),
|
|
7538
|
+
documentType: "observation",
|
|
7539
|
+
knowledgeLayer: resolveKnowledgeLayer("observation", obs.sourceDetail, obs.source),
|
|
7540
|
+
...compatibleVector ? { embedding: compatibleVector } : {}
|
|
7541
|
+
});
|
|
7542
|
+
} catch {
|
|
7543
|
+
}
|
|
7544
|
+
}
|
|
7545
|
+
if (batch.length === 0) continue;
|
|
7548
7546
|
try {
|
|
7549
7547
|
await insertMultiple(database, batch, batch.length);
|
|
7550
7548
|
for (const doc of batch) rememberObservationDoc(doc);
|
|
@@ -7566,7 +7564,7 @@ async function hydrateIndex(observations2, options = {}) {
|
|
|
7566
7564
|
}
|
|
7567
7565
|
await new Promise((resolve5) => setImmediate(resolve5));
|
|
7568
7566
|
}
|
|
7569
|
-
deferredCachedVectorHydration = options.skipCachedVectors ? null : deferCachedVectors ? attachCachedVectors(database,
|
|
7567
|
+
deferredCachedVectorHydration = options.skipCachedVectors ? null : deferCachedVectors ? attachCachedVectors(database, observations2).catch(() => {
|
|
7570
7568
|
}) : null;
|
|
7571
7569
|
return inserted;
|
|
7572
7570
|
}
|
|
@@ -7603,12 +7601,6 @@ async function updateObservationMetadata(projectId, observationId2, patch) {
|
|
|
7603
7601
|
async function removeObservation(oramaId) {
|
|
7604
7602
|
const database = await getDb();
|
|
7605
7603
|
await remove2(database, oramaId);
|
|
7606
|
-
for (const [key, doc] of docByObservationKey.entries()) {
|
|
7607
|
-
if (doc.id === oramaId) {
|
|
7608
|
-
docByObservationKey.delete(key);
|
|
7609
|
-
break;
|
|
7610
|
-
}
|
|
7611
|
-
}
|
|
7612
7604
|
}
|
|
7613
7605
|
async function searchObservations(options) {
|
|
7614
7606
|
const perf = !!process.env.MEMORIX_PERF;
|
|
@@ -7623,7 +7615,7 @@ async function searchObservations(options) {
|
|
|
7623
7615
|
const modeKey = options.projectId ?? SEARCH_MODE_DEFAULT_KEY;
|
|
7624
7616
|
const quality = options.quality ?? "balanced";
|
|
7625
7617
|
const database = await getDb();
|
|
7626
|
-
|
|
7618
|
+
rememberSearchMode(
|
|
7627
7619
|
modeKey,
|
|
7628
7620
|
quality === "fast" ? "fulltext (fast profile)" : embeddingEnabled ? "hybrid" : "fulltext"
|
|
7629
7621
|
);
|
|
@@ -7690,7 +7682,7 @@ async function searchObservations(options) {
|
|
|
7690
7682
|
if (provider2) {
|
|
7691
7683
|
const activeVectorDimensions = getVectorDimensions();
|
|
7692
7684
|
if (activeVectorDimensions !== null && provider2.dimensions !== activeVectorDimensions) {
|
|
7693
|
-
|
|
7685
|
+
rememberSearchMode(
|
|
7694
7686
|
modeKey,
|
|
7695
7687
|
`fulltext (embedding dimension mismatch: provider ${provider2.dimensions}d vs index ${activeVectorDimensions}d)`
|
|
7696
7688
|
);
|
|
@@ -7715,7 +7707,7 @@ async function searchObservations(options) {
|
|
|
7715
7707
|
mark("embedding");
|
|
7716
7708
|
const cjkRatio = (originalQuery.match(/[\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af]/g) || []).length / originalQuery.length;
|
|
7717
7709
|
const isCJKHeavy = cjkRatio > 0.3;
|
|
7718
|
-
|
|
7710
|
+
rememberSearchMode(modeKey, "hybrid");
|
|
7719
7711
|
searchParams = {
|
|
7720
7712
|
...searchParams,
|
|
7721
7713
|
mode: "hybrid",
|
|
@@ -7731,7 +7723,7 @@ async function searchObservations(options) {
|
|
|
7731
7723
|
}
|
|
7732
7724
|
}
|
|
7733
7725
|
} catch (error) {
|
|
7734
|
-
|
|
7726
|
+
rememberSearchMode(modeKey, "fulltext (embedding unavailable)");
|
|
7735
7727
|
console.error("[memorix] Embedding failed or timed out, falling back to fulltext search");
|
|
7736
7728
|
}
|
|
7737
7729
|
}
|
|
@@ -7741,7 +7733,7 @@ async function searchObservations(options) {
|
|
|
7741
7733
|
results = await search(database, searchParams);
|
|
7742
7734
|
} catch (error) {
|
|
7743
7735
|
if (queryVector && isVectorDimensionMismatchError(error)) {
|
|
7744
|
-
|
|
7736
|
+
rememberSearchMode(modeKey, "fulltext (embedding dimension mismatch)");
|
|
7745
7737
|
console.error("[memorix] Vector search dimension mismatch detected, retrying without embeddings");
|
|
7746
7738
|
results = await search(database, stripVectorSearchParams(searchParams));
|
|
7747
7739
|
} else {
|
|
@@ -7763,7 +7755,7 @@ async function searchObservations(options) {
|
|
|
7763
7755
|
},
|
|
7764
7756
|
similarity: 0.25
|
|
7765
7757
|
};
|
|
7766
|
-
|
|
7758
|
+
rememberSearchMode(modeKey, "vector-only (hybrid empty fallback)");
|
|
7767
7759
|
results = await search(database, vectorOnlyParams);
|
|
7768
7760
|
} catch {
|
|
7769
7761
|
}
|
|
@@ -8004,7 +7996,7 @@ async function searchObservations(options) {
|
|
|
8004
7996
|
const rerankedTop = neural.map((row) => candidateMap.get(row.id)).filter((entry) => entry != null);
|
|
8005
7997
|
if (rerankedTop.length > 0) {
|
|
8006
7998
|
intermediate = [...rerankedTop, ...intermediate.slice(RERANK_TOP_K)];
|
|
8007
|
-
|
|
7999
|
+
rememberSearchMode(modeKey, (lastSearchModeByProject.get(modeKey) ?? "fulltext") + " + neural rerank");
|
|
8008
8000
|
mark("rerank(usedNeural=true)");
|
|
8009
8001
|
}
|
|
8010
8002
|
}
|
|
@@ -8021,7 +8013,7 @@ async function searchObservations(options) {
|
|
|
8021
8013
|
);
|
|
8022
8014
|
mark(`rerank(usedLLM=${usedLLM})`);
|
|
8023
8015
|
if (usedLLM) {
|
|
8024
|
-
|
|
8016
|
+
rememberSearchMode(modeKey, (lastSearchModeByProject.get(modeKey) ?? "fulltext") + " + LLM rerank");
|
|
8025
8017
|
const rerankedTop = reranked.map((row) => candidateMap.get(row.id)).filter((entry) => entry != null);
|
|
8026
8018
|
if (rerankedTop.length > 0) {
|
|
8027
8019
|
intermediate = [...rerankedTop, ...intermediate.slice(RERANK_TOP_K)];
|
|
@@ -8094,13 +8086,6 @@ async function getObservationsByIds(ids, projectId) {
|
|
|
8094
8086
|
const database = await getDb();
|
|
8095
8087
|
const results = [];
|
|
8096
8088
|
for (const id of ids) {
|
|
8097
|
-
if (projectId) {
|
|
8098
|
-
const cached = docByObservationKey.get(makeEntryKey(projectId, id));
|
|
8099
|
-
if (cached) {
|
|
8100
|
-
results.push(cached);
|
|
8101
|
-
continue;
|
|
8102
|
-
}
|
|
8103
|
-
}
|
|
8104
8089
|
const searchResult = await search(database, {
|
|
8105
8090
|
term: "",
|
|
8106
8091
|
includeVectors: true,
|
|
@@ -8200,7 +8185,7 @@ function formatTime(isoDate) {
|
|
|
8200
8185
|
return isoDate;
|
|
8201
8186
|
}
|
|
8202
8187
|
}
|
|
8203
|
-
var db, dbInitPromise, dbGeneration, embeddingEnabled, embeddingDimensions, indexEmbeddingProvider, deferredCachedVectorHydration,
|
|
8188
|
+
var db, dbInitPromise, dbGeneration, embeddingEnabled, embeddingDimensions, indexEmbeddingProvider, deferredCachedVectorHydration, NON_CJK_HYBRID_SIMILARITY, lastSearchModeByProject, SEARCH_MODE_DEFAULT_KEY, MAX_SEARCH_MODE_KEYS, COMMAND_LOG_TITLE2, COMMAND_STYLE_TITLE, COMMAND_LIKE_QUERY2, COMMAND_INTENT_QUERY, NATURAL_LANGUAGE_MARKERS;
|
|
8204
8189
|
var init_orama_store = __esm({
|
|
8205
8190
|
"src/store/orama-store.ts"() {
|
|
8206
8191
|
"use strict";
|
|
@@ -8221,10 +8206,10 @@ var init_orama_store = __esm({
|
|
|
8221
8206
|
embeddingDimensions = null;
|
|
8222
8207
|
indexEmbeddingProvider = null;
|
|
8223
8208
|
deferredCachedVectorHydration = null;
|
|
8224
|
-
docByObservationKey = /* @__PURE__ */ new Map();
|
|
8225
8209
|
NON_CJK_HYBRID_SIMILARITY = 0.45;
|
|
8226
8210
|
lastSearchModeByProject = /* @__PURE__ */ new Map();
|
|
8227
8211
|
SEARCH_MODE_DEFAULT_KEY = "__global__";
|
|
8212
|
+
MAX_SEARCH_MODE_KEYS = 4096;
|
|
8228
8213
|
COMMAND_LOG_TITLE2 = /^(Ran:|Command:|Executed:)\s/i;
|
|
8229
8214
|
COMMAND_STYLE_TITLE = /(\bfindstr\b|\bSelect-String\b|\bGet-Content\b|\bnpx\s+vitest\b|\bnpx\s+tsc\b|\b2>&1\b)/i;
|
|
8230
8215
|
COMMAND_LIKE_QUERY2 = /\b(git|npm|npx|pnpm|yarn|node|bash|powershell|curl|memorix)\b/i;
|
|
@@ -9652,6 +9637,60 @@ var init_evidence_store = __esm({
|
|
|
9652
9637
|
}
|
|
9653
9638
|
});
|
|
9654
9639
|
|
|
9640
|
+
// src/runtime/maintenance-targets.ts
|
|
9641
|
+
var maintenance_targets_exports = {};
|
|
9642
|
+
__export(maintenance_targets_exports, {
|
|
9643
|
+
MaintenanceTargetStore: () => MaintenanceTargetStore
|
|
9644
|
+
});
|
|
9645
|
+
function rowToTarget(row) {
|
|
9646
|
+
return {
|
|
9647
|
+
projectId: row.project_id,
|
|
9648
|
+
projectRoot: row.project_root,
|
|
9649
|
+
dataDir: row.data_dir,
|
|
9650
|
+
updatedAt: Number(row.updated_at)
|
|
9651
|
+
};
|
|
9652
|
+
}
|
|
9653
|
+
var MaintenanceTargetStore;
|
|
9654
|
+
var init_maintenance_targets = __esm({
|
|
9655
|
+
"src/runtime/maintenance-targets.ts"() {
|
|
9656
|
+
"use strict";
|
|
9657
|
+
init_esm_shims();
|
|
9658
|
+
init_sqlite_db();
|
|
9659
|
+
MaintenanceTargetStore = class {
|
|
9660
|
+
db;
|
|
9661
|
+
constructor(dataDir) {
|
|
9662
|
+
this.db = getDatabase(dataDir);
|
|
9663
|
+
}
|
|
9664
|
+
register(input) {
|
|
9665
|
+
if (!input.projectId.trim()) throw new Error("Maintenance target requires a project ID");
|
|
9666
|
+
if (!input.projectRoot.trim()) throw new Error("Maintenance target requires a project root");
|
|
9667
|
+
if (!input.dataDir.trim()) throw new Error("Maintenance target requires a data directory");
|
|
9668
|
+
const now3 = input.now ?? Date.now();
|
|
9669
|
+
this.db.prepare(`
|
|
9670
|
+
INSERT INTO maintenance_targets (project_id, project_root, data_dir, updated_at)
|
|
9671
|
+
VALUES (?, ?, ?, ?)
|
|
9672
|
+
ON CONFLICT(project_id) DO UPDATE SET
|
|
9673
|
+
project_root = excluded.project_root,
|
|
9674
|
+
data_dir = excluded.data_dir,
|
|
9675
|
+
updated_at = excluded.updated_at
|
|
9676
|
+
`).run(input.projectId, input.projectRoot, input.dataDir, now3);
|
|
9677
|
+
return this.get(input.projectId);
|
|
9678
|
+
}
|
|
9679
|
+
get(projectId) {
|
|
9680
|
+
const row = this.db.prepare(`
|
|
9681
|
+
SELECT * FROM maintenance_targets WHERE project_id = ?
|
|
9682
|
+
`).get(projectId);
|
|
9683
|
+
return row ? rowToTarget(row) : void 0;
|
|
9684
|
+
}
|
|
9685
|
+
list() {
|
|
9686
|
+
return this.db.prepare(`
|
|
9687
|
+
SELECT * FROM maintenance_targets ORDER BY updated_at DESC
|
|
9688
|
+
`).all().map(rowToTarget);
|
|
9689
|
+
}
|
|
9690
|
+
};
|
|
9691
|
+
}
|
|
9692
|
+
});
|
|
9693
|
+
|
|
9655
9694
|
// src/runtime/isolated-maintenance.ts
|
|
9656
9695
|
import { spawn } from "child_process";
|
|
9657
9696
|
import { existsSync as existsSync8 } from "fs";
|
|
@@ -152188,10 +152227,21 @@ __export(vector_backfill_runner_exports, {
|
|
|
152188
152227
|
launchDetachedVectorBackfill: () => launchDetachedVectorBackfill,
|
|
152189
152228
|
main: () => main,
|
|
152190
152229
|
parseVectorBackfillRequest: () => parseVectorBackfillRequest,
|
|
152191
|
-
|
|
152230
|
+
releaseVectorBackfillLock: () => releaseVectorBackfillLock,
|
|
152231
|
+
resolveVectorBackfillRunnerPath: () => resolveVectorBackfillRunnerPath,
|
|
152232
|
+
vectorBackfillLockPath: () => vectorBackfillLockPath
|
|
152192
152233
|
});
|
|
152193
152234
|
import { spawn as spawn4 } from "child_process";
|
|
152194
|
-
import {
|
|
152235
|
+
import {
|
|
152236
|
+
closeSync,
|
|
152237
|
+
existsSync as existsSync12,
|
|
152238
|
+
mkdirSync as mkdirSync2,
|
|
152239
|
+
openSync,
|
|
152240
|
+
readFileSync as readFileSync9,
|
|
152241
|
+
statSync as statSync4,
|
|
152242
|
+
unlinkSync,
|
|
152243
|
+
writeFileSync as writeFileSync2
|
|
152244
|
+
} from "fs";
|
|
152195
152245
|
import path24 from "path";
|
|
152196
152246
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
152197
152247
|
function isNonEmptyString(value) {
|
|
@@ -152218,10 +152268,104 @@ function parseVectorBackfillRequest(raw) {
|
|
|
152218
152268
|
dataDir: value.dataDir
|
|
152219
152269
|
};
|
|
152220
152270
|
}
|
|
152271
|
+
function vectorBackfillLockPath(dataDir) {
|
|
152272
|
+
return path24.join(dataDir, VECTOR_BACKFILL_LOCK_FILE);
|
|
152273
|
+
}
|
|
152274
|
+
function processIsAlive(pid) {
|
|
152275
|
+
if (!Number.isSafeInteger(pid) || pid == null || pid <= 0) return false;
|
|
152276
|
+
try {
|
|
152277
|
+
process.kill(pid, 0);
|
|
152278
|
+
return true;
|
|
152279
|
+
} catch (error) {
|
|
152280
|
+
return error.code === "EPERM";
|
|
152281
|
+
}
|
|
152282
|
+
}
|
|
152283
|
+
function readVectorBackfillLock(lockPath) {
|
|
152284
|
+
try {
|
|
152285
|
+
const value = JSON.parse(readFileSync9(lockPath, "utf8"));
|
|
152286
|
+
if (typeof value.parentPid !== "number" || !Number.isSafeInteger(value.parentPid) || typeof value.startedAt !== "number" || !Number.isFinite(value.startedAt) || typeof value.projectId !== "string") return void 0;
|
|
152287
|
+
return {
|
|
152288
|
+
parentPid: value.parentPid,
|
|
152289
|
+
...typeof value.childPid === "number" ? { childPid: value.childPid } : {},
|
|
152290
|
+
startedAt: value.startedAt,
|
|
152291
|
+
projectId: value.projectId
|
|
152292
|
+
};
|
|
152293
|
+
} catch {
|
|
152294
|
+
return void 0;
|
|
152295
|
+
}
|
|
152296
|
+
}
|
|
152297
|
+
function writeVectorBackfillLock(lockPath, value) {
|
|
152298
|
+
writeFileSync2(lockPath, `${JSON.stringify(value)}
|
|
152299
|
+
`, "utf8");
|
|
152300
|
+
}
|
|
152301
|
+
function acquireVectorBackfillLock(dataDir, projectId, preferredPath) {
|
|
152302
|
+
const lockPath = preferredPath ?? vectorBackfillLockPath(dataDir);
|
|
152303
|
+
mkdirSync2(path24.dirname(lockPath), { recursive: true });
|
|
152304
|
+
const initial = {
|
|
152305
|
+
parentPid: process.pid,
|
|
152306
|
+
startedAt: Date.now(),
|
|
152307
|
+
projectId
|
|
152308
|
+
};
|
|
152309
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
152310
|
+
try {
|
|
152311
|
+
const fd = openSync(lockPath, "wx");
|
|
152312
|
+
try {
|
|
152313
|
+
writeFileSync2(fd, `${JSON.stringify(initial)}
|
|
152314
|
+
`, "utf8");
|
|
152315
|
+
} finally {
|
|
152316
|
+
closeSync(fd);
|
|
152317
|
+
}
|
|
152318
|
+
return {
|
|
152319
|
+
path: lockPath,
|
|
152320
|
+
setChildPid(pid) {
|
|
152321
|
+
try {
|
|
152322
|
+
writeVectorBackfillLock(lockPath, { ...initial, childPid: pid });
|
|
152323
|
+
} catch {
|
|
152324
|
+
}
|
|
152325
|
+
},
|
|
152326
|
+
release() {
|
|
152327
|
+
try {
|
|
152328
|
+
unlinkSync(lockPath);
|
|
152329
|
+
} catch {
|
|
152330
|
+
}
|
|
152331
|
+
}
|
|
152332
|
+
};
|
|
152333
|
+
} catch (error) {
|
|
152334
|
+
if (error.code !== "EEXIST") return void 0;
|
|
152335
|
+
const existing = readVectorBackfillLock(lockPath);
|
|
152336
|
+
const ownerAlive = existing && (processIsAlive(existing.childPid) || processIsAlive(existing.parentPid));
|
|
152337
|
+
if (ownerAlive) return void 0;
|
|
152338
|
+
let stale = false;
|
|
152339
|
+
try {
|
|
152340
|
+
stale = Date.now() - statSync4(lockPath).mtimeMs >= STALE_LOCK_RECOVERY_MS;
|
|
152341
|
+
} catch {
|
|
152342
|
+
stale = false;
|
|
152343
|
+
}
|
|
152344
|
+
if (!existing && !stale) return void 0;
|
|
152345
|
+
try {
|
|
152346
|
+
unlinkSync(lockPath);
|
|
152347
|
+
} catch {
|
|
152348
|
+
return void 0;
|
|
152349
|
+
}
|
|
152350
|
+
}
|
|
152351
|
+
}
|
|
152352
|
+
return void 0;
|
|
152353
|
+
}
|
|
152354
|
+
function releaseVectorBackfillLock(lockPath = process.env.MEMORIX_VECTOR_BACKFILL_LOCK) {
|
|
152355
|
+
if (!lockPath) return;
|
|
152356
|
+
const lock = readVectorBackfillLock(lockPath);
|
|
152357
|
+
if (lock && lock.childPid !== process.pid) return;
|
|
152358
|
+
try {
|
|
152359
|
+
unlinkSync(lockPath);
|
|
152360
|
+
} catch {
|
|
152361
|
+
}
|
|
152362
|
+
}
|
|
152221
152363
|
function launchDetachedVectorBackfill(request, options = {}) {
|
|
152222
152364
|
const runnerPath = options.runnerPath ?? resolveVectorBackfillRunnerPath();
|
|
152223
152365
|
const exists = options.exists ?? existsSync12;
|
|
152224
152366
|
if (!exists(runnerPath)) return false;
|
|
152367
|
+
const lock = acquireVectorBackfillLock(request.dataDir, request.projectId, options.lockPath);
|
|
152368
|
+
if (!lock) return false;
|
|
152225
152369
|
try {
|
|
152226
152370
|
const child = (options.spawn ?? spawn4)(process.execPath, [runnerPath], {
|
|
152227
152371
|
cwd: request.projectRoot,
|
|
@@ -152231,14 +152375,23 @@ function launchDetachedVectorBackfill(request, options = {}) {
|
|
|
152231
152375
|
stdio: "ignore",
|
|
152232
152376
|
// The request contains only local project metadata, never credentials.
|
|
152233
152377
|
// Environment transport avoids a live stdin pipe keeping the CLI alive.
|
|
152234
|
-
env: {
|
|
152378
|
+
env: {
|
|
152379
|
+
...process.env,
|
|
152380
|
+
MEMORIX_VECTOR_BACKFILL_REQUEST: JSON.stringify(request),
|
|
152381
|
+
MEMORIX_VECTOR_BACKFILL_LOCK: lock.path
|
|
152382
|
+
},
|
|
152235
152383
|
windowsHide: true
|
|
152236
152384
|
});
|
|
152385
|
+
if (child.pid) lock.setChildPid(child.pid);
|
|
152386
|
+
else lock.release();
|
|
152237
152387
|
child.once?.("error", () => {
|
|
152238
152388
|
});
|
|
152389
|
+
child.once?.("close", () => lock.release());
|
|
152390
|
+
if (typeof child.once !== "function") lock.release();
|
|
152239
152391
|
child.unref();
|
|
152240
|
-
return
|
|
152392
|
+
return Boolean(child.pid);
|
|
152241
152393
|
} catch {
|
|
152394
|
+
lock.release();
|
|
152242
152395
|
return false;
|
|
152243
152396
|
}
|
|
152244
152397
|
}
|
|
@@ -152250,12 +152403,32 @@ async function executeVectorBackfill(request) {
|
|
|
152250
152403
|
await prepareSearchIndex();
|
|
152251
152404
|
await getDeferredCachedVectorHydration()?.catch(() => {
|
|
152252
152405
|
});
|
|
152406
|
+
const queue = new MaintenanceJobStore(request.dataDir);
|
|
152407
|
+
const targets = new MaintenanceTargetStore(request.dataDir);
|
|
152408
|
+
let preparedRoot = request.projectRoot;
|
|
152409
|
+
const prepareTarget = async (target) => {
|
|
152410
|
+
if (target.projectRoot === preparedRoot) return;
|
|
152411
|
+
initProjectRoot(target.projectRoot);
|
|
152412
|
+
loadDotenv(target.projectRoot);
|
|
152413
|
+
preparedRoot = target.projectRoot;
|
|
152414
|
+
};
|
|
152415
|
+
const handler = async (job) => {
|
|
152416
|
+
const target = targets.get(job.projectId) ?? (job.projectId === request.projectId ? { projectId: request.projectId, projectRoot: request.projectRoot, dataDir: request.dataDir, updatedAt: Date.now() } : void 0);
|
|
152417
|
+
if (!target) return { action: "reschedule", delayMs: 3e4 };
|
|
152418
|
+
await prepareTarget(target);
|
|
152419
|
+
return createProjectMaintenanceHandler(job.projectId, target.dataDir, target.projectRoot)(job);
|
|
152420
|
+
};
|
|
152253
152421
|
const worker = new MaintenanceJobWorker(
|
|
152254
|
-
|
|
152255
|
-
|
|
152256
|
-
{
|
|
152422
|
+
queue,
|
|
152423
|
+
handler,
|
|
152424
|
+
{ kinds: ["vector-backfill"] }
|
|
152257
152425
|
);
|
|
152258
|
-
|
|
152426
|
+
let result = { state: "idle" };
|
|
152427
|
+
while (true) {
|
|
152428
|
+
result = await worker.runOnce();
|
|
152429
|
+
if (result.state === "idle") break;
|
|
152430
|
+
}
|
|
152431
|
+
return result;
|
|
152259
152432
|
}
|
|
152260
152433
|
async function readStdin() {
|
|
152261
152434
|
return new Promise((resolve5, reject) => {
|
|
@@ -152278,9 +152451,11 @@ async function main() {
|
|
|
152278
152451
|
`);
|
|
152279
152452
|
process.exitCode = 1;
|
|
152280
152453
|
} finally {
|
|
152454
|
+
releaseVectorBackfillLock();
|
|
152281
152455
|
closeAllDatabases();
|
|
152282
152456
|
}
|
|
152283
152457
|
}
|
|
152458
|
+
var VECTOR_BACKFILL_LOCK_FILE, STALE_LOCK_RECOVERY_MS;
|
|
152284
152459
|
var init_vector_backfill_runner = __esm({
|
|
152285
152460
|
"src/runtime/vector-backfill-runner.ts"() {
|
|
152286
152461
|
"use strict";
|
|
@@ -152293,7 +152468,10 @@ var init_vector_backfill_runner = __esm({
|
|
|
152293
152468
|
init_orama_store();
|
|
152294
152469
|
init_sqlite_db();
|
|
152295
152470
|
init_maintenance_jobs();
|
|
152471
|
+
init_maintenance_targets();
|
|
152296
152472
|
init_project_maintenance();
|
|
152473
|
+
VECTOR_BACKFILL_LOCK_FILE = ".memorix-vector-backfill.lock";
|
|
152474
|
+
STALE_LOCK_RECOVERY_MS = 24 * 60 * 60 * 1e3;
|
|
152297
152475
|
if (process.argv[1] && process.argv[1].endsWith("vector-backfill-runner.js")) {
|
|
152298
152476
|
void main();
|
|
152299
152477
|
}
|
|
@@ -152335,11 +152513,17 @@ function resetObservationRuntime() {
|
|
|
152335
152513
|
embeddingWorkerProjectRoot = void 0;
|
|
152336
152514
|
vectorMissingIds.clear();
|
|
152337
152515
|
vectorSchemaUpgradePromise = null;
|
|
152516
|
+
embeddingFailureLogTimestamps.clear();
|
|
152338
152517
|
}
|
|
152339
152518
|
function logEmbeddingFailureOnce(key, message) {
|
|
152340
152519
|
const now3 = Date.now();
|
|
152341
152520
|
const last = embeddingFailureLogTimestamps.get(key) ?? 0;
|
|
152342
152521
|
if (now3 - last < EMBEDDING_FAILURE_LOG_COOLDOWN_MS) return;
|
|
152522
|
+
if (!embeddingFailureLogTimestamps.has(key) && embeddingFailureLogTimestamps.size >= MAX_EMBEDDING_FAILURE_KEYS) {
|
|
152523
|
+
const oldest = embeddingFailureLogTimestamps.keys().next().value;
|
|
152524
|
+
if (oldest !== void 0) embeddingFailureLogTimestamps.delete(oldest);
|
|
152525
|
+
}
|
|
152526
|
+
embeddingFailureLogTimestamps.delete(key);
|
|
152343
152527
|
embeddingFailureLogTimestamps.set(key, now3);
|
|
152344
152528
|
console.error(message);
|
|
152345
152529
|
}
|
|
@@ -152369,13 +152553,14 @@ function queueVectorBackfill(projectId, options = {}) {
|
|
|
152369
152553
|
const dataDir = projectDir;
|
|
152370
152554
|
if (!dataDir) return;
|
|
152371
152555
|
void Promise.resolve().then(() => (init_maintenance_jobs(), maintenance_jobs_exports)).then(({ MaintenanceJobStore: MaintenanceJobStore2 }) => {
|
|
152372
|
-
new MaintenanceJobStore2(dataDir).enqueue({
|
|
152556
|
+
const job = new MaintenanceJobStore2(dataDir).enqueue({
|
|
152373
152557
|
projectId,
|
|
152374
152558
|
kind: "vector-backfill",
|
|
152375
152559
|
dedupeKey: "vector-backfill",
|
|
152376
152560
|
payload: { limit: 12 }
|
|
152377
152561
|
});
|
|
152378
|
-
|
|
152562
|
+
const due = !job || job.status === "pending" && job.runAfter <= Date.now();
|
|
152563
|
+
if (due && options.detachedWorker && options.projectRoot) {
|
|
152379
152564
|
void Promise.resolve().then(() => (init_vector_backfill_runner(), vector_backfill_runner_exports)).then(({ launchDetachedVectorBackfill: launchDetachedVectorBackfill2 }) => {
|
|
152380
152565
|
launchDetachedVectorBackfill2({
|
|
152381
152566
|
projectId,
|
|
@@ -153306,7 +153491,7 @@ async function backfillVectorEmbeddings(options = {}) {
|
|
|
153306
153491
|
...lastFailure ? { lastError: lastFailure } : {}
|
|
153307
153492
|
};
|
|
153308
153493
|
}
|
|
153309
|
-
var observations, nextId, projectDir, searchIndexPrepared, embeddingWriteMode, embeddingWorkerProjectRoot, corpusLoaded, loadedObservationStore, vectorMissingIds, vectorBackfillRunning, vectorSchemaUpgradePromise, lastVectorBackfill, embeddingFailureLogTimestamps, EMBEDDING_FAILURE_LOG_COOLDOWN_MS;
|
|
153494
|
+
var observations, nextId, projectDir, searchIndexPrepared, embeddingWriteMode, embeddingWorkerProjectRoot, corpusLoaded, loadedObservationStore, vectorMissingIds, vectorBackfillRunning, vectorSchemaUpgradePromise, lastVectorBackfill, embeddingFailureLogTimestamps, EMBEDDING_FAILURE_LOG_COOLDOWN_MS, MAX_EMBEDDING_FAILURE_KEYS;
|
|
153310
153495
|
var init_observations = __esm({
|
|
153311
153496
|
"src/memory/observations.ts"() {
|
|
153312
153497
|
"use strict";
|
|
@@ -153334,6 +153519,7 @@ var init_observations = __esm({
|
|
|
153334
153519
|
lastVectorBackfill = null;
|
|
153335
153520
|
embeddingFailureLogTimestamps = /* @__PURE__ */ new Map();
|
|
153336
153521
|
EMBEDDING_FAILURE_LOG_COOLDOWN_MS = 3e4;
|
|
153522
|
+
MAX_EMBEDDING_FAILURE_KEYS = 1024;
|
|
153337
153523
|
}
|
|
153338
153524
|
});
|
|
153339
153525
|
|
|
@@ -157010,7 +157196,7 @@ var init_sanitizer = __esm({
|
|
|
157010
157196
|
});
|
|
157011
157197
|
|
|
157012
157198
|
// src/workspace/applier.ts
|
|
157013
|
-
import { existsSync as existsSync13, mkdirSync as
|
|
157199
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync3, copyFileSync, writeFileSync as writeFileSync3, unlinkSync as unlinkSync2, renameSync } from "fs";
|
|
157014
157200
|
import { dirname } from "path";
|
|
157015
157201
|
var WorkspaceSyncApplier;
|
|
157016
157202
|
var init_applier = __esm({
|
|
@@ -157042,7 +157228,7 @@ var init_applier = __esm({
|
|
|
157042
157228
|
try {
|
|
157043
157229
|
const dir = dirname(file.filePath);
|
|
157044
157230
|
if (!existsSync13(dir)) {
|
|
157045
|
-
|
|
157231
|
+
mkdirSync3(dir, { recursive: true });
|
|
157046
157232
|
}
|
|
157047
157233
|
} catch (err) {
|
|
157048
157234
|
result.errors.push(`Cannot create directory for ${file.filePath}: ${err}`);
|
|
@@ -157067,7 +157253,7 @@ var init_applier = __esm({
|
|
|
157067
157253
|
for (const file of files) {
|
|
157068
157254
|
try {
|
|
157069
157255
|
const tempPath = file.filePath + `.tmp-${Date.now()}`;
|
|
157070
|
-
|
|
157256
|
+
writeFileSync3(tempPath, file.content, "utf-8");
|
|
157071
157257
|
renameSync(tempPath, file.filePath);
|
|
157072
157258
|
result.filesWritten.push(file.filePath);
|
|
157073
157259
|
} catch (err) {
|
|
@@ -157102,7 +157288,7 @@ var init_applier = __esm({
|
|
|
157102
157288
|
for (const backup of backups) {
|
|
157103
157289
|
try {
|
|
157104
157290
|
if (existsSync13(backup.backupPath)) {
|
|
157105
|
-
|
|
157291
|
+
unlinkSync2(backup.backupPath);
|
|
157106
157292
|
}
|
|
157107
157293
|
} catch {
|
|
157108
157294
|
}
|
|
@@ -157113,7 +157299,7 @@ var init_applier = __esm({
|
|
|
157113
157299
|
});
|
|
157114
157300
|
|
|
157115
157301
|
// src/workspace/engine.ts
|
|
157116
|
-
import { readFileSync as
|
|
157302
|
+
import { readFileSync as readFileSync10, readdirSync as readdirSync3, existsSync as existsSync14, cpSync, mkdirSync as mkdirSync4 } from "fs";
|
|
157117
157303
|
import { join as join19 } from "path";
|
|
157118
157304
|
import { homedir as homedir21 } from "os";
|
|
157119
157305
|
var WorkspaceSyncEngine;
|
|
@@ -157195,7 +157381,7 @@ var init_engine4 = __esm({
|
|
|
157195
157381
|
for (const path37 of pathsToCheck) {
|
|
157196
157382
|
if (existsSync14(path37)) {
|
|
157197
157383
|
try {
|
|
157198
|
-
const content =
|
|
157384
|
+
const content = readFileSync10(path37, "utf-8");
|
|
157199
157385
|
const servers = adapter.parse(content);
|
|
157200
157386
|
for (const s2 of servers) {
|
|
157201
157387
|
if (!merged.has(s2.name)) merged.set(s2.name, s2);
|
|
@@ -157249,7 +157435,7 @@ var init_engine4 = __esm({
|
|
|
157249
157435
|
let configContent;
|
|
157250
157436
|
if (target === "antigravity" && existsSync14(configPath)) {
|
|
157251
157437
|
try {
|
|
157252
|
-
const existing = JSON.parse(
|
|
157438
|
+
const existing = JSON.parse(readFileSync10(configPath, "utf-8"));
|
|
157253
157439
|
const generated = JSON.parse(adapter.generate(result.mcpServers.scanned));
|
|
157254
157440
|
existing.mcpServers = { ...existing.mcpServers ?? {}, ...generated.mcpServers };
|
|
157255
157441
|
configContent = JSON.stringify(existing, null, 2);
|
|
@@ -157332,7 +157518,7 @@ var init_engine4 = __esm({
|
|
|
157332
157518
|
if (!existsSync14(skillMd)) continue;
|
|
157333
157519
|
let description = "";
|
|
157334
157520
|
try {
|
|
157335
|
-
const content =
|
|
157521
|
+
const content = readFileSync10(skillMd, "utf-8");
|
|
157336
157522
|
const match2 = content.match(/^---[\s\S]*?description:\s*["']?(.+?)["']?\s*$/m);
|
|
157337
157523
|
if (match2) description = match2[1];
|
|
157338
157524
|
} catch {
|
|
@@ -157383,7 +157569,7 @@ var init_engine4 = __esm({
|
|
|
157383
157569
|
continue;
|
|
157384
157570
|
}
|
|
157385
157571
|
try {
|
|
157386
|
-
|
|
157572
|
+
mkdirSync4(targetDir, { recursive: true });
|
|
157387
157573
|
cpSync(skill2.sourcePath, dest, { recursive: true });
|
|
157388
157574
|
copied.push(skill2.name);
|
|
157389
157575
|
} catch {
|
|
@@ -157399,7 +157585,7 @@ var init_engine4 = __esm({
|
|
|
157399
157585
|
const files = readdirSync3(wfDir).filter((f3) => f3.endsWith(".md"));
|
|
157400
157586
|
for (const file of files) {
|
|
157401
157587
|
try {
|
|
157402
|
-
const content =
|
|
157588
|
+
const content = readFileSync10(join19(wfDir, file), "utf-8");
|
|
157403
157589
|
workflows.push(this.workflowSyncer.parseWindsurfWorkflow(file, content));
|
|
157404
157590
|
} catch {
|
|
157405
157591
|
}
|
|
@@ -158792,7 +158978,7 @@ var init_request_context = __esm({
|
|
|
158792
158978
|
function getMcpServerInfo() {
|
|
158793
158979
|
return {
|
|
158794
158980
|
name: "memorix",
|
|
158795
|
-
version: true ? "1.
|
|
158981
|
+
version: true ? "1.9.0" : "1.0.1"
|
|
158796
158982
|
};
|
|
158797
158983
|
}
|
|
158798
158984
|
function createMcpDiscoverResult(capabilities, serverInfo) {
|
|
@@ -158854,62 +159040,13 @@ var init_mcp_compat = __esm({
|
|
|
158854
159040
|
}
|
|
158855
159041
|
});
|
|
158856
159042
|
|
|
158857
|
-
// src/runtime/maintenance-targets.ts
|
|
158858
|
-
var maintenance_targets_exports = {};
|
|
158859
|
-
__export(maintenance_targets_exports, {
|
|
158860
|
-
MaintenanceTargetStore: () => MaintenanceTargetStore
|
|
158861
|
-
});
|
|
158862
|
-
function rowToTarget(row) {
|
|
158863
|
-
return {
|
|
158864
|
-
projectId: row.project_id,
|
|
158865
|
-
projectRoot: row.project_root,
|
|
158866
|
-
dataDir: row.data_dir,
|
|
158867
|
-
updatedAt: Number(row.updated_at)
|
|
158868
|
-
};
|
|
158869
|
-
}
|
|
158870
|
-
var MaintenanceTargetStore;
|
|
158871
|
-
var init_maintenance_targets = __esm({
|
|
158872
|
-
"src/runtime/maintenance-targets.ts"() {
|
|
158873
|
-
"use strict";
|
|
158874
|
-
init_esm_shims();
|
|
158875
|
-
init_sqlite_db();
|
|
158876
|
-
MaintenanceTargetStore = class {
|
|
158877
|
-
db;
|
|
158878
|
-
constructor(dataDir) {
|
|
158879
|
-
this.db = getDatabase(dataDir);
|
|
158880
|
-
}
|
|
158881
|
-
register(input) {
|
|
158882
|
-
if (!input.projectId.trim()) throw new Error("Maintenance target requires a project ID");
|
|
158883
|
-
if (!input.projectRoot.trim()) throw new Error("Maintenance target requires a project root");
|
|
158884
|
-
if (!input.dataDir.trim()) throw new Error("Maintenance target requires a data directory");
|
|
158885
|
-
const now3 = input.now ?? Date.now();
|
|
158886
|
-
this.db.prepare(`
|
|
158887
|
-
INSERT INTO maintenance_targets (project_id, project_root, data_dir, updated_at)
|
|
158888
|
-
VALUES (?, ?, ?, ?)
|
|
158889
|
-
ON CONFLICT(project_id) DO UPDATE SET
|
|
158890
|
-
project_root = excluded.project_root,
|
|
158891
|
-
data_dir = excluded.data_dir,
|
|
158892
|
-
updated_at = excluded.updated_at
|
|
158893
|
-
`).run(input.projectId, input.projectRoot, input.dataDir, now3);
|
|
158894
|
-
return this.get(input.projectId);
|
|
158895
|
-
}
|
|
158896
|
-
get(projectId) {
|
|
158897
|
-
const row = this.db.prepare(`
|
|
158898
|
-
SELECT * FROM maintenance_targets WHERE project_id = ?
|
|
158899
|
-
`).get(projectId);
|
|
158900
|
-
return row ? rowToTarget(row) : void 0;
|
|
158901
|
-
}
|
|
158902
|
-
};
|
|
158903
|
-
}
|
|
158904
|
-
});
|
|
158905
|
-
|
|
158906
159043
|
// src/config/behavior.ts
|
|
158907
159044
|
var behavior_exports = {};
|
|
158908
159045
|
__export(behavior_exports, {
|
|
158909
159046
|
getBehaviorConfig: () => getBehaviorConfig,
|
|
158910
159047
|
resetBehaviorConfigCache: () => resetBehaviorConfigCache
|
|
158911
159048
|
});
|
|
158912
|
-
import { existsSync as existsSync15, readFileSync as
|
|
159049
|
+
import { existsSync as existsSync15, readFileSync as readFileSync11 } from "fs";
|
|
158913
159050
|
import { homedir as homedir22 } from "os";
|
|
158914
159051
|
function isSessionInject(value) {
|
|
158915
159052
|
return value === "full" || value === "minimal" || value === "silent";
|
|
@@ -158921,7 +159058,7 @@ function legacyBehavior(homeDir) {
|
|
|
158921
159058
|
const configPath = getLegacyConfigJsonPath(homeDir);
|
|
158922
159059
|
try {
|
|
158923
159060
|
if (!existsSync15(configPath)) return {};
|
|
158924
|
-
const parsed = JSON.parse(
|
|
159061
|
+
const parsed = JSON.parse(readFileSync11(configPath, "utf-8"));
|
|
158925
159062
|
return parsed.behavior && typeof parsed.behavior === "object" && !Array.isArray(parsed.behavior) ? parsed.behavior : {};
|
|
158926
159063
|
} catch {
|
|
158927
159064
|
return {};
|
|
@@ -160274,12 +160411,12 @@ __export(current_facts_exports, {
|
|
|
160274
160411
|
formatGitFact: () => formatGitFact
|
|
160275
160412
|
});
|
|
160276
160413
|
import { execFileSync } from "child_process";
|
|
160277
|
-
import { existsSync as existsSync16, readFileSync as
|
|
160414
|
+
import { existsSync as existsSync16, readFileSync as readFileSync12 } from "fs";
|
|
160278
160415
|
import path28 from "path";
|
|
160279
160416
|
function readTextIfExists(filePath) {
|
|
160280
160417
|
try {
|
|
160281
160418
|
if (!existsSync16(filePath)) return null;
|
|
160282
|
-
return
|
|
160419
|
+
return readFileSync12(filePath, "utf8");
|
|
160283
160420
|
} catch {
|
|
160284
160421
|
return null;
|
|
160285
160422
|
}
|
|
@@ -160569,7 +160706,7 @@ __export(external_provider_exports, {
|
|
|
160569
160706
|
runExternalCodeGraphLifecycle: () => runExternalCodeGraphLifecycle
|
|
160570
160707
|
});
|
|
160571
160708
|
import { spawn as spawn5 } from "child_process";
|
|
160572
|
-
import { existsSync as existsSync17, readFileSync as
|
|
160709
|
+
import { existsSync as existsSync17, readFileSync as readFileSync13 } from "fs";
|
|
160573
160710
|
import { delimiter, dirname as dirname2, extname, isAbsolute as isAbsolute3, join as join20, relative as relative4, resolve as resolve3, sep } from "path";
|
|
160574
160711
|
function boundedTimeout(value) {
|
|
160575
160712
|
if (!Number.isFinite(value)) return DEFAULT_EXTERNAL_CODEGRAPH_TIMEOUT_MS;
|
|
@@ -160616,7 +160753,7 @@ function resolveLaunch(command) {
|
|
|
160616
160753
|
return { executable: node, prefixArgs: ["--liftoff-only", entry] };
|
|
160617
160754
|
}
|
|
160618
160755
|
try {
|
|
160619
|
-
const shim =
|
|
160756
|
+
const shim = readFileSync13(candidate, "utf8");
|
|
160620
160757
|
const match2 = shim.match(/["']([^"']*%(?:~)?dp0%?[^"']*\.m?js)["']/i);
|
|
160621
160758
|
if (match2?.[1]) {
|
|
160622
160759
|
const base = dirname2(candidate).endsWith(sep) ? dirname2(candidate) : dirname2(candidate) + sep;
|
|
@@ -161876,7 +162013,7 @@ __export(auto_context_exports, {
|
|
|
161876
162013
|
formatAutoProjectContextSummary: () => formatAutoProjectContextSummary,
|
|
161877
162014
|
formatLegacyAutoProjectContextPrompt: () => formatLegacyAutoProjectContextPrompt
|
|
161878
162015
|
});
|
|
161879
|
-
import { existsSync as existsSync18, statSync as
|
|
162016
|
+
import { existsSync as existsSync18, statSync as statSync5 } from "fs";
|
|
161880
162017
|
import path29 from "path";
|
|
161881
162018
|
function activeProjectObservations(observations2, projectId) {
|
|
161882
162019
|
return observations2.filter((obs) => obs.projectId === projectId && (obs.status ?? "active") === "active");
|
|
@@ -162223,7 +162360,7 @@ function existingLensCandidates(rootPath, lens) {
|
|
|
162223
162360
|
const absolute = path29.join(rootPath, candidate);
|
|
162224
162361
|
try {
|
|
162225
162362
|
if (!existsSync18(absolute)) continue;
|
|
162226
|
-
const stat5 =
|
|
162363
|
+
const stat5 = statSync5(absolute);
|
|
162227
162364
|
if (stat5.isFile()) out.push(candidate);
|
|
162228
162365
|
if (stat5.isDirectory()) out.push(candidate.replace(/\\/g, "/"));
|
|
162229
162366
|
} catch {
|
|
@@ -162756,7 +162893,7 @@ var engine_exports2 = {};
|
|
|
162756
162893
|
__export(engine_exports2, {
|
|
162757
162894
|
SkillsEngine: () => SkillsEngine
|
|
162758
162895
|
});
|
|
162759
|
-
import { existsSync as existsSync19, readFileSync as
|
|
162896
|
+
import { existsSync as existsSync19, readFileSync as readFileSync14, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5, readdirSync as readdirSync4 } from "fs";
|
|
162760
162897
|
import { join as join21 } from "path";
|
|
162761
162898
|
import { homedir as homedir23 } from "os";
|
|
162762
162899
|
var SKILLS_DIRS, SKILL_WORTHY_TYPES, MIN_OBS_FOR_SKILL, MIN_SCORE_FOR_SKILL, LOW_SIGNAL_TITLE_PATTERNS, LOW_SIGNAL_ENTITY_PATTERNS, COMMAND_TRACE_PATTERNS2, SkillsEngine;
|
|
@@ -162847,7 +162984,7 @@ var init_engine5 = __esm({
|
|
|
162847
162984
|
const skillMd = join21(skillsRoot, name, "SKILL.md");
|
|
162848
162985
|
if (!existsSync19(skillMd)) continue;
|
|
162849
162986
|
try {
|
|
162850
|
-
const content =
|
|
162987
|
+
const content = readFileSync14(skillMd, "utf-8");
|
|
162851
162988
|
const description = this.parseDescription(content);
|
|
162852
162989
|
skills.push({
|
|
162853
162990
|
name,
|
|
@@ -162897,8 +163034,8 @@ var init_engine5 = __esm({
|
|
|
162897
163034
|
if (!dirs || dirs.length === 0) return null;
|
|
162898
163035
|
const targetDir = join21(this.projectRoot, dirs[0], skill2.name);
|
|
162899
163036
|
try {
|
|
162900
|
-
|
|
162901
|
-
|
|
163037
|
+
mkdirSync5(targetDir, { recursive: true });
|
|
163038
|
+
writeFileSync4(join21(targetDir, "SKILL.md"), skill2.content, "utf-8");
|
|
162902
163039
|
return join21(dirs[0], skill2.name, "SKILL.md");
|
|
162903
163040
|
} catch {
|
|
162904
163041
|
return null;
|
|
@@ -166668,7 +166805,7 @@ var init_task_graph = __esm({
|
|
|
166668
166805
|
|
|
166669
166806
|
// src/orchestrate/context-collector.ts
|
|
166670
166807
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
166671
|
-
import { readFileSync as
|
|
166808
|
+
import { readFileSync as readFileSync15, existsSync as existsSync20 } from "fs";
|
|
166672
166809
|
import { join as join22 } from "path";
|
|
166673
166810
|
function normalizeEntryLimit(value, fallback) {
|
|
166674
166811
|
if (!Number.isSafeInteger(value) || value < 1) return fallback;
|
|
@@ -166746,7 +166883,7 @@ function collectDependencies(projectDir2) {
|
|
|
166746
166883
|
try {
|
|
166747
166884
|
const pkgPath = join22(projectDir2, "package.json");
|
|
166748
166885
|
if (!existsSync20(pkgPath)) return "";
|
|
166749
|
-
const pkg = JSON.parse(
|
|
166886
|
+
const pkg = JSON.parse(readFileSync15(pkgPath, "utf-8"));
|
|
166750
166887
|
const parts = [];
|
|
166751
166888
|
if (pkg.dependencies && Object.keys(pkg.dependencies).length > 0) {
|
|
166752
166889
|
parts.push(`dependencies: ${Object.keys(pkg.dependencies).join(", ")}`);
|
|
@@ -169246,18 +169383,18 @@ __export(hooks_path_exports, {
|
|
|
169246
169383
|
resolveGitDir: () => resolveGitDir,
|
|
169247
169384
|
resolveHooksDir: () => resolveHooksDir
|
|
169248
169385
|
});
|
|
169249
|
-
import { existsSync as existsSync21, readFileSync as
|
|
169386
|
+
import { existsSync as existsSync21, readFileSync as readFileSync16, statSync as statSync6, mkdirSync as mkdirSync6 } from "fs";
|
|
169250
169387
|
import path34 from "path";
|
|
169251
169388
|
function resolveGitDir(projectRoot) {
|
|
169252
169389
|
const dotGit = path34.join(projectRoot, ".git");
|
|
169253
169390
|
if (!existsSync21(dotGit)) return null;
|
|
169254
|
-
const stat5 =
|
|
169391
|
+
const stat5 = statSync6(dotGit);
|
|
169255
169392
|
if (stat5.isDirectory()) {
|
|
169256
169393
|
return dotGit;
|
|
169257
169394
|
}
|
|
169258
169395
|
if (stat5.isFile()) {
|
|
169259
169396
|
try {
|
|
169260
|
-
const content =
|
|
169397
|
+
const content = readFileSync16(dotGit, "utf-8").trim();
|
|
169261
169398
|
const match2 = content.match(/^gitdir:\s*(.+)$/);
|
|
169262
169399
|
if (match2) {
|
|
169263
169400
|
const gitdir = match2[1].trim();
|
|
@@ -169283,7 +169420,7 @@ function resolveHooksDir(projectRoot) {
|
|
|
169283
169420
|
function ensureHooksDir(projectRoot) {
|
|
169284
169421
|
const resolved = resolveHooksDir(projectRoot);
|
|
169285
169422
|
if (!resolved) return null;
|
|
169286
|
-
|
|
169423
|
+
mkdirSync6(resolved.hooksDir, { recursive: true });
|
|
169287
169424
|
return resolved;
|
|
169288
169425
|
}
|
|
169289
169426
|
var init_hooks_path = __esm({
|
|
@@ -173857,10 +173994,10 @@ Preview: ${analysis.description.slice(0, 300)}${analysis.description.length > 30
|
|
|
173857
173994
|
const { ensureHooksDir: ensureHooksDir2 } = await Promise.resolve().then(() => (init_hooks_path(), hooks_path_exports));
|
|
173858
173995
|
const resolved = ensureHooksDir2(project.rootPath);
|
|
173859
173996
|
if (resolved) {
|
|
173860
|
-
const { existsSync: existsSync22, readFileSync:
|
|
173997
|
+
const { existsSync: existsSync22, readFileSync: readFileSync17, writeFileSync: writeFileSync5, chmodSync } = await import("fs");
|
|
173861
173998
|
const { hookPath } = resolved;
|
|
173862
173999
|
const HOOK_MARKER = "# [memorix-git-hook]";
|
|
173863
|
-
const needsInstall = !existsSync22(hookPath) || !
|
|
174000
|
+
const needsInstall = !existsSync22(hookPath) || !readFileSync17(hookPath, "utf-8").includes(HOOK_MARKER);
|
|
173864
174001
|
if (needsInstall) {
|
|
173865
174002
|
const hookScript = `#!/bin/sh
|
|
173866
174003
|
${HOOK_MARKER}
|
|
@@ -173870,8 +174007,8 @@ if command -v memorix >/dev/null 2>&1; then
|
|
|
173870
174007
|
fi
|
|
173871
174008
|
`;
|
|
173872
174009
|
if (existsSync22(hookPath)) {
|
|
173873
|
-
const existing =
|
|
173874
|
-
|
|
174010
|
+
const existing = readFileSync17(hookPath, "utf-8");
|
|
174011
|
+
writeFileSync5(hookPath, existing.trimEnd() + `
|
|
173875
174012
|
|
|
173876
174013
|
${HOOK_MARKER}
|
|
173877
174014
|
if command -v memorix >/dev/null 2>&1; then
|
|
@@ -173879,7 +174016,7 @@ if command -v memorix >/dev/null 2>&1; then
|
|
|
173879
174016
|
fi
|
|
173880
174017
|
`, "utf-8");
|
|
173881
174018
|
} else {
|
|
173882
|
-
|
|
174019
|
+
writeFileSync5(hookPath, hookScript, "utf-8");
|
|
173883
174020
|
}
|
|
173884
174021
|
try {
|
|
173885
174022
|
chmodSync(hookPath, 493);
|
|
@@ -174541,7 +174678,7 @@ var init_serve_shared = __esm({
|
|
|
174541
174678
|
|
|
174542
174679
|
// src/cli/version.ts
|
|
174543
174680
|
function getCliVersion() {
|
|
174544
|
-
return true ? "1.
|
|
174681
|
+
return true ? "1.9.0" : pkg.version;
|
|
174545
174682
|
}
|
|
174546
174683
|
var init_version3 = __esm({
|
|
174547
174684
|
"src/cli/version.ts"() {
|