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.
Files changed (47) hide show
  1. package/README.md +42 -25
  2. package/dist/{Store-BtdYuiUx.d.mts → Store-BJ8b6xbs.d.mts} +2 -0
  3. package/dist/{Store-BtdYuiUx.d.ts → Store-BJ8b6xbs.d.ts} +2 -0
  4. package/dist/cli/index.js +475 -5708
  5. package/dist/cli/index.js.map +1 -1
  6. package/dist/cli/index.mjs +475 -5709
  7. package/dist/cli/index.mjs.map +1 -1
  8. package/dist/{index-yTOihMUk.d.mts → index-2AoCh09i.d.mts} +1 -1
  9. package/dist/{index-B2oTMNlL.d.ts → index-BZrUZX8Z.d.ts} +1 -1
  10. package/dist/{index-B8PTQKy9.d.mts → index-CHbW0NJZ.d.mts} +1 -1
  11. package/dist/{index-DWk78ifo.d.ts → index-CfqixdlW.d.ts} +1 -1
  12. package/dist/index.d.mts +4 -4
  13. package/dist/index.d.ts +4 -4
  14. package/dist/index.js +328 -5739
  15. package/dist/index.js.map +1 -1
  16. package/dist/index.mjs +327 -5739
  17. package/dist/index.mjs.map +1 -1
  18. package/dist/mcp/index.d.mts +2 -2
  19. package/dist/mcp/index.d.ts +2 -2
  20. package/dist/mcp/index.js +19 -2
  21. package/dist/mcp/index.js.map +1 -1
  22. package/dist/mcp/index.mjs +26 -2
  23. package/dist/mcp/index.mjs.map +1 -1
  24. package/dist/sdk/index.d.mts +202 -50
  25. package/dist/sdk/index.d.ts +202 -50
  26. package/dist/sdk/index.js +76 -34
  27. package/dist/sdk/index.js.map +1 -1
  28. package/dist/sdk/index.mjs +76 -34
  29. package/dist/sdk/index.mjs.map +1 -1
  30. package/dist/server/api.d.mts +1 -1
  31. package/dist/server/api.d.ts +1 -1
  32. package/dist/server/api.js +231 -154
  33. package/dist/server/api.js.map +1 -1
  34. package/dist/server/api.mjs +231 -154
  35. package/dist/server/api.mjs.map +1 -1
  36. package/dist/server/index.d.mts +2 -2
  37. package/dist/server/index.d.ts +2 -2
  38. package/dist/server/index.js +296 -5711
  39. package/dist/server/index.js.map +1 -1
  40. package/dist/server/index.mjs +295 -5711
  41. package/dist/server/index.mjs.map +1 -1
  42. package/dist/server/websocket.d.mts +1 -1
  43. package/dist/server/websocket.d.ts +1 -1
  44. package/dist/ws/index.d.mts +1 -1
  45. package/dist/ws/index.d.ts +1 -1
  46. package/package.json +1 -1
  47. package/dist/sharp-win32-x64-CXV3GA3G.node +0 -0
@@ -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", CONFIG.embeddings.model, {
174
- quantized: true
175
- // Use quantized model for faster download
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 ext = await getExtractor();
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, CONFIG.embeddings.max_text_length);
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 ext = await getExtractor();
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, CONFIG.embeddings.max_text_length);
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
- init_config();
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: "2.0.0" }
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: "2.0.0",
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
- return token ? store.getAssistant(token) : void 0;
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
- init_config();
1339
- var FILES_DIR = (0, import_path2.resolve)(process.cwd(), CONFIG.storage.files_dir);
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)(FILES_DIR, hash.slice(0, 2), hash.slice(2));
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 FILES_DIR2 = (0, import_path3.resolve)(process.cwd(), "data", "files");
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)(FILES_DIR2)) {
1435
- zip.addLocalFolder(FILES_DIR2, "files");
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)(FILES_DIR2) ? sha256Dir(FILES_DIR2) : "";
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, "../../../package.json"), "utf-8"));
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.1";
1646
+ return "2.1.0";
1570
1647
  }
1571
1648
  })();
1572
1649
  function handleHealth(store, pathname, method, res) {