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.js
CHANGED
|
@@ -30,130 +30,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
30
30
|
));
|
|
31
31
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
32
|
|
|
33
|
-
// src/config.ts
|
|
34
|
-
function parseValue(v) {
|
|
35
|
-
const trimmed = v.trim();
|
|
36
|
-
if (trimmed === "true") return true;
|
|
37
|
-
if (trimmed === "false") return false;
|
|
38
|
-
if (trimmed === "null" || trimmed === "~") return null;
|
|
39
|
-
if (/^-?\d+$/.test(trimmed)) return parseInt(trimmed, 10);
|
|
40
|
-
if (/^-?\d+\.\d+$/.test(trimmed)) return parseFloat(trimmed);
|
|
41
|
-
if (trimmed.startsWith('"') && trimmed.endsWith('"') || trimmed.startsWith("'") && trimmed.endsWith("'")) {
|
|
42
|
-
return trimmed.slice(1, -1);
|
|
43
|
-
}
|
|
44
|
-
return trimmed;
|
|
45
|
-
}
|
|
46
|
-
function parseYaml(text) {
|
|
47
|
-
const lines = text.split("\n");
|
|
48
|
-
const root = {};
|
|
49
|
-
const stack = [{ obj: root, indent: -1, isArray: false }];
|
|
50
|
-
for (const rawLine of lines) {
|
|
51
|
-
const commentIdx = rawLine.indexOf("#");
|
|
52
|
-
const line = commentIdx >= 0 ? rawLine.slice(0, commentIdx) : rawLine;
|
|
53
|
-
if (!line.trim()) continue;
|
|
54
|
-
const indent = line.length - line.trimStart().length;
|
|
55
|
-
const trimmed = line.trim();
|
|
56
|
-
while (stack.length > 1 && stack[stack.length - 1].indent >= indent) {
|
|
57
|
-
stack.pop();
|
|
58
|
-
}
|
|
59
|
-
const parent = stack[stack.length - 1];
|
|
60
|
-
if (trimmed.startsWith("- ")) {
|
|
61
|
-
const valueStr2 = trimmed.slice(2).trim();
|
|
62
|
-
if (!parent.isArray) {
|
|
63
|
-
}
|
|
64
|
-
let target = parent.obj;
|
|
65
|
-
if (!Array.isArray(target)) {
|
|
66
|
-
target = [];
|
|
67
|
-
}
|
|
68
|
-
if (valueStr2.includes(":")) {
|
|
69
|
-
const item = {};
|
|
70
|
-
const colonIdx2 = valueStr2.indexOf(":");
|
|
71
|
-
const k = valueStr2.slice(0, colonIdx2).trim();
|
|
72
|
-
const v = valueStr2.slice(colonIdx2 + 1).trim();
|
|
73
|
-
item[k] = parseValue(v);
|
|
74
|
-
target.push(item);
|
|
75
|
-
} else {
|
|
76
|
-
target.push(parseValue(valueStr2));
|
|
77
|
-
}
|
|
78
|
-
continue;
|
|
79
|
-
}
|
|
80
|
-
const colonIdx = trimmed.indexOf(":");
|
|
81
|
-
if (colonIdx === -1) continue;
|
|
82
|
-
const key = trimmed.slice(0, colonIdx).trim();
|
|
83
|
-
const valueStr = trimmed.slice(colonIdx + 1).trim();
|
|
84
|
-
if (!valueStr) {
|
|
85
|
-
const newObj = {};
|
|
86
|
-
parent.obj[key] = newObj;
|
|
87
|
-
stack.push({ obj: newObj, indent, isArray: false });
|
|
88
|
-
} else {
|
|
89
|
-
parent.obj[key] = parseValue(valueStr);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
return root;
|
|
93
|
-
}
|
|
94
|
-
function loadConfig() {
|
|
95
|
-
const configPath = (0, import_path.resolve)(process.cwd(), "config.yaml");
|
|
96
|
-
if (!(0, import_fs.existsSync)(configPath)) {
|
|
97
|
-
console.warn("[Config] config.yaml not found, using defaults");
|
|
98
|
-
return defaultConfig();
|
|
99
|
-
}
|
|
100
|
-
try {
|
|
101
|
-
const raw = (0, import_fs.readFileSync)(configPath, "utf-8");
|
|
102
|
-
const parsed = parseYaml(raw);
|
|
103
|
-
return mergeDeep(defaultConfig(), parsed);
|
|
104
|
-
} catch (err) {
|
|
105
|
-
console.error("[Config] Failed to parse config.yaml:", err.message);
|
|
106
|
-
return defaultConfig();
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
function getVersion() {
|
|
110
|
-
try {
|
|
111
|
-
const pkg = JSON.parse((0, import_fs.readFileSync)((0, import_path.resolve)(__dirname, "../package.json"), "utf-8"));
|
|
112
|
-
return pkg.version;
|
|
113
|
-
} catch {
|
|
114
|
-
try {
|
|
115
|
-
const pkg = JSON.parse((0, import_fs.readFileSync)((0, import_path.resolve)(process.cwd(), "package.json"), "utf-8"));
|
|
116
|
-
return pkg.version;
|
|
117
|
-
} catch {
|
|
118
|
-
return "2.0.1";
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
function defaultConfig() {
|
|
123
|
-
return {
|
|
124
|
-
server: { port: 7321, host: "localhost", version: getVersion() },
|
|
125
|
-
database: { path: "data/nexus.db", wal_mode: true, vec_extension_path: "data/vec0" },
|
|
126
|
-
storage: { files_dir: "data/files", max_file_size_mb: 50, backups_dir: "data/backups", backup_interval_hours: 24, max_backups: 7 },
|
|
127
|
-
limits: { max_atoms_per_project: 1e4, rate_limit_requests: 100, rate_limit_window_ms: 6e4 },
|
|
128
|
-
embeddings: { model: "Xenova/all-MiniLM-L6-v2", dimension: 384, max_text_length: 1e4 },
|
|
129
|
-
features: { mcp_enabled: true, auto_index_enabled: true, file_processing_enabled: true },
|
|
130
|
-
index: { debounce_ms: 3e4 },
|
|
131
|
-
search: { semantic_weight: 0.6, fts_weight: 0.4 },
|
|
132
|
-
bonds: { default_type: "relates" }
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
function mergeDeep(target, source) {
|
|
136
|
-
if (!source || typeof source !== "object") return target;
|
|
137
|
-
const output = { ...target };
|
|
138
|
-
for (const key of Object.keys(source)) {
|
|
139
|
-
if (source[key] && typeof source[key] === "object" && !Array.isArray(source[key])) {
|
|
140
|
-
output[key] = mergeDeep(target[key] || {}, source[key]);
|
|
141
|
-
} else {
|
|
142
|
-
output[key] = source[key];
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
return output;
|
|
146
|
-
}
|
|
147
|
-
var import_fs, import_path, CONFIG;
|
|
148
|
-
var init_config = __esm({
|
|
149
|
-
"src/config.ts"() {
|
|
150
|
-
"use strict";
|
|
151
|
-
import_fs = require("fs");
|
|
152
|
-
import_path = require("path");
|
|
153
|
-
CONFIG = loadConfig();
|
|
154
|
-
}
|
|
155
|
-
});
|
|
156
|
-
|
|
157
33
|
// src/server/embedder.ts
|
|
158
34
|
var embedder_exports = {};
|
|
159
35
|
__export(embedder_exports, {
|
|
@@ -161,20 +37,18 @@ __export(embedder_exports, {
|
|
|
161
37
|
embedTexts: () => embedTexts,
|
|
162
38
|
isReady: () => isReady
|
|
163
39
|
});
|
|
164
|
-
async function getExtractor() {
|
|
165
|
-
if (extractor) return extractor;
|
|
166
|
-
if (loadError) return null;
|
|
40
|
+
async function getExtractor(model) {
|
|
41
|
+
if (extractor && loadedModel === model) return extractor;
|
|
42
|
+
if (loadError && loadedModel === model) return null;
|
|
167
43
|
if (loading) {
|
|
168
44
|
while (loading) await new Promise((r) => setTimeout(r, 100));
|
|
169
|
-
return extractor;
|
|
45
|
+
return extractor && loadedModel === model ? extractor : null;
|
|
170
46
|
}
|
|
171
47
|
loading = true;
|
|
172
48
|
try {
|
|
173
|
-
extractor = await (0, import_transformers.pipeline)("feature-extraction",
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
});
|
|
177
|
-
console.log(`[Embedder] Model loaded: ${CONFIG.embeddings.model}`);
|
|
49
|
+
extractor = await (0, import_transformers.pipeline)("feature-extraction", model, { quantized: true });
|
|
50
|
+
loadedModel = model;
|
|
51
|
+
console.log(`[Embedder] Model loaded: ${model}`);
|
|
178
52
|
return extractor;
|
|
179
53
|
} catch (err) {
|
|
180
54
|
loadError = err;
|
|
@@ -184,10 +58,11 @@ async function getExtractor() {
|
|
|
184
58
|
loading = false;
|
|
185
59
|
}
|
|
186
60
|
}
|
|
187
|
-
async function embedText(text) {
|
|
188
|
-
const
|
|
61
|
+
async function embedText(text, model, maxLength) {
|
|
62
|
+
const m = model || DEFAULT_MODEL;
|
|
63
|
+
const ext = await getExtractor(m);
|
|
189
64
|
if (!ext) return null;
|
|
190
|
-
const truncated = text.slice(0,
|
|
65
|
+
const truncated = text.slice(0, maxLength || DEFAULT_MAX_LENGTH);
|
|
191
66
|
if (!truncated.trim()) return null;
|
|
192
67
|
try {
|
|
193
68
|
const output = await ext(truncated, { pooling: "mean", normalize: true });
|
|
@@ -197,12 +72,13 @@ async function embedText(text) {
|
|
|
197
72
|
return null;
|
|
198
73
|
}
|
|
199
74
|
}
|
|
200
|
-
async function embedTexts(texts) {
|
|
201
|
-
const
|
|
75
|
+
async function embedTexts(texts, model, maxLength) {
|
|
76
|
+
const m = model || DEFAULT_MODEL;
|
|
77
|
+
const ext = await getExtractor(m);
|
|
202
78
|
if (!ext) return texts.map(() => null);
|
|
203
79
|
const results = [];
|
|
204
80
|
for (const text of texts) {
|
|
205
|
-
const truncated = text.slice(0,
|
|
81
|
+
const truncated = text.slice(0, maxLength || DEFAULT_MAX_LENGTH);
|
|
206
82
|
if (!truncated.trim()) {
|
|
207
83
|
results.push(null);
|
|
208
84
|
continue;
|
|
@@ -219,15 +95,17 @@ async function embedTexts(texts) {
|
|
|
219
95
|
function isReady() {
|
|
220
96
|
return extractor !== null;
|
|
221
97
|
}
|
|
222
|
-
var import_transformers, extractor, loading, loadError;
|
|
98
|
+
var import_transformers, DEFAULT_MODEL, DEFAULT_MAX_LENGTH, extractor, loading, loadError, loadedModel;
|
|
223
99
|
var init_embedder = __esm({
|
|
224
100
|
"src/server/embedder.ts"() {
|
|
225
101
|
"use strict";
|
|
226
102
|
import_transformers = require("@xenova/transformers");
|
|
227
|
-
|
|
103
|
+
DEFAULT_MODEL = "Xenova/all-MiniLM-L6-v2";
|
|
104
|
+
DEFAULT_MAX_LENGTH = 1e4;
|
|
228
105
|
extractor = null;
|
|
229
106
|
loading = false;
|
|
230
107
|
loadError = null;
|
|
108
|
+
loadedModel = "";
|
|
231
109
|
}
|
|
232
110
|
});
|
|
233
111
|
|
|
@@ -455,6 +333,23 @@ var TOOLS = [
|
|
|
455
333
|
];
|
|
456
334
|
|
|
457
335
|
// src/mcp/server.ts
|
|
336
|
+
function getVersion() {
|
|
337
|
+
try {
|
|
338
|
+
const { readFileSync: readFileSync4 } = require("fs");
|
|
339
|
+
const { resolve: resolve4 } = require("path");
|
|
340
|
+
const pkg = JSON.parse(readFileSync4(resolve4(__dirname, "../../package.json"), "utf-8"));
|
|
341
|
+
return pkg.version;
|
|
342
|
+
} catch {
|
|
343
|
+
try {
|
|
344
|
+
const { readFileSync: readFileSync4 } = require("fs");
|
|
345
|
+
const { resolve: resolve4 } = require("path");
|
|
346
|
+
const pkg = JSON.parse(readFileSync4(resolve4(process.cwd(), "package.json"), "utf-8"));
|
|
347
|
+
return pkg.version;
|
|
348
|
+
} catch {
|
|
349
|
+
return "2.1.0";
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
458
353
|
var McpServer = class {
|
|
459
354
|
store;
|
|
460
355
|
toolMap = /* @__PURE__ */ new Map();
|
|
@@ -475,7 +370,7 @@ var McpServer = class {
|
|
|
475
370
|
return this.ok(req.id, {
|
|
476
371
|
protocolVersion: "2024-11-05",
|
|
477
372
|
capabilities: { tools: {}, resources: {}, prompts: {} },
|
|
478
|
-
serverInfo: { name: "mnemosyne-mcp", version:
|
|
373
|
+
serverInfo: { name: "mnemosyne-mcp", version: getVersion() }
|
|
479
374
|
});
|
|
480
375
|
case "tools/list":
|
|
481
376
|
return this.ok(req.id, {
|
|
@@ -502,7 +397,7 @@ var McpServer = class {
|
|
|
502
397
|
getManifest() {
|
|
503
398
|
return {
|
|
504
399
|
name: "Mnemosyne",
|
|
505
|
-
version:
|
|
400
|
+
version: getVersion(),
|
|
506
401
|
description: "Knowledge base MCP server for projects, atoms, blocks, and bonds.",
|
|
507
402
|
protocol: "mcp",
|
|
508
403
|
transport: ["stdio", "sse"],
|
|
@@ -607,7 +502,25 @@ function setCorsHeaders(res) {
|
|
|
607
502
|
}
|
|
608
503
|
function authenticate(store, req) {
|
|
609
504
|
const token = req.headers.authorization?.replace("Bearer ", "");
|
|
610
|
-
|
|
505
|
+
if (token) {
|
|
506
|
+
return store.getAssistant(token);
|
|
507
|
+
}
|
|
508
|
+
const host = req.headers.host || "";
|
|
509
|
+
const isLocalhost = host.startsWith("localhost:") || host.startsWith("127.0.0.1:") || host === "localhost" || host === "127.0.0.1";
|
|
510
|
+
if (isLocalhost) {
|
|
511
|
+
return {
|
|
512
|
+
id: "local-dev",
|
|
513
|
+
name: "Local Developer",
|
|
514
|
+
role: "owner",
|
|
515
|
+
permissions: {},
|
|
516
|
+
status: "active",
|
|
517
|
+
provider: null,
|
|
518
|
+
connected_at: Date.now(),
|
|
519
|
+
last_seen: Date.now(),
|
|
520
|
+
metadata: {}
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
return void 0;
|
|
611
524
|
}
|
|
612
525
|
|
|
613
526
|
// src/api/utils.ts
|
|
@@ -918,6 +831,16 @@ function handleAssistants(store, pathname, method, res, body) {
|
|
|
918
831
|
json(res, 200, { assistants });
|
|
919
832
|
return true;
|
|
920
833
|
}
|
|
834
|
+
if (pathname.match(/^\/api\/v1\/assistants\/[^\/]+$/) && method === "GET") {
|
|
835
|
+
const id = pathname.replace("/api/v1/assistants/", "");
|
|
836
|
+
const assistant = store.getAssistant(id);
|
|
837
|
+
if (!assistant) {
|
|
838
|
+
json(res, 404, { error: "assistant_not_found" });
|
|
839
|
+
return true;
|
|
840
|
+
}
|
|
841
|
+
json(res, 200, { assistant });
|
|
842
|
+
return true;
|
|
843
|
+
}
|
|
921
844
|
if (pathname.match(/^\/api\/v1\/assistants\/[^\/]+$/) && method === "PATCH") {
|
|
922
845
|
const id = pathname.replace("/api/v1/assistants/", "");
|
|
923
846
|
const a = body;
|
|
@@ -958,6 +881,22 @@ function handleProjects(store, pathname, method, res, body, searchParams) {
|
|
|
958
881
|
json(res, 200, { success: true, project });
|
|
959
882
|
return true;
|
|
960
883
|
}
|
|
884
|
+
if (pathname.match(/^\/api\/v1\/projects\/[^/]+$/) && method === "GET") {
|
|
885
|
+
const id = pathname.replace("/api/v1/projects/", "");
|
|
886
|
+
const project = store.getProject(id);
|
|
887
|
+
if (!project) {
|
|
888
|
+
json(res, 404, { error: "project_not_found" });
|
|
889
|
+
return true;
|
|
890
|
+
}
|
|
891
|
+
json(res, 200, { project });
|
|
892
|
+
return true;
|
|
893
|
+
}
|
|
894
|
+
if (pathname.match(/^\/api\/v1\/projects\/[^/]+$/) && method === "DELETE") {
|
|
895
|
+
const id = pathname.replace("/api/v1/projects/", "");
|
|
896
|
+
const ok = store.deleteProject(id);
|
|
897
|
+
json(res, ok ? 200 : 404, { success: ok });
|
|
898
|
+
return true;
|
|
899
|
+
}
|
|
961
900
|
const projectIndexMatch = pathname.match(/^\/api\/v1\/projects\/([^/]+)\/index$/);
|
|
962
901
|
if (projectIndexMatch && method === "GET") {
|
|
963
902
|
const projectId = resolveProjectId(store, projectIndexMatch[1]);
|
|
@@ -1189,6 +1128,10 @@ function handleAtoms(store, pathname, method, res, body, searchParams, assistant
|
|
|
1189
1128
|
|
|
1190
1129
|
// src/api/routes/bonds.ts
|
|
1191
1130
|
function handleBonds(store, pathname, method, res, body) {
|
|
1131
|
+
if (pathname === "/api/v1/bonds" && method === "GET") {
|
|
1132
|
+
json(res, 200, store.getAllBonds());
|
|
1133
|
+
return true;
|
|
1134
|
+
}
|
|
1192
1135
|
if (pathname.match(/^\/api\/v1\/atoms\/[^\/]+\/bonds$/) && method === "GET") {
|
|
1193
1136
|
const atomId = pathname.replace("/api/v1/atoms/", "").replace("/bonds", "");
|
|
1194
1137
|
json(res, 200, store.getBondsByAtom(atomId));
|
|
@@ -1316,7 +1259,7 @@ async function handleSearch(store, pathname, method, res, searchParams) {
|
|
|
1316
1259
|
let results = [];
|
|
1317
1260
|
if (semantic) {
|
|
1318
1261
|
const { embedText: embedText2 } = await Promise.resolve().then(() => (init_embedder(), embedder_exports));
|
|
1319
|
-
const queryEmbedding = await embedText2(q);
|
|
1262
|
+
const queryEmbedding = await embedText2(q, store.config.embeddings.model, store.config.embeddings.max_text_length);
|
|
1320
1263
|
if (queryEmbedding) {
|
|
1321
1264
|
results = store.searchHybrid(projectId, q, queryEmbedding, limit);
|
|
1322
1265
|
} else {
|
|
@@ -1335,13 +1278,147 @@ async function handleSearch(store, pathname, method, res, searchParams) {
|
|
|
1335
1278
|
var import_crypto = require("crypto");
|
|
1336
1279
|
var import_fs2 = require("fs");
|
|
1337
1280
|
var import_path2 = require("path");
|
|
1338
|
-
|
|
1339
|
-
|
|
1281
|
+
|
|
1282
|
+
// src/config.ts
|
|
1283
|
+
var import_fs = require("fs");
|
|
1284
|
+
var import_path = require("path");
|
|
1285
|
+
function parseValue(v) {
|
|
1286
|
+
const trimmed = v.trim();
|
|
1287
|
+
if (trimmed === "true") return true;
|
|
1288
|
+
if (trimmed === "false") return false;
|
|
1289
|
+
if (trimmed === "null" || trimmed === "~") return null;
|
|
1290
|
+
if (/^-?\d+$/.test(trimmed)) return parseInt(trimmed, 10);
|
|
1291
|
+
if (/^-?\d+\.\d+$/.test(trimmed)) return parseFloat(trimmed);
|
|
1292
|
+
if (trimmed.startsWith('"') && trimmed.endsWith('"') || trimmed.startsWith("'") && trimmed.endsWith("'")) {
|
|
1293
|
+
return trimmed.slice(1, -1);
|
|
1294
|
+
}
|
|
1295
|
+
return trimmed;
|
|
1296
|
+
}
|
|
1297
|
+
function parseYaml(text) {
|
|
1298
|
+
const lines = text.split("\n");
|
|
1299
|
+
const root = {};
|
|
1300
|
+
const stack = [{ obj: root, indent: -1, isArray: false }];
|
|
1301
|
+
for (const rawLine of lines) {
|
|
1302
|
+
const commentIdx = rawLine.indexOf("#");
|
|
1303
|
+
const line = commentIdx >= 0 ? rawLine.slice(0, commentIdx) : rawLine;
|
|
1304
|
+
if (!line.trim()) continue;
|
|
1305
|
+
const indent = line.length - line.trimStart().length;
|
|
1306
|
+
const trimmed = line.trim();
|
|
1307
|
+
while (stack.length > 1 && stack[stack.length - 1].indent >= indent) {
|
|
1308
|
+
stack.pop();
|
|
1309
|
+
}
|
|
1310
|
+
const parent = stack[stack.length - 1];
|
|
1311
|
+
if (trimmed.startsWith("- ")) {
|
|
1312
|
+
const valueStr2 = trimmed.slice(2).trim();
|
|
1313
|
+
if (!parent.isArray) {
|
|
1314
|
+
}
|
|
1315
|
+
let target = parent.obj;
|
|
1316
|
+
if (!Array.isArray(target)) {
|
|
1317
|
+
target = [];
|
|
1318
|
+
}
|
|
1319
|
+
if (valueStr2.includes(":")) {
|
|
1320
|
+
const item = {};
|
|
1321
|
+
const colonIdx2 = valueStr2.indexOf(":");
|
|
1322
|
+
const k = valueStr2.slice(0, colonIdx2).trim();
|
|
1323
|
+
const v = valueStr2.slice(colonIdx2 + 1).trim();
|
|
1324
|
+
item[k] = parseValue(v);
|
|
1325
|
+
target.push(item);
|
|
1326
|
+
} else {
|
|
1327
|
+
target.push(parseValue(valueStr2));
|
|
1328
|
+
}
|
|
1329
|
+
continue;
|
|
1330
|
+
}
|
|
1331
|
+
const colonIdx = trimmed.indexOf(":");
|
|
1332
|
+
if (colonIdx === -1) continue;
|
|
1333
|
+
const key = trimmed.slice(0, colonIdx).trim();
|
|
1334
|
+
const valueStr = trimmed.slice(colonIdx + 1).trim();
|
|
1335
|
+
if (!valueStr) {
|
|
1336
|
+
const newObj = {};
|
|
1337
|
+
parent.obj[key] = newObj;
|
|
1338
|
+
stack.push({ obj: newObj, indent, isArray: false });
|
|
1339
|
+
} else {
|
|
1340
|
+
parent.obj[key] = parseValue(valueStr);
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
return root;
|
|
1344
|
+
}
|
|
1345
|
+
function loadConfig() {
|
|
1346
|
+
const configPath = (0, import_path.resolve)(process.cwd(), "config.yaml");
|
|
1347
|
+
if (!(0, import_fs.existsSync)(configPath)) {
|
|
1348
|
+
console.warn("[Config] config.yaml not found, using defaults");
|
|
1349
|
+
return defaultConfig();
|
|
1350
|
+
}
|
|
1351
|
+
try {
|
|
1352
|
+
const raw = (0, import_fs.readFileSync)(configPath, "utf-8");
|
|
1353
|
+
const parsed = parseYaml(raw);
|
|
1354
|
+
return mergeDeep(defaultConfig(), parsed);
|
|
1355
|
+
} catch (err) {
|
|
1356
|
+
console.error("[Config] Failed to parse config.yaml:", err.message);
|
|
1357
|
+
return defaultConfig();
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
function getVersion2() {
|
|
1361
|
+
try {
|
|
1362
|
+
const { readFileSync: readFileSync4 } = require("fs");
|
|
1363
|
+
const { resolve: resolve4 } = require("path");
|
|
1364
|
+
const pkg = JSON.parse(readFileSync4(resolve4(__dirname, "../package.json"), "utf-8"));
|
|
1365
|
+
return pkg.version;
|
|
1366
|
+
} catch {
|
|
1367
|
+
try {
|
|
1368
|
+
const { readFileSync: readFileSync4 } = require("fs");
|
|
1369
|
+
const { resolve: resolve4 } = require("path");
|
|
1370
|
+
const pkg = JSON.parse(readFileSync4(resolve4(process.cwd(), "package.json"), "utf-8"));
|
|
1371
|
+
return pkg.version;
|
|
1372
|
+
} catch {
|
|
1373
|
+
return "2.1.0";
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
function defaultConfig() {
|
|
1378
|
+
return {
|
|
1379
|
+
server: { port: 7321, host: "localhost", version: getVersion2() },
|
|
1380
|
+
database: { path: "data/nexus.db", wal_mode: true, vec_extension_path: "data/vec0" },
|
|
1381
|
+
storage: { files_dir: "data/files", max_file_size_mb: 50, backups_dir: "data/backups", backup_interval_hours: 24, max_backups: 7 },
|
|
1382
|
+
limits: { max_atoms_per_project: 1e4, rate_limit_requests: 100, rate_limit_window_ms: 6e4 },
|
|
1383
|
+
embeddings: { model: "Xenova/all-MiniLM-L6-v2", dimension: 384, max_text_length: 1e4 },
|
|
1384
|
+
features: { mcp_enabled: true, auto_index_enabled: true, file_processing_enabled: true },
|
|
1385
|
+
index: { debounce_ms: 3e4 },
|
|
1386
|
+
search: { semantic_weight: 0.6, fts_weight: 0.4 },
|
|
1387
|
+
bonds: { default_type: "relates" }
|
|
1388
|
+
};
|
|
1389
|
+
}
|
|
1390
|
+
function mergeDeep(target, source) {
|
|
1391
|
+
if (!source || typeof source !== "object") return target;
|
|
1392
|
+
const output = { ...target };
|
|
1393
|
+
for (const key of Object.keys(source)) {
|
|
1394
|
+
if (source[key] && typeof source[key] === "object" && !Array.isArray(source[key])) {
|
|
1395
|
+
output[key] = mergeDeep(target[key] || {}, source[key]);
|
|
1396
|
+
} else {
|
|
1397
|
+
output[key] = source[key];
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
return output;
|
|
1401
|
+
}
|
|
1402
|
+
var _config = null;
|
|
1403
|
+
function getConfig() {
|
|
1404
|
+
if (!_config) _config = loadConfig();
|
|
1405
|
+
return _config;
|
|
1406
|
+
}
|
|
1407
|
+
var CONFIG = new Proxy({}, {
|
|
1408
|
+
get(_, prop) {
|
|
1409
|
+
return getConfig()[prop];
|
|
1410
|
+
}
|
|
1411
|
+
});
|
|
1412
|
+
|
|
1413
|
+
// src/server/files.ts
|
|
1414
|
+
function getFilesDir() {
|
|
1415
|
+
return (0, import_path2.resolve)(process.cwd(), CONFIG.storage.files_dir);
|
|
1416
|
+
}
|
|
1340
1417
|
function ensureDir(path) {
|
|
1341
1418
|
if (!(0, import_fs2.existsSync)(path)) (0, import_fs2.mkdirSync)(path, { recursive: true });
|
|
1342
1419
|
}
|
|
1343
1420
|
function hashPath(hash) {
|
|
1344
|
-
return (0, import_path2.resolve)(
|
|
1421
|
+
return (0, import_path2.resolve)(getFilesDir(), hash.slice(0, 2), hash.slice(2));
|
|
1345
1422
|
}
|
|
1346
1423
|
function computeHash(buffer) {
|
|
1347
1424
|
return (0, import_crypto.createHash)("sha256").update(buffer).digest("hex");
|
|
@@ -1411,7 +1488,7 @@ var import_crypto2 = require("crypto");
|
|
|
1411
1488
|
var import_fs3 = require("fs");
|
|
1412
1489
|
var import_path3 = require("path");
|
|
1413
1490
|
var DB_PATH = (0, import_path3.resolve)(process.cwd(), "data", "nexus.db");
|
|
1414
|
-
var
|
|
1491
|
+
var FILES_DIR = (0, import_path3.resolve)(process.cwd(), "data", "files");
|
|
1415
1492
|
function sha256File(path) {
|
|
1416
1493
|
return (0, import_crypto2.createHash)("sha256").update((0, import_fs3.readFileSync)(path)).digest("hex");
|
|
1417
1494
|
}
|
|
@@ -1431,11 +1508,11 @@ function sha256Dir(dir) {
|
|
|
1431
1508
|
function buildMnemosyneExport(projectId, projectName) {
|
|
1432
1509
|
const zip = new import_adm_zip.default();
|
|
1433
1510
|
zip.addLocalFile(DB_PATH, "", "nexus.db");
|
|
1434
|
-
if ((0, import_fs3.existsSync)(
|
|
1435
|
-
zip.addLocalFolder(
|
|
1511
|
+
if ((0, import_fs3.existsSync)(FILES_DIR)) {
|
|
1512
|
+
zip.addLocalFolder(FILES_DIR, "files");
|
|
1436
1513
|
}
|
|
1437
1514
|
const dbChecksum = sha256File(DB_PATH);
|
|
1438
|
-
const filesChecksum = (0, import_fs3.existsSync)(
|
|
1515
|
+
const filesChecksum = (0, import_fs3.existsSync)(FILES_DIR) ? sha256Dir(FILES_DIR) : "";
|
|
1439
1516
|
const manifest = {
|
|
1440
1517
|
version: "1.1",
|
|
1441
1518
|
app: "Mnemosyne",
|
|
@@ -1563,10 +1640,10 @@ function handleEvents(store, pathname, method, res, searchParams) {
|
|
|
1563
1640
|
// src/api/routes/health.ts
|
|
1564
1641
|
var PKG_VERSION = (() => {
|
|
1565
1642
|
try {
|
|
1566
|
-
const pkg = JSON.parse(require("fs").readFileSync(require("path").resolve(__dirname, "
|
|
1643
|
+
const pkg = JSON.parse(require("fs").readFileSync(require("path").resolve(__dirname, "../../package.json"), "utf-8"));
|
|
1567
1644
|
return pkg.version;
|
|
1568
1645
|
} catch {
|
|
1569
|
-
return "2.0
|
|
1646
|
+
return "2.1.0";
|
|
1570
1647
|
}
|
|
1571
1648
|
})();
|
|
1572
1649
|
function handleHealth(store, pathname, method, res) {
|