memorix 1.9.1 → 1.9.2
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 +11 -0
- package/README.md +17 -4
- package/README.zh-CN.md +8 -4
- package/dist/cli/index.js +132 -104
- package/dist/index.js +61 -47
- package/dist/maintenance-runner.js +10 -5
- package/dist/media-audio-runner.js +12 -7
- package/dist/media-video-runner.js +10 -5
- package/dist/memcode-runtime/CHANGELOG.md +11 -0
- package/dist/sdk.js +60 -46
- package/dist/vector-backfill-runner.js +10 -5
- package/docs/INTEGRATIONS.md +4 -0
- package/docs/SETUP.md +5 -0
- package/package.json +1 -2
- package/plugins/antigravity/memorix/plugin.json +1 -1
- package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
- package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
- package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/copilot/memorix/plugin.json +1 -1
- package/plugins/gemini/memorix/gemini-extension.json +1 -1
- package/plugins/hermes/memorix/plugin.yaml +1 -1
- package/plugins/omp/memorix/package.json +1 -1
- package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/pi/memorix/package.json +1 -1
- package/server.json +2 -2
- package/src/cli/commands/memory.ts +2 -1
- package/src/cli/default-mode.ts +15 -0
- package/src/cli/index.ts +10 -1
- package/src/codegraph/lite-provider.ts +10 -1
- package/src/dashboard/maintenance.ts +11 -2
- package/src/memory/consolidation.ts +15 -6
- package/assets/star-history-dark.svg +0 -30
- package/assets/star-history-light.svg +0 -30
- package/assets/star-history.json +0 -712
package/dist/index.js
CHANGED
|
@@ -10882,7 +10882,8 @@ function clampCursor(afterId) {
|
|
|
10882
10882
|
}
|
|
10883
10883
|
async function loadConsolidationPage(projectId, options) {
|
|
10884
10884
|
const limit2 = clampBatchSize(options.limit);
|
|
10885
|
-
const
|
|
10885
|
+
const store = options.store ?? getObservationStore();
|
|
10886
|
+
const page = await store.loadByProject(projectId, {
|
|
10886
10887
|
status: "active",
|
|
10887
10888
|
afterId: clampCursor(options.afterId),
|
|
10888
10889
|
limit: limit2 + 1
|
|
@@ -10942,7 +10943,7 @@ async function findConsolidationCandidates(_projectDir, projectId, opts) {
|
|
|
10942
10943
|
return findClusters(page.observations, threshold);
|
|
10943
10944
|
}
|
|
10944
10945
|
async function executeConsolidation(_projectDir, projectId, opts) {
|
|
10945
|
-
const store = getObservationStore();
|
|
10946
|
+
const store = opts?.store ?? getObservationStore();
|
|
10946
10947
|
const page = await loadConsolidationPage(projectId, opts ?? {});
|
|
10947
10948
|
const clusters = findClusters(page.observations, opts?.threshold ?? DEFAULT_SIMILARITY_THRESHOLD);
|
|
10948
10949
|
if (clusters.length === 0) {
|
|
@@ -148882,7 +148883,7 @@ __export(lite_provider_exports, {
|
|
|
148882
148883
|
refreshProjectLite: () => refreshProjectLite
|
|
148883
148884
|
});
|
|
148884
148885
|
import { createHash as createHash10 } from "crypto";
|
|
148885
|
-
import { readdirSync as readdirSync2, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
|
|
148886
|
+
import { existsSync as existsSync12, readdirSync as readdirSync2, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
|
|
148886
148887
|
import { join as join4, relative as relative2 } from "path";
|
|
148887
148888
|
function hashText2(text3) {
|
|
148888
148889
|
return createHash10("sha256").update(text3).digest("hex");
|
|
@@ -148899,6 +148900,9 @@ function resolveMaxFileBytes(value) {
|
|
|
148899
148900
|
if (!Number.isFinite(value)) return DEFAULT_CODEGRAPH_MAX_FILE_BYTES;
|
|
148900
148901
|
return Math.max(1, Math.floor(value));
|
|
148901
148902
|
}
|
|
148903
|
+
function isPythonVirtualenvDir(dir) {
|
|
148904
|
+
return existsSync12(join4(dir, "pyvenv.cfg"));
|
|
148905
|
+
}
|
|
148902
148906
|
function walk(root, exclude, maxFiles) {
|
|
148903
148907
|
const out = [];
|
|
148904
148908
|
const visit = (dir) => {
|
|
@@ -148916,6 +148920,7 @@ function walk(root, exclude, maxFiles) {
|
|
|
148916
148920
|
if (entry.isDirectory()) {
|
|
148917
148921
|
if (entry.name === ".git" || entry.name === ".worktrees" || entry.name === ".tmp" || entry.name === "node_modules") continue;
|
|
148918
148922
|
if (rel === ".claude/worktrees" || rel.startsWith(".claude/worktrees/")) continue;
|
|
148923
|
+
if (isPythonVirtualenvDir(abs)) continue;
|
|
148919
148924
|
visit(abs);
|
|
148920
148925
|
if (out.length >= maxFiles) return;
|
|
148921
148926
|
continue;
|
|
@@ -152812,7 +152817,7 @@ __export(vector_backfill_runner_exports, {
|
|
|
152812
152817
|
import { spawn as spawn4 } from "child_process";
|
|
152813
152818
|
import {
|
|
152814
152819
|
closeSync,
|
|
152815
|
-
existsSync as
|
|
152820
|
+
existsSync as existsSync13,
|
|
152816
152821
|
mkdirSync as mkdirSync2,
|
|
152817
152822
|
openSync,
|
|
152818
152823
|
readFileSync as readFileSync9,
|
|
@@ -152940,7 +152945,7 @@ function releaseVectorBackfillLock(lockPath = process.env.MEMORIX_VECTOR_BACKFIL
|
|
|
152940
152945
|
}
|
|
152941
152946
|
function launchDetachedVectorBackfill(request, options = {}) {
|
|
152942
152947
|
const runnerPath = options.runnerPath ?? resolveVectorBackfillRunnerPath();
|
|
152943
|
-
const exists = options.exists ??
|
|
152948
|
+
const exists = options.exists ?? existsSync13;
|
|
152944
152949
|
if (!exists(runnerPath)) return false;
|
|
152945
152950
|
const lock = acquireVectorBackfillLock(request.dataDir, request.projectId, options.lockPath);
|
|
152946
152951
|
if (!lock) return false;
|
|
@@ -157861,7 +157866,7 @@ var init_sanitizer = __esm({
|
|
|
157861
157866
|
});
|
|
157862
157867
|
|
|
157863
157868
|
// src/workspace/applier.ts
|
|
157864
|
-
import { existsSync as
|
|
157869
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync3, copyFileSync, writeFileSync as writeFileSync3, unlinkSync as unlinkSync2, renameSync } from "fs";
|
|
157865
157870
|
import { dirname } from "path";
|
|
157866
157871
|
var WorkspaceSyncApplier;
|
|
157867
157872
|
var init_applier = __esm({
|
|
@@ -157892,7 +157897,7 @@ var init_applier = __esm({
|
|
|
157892
157897
|
for (const file of files) {
|
|
157893
157898
|
try {
|
|
157894
157899
|
const dir = dirname(file.filePath);
|
|
157895
|
-
if (!
|
|
157900
|
+
if (!existsSync14(dir)) {
|
|
157896
157901
|
mkdirSync3(dir, { recursive: true });
|
|
157897
157902
|
}
|
|
157898
157903
|
} catch (err) {
|
|
@@ -157901,7 +157906,7 @@ var init_applier = __esm({
|
|
|
157901
157906
|
}
|
|
157902
157907
|
}
|
|
157903
157908
|
for (const file of files) {
|
|
157904
|
-
if (
|
|
157909
|
+
if (existsSync14(file.filePath)) {
|
|
157905
157910
|
try {
|
|
157906
157911
|
const backupPath = file.filePath + `.backup-${Date.now()}`;
|
|
157907
157912
|
copyFileSync(file.filePath, backupPath);
|
|
@@ -157952,7 +157957,7 @@ var init_applier = __esm({
|
|
|
157952
157957
|
cleanBackups(backups) {
|
|
157953
157958
|
for (const backup of backups) {
|
|
157954
157959
|
try {
|
|
157955
|
-
if (
|
|
157960
|
+
if (existsSync14(backup.backupPath)) {
|
|
157956
157961
|
unlinkSync2(backup.backupPath);
|
|
157957
157962
|
}
|
|
157958
157963
|
} catch {
|
|
@@ -157964,7 +157969,7 @@ var init_applier = __esm({
|
|
|
157964
157969
|
});
|
|
157965
157970
|
|
|
157966
157971
|
// src/workspace/engine.ts
|
|
157967
|
-
import { readFileSync as readFileSync10, readdirSync as readdirSync3, existsSync as
|
|
157972
|
+
import { readFileSync as readFileSync10, readdirSync as readdirSync3, existsSync as existsSync15, cpSync, mkdirSync as mkdirSync4 } from "fs";
|
|
157968
157973
|
import { join as join19 } from "path";
|
|
157969
157974
|
import { homedir as homedir21 } from "os";
|
|
157970
157975
|
var WorkspaceSyncEngine;
|
|
@@ -158044,7 +158049,7 @@ var init_engine4 = __esm({
|
|
|
158044
158049
|
}
|
|
158045
158050
|
const merged = /* @__PURE__ */ new Map();
|
|
158046
158051
|
for (const path38 of pathsToCheck) {
|
|
158047
|
-
if (
|
|
158052
|
+
if (existsSync15(path38)) {
|
|
158048
158053
|
try {
|
|
158049
158054
|
const content = readFileSync10(path38, "utf-8");
|
|
158050
158055
|
const servers = adapter.parse(content);
|
|
@@ -158098,7 +158103,7 @@ var init_engine4 = __esm({
|
|
|
158098
158103
|
const adapter = this.adapters.get(target);
|
|
158099
158104
|
const configPath = adapter.getConfigPath(this.projectRoot);
|
|
158100
158105
|
let configContent;
|
|
158101
|
-
if (target === "antigravity" &&
|
|
158106
|
+
if (target === "antigravity" && existsSync15(configPath)) {
|
|
158102
158107
|
try {
|
|
158103
158108
|
const existing = JSON.parse(readFileSync10(configPath, "utf-8"));
|
|
158104
158109
|
const generated = JSON.parse(adapter.generate(result.mcpServers.scanned));
|
|
@@ -158174,13 +158179,13 @@ var init_engine4 = __esm({
|
|
|
158174
158179
|
join19(home, dir)
|
|
158175
158180
|
];
|
|
158176
158181
|
for (const skillsRoot of paths) {
|
|
158177
|
-
if (!
|
|
158182
|
+
if (!existsSync15(skillsRoot)) continue;
|
|
158178
158183
|
try {
|
|
158179
158184
|
const entries = readdirSync3(skillsRoot, { withFileTypes: true });
|
|
158180
158185
|
for (const entry of entries) {
|
|
158181
158186
|
if (!entry.isDirectory()) continue;
|
|
158182
158187
|
const skillMd = join19(skillsRoot, entry.name, "SKILL.md");
|
|
158183
|
-
if (!
|
|
158188
|
+
if (!existsSync15(skillMd)) continue;
|
|
158184
158189
|
let description = "";
|
|
158185
158190
|
try {
|
|
158186
158191
|
const content = readFileSync10(skillMd, "utf-8");
|
|
@@ -158229,7 +158234,7 @@ var init_engine4 = __esm({
|
|
|
158229
158234
|
for (const skill2 of skills) {
|
|
158230
158235
|
if (skill2.sourceAgent === target) continue;
|
|
158231
158236
|
const dest = join19(targetDir, skill2.name);
|
|
158232
|
-
if (
|
|
158237
|
+
if (existsSync15(dest)) {
|
|
158233
158238
|
skipped.push(`${skill2.name} (already exists in ${target})`);
|
|
158234
158239
|
continue;
|
|
158235
158240
|
}
|
|
@@ -158245,7 +158250,7 @@ var init_engine4 = __esm({
|
|
|
158245
158250
|
scanWorkflows() {
|
|
158246
158251
|
const workflows = [];
|
|
158247
158252
|
const wfDir = join19(this.projectRoot, ".windsurf", "workflows");
|
|
158248
|
-
if (!
|
|
158253
|
+
if (!existsSync15(wfDir)) return workflows;
|
|
158249
158254
|
try {
|
|
158250
158255
|
const files = readdirSync3(wfDir).filter((f3) => f3.endsWith(".md"));
|
|
158251
158256
|
for (const file of files) {
|
|
@@ -159643,7 +159648,7 @@ var init_request_context = __esm({
|
|
|
159643
159648
|
function getMcpServerInfo() {
|
|
159644
159649
|
return {
|
|
159645
159650
|
name: "memorix",
|
|
159646
|
-
version: true ? "1.9.
|
|
159651
|
+
version: true ? "1.9.2" : "1.0.1"
|
|
159647
159652
|
};
|
|
159648
159653
|
}
|
|
159649
159654
|
function createMcpDiscoverResult(capabilities, serverInfo) {
|
|
@@ -159711,7 +159716,7 @@ __export(behavior_exports, {
|
|
|
159711
159716
|
getBehaviorConfig: () => getBehaviorConfig,
|
|
159712
159717
|
resetBehaviorConfigCache: () => resetBehaviorConfigCache
|
|
159713
159718
|
});
|
|
159714
|
-
import { existsSync as
|
|
159719
|
+
import { existsSync as existsSync16, readFileSync as readFileSync11 } from "fs";
|
|
159715
159720
|
import { homedir as homedir22 } from "os";
|
|
159716
159721
|
function isSessionInject(value) {
|
|
159717
159722
|
return value === "full" || value === "minimal" || value === "silent";
|
|
@@ -159722,7 +159727,7 @@ function isFormationMode(value) {
|
|
|
159722
159727
|
function legacyBehavior(homeDir) {
|
|
159723
159728
|
const configPath = getLegacyConfigJsonPath(homeDir);
|
|
159724
159729
|
try {
|
|
159725
|
-
if (!
|
|
159730
|
+
if (!existsSync16(configPath)) return {};
|
|
159726
159731
|
const parsed = JSON.parse(readFileSync11(configPath, "utf-8"));
|
|
159727
159732
|
return parsed.behavior && typeof parsed.behavior === "object" && !Array.isArray(parsed.behavior) ? parsed.behavior : {};
|
|
159728
159733
|
} catch {
|
|
@@ -161076,11 +161081,11 @@ __export(current_facts_exports, {
|
|
|
161076
161081
|
formatGitFact: () => formatGitFact
|
|
161077
161082
|
});
|
|
161078
161083
|
import { execFileSync } from "child_process";
|
|
161079
|
-
import { existsSync as
|
|
161084
|
+
import { existsSync as existsSync17, readFileSync as readFileSync12 } from "fs";
|
|
161080
161085
|
import path29 from "path";
|
|
161081
161086
|
function readTextIfExists(filePath) {
|
|
161082
161087
|
try {
|
|
161083
|
-
if (!
|
|
161088
|
+
if (!existsSync17(filePath)) return null;
|
|
161084
161089
|
return readFileSync12(filePath, "utf8");
|
|
161085
161090
|
} catch {
|
|
161086
161091
|
return null;
|
|
@@ -161371,7 +161376,7 @@ __export(external_provider_exports, {
|
|
|
161371
161376
|
runExternalCodeGraphLifecycle: () => runExternalCodeGraphLifecycle
|
|
161372
161377
|
});
|
|
161373
161378
|
import { spawn as spawn5 } from "child_process";
|
|
161374
|
-
import { existsSync as
|
|
161379
|
+
import { existsSync as existsSync18, readFileSync as readFileSync13 } from "fs";
|
|
161375
161380
|
import { delimiter, dirname as dirname2, extname, isAbsolute as isAbsolute3, join as join20, relative as relative4, resolve as resolve3, sep } from "path";
|
|
161376
161381
|
function boundedTimeout(value) {
|
|
161377
161382
|
if (!Number.isFinite(value)) return DEFAULT_EXTERNAL_CODEGRAPH_TIMEOUT_MS;
|
|
@@ -161408,13 +161413,13 @@ function resolveCommandCandidates(command) {
|
|
|
161408
161413
|
}
|
|
161409
161414
|
function resolveLaunch(command) {
|
|
161410
161415
|
for (const candidate of resolveCommandCandidates(command)) {
|
|
161411
|
-
if (!
|
|
161416
|
+
if (!existsSync18(candidate)) continue;
|
|
161412
161417
|
const extension3 = extname(candidate).toLowerCase();
|
|
161413
161418
|
if (extension3 === ".cmd") {
|
|
161414
161419
|
const bundleRoot = resolve3(dirname2(candidate), "..");
|
|
161415
161420
|
const node = join20(bundleRoot, "node.exe");
|
|
161416
161421
|
const entry = join20(bundleRoot, "lib", "dist", "bin", "codegraph.js");
|
|
161417
|
-
if (
|
|
161422
|
+
if (existsSync18(node) && existsSync18(entry)) {
|
|
161418
161423
|
return { executable: node, prefixArgs: ["--liftoff-only", entry] };
|
|
161419
161424
|
}
|
|
161420
161425
|
try {
|
|
@@ -161423,7 +161428,7 @@ function resolveLaunch(command) {
|
|
|
161423
161428
|
if (match2?.[1]) {
|
|
161424
161429
|
const base = dirname2(candidate).endsWith(sep) ? dirname2(candidate) : dirname2(candidate) + sep;
|
|
161425
161430
|
const entry2 = resolve3(match2[1].replace(/%(?:~)?dp0%?/gi, base));
|
|
161426
|
-
if (
|
|
161431
|
+
if (existsSync18(entry2)) return { executable: process.execPath, prefixArgs: [entry2] };
|
|
161427
161432
|
}
|
|
161428
161433
|
} catch {
|
|
161429
161434
|
}
|
|
@@ -161571,7 +161576,7 @@ async function inspectExternalCodeGraph(input) {
|
|
|
161571
161576
|
const health2 = { state: "disabled", reason: "External CodeGraph is disabled by configuration." };
|
|
161572
161577
|
return { health: health2, quality: providerQuality({ mode, health: health2 }) };
|
|
161573
161578
|
}
|
|
161574
|
-
if (!
|
|
161579
|
+
if (!existsSync18(join20(input.projectRoot, ".codegraph"))) {
|
|
161575
161580
|
const health2 = { state: "not-detected", reason: "No local .codegraph index is present for this project." };
|
|
161576
161581
|
return { health: health2, quality: providerQuality({ mode, health: health2 }) };
|
|
161577
161582
|
}
|
|
@@ -161607,7 +161612,7 @@ async function runExternalCodeGraphLifecycle(input) {
|
|
|
161607
161612
|
};
|
|
161608
161613
|
}
|
|
161609
161614
|
const indexPath = join20(input.projectRoot, ".codegraph");
|
|
161610
|
-
if (input.action === "sync" && !
|
|
161615
|
+
if (input.action === "sync" && !existsSync18(indexPath)) {
|
|
161611
161616
|
const health = { state: "not-detected", reason: "No local .codegraph index is present for this project." };
|
|
161612
161617
|
return {
|
|
161613
161618
|
action: input.action,
|
|
@@ -161617,7 +161622,7 @@ async function runExternalCodeGraphLifecycle(input) {
|
|
|
161617
161622
|
quality: providerQuality({ mode, health })
|
|
161618
161623
|
};
|
|
161619
161624
|
}
|
|
161620
|
-
if (input.action === "init" &&
|
|
161625
|
+
if (input.action === "init" && existsSync18(indexPath)) {
|
|
161621
161626
|
const inspected2 = await inspectExternalCodeGraph(input);
|
|
161622
161627
|
return {
|
|
161623
161628
|
action: input.action,
|
|
@@ -162678,7 +162683,7 @@ __export(auto_context_exports, {
|
|
|
162678
162683
|
formatAutoProjectContextSummary: () => formatAutoProjectContextSummary,
|
|
162679
162684
|
formatLegacyAutoProjectContextPrompt: () => formatLegacyAutoProjectContextPrompt
|
|
162680
162685
|
});
|
|
162681
|
-
import { existsSync as
|
|
162686
|
+
import { existsSync as existsSync19, statSync as statSync5 } from "fs";
|
|
162682
162687
|
import path30 from "path";
|
|
162683
162688
|
function activeProjectObservations(observations2, projectId) {
|
|
162684
162689
|
return observations2.filter((obs) => obs.projectId === projectId && (obs.status ?? "active") === "active");
|
|
@@ -163024,7 +163029,7 @@ function existingLensCandidates(rootPath, lens) {
|
|
|
163024
163029
|
for (const candidate of lensPathCandidates(lens)) {
|
|
163025
163030
|
const absolute = path30.join(rootPath, candidate);
|
|
163026
163031
|
try {
|
|
163027
|
-
if (!
|
|
163032
|
+
if (!existsSync19(absolute)) continue;
|
|
163028
163033
|
const stat5 = statSync5(absolute);
|
|
163029
163034
|
if (stat5.isFile()) out.push(candidate);
|
|
163030
163035
|
if (stat5.isDirectory()) out.push(candidate.replace(/\\/g, "/"));
|
|
@@ -163558,7 +163563,7 @@ var engine_exports2 = {};
|
|
|
163558
163563
|
__export(engine_exports2, {
|
|
163559
163564
|
SkillsEngine: () => SkillsEngine
|
|
163560
163565
|
});
|
|
163561
|
-
import { existsSync as
|
|
163566
|
+
import { existsSync as existsSync20, readFileSync as readFileSync14, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5, readdirSync as readdirSync4 } from "fs";
|
|
163562
163567
|
import { join as join21 } from "path";
|
|
163563
163568
|
import { homedir as homedir23 } from "os";
|
|
163564
163569
|
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;
|
|
@@ -163639,7 +163644,7 @@ var init_engine5 = __esm({
|
|
|
163639
163644
|
paths.push(join21(home, dir));
|
|
163640
163645
|
}
|
|
163641
163646
|
for (const skillsRoot of paths) {
|
|
163642
|
-
if (!
|
|
163647
|
+
if (!existsSync20(skillsRoot)) continue;
|
|
163643
163648
|
try {
|
|
163644
163649
|
const entries = readdirSync4(skillsRoot, { withFileTypes: true });
|
|
163645
163650
|
for (const entry of entries) {
|
|
@@ -163647,7 +163652,7 @@ var init_engine5 = __esm({
|
|
|
163647
163652
|
const name = entry.name;
|
|
163648
163653
|
if (seen.has(name)) continue;
|
|
163649
163654
|
const skillMd = join21(skillsRoot, name, "SKILL.md");
|
|
163650
|
-
if (!
|
|
163655
|
+
if (!existsSync20(skillMd)) continue;
|
|
163651
163656
|
try {
|
|
163652
163657
|
const content = readFileSync14(skillMd, "utf-8");
|
|
163653
163658
|
const description = this.parseDescription(content);
|
|
@@ -165448,7 +165453,8 @@ async function executeDeduplicate(context, payload, token) {
|
|
|
165448
165453
|
async function previewConsolidate(context) {
|
|
165449
165454
|
const clusters = await findConsolidationCandidates(
|
|
165450
165455
|
context.projectRoot ?? context.dataDir,
|
|
165451
|
-
context.projectId
|
|
165456
|
+
context.projectId,
|
|
165457
|
+
{ store: context.store }
|
|
165452
165458
|
);
|
|
165453
165459
|
const payload = { clusterIds: normalizeClusters(clusters.map((cluster) => cluster.ids)) };
|
|
165454
165460
|
return {
|
|
@@ -165471,11 +165477,19 @@ async function executeConsolidate(context, payload, token) {
|
|
|
165471
165477
|
const clusterIds = record80.clusterIds.map((ids, index) => payloadIds(ids, `clusterIds[${index}]`));
|
|
165472
165478
|
const normalized = { clusterIds: normalizeClusters(clusterIds) };
|
|
165473
165479
|
verify("consolidate", context.projectId, normalized, token);
|
|
165474
|
-
const current = await findConsolidationCandidates(
|
|
165480
|
+
const current = await findConsolidationCandidates(
|
|
165481
|
+
context.projectRoot ?? context.dataDir,
|
|
165482
|
+
context.projectId,
|
|
165483
|
+
{ store: context.store }
|
|
165484
|
+
);
|
|
165475
165485
|
if (JSON.stringify(normalized.clusterIds) !== JSON.stringify(normalizeClusters(current.map((cluster) => cluster.ids)))) {
|
|
165476
165486
|
throw new DashboardMaintenanceError("Memory changed after the preview. Refresh before consolidating.", 409);
|
|
165477
165487
|
}
|
|
165478
|
-
const result = await executeConsolidation(
|
|
165488
|
+
const result = await executeConsolidation(
|
|
165489
|
+
context.projectRoot ?? context.dataDir,
|
|
165490
|
+
context.projectId,
|
|
165491
|
+
{ store: context.store }
|
|
165492
|
+
);
|
|
165479
165493
|
return { action: "consolidate", projectId: context.projectId, ...result };
|
|
165480
165494
|
}
|
|
165481
165495
|
async function retentionCandidates(context) {
|
|
@@ -166632,7 +166646,7 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
166632
166646
|
}
|
|
166633
166647
|
case "/config": {
|
|
166634
166648
|
const os6 = await import("os");
|
|
166635
|
-
const { existsSync:
|
|
166649
|
+
const { existsSync: existsSync23 } = await import("fs");
|
|
166636
166650
|
const { join: join26 } = await import("path");
|
|
166637
166651
|
const configProjectRoot = effectiveProjectRoot;
|
|
166638
166652
|
const resolved = getResolvedConfig({ projectRoot: configProjectRoot });
|
|
@@ -166660,7 +166674,7 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
|
|
|
166660
166674
|
if (fpath === null) {
|
|
166661
166675
|
files[key] = { exists: false, path: "unavailable", unavailable: true };
|
|
166662
166676
|
} else {
|
|
166663
|
-
files[key] = { exists:
|
|
166677
|
+
files[key] = { exists: existsSync23(fpath), path: fpath };
|
|
166664
166678
|
}
|
|
166665
166679
|
}
|
|
166666
166680
|
} catch {
|
|
@@ -167470,7 +167484,7 @@ var init_task_graph = __esm({
|
|
|
167470
167484
|
|
|
167471
167485
|
// src/orchestrate/context-collector.ts
|
|
167472
167486
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
167473
|
-
import { readFileSync as readFileSync15, existsSync as
|
|
167487
|
+
import { readFileSync as readFileSync15, existsSync as existsSync21 } from "fs";
|
|
167474
167488
|
import { join as join22 } from "path";
|
|
167475
167489
|
function normalizeEntryLimit(value, fallback) {
|
|
167476
167490
|
if (!Number.isSafeInteger(value) || value < 1) return fallback;
|
|
@@ -167547,7 +167561,7 @@ function collectFileTree(projectDir2, maxEntries) {
|
|
|
167547
167561
|
function collectDependencies(projectDir2) {
|
|
167548
167562
|
try {
|
|
167549
167563
|
const pkgPath = join22(projectDir2, "package.json");
|
|
167550
|
-
if (!
|
|
167564
|
+
if (!existsSync21(pkgPath)) return "";
|
|
167551
167565
|
const pkg = JSON.parse(readFileSync15(pkgPath, "utf-8"));
|
|
167552
167566
|
const parts = [];
|
|
167553
167567
|
if (pkg.dependencies && Object.keys(pkg.dependencies).length > 0) {
|
|
@@ -170048,11 +170062,11 @@ __export(hooks_path_exports, {
|
|
|
170048
170062
|
resolveGitDir: () => resolveGitDir,
|
|
170049
170063
|
resolveHooksDir: () => resolveHooksDir
|
|
170050
170064
|
});
|
|
170051
|
-
import { existsSync as
|
|
170065
|
+
import { existsSync as existsSync22, readFileSync as readFileSync16, statSync as statSync6, mkdirSync as mkdirSync6 } from "fs";
|
|
170052
170066
|
import path35 from "path";
|
|
170053
170067
|
function resolveGitDir(projectRoot) {
|
|
170054
170068
|
const dotGit = path35.join(projectRoot, ".git");
|
|
170055
|
-
if (!
|
|
170069
|
+
if (!existsSync22(dotGit)) return null;
|
|
170056
170070
|
const stat5 = statSync6(dotGit);
|
|
170057
170071
|
if (stat5.isDirectory()) {
|
|
170058
170072
|
return dotGit;
|
|
@@ -170064,7 +170078,7 @@ function resolveGitDir(projectRoot) {
|
|
|
170064
170078
|
if (match2) {
|
|
170065
170079
|
const gitdir = match2[1].trim();
|
|
170066
170080
|
const resolved = path35.isAbsolute(gitdir) ? gitdir : path35.resolve(projectRoot, gitdir);
|
|
170067
|
-
if (
|
|
170081
|
+
if (existsSync22(resolved)) {
|
|
170068
170082
|
return resolved;
|
|
170069
170083
|
}
|
|
170070
170084
|
}
|
|
@@ -174659,10 +174673,10 @@ Preview: ${analysis.description.slice(0, 300)}${analysis.description.length > 30
|
|
|
174659
174673
|
const { ensureHooksDir: ensureHooksDir2 } = await Promise.resolve().then(() => (init_hooks_path(), hooks_path_exports));
|
|
174660
174674
|
const resolved = ensureHooksDir2(project.rootPath);
|
|
174661
174675
|
if (resolved) {
|
|
174662
|
-
const { existsSync:
|
|
174676
|
+
const { existsSync: existsSync23, readFileSync: readFileSync17, writeFileSync: writeFileSync5, chmodSync } = await import("fs");
|
|
174663
174677
|
const { hookPath } = resolved;
|
|
174664
174678
|
const HOOK_MARKER = "# [memorix-git-hook]";
|
|
174665
|
-
const needsInstall = !
|
|
174679
|
+
const needsInstall = !existsSync23(hookPath) || !readFileSync17(hookPath, "utf-8").includes(HOOK_MARKER);
|
|
174666
174680
|
if (needsInstall) {
|
|
174667
174681
|
const hookScript = `#!/bin/sh
|
|
174668
174682
|
${HOOK_MARKER}
|
|
@@ -174671,7 +174685,7 @@ if command -v memorix >/dev/null 2>&1; then
|
|
|
174671
174685
|
memorix ingest commit --auto >/dev/null 2>&1 &
|
|
174672
174686
|
fi
|
|
174673
174687
|
`;
|
|
174674
|
-
if (
|
|
174688
|
+
if (existsSync23(hookPath)) {
|
|
174675
174689
|
const existing = readFileSync17(hookPath, "utf-8");
|
|
174676
174690
|
writeFileSync5(hookPath, existing.trimEnd() + `
|
|
174677
174691
|
|
|
@@ -175343,7 +175357,7 @@ var init_serve_shared = __esm({
|
|
|
175343
175357
|
|
|
175344
175358
|
// src/cli/version.ts
|
|
175345
175359
|
function getCliVersion() {
|
|
175346
|
-
return true ? "1.9.
|
|
175360
|
+
return true ? "1.9.2" : pkg.version;
|
|
175347
175361
|
}
|
|
175348
175362
|
var init_version3 = __esm({
|
|
175349
175363
|
"src/cli/version.ts"() {
|
|
@@ -9418,7 +9418,8 @@ function clampCursor(afterId) {
|
|
|
9418
9418
|
}
|
|
9419
9419
|
async function loadConsolidationPage(projectId, options) {
|
|
9420
9420
|
const limit2 = clampBatchSize(options.limit);
|
|
9421
|
-
const
|
|
9421
|
+
const store = options.store ?? getObservationStore();
|
|
9422
|
+
const page = await store.loadByProject(projectId, {
|
|
9422
9423
|
status: "active",
|
|
9423
9424
|
afterId: clampCursor(options.afterId),
|
|
9424
9425
|
limit: limit2 + 1
|
|
@@ -9478,7 +9479,7 @@ async function findConsolidationCandidates(_projectDir, projectId, opts) {
|
|
|
9478
9479
|
return findClusters(page.observations, threshold);
|
|
9479
9480
|
}
|
|
9480
9481
|
async function executeConsolidation(_projectDir, projectId, opts) {
|
|
9481
|
-
const store = getObservationStore();
|
|
9482
|
+
const store = opts?.store ?? getObservationStore();
|
|
9482
9483
|
const page = await loadConsolidationPage(projectId, opts ?? {});
|
|
9483
9484
|
const clusters = findClusters(page.observations, opts?.threshold ?? DEFAULT_SIMILARITY_THRESHOLD);
|
|
9484
9485
|
if (clusters.length === 0) {
|
|
@@ -147104,7 +147105,7 @@ __export(lite_provider_exports, {
|
|
|
147104
147105
|
refreshProjectLite: () => refreshProjectLite
|
|
147105
147106
|
});
|
|
147106
147107
|
import { createHash as createHash10 } from "crypto";
|
|
147107
|
-
import { readdirSync as readdirSync2, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
|
|
147108
|
+
import { existsSync as existsSync12, readdirSync as readdirSync2, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
|
|
147108
147109
|
import { join as join4, relative as relative2 } from "path";
|
|
147109
147110
|
function hashText2(text2) {
|
|
147110
147111
|
return createHash10("sha256").update(text2).digest("hex");
|
|
@@ -147121,6 +147122,9 @@ function resolveMaxFileBytes(value) {
|
|
|
147121
147122
|
if (!Number.isFinite(value)) return DEFAULT_CODEGRAPH_MAX_FILE_BYTES;
|
|
147122
147123
|
return Math.max(1, Math.floor(value));
|
|
147123
147124
|
}
|
|
147125
|
+
function isPythonVirtualenvDir(dir) {
|
|
147126
|
+
return existsSync12(join4(dir, "pyvenv.cfg"));
|
|
147127
|
+
}
|
|
147124
147128
|
function walk(root, exclude, maxFiles) {
|
|
147125
147129
|
const out = [];
|
|
147126
147130
|
const visit = (dir) => {
|
|
@@ -147138,6 +147142,7 @@ function walk(root, exclude, maxFiles) {
|
|
|
147138
147142
|
if (entry.isDirectory()) {
|
|
147139
147143
|
if (entry.name === ".git" || entry.name === ".worktrees" || entry.name === ".tmp" || entry.name === "node_modules") continue;
|
|
147140
147144
|
if (rel === ".claude/worktrees" || rel.startsWith(".claude/worktrees/")) continue;
|
|
147145
|
+
if (isPythonVirtualenvDir(abs)) continue;
|
|
147141
147146
|
visit(abs);
|
|
147142
147147
|
if (out.length >= maxFiles) return;
|
|
147143
147148
|
continue;
|
|
@@ -150657,7 +150662,7 @@ __export(vector_backfill_runner_exports, {
|
|
|
150657
150662
|
import { spawn as spawn4 } from "child_process";
|
|
150658
150663
|
import {
|
|
150659
150664
|
closeSync,
|
|
150660
|
-
existsSync as
|
|
150665
|
+
existsSync as existsSync13,
|
|
150661
150666
|
mkdirSync as mkdirSync2,
|
|
150662
150667
|
openSync,
|
|
150663
150668
|
readFileSync as readFileSync9,
|
|
@@ -150785,7 +150790,7 @@ function releaseVectorBackfillLock(lockPath = process.env.MEMORIX_VECTOR_BACKFIL
|
|
|
150785
150790
|
}
|
|
150786
150791
|
function launchDetachedVectorBackfill(request, options = {}) {
|
|
150787
150792
|
const runnerPath = options.runnerPath ?? resolveVectorBackfillRunnerPath();
|
|
150788
|
-
const exists = options.exists ??
|
|
150793
|
+
const exists = options.exists ?? existsSync13;
|
|
150789
150794
|
if (!exists(runnerPath)) return false;
|
|
150790
150795
|
const lock = acquireVectorBackfillLock(request.dataDir, request.projectId, options.lockPath);
|
|
150791
150796
|
if (!lock) return false;
|
|
@@ -9870,7 +9870,8 @@ function clampCursor(afterId) {
|
|
|
9870
9870
|
}
|
|
9871
9871
|
async function loadConsolidationPage(projectId, options) {
|
|
9872
9872
|
const limit2 = clampBatchSize(options.limit);
|
|
9873
|
-
const
|
|
9873
|
+
const store = options.store ?? getObservationStore();
|
|
9874
|
+
const page = await store.loadByProject(projectId, {
|
|
9874
9875
|
status: "active",
|
|
9875
9876
|
afterId: clampCursor(options.afterId),
|
|
9876
9877
|
limit: limit2 + 1
|
|
@@ -9930,7 +9931,7 @@ async function findConsolidationCandidates(_projectDir, projectId, opts) {
|
|
|
9930
9931
|
return findClusters(page.observations, threshold);
|
|
9931
9932
|
}
|
|
9932
9933
|
async function executeConsolidation(_projectDir, projectId, opts) {
|
|
9933
|
-
const store = getObservationStore();
|
|
9934
|
+
const store = opts?.store ?? getObservationStore();
|
|
9934
9935
|
const page = await loadConsolidationPage(projectId, opts ?? {});
|
|
9935
9936
|
const clusters = findClusters(page.observations, opts?.threshold ?? DEFAULT_SIMILARITY_THRESHOLD);
|
|
9936
9937
|
if (clusters.length === 0) {
|
|
@@ -146735,7 +146736,7 @@ __export(lite_provider_exports, {
|
|
|
146735
146736
|
refreshProjectLite: () => refreshProjectLite
|
|
146736
146737
|
});
|
|
146737
146738
|
import { createHash as createHash10 } from "crypto";
|
|
146738
|
-
import { readdirSync as readdirSync2, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
|
|
146739
|
+
import { existsSync as existsSync10, readdirSync as readdirSync2, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
|
|
146739
146740
|
import { join as join4, relative as relative2 } from "path";
|
|
146740
146741
|
function hashText2(text2) {
|
|
146741
146742
|
return createHash10("sha256").update(text2).digest("hex");
|
|
@@ -146752,6 +146753,9 @@ function resolveMaxFileBytes(value) {
|
|
|
146752
146753
|
if (!Number.isFinite(value)) return DEFAULT_CODEGRAPH_MAX_FILE_BYTES;
|
|
146753
146754
|
return Math.max(1, Math.floor(value));
|
|
146754
146755
|
}
|
|
146756
|
+
function isPythonVirtualenvDir(dir) {
|
|
146757
|
+
return existsSync10(join4(dir, "pyvenv.cfg"));
|
|
146758
|
+
}
|
|
146755
146759
|
function walk(root, exclude, maxFiles) {
|
|
146756
146760
|
const out = [];
|
|
146757
146761
|
const visit = (dir) => {
|
|
@@ -146769,6 +146773,7 @@ function walk(root, exclude, maxFiles) {
|
|
|
146769
146773
|
if (entry.isDirectory()) {
|
|
146770
146774
|
if (entry.name === ".git" || entry.name === ".worktrees" || entry.name === ".tmp" || entry.name === "node_modules") continue;
|
|
146771
146775
|
if (rel === ".claude/worktrees" || rel.startsWith(".claude/worktrees/")) continue;
|
|
146776
|
+
if (isPythonVirtualenvDir(abs)) continue;
|
|
146772
146777
|
visit(abs);
|
|
146773
146778
|
if (out.length >= maxFiles) return;
|
|
146774
146779
|
continue;
|
|
@@ -150288,7 +150293,7 @@ __export(vector_backfill_runner_exports, {
|
|
|
150288
150293
|
import { spawn as spawn2 } from "child_process";
|
|
150289
150294
|
import {
|
|
150290
150295
|
closeSync,
|
|
150291
|
-
existsSync as
|
|
150296
|
+
existsSync as existsSync11,
|
|
150292
150297
|
mkdirSync as mkdirSync2,
|
|
150293
150298
|
openSync,
|
|
150294
150299
|
readFileSync as readFileSync9,
|
|
@@ -150416,7 +150421,7 @@ function releaseVectorBackfillLock(lockPath = process.env.MEMORIX_VECTOR_BACKFIL
|
|
|
150416
150421
|
}
|
|
150417
150422
|
function launchDetachedVectorBackfill(request, options = {}) {
|
|
150418
150423
|
const runnerPath = options.runnerPath ?? resolveVectorBackfillRunnerPath();
|
|
150419
|
-
const exists = options.exists ??
|
|
150424
|
+
const exists = options.exists ?? existsSync11;
|
|
150420
150425
|
if (!exists(runnerPath)) return false;
|
|
150421
150426
|
const lock = acquireVectorBackfillLock(request.dataDir, request.projectId, options.lockPath);
|
|
150422
150427
|
if (!lock) return false;
|
|
@@ -151711,7 +151716,7 @@ __export(audio_jobs_exports, {
|
|
|
151711
151716
|
transcribeAudio: () => transcribeAudio
|
|
151712
151717
|
});
|
|
151713
151718
|
import { spawn as spawn3 } from "child_process";
|
|
151714
|
-
import { existsSync as
|
|
151719
|
+
import { existsSync as existsSync12 } from "fs";
|
|
151715
151720
|
import path21 from "path";
|
|
151716
151721
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
151717
151722
|
function safeError3(error) {
|
|
@@ -151962,7 +151967,7 @@ function resolveMediaAudioRunnerPath(moduleUrl = import.meta.url) {
|
|
|
151962
151967
|
}
|
|
151963
151968
|
function launchMediaAudioRunner(request, options = {}) {
|
|
151964
151969
|
const runnerPath = options.runnerPath ?? resolveMediaAudioRunnerPath();
|
|
151965
|
-
if (!
|
|
151970
|
+
if (!existsSync12(runnerPath)) return { launched: false, reason: "Audio runner is unavailable until Memorix is built or reinstalled." };
|
|
151966
151971
|
try {
|
|
151967
151972
|
const child = spawn3(process.execPath, [runnerPath, JSON.stringify(request)], {
|
|
151968
151973
|
cwd: request.projectRoot,
|
|
@@ -9388,7 +9388,8 @@ function clampCursor(afterId) {
|
|
|
9388
9388
|
}
|
|
9389
9389
|
async function loadConsolidationPage(projectId, options) {
|
|
9390
9390
|
const limit2 = clampBatchSize(options.limit);
|
|
9391
|
-
const
|
|
9391
|
+
const store = options.store ?? getObservationStore();
|
|
9392
|
+
const page = await store.loadByProject(projectId, {
|
|
9392
9393
|
status: "active",
|
|
9393
9394
|
afterId: clampCursor(options.afterId),
|
|
9394
9395
|
limit: limit2 + 1
|
|
@@ -9448,7 +9449,7 @@ async function findConsolidationCandidates(_projectDir, projectId, opts) {
|
|
|
9448
9449
|
return findClusters(page.observations, threshold);
|
|
9449
9450
|
}
|
|
9450
9451
|
async function executeConsolidation(_projectDir, projectId, opts) {
|
|
9451
|
-
const store = getObservationStore();
|
|
9452
|
+
const store = opts?.store ?? getObservationStore();
|
|
9452
9453
|
const page = await loadConsolidationPage(projectId, opts ?? {});
|
|
9453
9454
|
const clusters = findClusters(page.observations, opts?.threshold ?? DEFAULT_SIMILARITY_THRESHOLD);
|
|
9454
9455
|
if (clusters.length === 0) {
|
|
@@ -147074,7 +147075,7 @@ __export(lite_provider_exports, {
|
|
|
147074
147075
|
refreshProjectLite: () => refreshProjectLite
|
|
147075
147076
|
});
|
|
147076
147077
|
import { createHash as createHash10 } from "crypto";
|
|
147077
|
-
import { readdirSync as readdirSync2, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
|
|
147078
|
+
import { existsSync as existsSync11, readdirSync as readdirSync2, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
|
|
147078
147079
|
import { join as join4, relative as relative2 } from "path";
|
|
147079
147080
|
function hashText2(text2) {
|
|
147080
147081
|
return createHash10("sha256").update(text2).digest("hex");
|
|
@@ -147091,6 +147092,9 @@ function resolveMaxFileBytes(value) {
|
|
|
147091
147092
|
if (!Number.isFinite(value)) return DEFAULT_CODEGRAPH_MAX_FILE_BYTES;
|
|
147092
147093
|
return Math.max(1, Math.floor(value));
|
|
147093
147094
|
}
|
|
147095
|
+
function isPythonVirtualenvDir(dir) {
|
|
147096
|
+
return existsSync11(join4(dir, "pyvenv.cfg"));
|
|
147097
|
+
}
|
|
147094
147098
|
function walk(root, exclude, maxFiles) {
|
|
147095
147099
|
const out = [];
|
|
147096
147100
|
const visit = (dir) => {
|
|
@@ -147108,6 +147112,7 @@ function walk(root, exclude, maxFiles) {
|
|
|
147108
147112
|
if (entry.isDirectory()) {
|
|
147109
147113
|
if (entry.name === ".git" || entry.name === ".worktrees" || entry.name === ".tmp" || entry.name === "node_modules") continue;
|
|
147110
147114
|
if (rel === ".claude/worktrees" || rel.startsWith(".claude/worktrees/")) continue;
|
|
147115
|
+
if (isPythonVirtualenvDir(abs)) continue;
|
|
147111
147116
|
visit(abs);
|
|
147112
147117
|
if (out.length >= maxFiles) return;
|
|
147113
147118
|
continue;
|
|
@@ -150627,7 +150632,7 @@ __export(vector_backfill_runner_exports, {
|
|
|
150627
150632
|
import { spawn as spawn3 } from "child_process";
|
|
150628
150633
|
import {
|
|
150629
150634
|
closeSync,
|
|
150630
|
-
existsSync as
|
|
150635
|
+
existsSync as existsSync12,
|
|
150631
150636
|
mkdirSync as mkdirSync2,
|
|
150632
150637
|
openSync,
|
|
150633
150638
|
readFileSync as readFileSync9,
|
|
@@ -150755,7 +150760,7 @@ function releaseVectorBackfillLock(lockPath = process.env.MEMORIX_VECTOR_BACKFIL
|
|
|
150755
150760
|
}
|
|
150756
150761
|
function launchDetachedVectorBackfill(request, options = {}) {
|
|
150757
150762
|
const runnerPath = options.runnerPath ?? resolveVectorBackfillRunnerPath();
|
|
150758
|
-
const exists = options.exists ??
|
|
150763
|
+
const exists = options.exists ?? existsSync12;
|
|
150759
150764
|
if (!exists(runnerPath)) return false;
|
|
150760
150765
|
const lock = acquireVectorBackfillLock(request.dataDir, request.projectId, options.lockPath);
|
|
150761
150766
|
if (!lock) return false;
|
|
@@ -4,6 +4,17 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [1.9.2] - 2026-09-11
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- **Non-interactive MCP startup** -- running the package without arguments
|
|
11
|
+
through piped stdio now starts the MCP server, while a real terminal keeps
|
|
12
|
+
opening the bundled memcode agent. This makes generic npm MCP launchers and
|
|
13
|
+
registry handshake checks use the correct protocol entry point.
|
|
14
|
+
- **Maintenance initialization** -- dashboard Consolidate uses its
|
|
15
|
+
request-scoped observation store, and CLI deduplication initializes the
|
|
16
|
+
project memory LLM before checking availability.
|
|
17
|
+
|
|
7
18
|
## [1.9.1] - 2026-09-08
|
|
8
19
|
|
|
9
20
|
### Changed
|