mnemosyne-core 2.0.2 → 2.1.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/README.md +42 -25
- package/dist/{Store-BtdYuiUx.d.mts → Store-BJ8b6xbs.d.mts} +2 -0
- package/dist/{Store-BtdYuiUx.d.ts → Store-BJ8b6xbs.d.ts} +2 -0
- package/dist/cli/index.js +475 -5708
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +475 -5709
- package/dist/cli/index.mjs.map +1 -1
- package/dist/{index-yTOihMUk.d.mts → index-2AoCh09i.d.mts} +1 -1
- package/dist/{index-B2oTMNlL.d.ts → index-BZrUZX8Z.d.ts} +1 -1
- package/dist/{index-B8PTQKy9.d.mts → index-CHbW0NJZ.d.mts} +1 -1
- package/dist/{index-DWk78ifo.d.ts → index-CfqixdlW.d.ts} +1 -1
- package/dist/index.d.mts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +328 -5739
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +327 -5739
- package/dist/index.mjs.map +1 -1
- package/dist/mcp/index.d.mts +2 -2
- package/dist/mcp/index.d.ts +2 -2
- package/dist/mcp/index.js +19 -2
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/index.mjs +26 -2
- package/dist/mcp/index.mjs.map +1 -1
- package/dist/sdk/index.d.mts +202 -50
- package/dist/sdk/index.d.ts +202 -50
- package/dist/sdk/index.js +76 -34
- package/dist/sdk/index.js.map +1 -1
- package/dist/sdk/index.mjs +76 -34
- package/dist/sdk/index.mjs.map +1 -1
- package/dist/server/api.d.mts +1 -1
- package/dist/server/api.d.ts +1 -1
- package/dist/server/api.js +231 -154
- package/dist/server/api.js.map +1 -1
- package/dist/server/api.mjs +231 -154
- package/dist/server/api.mjs.map +1 -1
- package/dist/server/index.d.mts +2 -2
- package/dist/server/index.d.ts +2 -2
- package/dist/server/index.js +296 -5711
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +295 -5711
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/websocket.d.mts +1 -1
- package/dist/server/websocket.d.ts +1 -1
- package/dist/ws/index.d.mts +1 -1
- package/dist/ws/index.d.ts +1 -1
- package/package.json +1 -1
- package/dist/sharp-win32-x64-CXV3GA3G.node +0 -0
package/dist/server/api.mjs
CHANGED
|
@@ -14,130 +14,6 @@ var __export = (target, all) => {
|
|
|
14
14
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
// src/config.ts
|
|
18
|
-
import { readFileSync, existsSync } from "fs";
|
|
19
|
-
import { resolve } from "path";
|
|
20
|
-
function parseValue(v) {
|
|
21
|
-
const trimmed = v.trim();
|
|
22
|
-
if (trimmed === "true") return true;
|
|
23
|
-
if (trimmed === "false") return false;
|
|
24
|
-
if (trimmed === "null" || trimmed === "~") return null;
|
|
25
|
-
if (/^-?\d+$/.test(trimmed)) return parseInt(trimmed, 10);
|
|
26
|
-
if (/^-?\d+\.\d+$/.test(trimmed)) return parseFloat(trimmed);
|
|
27
|
-
if (trimmed.startsWith('"') && trimmed.endsWith('"') || trimmed.startsWith("'") && trimmed.endsWith("'")) {
|
|
28
|
-
return trimmed.slice(1, -1);
|
|
29
|
-
}
|
|
30
|
-
return trimmed;
|
|
31
|
-
}
|
|
32
|
-
function parseYaml(text) {
|
|
33
|
-
const lines = text.split("\n");
|
|
34
|
-
const root = {};
|
|
35
|
-
const stack = [{ obj: root, indent: -1, isArray: false }];
|
|
36
|
-
for (const rawLine of lines) {
|
|
37
|
-
const commentIdx = rawLine.indexOf("#");
|
|
38
|
-
const line = commentIdx >= 0 ? rawLine.slice(0, commentIdx) : rawLine;
|
|
39
|
-
if (!line.trim()) continue;
|
|
40
|
-
const indent = line.length - line.trimStart().length;
|
|
41
|
-
const trimmed = line.trim();
|
|
42
|
-
while (stack.length > 1 && stack[stack.length - 1].indent >= indent) {
|
|
43
|
-
stack.pop();
|
|
44
|
-
}
|
|
45
|
-
const parent = stack[stack.length - 1];
|
|
46
|
-
if (trimmed.startsWith("- ")) {
|
|
47
|
-
const valueStr2 = trimmed.slice(2).trim();
|
|
48
|
-
if (!parent.isArray) {
|
|
49
|
-
}
|
|
50
|
-
let target = parent.obj;
|
|
51
|
-
if (!Array.isArray(target)) {
|
|
52
|
-
target = [];
|
|
53
|
-
}
|
|
54
|
-
if (valueStr2.includes(":")) {
|
|
55
|
-
const item = {};
|
|
56
|
-
const colonIdx2 = valueStr2.indexOf(":");
|
|
57
|
-
const k = valueStr2.slice(0, colonIdx2).trim();
|
|
58
|
-
const v = valueStr2.slice(colonIdx2 + 1).trim();
|
|
59
|
-
item[k] = parseValue(v);
|
|
60
|
-
target.push(item);
|
|
61
|
-
} else {
|
|
62
|
-
target.push(parseValue(valueStr2));
|
|
63
|
-
}
|
|
64
|
-
continue;
|
|
65
|
-
}
|
|
66
|
-
const colonIdx = trimmed.indexOf(":");
|
|
67
|
-
if (colonIdx === -1) continue;
|
|
68
|
-
const key = trimmed.slice(0, colonIdx).trim();
|
|
69
|
-
const valueStr = trimmed.slice(colonIdx + 1).trim();
|
|
70
|
-
if (!valueStr) {
|
|
71
|
-
const newObj = {};
|
|
72
|
-
parent.obj[key] = newObj;
|
|
73
|
-
stack.push({ obj: newObj, indent, isArray: false });
|
|
74
|
-
} else {
|
|
75
|
-
parent.obj[key] = parseValue(valueStr);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
return root;
|
|
79
|
-
}
|
|
80
|
-
function loadConfig() {
|
|
81
|
-
const configPath = resolve(process.cwd(), "config.yaml");
|
|
82
|
-
if (!existsSync(configPath)) {
|
|
83
|
-
console.warn("[Config] config.yaml not found, using defaults");
|
|
84
|
-
return defaultConfig();
|
|
85
|
-
}
|
|
86
|
-
try {
|
|
87
|
-
const raw = readFileSync(configPath, "utf-8");
|
|
88
|
-
const parsed = parseYaml(raw);
|
|
89
|
-
return mergeDeep(defaultConfig(), parsed);
|
|
90
|
-
} catch (err) {
|
|
91
|
-
console.error("[Config] Failed to parse config.yaml:", err.message);
|
|
92
|
-
return defaultConfig();
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
function getVersion() {
|
|
96
|
-
try {
|
|
97
|
-
const pkg = JSON.parse(readFileSync(resolve(__dirname, "../package.json"), "utf-8"));
|
|
98
|
-
return pkg.version;
|
|
99
|
-
} catch {
|
|
100
|
-
try {
|
|
101
|
-
const pkg = JSON.parse(readFileSync(resolve(process.cwd(), "package.json"), "utf-8"));
|
|
102
|
-
return pkg.version;
|
|
103
|
-
} catch {
|
|
104
|
-
return "2.0.1";
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
function defaultConfig() {
|
|
109
|
-
return {
|
|
110
|
-
server: { port: 7321, host: "localhost", version: getVersion() },
|
|
111
|
-
database: { path: "data/nexus.db", wal_mode: true, vec_extension_path: "data/vec0" },
|
|
112
|
-
storage: { files_dir: "data/files", max_file_size_mb: 50, backups_dir: "data/backups", backup_interval_hours: 24, max_backups: 7 },
|
|
113
|
-
limits: { max_atoms_per_project: 1e4, rate_limit_requests: 100, rate_limit_window_ms: 6e4 },
|
|
114
|
-
embeddings: { model: "Xenova/all-MiniLM-L6-v2", dimension: 384, max_text_length: 1e4 },
|
|
115
|
-
features: { mcp_enabled: true, auto_index_enabled: true, file_processing_enabled: true },
|
|
116
|
-
index: { debounce_ms: 3e4 },
|
|
117
|
-
search: { semantic_weight: 0.6, fts_weight: 0.4 },
|
|
118
|
-
bonds: { default_type: "relates" }
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
function mergeDeep(target, source) {
|
|
122
|
-
if (!source || typeof source !== "object") return target;
|
|
123
|
-
const output = { ...target };
|
|
124
|
-
for (const key of Object.keys(source)) {
|
|
125
|
-
if (source[key] && typeof source[key] === "object" && !Array.isArray(source[key])) {
|
|
126
|
-
output[key] = mergeDeep(target[key] || {}, source[key]);
|
|
127
|
-
} else {
|
|
128
|
-
output[key] = source[key];
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
return output;
|
|
132
|
-
}
|
|
133
|
-
var CONFIG;
|
|
134
|
-
var init_config = __esm({
|
|
135
|
-
"src/config.ts"() {
|
|
136
|
-
"use strict";
|
|
137
|
-
CONFIG = loadConfig();
|
|
138
|
-
}
|
|
139
|
-
});
|
|
140
|
-
|
|
141
17
|
// src/server/embedder.ts
|
|
142
18
|
var embedder_exports = {};
|
|
143
19
|
__export(embedder_exports, {
|
|
@@ -146,20 +22,18 @@ __export(embedder_exports, {
|
|
|
146
22
|
isReady: () => isReady
|
|
147
23
|
});
|
|
148
24
|
import { pipeline } from "@xenova/transformers";
|
|
149
|
-
async function getExtractor() {
|
|
150
|
-
if (extractor) return extractor;
|
|
151
|
-
if (loadError) return null;
|
|
25
|
+
async function getExtractor(model) {
|
|
26
|
+
if (extractor && loadedModel === model) return extractor;
|
|
27
|
+
if (loadError && loadedModel === model) return null;
|
|
152
28
|
if (loading) {
|
|
153
29
|
while (loading) await new Promise((r) => setTimeout(r, 100));
|
|
154
|
-
return extractor;
|
|
30
|
+
return extractor && loadedModel === model ? extractor : null;
|
|
155
31
|
}
|
|
156
32
|
loading = true;
|
|
157
33
|
try {
|
|
158
|
-
extractor = await pipeline("feature-extraction",
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
});
|
|
162
|
-
console.log(`[Embedder] Model loaded: ${CONFIG.embeddings.model}`);
|
|
34
|
+
extractor = await pipeline("feature-extraction", model, { quantized: true });
|
|
35
|
+
loadedModel = model;
|
|
36
|
+
console.log(`[Embedder] Model loaded: ${model}`);
|
|
163
37
|
return extractor;
|
|
164
38
|
} catch (err) {
|
|
165
39
|
loadError = err;
|
|
@@ -169,10 +43,11 @@ async function getExtractor() {
|
|
|
169
43
|
loading = false;
|
|
170
44
|
}
|
|
171
45
|
}
|
|
172
|
-
async function embedText(text) {
|
|
173
|
-
const
|
|
46
|
+
async function embedText(text, model, maxLength) {
|
|
47
|
+
const m = model || DEFAULT_MODEL;
|
|
48
|
+
const ext = await getExtractor(m);
|
|
174
49
|
if (!ext) return null;
|
|
175
|
-
const truncated = text.slice(0,
|
|
50
|
+
const truncated = text.slice(0, maxLength || DEFAULT_MAX_LENGTH);
|
|
176
51
|
if (!truncated.trim()) return null;
|
|
177
52
|
try {
|
|
178
53
|
const output = await ext(truncated, { pooling: "mean", normalize: true });
|
|
@@ -182,12 +57,13 @@ async function embedText(text) {
|
|
|
182
57
|
return null;
|
|
183
58
|
}
|
|
184
59
|
}
|
|
185
|
-
async function embedTexts(texts) {
|
|
186
|
-
const
|
|
60
|
+
async function embedTexts(texts, model, maxLength) {
|
|
61
|
+
const m = model || DEFAULT_MODEL;
|
|
62
|
+
const ext = await getExtractor(m);
|
|
187
63
|
if (!ext) return texts.map(() => null);
|
|
188
64
|
const results = [];
|
|
189
65
|
for (const text of texts) {
|
|
190
|
-
const truncated = text.slice(0,
|
|
66
|
+
const truncated = text.slice(0, maxLength || DEFAULT_MAX_LENGTH);
|
|
191
67
|
if (!truncated.trim()) {
|
|
192
68
|
results.push(null);
|
|
193
69
|
continue;
|
|
@@ -204,14 +80,16 @@ async function embedTexts(texts) {
|
|
|
204
80
|
function isReady() {
|
|
205
81
|
return extractor !== null;
|
|
206
82
|
}
|
|
207
|
-
var extractor, loading, loadError;
|
|
83
|
+
var DEFAULT_MODEL, DEFAULT_MAX_LENGTH, extractor, loading, loadError, loadedModel;
|
|
208
84
|
var init_embedder = __esm({
|
|
209
85
|
"src/server/embedder.ts"() {
|
|
210
86
|
"use strict";
|
|
211
|
-
|
|
87
|
+
DEFAULT_MODEL = "Xenova/all-MiniLM-L6-v2";
|
|
88
|
+
DEFAULT_MAX_LENGTH = 1e4;
|
|
212
89
|
extractor = null;
|
|
213
90
|
loading = false;
|
|
214
91
|
loadError = null;
|
|
92
|
+
loadedModel = "";
|
|
215
93
|
}
|
|
216
94
|
});
|
|
217
95
|
|
|
@@ -432,6 +310,23 @@ var TOOLS = [
|
|
|
432
310
|
];
|
|
433
311
|
|
|
434
312
|
// src/mcp/server.ts
|
|
313
|
+
function getVersion() {
|
|
314
|
+
try {
|
|
315
|
+
const { readFileSync: readFileSync4 } = __require("fs");
|
|
316
|
+
const { resolve: resolve4 } = __require("path");
|
|
317
|
+
const pkg = JSON.parse(readFileSync4(resolve4(__dirname, "../../package.json"), "utf-8"));
|
|
318
|
+
return pkg.version;
|
|
319
|
+
} catch {
|
|
320
|
+
try {
|
|
321
|
+
const { readFileSync: readFileSync4 } = __require("fs");
|
|
322
|
+
const { resolve: resolve4 } = __require("path");
|
|
323
|
+
const pkg = JSON.parse(readFileSync4(resolve4(process.cwd(), "package.json"), "utf-8"));
|
|
324
|
+
return pkg.version;
|
|
325
|
+
} catch {
|
|
326
|
+
return "2.1.0";
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
435
330
|
var McpServer = class {
|
|
436
331
|
store;
|
|
437
332
|
toolMap = /* @__PURE__ */ new Map();
|
|
@@ -452,7 +347,7 @@ var McpServer = class {
|
|
|
452
347
|
return this.ok(req.id, {
|
|
453
348
|
protocolVersion: "2024-11-05",
|
|
454
349
|
capabilities: { tools: {}, resources: {}, prompts: {} },
|
|
455
|
-
serverInfo: { name: "mnemosyne-mcp", version:
|
|
350
|
+
serverInfo: { name: "mnemosyne-mcp", version: getVersion() }
|
|
456
351
|
});
|
|
457
352
|
case "tools/list":
|
|
458
353
|
return this.ok(req.id, {
|
|
@@ -479,7 +374,7 @@ var McpServer = class {
|
|
|
479
374
|
getManifest() {
|
|
480
375
|
return {
|
|
481
376
|
name: "Mnemosyne",
|
|
482
|
-
version:
|
|
377
|
+
version: getVersion(),
|
|
483
378
|
description: "Knowledge base MCP server for projects, atoms, blocks, and bonds.",
|
|
484
379
|
protocol: "mcp",
|
|
485
380
|
transport: ["stdio", "sse"],
|
|
@@ -584,7 +479,25 @@ function setCorsHeaders(res) {
|
|
|
584
479
|
}
|
|
585
480
|
function authenticate(store, req) {
|
|
586
481
|
const token = req.headers.authorization?.replace("Bearer ", "");
|
|
587
|
-
|
|
482
|
+
if (token) {
|
|
483
|
+
return store.getAssistant(token);
|
|
484
|
+
}
|
|
485
|
+
const host = req.headers.host || "";
|
|
486
|
+
const isLocalhost = host.startsWith("localhost:") || host.startsWith("127.0.0.1:") || host === "localhost" || host === "127.0.0.1";
|
|
487
|
+
if (isLocalhost) {
|
|
488
|
+
return {
|
|
489
|
+
id: "local-dev",
|
|
490
|
+
name: "Local Developer",
|
|
491
|
+
role: "owner",
|
|
492
|
+
permissions: {},
|
|
493
|
+
status: "active",
|
|
494
|
+
provider: null,
|
|
495
|
+
connected_at: Date.now(),
|
|
496
|
+
last_seen: Date.now(),
|
|
497
|
+
metadata: {}
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
return void 0;
|
|
588
501
|
}
|
|
589
502
|
|
|
590
503
|
// src/api/utils.ts
|
|
@@ -895,6 +808,16 @@ function handleAssistants(store, pathname, method, res, body) {
|
|
|
895
808
|
json(res, 200, { assistants });
|
|
896
809
|
return true;
|
|
897
810
|
}
|
|
811
|
+
if (pathname.match(/^\/api\/v1\/assistants\/[^\/]+$/) && method === "GET") {
|
|
812
|
+
const id = pathname.replace("/api/v1/assistants/", "");
|
|
813
|
+
const assistant = store.getAssistant(id);
|
|
814
|
+
if (!assistant) {
|
|
815
|
+
json(res, 404, { error: "assistant_not_found" });
|
|
816
|
+
return true;
|
|
817
|
+
}
|
|
818
|
+
json(res, 200, { assistant });
|
|
819
|
+
return true;
|
|
820
|
+
}
|
|
898
821
|
if (pathname.match(/^\/api\/v1\/assistants\/[^\/]+$/) && method === "PATCH") {
|
|
899
822
|
const id = pathname.replace("/api/v1/assistants/", "");
|
|
900
823
|
const a = body;
|
|
@@ -935,6 +858,22 @@ function handleProjects(store, pathname, method, res, body, searchParams) {
|
|
|
935
858
|
json(res, 200, { success: true, project });
|
|
936
859
|
return true;
|
|
937
860
|
}
|
|
861
|
+
if (pathname.match(/^\/api\/v1\/projects\/[^/]+$/) && method === "GET") {
|
|
862
|
+
const id = pathname.replace("/api/v1/projects/", "");
|
|
863
|
+
const project = store.getProject(id);
|
|
864
|
+
if (!project) {
|
|
865
|
+
json(res, 404, { error: "project_not_found" });
|
|
866
|
+
return true;
|
|
867
|
+
}
|
|
868
|
+
json(res, 200, { project });
|
|
869
|
+
return true;
|
|
870
|
+
}
|
|
871
|
+
if (pathname.match(/^\/api\/v1\/projects\/[^/]+$/) && method === "DELETE") {
|
|
872
|
+
const id = pathname.replace("/api/v1/projects/", "");
|
|
873
|
+
const ok = store.deleteProject(id);
|
|
874
|
+
json(res, ok ? 200 : 404, { success: ok });
|
|
875
|
+
return true;
|
|
876
|
+
}
|
|
938
877
|
const projectIndexMatch = pathname.match(/^\/api\/v1\/projects\/([^/]+)\/index$/);
|
|
939
878
|
if (projectIndexMatch && method === "GET") {
|
|
940
879
|
const projectId = resolveProjectId(store, projectIndexMatch[1]);
|
|
@@ -1166,6 +1105,10 @@ function handleAtoms(store, pathname, method, res, body, searchParams, assistant
|
|
|
1166
1105
|
|
|
1167
1106
|
// src/api/routes/bonds.ts
|
|
1168
1107
|
function handleBonds(store, pathname, method, res, body) {
|
|
1108
|
+
if (pathname === "/api/v1/bonds" && method === "GET") {
|
|
1109
|
+
json(res, 200, store.getAllBonds());
|
|
1110
|
+
return true;
|
|
1111
|
+
}
|
|
1169
1112
|
if (pathname.match(/^\/api\/v1\/atoms\/[^\/]+\/bonds$/) && method === "GET") {
|
|
1170
1113
|
const atomId = pathname.replace("/api/v1/atoms/", "").replace("/bonds", "");
|
|
1171
1114
|
json(res, 200, store.getBondsByAtom(atomId));
|
|
@@ -1293,7 +1236,7 @@ async function handleSearch(store, pathname, method, res, searchParams) {
|
|
|
1293
1236
|
let results = [];
|
|
1294
1237
|
if (semantic) {
|
|
1295
1238
|
const { embedText: embedText2 } = await Promise.resolve().then(() => (init_embedder(), embedder_exports));
|
|
1296
|
-
const queryEmbedding = await embedText2(q);
|
|
1239
|
+
const queryEmbedding = await embedText2(q, store.config.embeddings.model, store.config.embeddings.max_text_length);
|
|
1297
1240
|
if (queryEmbedding) {
|
|
1298
1241
|
results = store.searchHybrid(projectId, q, queryEmbedding, limit);
|
|
1299
1242
|
} else {
|
|
@@ -1309,16 +1252,150 @@ async function handleSearch(store, pathname, method, res, searchParams) {
|
|
|
1309
1252
|
}
|
|
1310
1253
|
|
|
1311
1254
|
// src/server/files.ts
|
|
1312
|
-
init_config();
|
|
1313
1255
|
import { createHash } from "crypto";
|
|
1314
1256
|
import { mkdirSync, existsSync as existsSync2, writeFileSync, readFileSync as readFileSync2 } from "fs";
|
|
1315
1257
|
import { resolve as resolve2, dirname } from "path";
|
|
1316
|
-
|
|
1258
|
+
|
|
1259
|
+
// src/config.ts
|
|
1260
|
+
import { readFileSync, existsSync } from "fs";
|
|
1261
|
+
import { resolve } from "path";
|
|
1262
|
+
function parseValue(v) {
|
|
1263
|
+
const trimmed = v.trim();
|
|
1264
|
+
if (trimmed === "true") return true;
|
|
1265
|
+
if (trimmed === "false") return false;
|
|
1266
|
+
if (trimmed === "null" || trimmed === "~") return null;
|
|
1267
|
+
if (/^-?\d+$/.test(trimmed)) return parseInt(trimmed, 10);
|
|
1268
|
+
if (/^-?\d+\.\d+$/.test(trimmed)) return parseFloat(trimmed);
|
|
1269
|
+
if (trimmed.startsWith('"') && trimmed.endsWith('"') || trimmed.startsWith("'") && trimmed.endsWith("'")) {
|
|
1270
|
+
return trimmed.slice(1, -1);
|
|
1271
|
+
}
|
|
1272
|
+
return trimmed;
|
|
1273
|
+
}
|
|
1274
|
+
function parseYaml(text) {
|
|
1275
|
+
const lines = text.split("\n");
|
|
1276
|
+
const root = {};
|
|
1277
|
+
const stack = [{ obj: root, indent: -1, isArray: false }];
|
|
1278
|
+
for (const rawLine of lines) {
|
|
1279
|
+
const commentIdx = rawLine.indexOf("#");
|
|
1280
|
+
const line = commentIdx >= 0 ? rawLine.slice(0, commentIdx) : rawLine;
|
|
1281
|
+
if (!line.trim()) continue;
|
|
1282
|
+
const indent = line.length - line.trimStart().length;
|
|
1283
|
+
const trimmed = line.trim();
|
|
1284
|
+
while (stack.length > 1 && stack[stack.length - 1].indent >= indent) {
|
|
1285
|
+
stack.pop();
|
|
1286
|
+
}
|
|
1287
|
+
const parent = stack[stack.length - 1];
|
|
1288
|
+
if (trimmed.startsWith("- ")) {
|
|
1289
|
+
const valueStr2 = trimmed.slice(2).trim();
|
|
1290
|
+
if (!parent.isArray) {
|
|
1291
|
+
}
|
|
1292
|
+
let target = parent.obj;
|
|
1293
|
+
if (!Array.isArray(target)) {
|
|
1294
|
+
target = [];
|
|
1295
|
+
}
|
|
1296
|
+
if (valueStr2.includes(":")) {
|
|
1297
|
+
const item = {};
|
|
1298
|
+
const colonIdx2 = valueStr2.indexOf(":");
|
|
1299
|
+
const k = valueStr2.slice(0, colonIdx2).trim();
|
|
1300
|
+
const v = valueStr2.slice(colonIdx2 + 1).trim();
|
|
1301
|
+
item[k] = parseValue(v);
|
|
1302
|
+
target.push(item);
|
|
1303
|
+
} else {
|
|
1304
|
+
target.push(parseValue(valueStr2));
|
|
1305
|
+
}
|
|
1306
|
+
continue;
|
|
1307
|
+
}
|
|
1308
|
+
const colonIdx = trimmed.indexOf(":");
|
|
1309
|
+
if (colonIdx === -1) continue;
|
|
1310
|
+
const key = trimmed.slice(0, colonIdx).trim();
|
|
1311
|
+
const valueStr = trimmed.slice(colonIdx + 1).trim();
|
|
1312
|
+
if (!valueStr) {
|
|
1313
|
+
const newObj = {};
|
|
1314
|
+
parent.obj[key] = newObj;
|
|
1315
|
+
stack.push({ obj: newObj, indent, isArray: false });
|
|
1316
|
+
} else {
|
|
1317
|
+
parent.obj[key] = parseValue(valueStr);
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
return root;
|
|
1321
|
+
}
|
|
1322
|
+
function loadConfig() {
|
|
1323
|
+
const configPath = resolve(process.cwd(), "config.yaml");
|
|
1324
|
+
if (!existsSync(configPath)) {
|
|
1325
|
+
console.warn("[Config] config.yaml not found, using defaults");
|
|
1326
|
+
return defaultConfig();
|
|
1327
|
+
}
|
|
1328
|
+
try {
|
|
1329
|
+
const raw = readFileSync(configPath, "utf-8");
|
|
1330
|
+
const parsed = parseYaml(raw);
|
|
1331
|
+
return mergeDeep(defaultConfig(), parsed);
|
|
1332
|
+
} catch (err) {
|
|
1333
|
+
console.error("[Config] Failed to parse config.yaml:", err.message);
|
|
1334
|
+
return defaultConfig();
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
function getVersion2() {
|
|
1338
|
+
try {
|
|
1339
|
+
const { readFileSync: readFileSync4 } = __require("fs");
|
|
1340
|
+
const { resolve: resolve4 } = __require("path");
|
|
1341
|
+
const pkg = JSON.parse(readFileSync4(resolve4(__dirname, "../package.json"), "utf-8"));
|
|
1342
|
+
return pkg.version;
|
|
1343
|
+
} catch {
|
|
1344
|
+
try {
|
|
1345
|
+
const { readFileSync: readFileSync4 } = __require("fs");
|
|
1346
|
+
const { resolve: resolve4 } = __require("path");
|
|
1347
|
+
const pkg = JSON.parse(readFileSync4(resolve4(process.cwd(), "package.json"), "utf-8"));
|
|
1348
|
+
return pkg.version;
|
|
1349
|
+
} catch {
|
|
1350
|
+
return "2.1.0";
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
function defaultConfig() {
|
|
1355
|
+
return {
|
|
1356
|
+
server: { port: 7321, host: "localhost", version: getVersion2() },
|
|
1357
|
+
database: { path: "data/nexus.db", wal_mode: true, vec_extension_path: "data/vec0" },
|
|
1358
|
+
storage: { files_dir: "data/files", max_file_size_mb: 50, backups_dir: "data/backups", backup_interval_hours: 24, max_backups: 7 },
|
|
1359
|
+
limits: { max_atoms_per_project: 1e4, rate_limit_requests: 100, rate_limit_window_ms: 6e4 },
|
|
1360
|
+
embeddings: { model: "Xenova/all-MiniLM-L6-v2", dimension: 384, max_text_length: 1e4 },
|
|
1361
|
+
features: { mcp_enabled: true, auto_index_enabled: true, file_processing_enabled: true },
|
|
1362
|
+
index: { debounce_ms: 3e4 },
|
|
1363
|
+
search: { semantic_weight: 0.6, fts_weight: 0.4 },
|
|
1364
|
+
bonds: { default_type: "relates" }
|
|
1365
|
+
};
|
|
1366
|
+
}
|
|
1367
|
+
function mergeDeep(target, source) {
|
|
1368
|
+
if (!source || typeof source !== "object") return target;
|
|
1369
|
+
const output = { ...target };
|
|
1370
|
+
for (const key of Object.keys(source)) {
|
|
1371
|
+
if (source[key] && typeof source[key] === "object" && !Array.isArray(source[key])) {
|
|
1372
|
+
output[key] = mergeDeep(target[key] || {}, source[key]);
|
|
1373
|
+
} else {
|
|
1374
|
+
output[key] = source[key];
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
return output;
|
|
1378
|
+
}
|
|
1379
|
+
var _config = null;
|
|
1380
|
+
function getConfig() {
|
|
1381
|
+
if (!_config) _config = loadConfig();
|
|
1382
|
+
return _config;
|
|
1383
|
+
}
|
|
1384
|
+
var CONFIG = new Proxy({}, {
|
|
1385
|
+
get(_, prop) {
|
|
1386
|
+
return getConfig()[prop];
|
|
1387
|
+
}
|
|
1388
|
+
});
|
|
1389
|
+
|
|
1390
|
+
// src/server/files.ts
|
|
1391
|
+
function getFilesDir() {
|
|
1392
|
+
return resolve2(process.cwd(), CONFIG.storage.files_dir);
|
|
1393
|
+
}
|
|
1317
1394
|
function ensureDir(path) {
|
|
1318
1395
|
if (!existsSync2(path)) mkdirSync(path, { recursive: true });
|
|
1319
1396
|
}
|
|
1320
1397
|
function hashPath(hash) {
|
|
1321
|
-
return resolve2(
|
|
1398
|
+
return resolve2(getFilesDir(), hash.slice(0, 2), hash.slice(2));
|
|
1322
1399
|
}
|
|
1323
1400
|
function computeHash(buffer) {
|
|
1324
1401
|
return createHash("sha256").update(buffer).digest("hex");
|
|
@@ -1388,7 +1465,7 @@ import { createHash as createHash2 } from "crypto";
|
|
|
1388
1465
|
import { readFileSync as readFileSync3, existsSync as existsSync3, readdirSync, statSync } from "fs";
|
|
1389
1466
|
import { resolve as resolve3 } from "path";
|
|
1390
1467
|
var DB_PATH = resolve3(process.cwd(), "data", "nexus.db");
|
|
1391
|
-
var
|
|
1468
|
+
var FILES_DIR = resolve3(process.cwd(), "data", "files");
|
|
1392
1469
|
function sha256File(path) {
|
|
1393
1470
|
return createHash2("sha256").update(readFileSync3(path)).digest("hex");
|
|
1394
1471
|
}
|
|
@@ -1408,11 +1485,11 @@ function sha256Dir(dir) {
|
|
|
1408
1485
|
function buildMnemosyneExport(projectId, projectName) {
|
|
1409
1486
|
const zip = new AdmZip();
|
|
1410
1487
|
zip.addLocalFile(DB_PATH, "", "nexus.db");
|
|
1411
|
-
if (existsSync3(
|
|
1412
|
-
zip.addLocalFolder(
|
|
1488
|
+
if (existsSync3(FILES_DIR)) {
|
|
1489
|
+
zip.addLocalFolder(FILES_DIR, "files");
|
|
1413
1490
|
}
|
|
1414
1491
|
const dbChecksum = sha256File(DB_PATH);
|
|
1415
|
-
const filesChecksum = existsSync3(
|
|
1492
|
+
const filesChecksum = existsSync3(FILES_DIR) ? sha256Dir(FILES_DIR) : "";
|
|
1416
1493
|
const manifest = {
|
|
1417
1494
|
version: "1.1",
|
|
1418
1495
|
app: "Mnemosyne",
|
|
@@ -1540,10 +1617,10 @@ function handleEvents(store, pathname, method, res, searchParams) {
|
|
|
1540
1617
|
// src/api/routes/health.ts
|
|
1541
1618
|
var PKG_VERSION = (() => {
|
|
1542
1619
|
try {
|
|
1543
|
-
const pkg = JSON.parse(__require("fs").readFileSync(__require("path").resolve(__dirname, "
|
|
1620
|
+
const pkg = JSON.parse(__require("fs").readFileSync(__require("path").resolve(__dirname, "../../package.json"), "utf-8"));
|
|
1544
1621
|
return pkg.version;
|
|
1545
1622
|
} catch {
|
|
1546
|
-
return "2.0
|
|
1623
|
+
return "2.1.0";
|
|
1547
1624
|
}
|
|
1548
1625
|
})();
|
|
1549
1626
|
function handleHealth(store, pathname, method, res) {
|