mnemosyne-core 2.0.0 → 2.0.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/dist/cli/index.js CHANGED
@@ -3548,9 +3548,22 @@ function loadConfig() {
3548
3548
  return defaultConfig();
3549
3549
  }
3550
3550
  }
3551
+ function getVersion() {
3552
+ try {
3553
+ const pkg = JSON.parse((0, import_fs.readFileSync)((0, import_path.resolve)(__dirname, "../package.json"), "utf-8"));
3554
+ return pkg.version;
3555
+ } catch {
3556
+ try {
3557
+ const pkg = JSON.parse((0, import_fs.readFileSync)((0, import_path.resolve)(process.cwd(), "package.json"), "utf-8"));
3558
+ return pkg.version;
3559
+ } catch {
3560
+ return "2.0.1";
3561
+ }
3562
+ }
3563
+ }
3551
3564
  function defaultConfig() {
3552
3565
  return {
3553
- server: { port: 7321, host: "localhost", version: "2.0.0" },
3566
+ server: { port: 7321, host: "localhost", version: getVersion() },
3554
3567
  database: { path: "data/nexus.db", wal_mode: true, vec_extension_path: "data/vec0" },
3555
3568
  storage: { files_dir: "data/files", max_file_size_mb: 50, backups_dir: "data/backups", backup_interval_hours: 24, max_backups: 7 },
3556
3569
  limits: { max_atoms_per_project: 1e4, rate_limit_requests: 100, rate_limit_window_ms: 6e4 },
@@ -4351,7 +4364,7 @@ var require_filesystem = __commonJS({
4351
4364
  var LDD_PATH = "/usr/bin/ldd";
4352
4365
  var SELF_PATH = "/proc/self/exe";
4353
4366
  var MAX_LENGTH = 2048;
4354
- var readFileSync9 = (path) => {
4367
+ var readFileSync7 = (path) => {
4355
4368
  const fd = fs.openSync(path, "r");
4356
4369
  const buffer = Buffer.alloc(MAX_LENGTH);
4357
4370
  const bytesRead = fs.readSync(fd, buffer, 0, MAX_LENGTH, 0);
@@ -4376,7 +4389,7 @@ var require_filesystem = __commonJS({
4376
4389
  module2.exports = {
4377
4390
  LDD_PATH,
4378
4391
  SELF_PATH,
4379
- readFileSync: readFileSync9,
4392
+ readFileSync: readFileSync7,
4380
4393
  readFile
4381
4394
  };
4382
4395
  }
@@ -4425,7 +4438,7 @@ var require_detect_libc = __commonJS({
4425
4438
  "use strict";
4426
4439
  var childProcess = require("child_process");
4427
4440
  var { isLinux, getReport } = require_process();
4428
- var { LDD_PATH, SELF_PATH, readFile, readFileSync: readFileSync9 } = require_filesystem();
4441
+ var { LDD_PATH, SELF_PATH, readFile, readFileSync: readFileSync7 } = require_filesystem();
4429
4442
  var { interpreterPath } = require_elf();
4430
4443
  var cachedFamilyInterpreter;
4431
4444
  var cachedFamilyFilesystem;
@@ -4517,7 +4530,7 @@ var require_detect_libc = __commonJS({
4517
4530
  }
4518
4531
  cachedFamilyFilesystem = null;
4519
4532
  try {
4520
- const lddContent = readFileSync9(LDD_PATH);
4533
+ const lddContent = readFileSync7(LDD_PATH);
4521
4534
  cachedFamilyFilesystem = getFamilyFromLddContent(lddContent);
4522
4535
  } catch (e) {
4523
4536
  }
@@ -4542,7 +4555,7 @@ var require_detect_libc = __commonJS({
4542
4555
  }
4543
4556
  cachedFamilyInterpreter = null;
4544
4557
  try {
4545
- const selfContent = readFileSync9(SELF_PATH);
4558
+ const selfContent = readFileSync7(SELF_PATH);
4546
4559
  const path = interpreterPath(selfContent);
4547
4560
  cachedFamilyInterpreter = familyFromInterpreterPath(path);
4548
4561
  } catch (e) {
@@ -4606,7 +4619,7 @@ var require_detect_libc = __commonJS({
4606
4619
  }
4607
4620
  cachedVersionFilesystem = null;
4608
4621
  try {
4609
- const lddContent = readFileSync9(LDD_PATH);
4622
+ const lddContent = readFileSync7(LDD_PATH);
4610
4623
  const versionMatch = lddContent.match(RE_GLIBC_VERSION);
4611
4624
  if (versionMatch) {
4612
4625
  cachedVersionFilesystem = versionMatch[1];
@@ -13103,7 +13116,6 @@ var import_path9 = require("path");
13103
13116
 
13104
13117
  // src/core/Mnemosyne.ts
13105
13118
  var import_better_sqlite32 = __toESM(require("better-sqlite3"));
13106
- var import_fs5 = require("fs");
13107
13119
  var import_path5 = require("path");
13108
13120
 
13109
13121
  // src/core/types.ts
@@ -14327,9 +14339,26 @@ function parseYaml2(text) {
14327
14339
  }
14328
14340
  return root;
14329
14341
  }
14342
+ function getVersion2() {
14343
+ try {
14344
+ const { readFileSync: readFileSync7 } = require("fs");
14345
+ const { resolve: resolve13 } = require("path");
14346
+ const pkg = JSON.parse(readFileSync7(resolve13(__dirname, "../../package.json"), "utf-8"));
14347
+ return pkg.version;
14348
+ } catch {
14349
+ try {
14350
+ const { readFileSync: readFileSync7 } = require("fs");
14351
+ const { resolve: resolve13 } = require("path");
14352
+ const pkg = JSON.parse(readFileSync7(resolve13(process.cwd(), "package.json"), "utf-8"));
14353
+ return pkg.version;
14354
+ } catch {
14355
+ return "2.0.1";
14356
+ }
14357
+ }
14358
+ }
14330
14359
  function defaultConfig2() {
14331
14360
  return {
14332
- server: { port: 7321, host: "localhost", version: "2.0.0" },
14361
+ server: { port: 7321, host: "localhost", version: getVersion2() },
14333
14362
  database: { path: "data/nexus.db", wal_mode: true, vec_extension_path: "data/vec0" },
14334
14363
  storage: { files_dir: "data/files", max_file_size_mb: 50, backups_dir: "data/backups", backup_interval_hours: 24, max_backups: 7 },
14335
14364
  limits: { max_atoms_per_project: 1e4, rate_limit_requests: 100, rate_limit_window_ms: 6e4 },
@@ -14352,8 +14381,8 @@ function mergeDeep2(target, source) {
14352
14381
  }
14353
14382
  return output;
14354
14383
  }
14355
- function loadConfig2(configPath) {
14356
- const path = configPath ? (0, import_path4.resolve)(configPath) : (0, import_path4.resolve)(process.cwd(), "config.yaml");
14384
+ function loadConfig2(configPath, baseDir = process.cwd()) {
14385
+ const path = configPath ? (0, import_path4.resolve)(configPath) : (0, import_path4.resolve)(baseDir, "config.yaml");
14357
14386
  if (!(0, import_fs4.existsSync)(path)) {
14358
14387
  if (!configPath) console.warn("[Config] config.yaml not found, using defaults");
14359
14388
  return defaultConfig2();
@@ -14369,23 +14398,237 @@ function loadConfig2(configPath) {
14369
14398
  }
14370
14399
  var MnemosyneConfig = class {
14371
14400
  config;
14401
+ baseDir;
14372
14402
  constructor(options) {
14373
- this.config = loadConfig2(options?.configPath);
14403
+ this.baseDir = options?.baseDir || process.cwd();
14404
+ this.config = loadConfig2(options?.configPath, this.baseDir);
14374
14405
  if (options?.overrides) {
14375
14406
  this.config = mergeDeep2(this.config, options.overrides);
14376
14407
  }
14377
14408
  }
14378
14409
  get dbPath() {
14379
- return (0, import_path4.resolve)(process.cwd(), this.config.database.path);
14410
+ return (0, import_path4.resolve)(this.baseDir, this.config.database.path);
14380
14411
  }
14381
14412
  get filesDir() {
14382
- return (0, import_path4.resolve)(process.cwd(), this.config.storage.files_dir);
14413
+ return (0, import_path4.resolve)(this.baseDir, this.config.storage.files_dir);
14383
14414
  }
14384
14415
  get backupsDir() {
14385
- return (0, import_path4.resolve)(process.cwd(), this.config.storage.backups_dir);
14416
+ return (0, import_path4.resolve)(this.baseDir, this.config.storage.backups_dir);
14417
+ }
14418
+ get baseDirPath() {
14419
+ return this.baseDir;
14386
14420
  }
14387
14421
  };
14388
14422
 
14423
+ // src/db/schema.ts
14424
+ var SCHEMA_SQL = `-- Mnemosyne v1.1 Database Schema
14425
+ -- SQLite with sqlite-vec extension for semantic search
14426
+
14427
+ -- PROJECTS (Spaces)
14428
+ CREATE TABLE IF NOT EXISTS projects (
14429
+ id TEXT PRIMARY KEY,
14430
+ name TEXT NOT NULL UNIQUE,
14431
+ description TEXT,
14432
+ icon TEXT DEFAULT '\u25C9',
14433
+ color TEXT DEFAULT '#6366f1',
14434
+ created_at INTEGER DEFAULT (unixepoch()),
14435
+ updated_at INTEGER DEFAULT (unixepoch()),
14436
+ owner TEXT DEFAULT 'human',
14437
+ metadata TEXT DEFAULT '{}'
14438
+ );
14439
+
14440
+ -- ATOMS (Ideas/Nodes)
14441
+ CREATE TABLE IF NOT EXISTS atoms (
14442
+ id TEXT PRIMARY KEY,
14443
+ project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
14444
+ parent_id TEXT REFERENCES atoms(id) ON DELETE CASCADE,
14445
+ title TEXT NOT NULL,
14446
+ summary TEXT,
14447
+ icon TEXT DEFAULT '\u25CF',
14448
+ color TEXT,
14449
+ x REAL,
14450
+ y REAL,
14451
+ auto_path TEXT,
14452
+ path_overridden INTEGER DEFAULT 0,
14453
+ status TEXT DEFAULT 'draft',
14454
+ status_updated_at INTEGER DEFAULT (unixepoch()),
14455
+ embedding_status TEXT DEFAULT 'pending',
14456
+ embedding_error TEXT,
14457
+ block_count INTEGER DEFAULT 0,
14458
+ bond_count INTEGER DEFAULT 0,
14459
+ template_id TEXT,
14460
+ created_at INTEGER DEFAULT (unixepoch()),
14461
+ updated_at INTEGER DEFAULT (unixepoch()),
14462
+ version INTEGER DEFAULT 1,
14463
+ locked_by TEXT,
14464
+ locked_at INTEGER,
14465
+ locked_reason TEXT,
14466
+ owner TEXT DEFAULT 'human',
14467
+ metadata TEXT DEFAULT '{}'
14468
+ );
14469
+
14470
+ -- BLOCKS (Content pieces inside atoms)
14471
+ CREATE TABLE IF NOT EXISTS blocks (
14472
+ id TEXT PRIMARY KEY,
14473
+ atom_id TEXT NOT NULL REFERENCES atoms(id) ON DELETE CASCADE,
14474
+ type TEXT NOT NULL DEFAULT 'text',
14475
+ content TEXT,
14476
+ order_index INTEGER DEFAULT 0,
14477
+ created_at INTEGER DEFAULT (unixepoch()),
14478
+ updated_at INTEGER DEFAULT (unixepoch()),
14479
+ metadata TEXT DEFAULT '{}'
14480
+ );
14481
+
14482
+ -- BONDS (Graph connections between atoms)
14483
+ CREATE TABLE IF NOT EXISTS bonds (
14484
+ id TEXT PRIMARY KEY,
14485
+ source_id TEXT NOT NULL REFERENCES atoms(id) ON DELETE CASCADE,
14486
+ target_id TEXT NOT NULL REFERENCES atoms(id) ON DELETE CASCADE,
14487
+ label TEXT DEFAULT 'connects',
14488
+ color TEXT,
14489
+ created_at INTEGER DEFAULT (unixepoch()),
14490
+ UNIQUE(source_id, target_id)
14491
+ );
14492
+
14493
+ -- ATTACHMENTS (Files in CAS)
14494
+ CREATE TABLE IF NOT EXISTS attachments (
14495
+ id TEXT PRIMARY KEY,
14496
+ block_id TEXT REFERENCES blocks(id) ON DELETE CASCADE,
14497
+ file_name TEXT NOT NULL,
14498
+ file_hash TEXT NOT NULL,
14499
+ file_size INTEGER,
14500
+ mime_type TEXT,
14501
+ created_at INTEGER DEFAULT (unixepoch()),
14502
+ UNIQUE(file_hash)
14503
+ );
14504
+
14505
+ -- EVENT LOG (Immutable audit trail)
14506
+ CREATE TABLE IF NOT EXISTS event_log (
14507
+ id TEXT PRIMARY KEY,
14508
+ timestamp INTEGER DEFAULT (unixepoch()),
14509
+ event_type TEXT NOT NULL,
14510
+ project_id TEXT,
14511
+ atom_id TEXT,
14512
+ block_id TEXT,
14513
+ bond_id TEXT,
14514
+ actor TEXT NOT NULL DEFAULT 'system',
14515
+ actor_type TEXT DEFAULT 'system',
14516
+ diff TEXT,
14517
+ trigger TEXT,
14518
+ metadata TEXT DEFAULT '{}'
14519
+ );
14520
+
14521
+ -- ASSISTANTS (AI Agents)
14522
+ CREATE TABLE IF NOT EXISTS assistants (
14523
+ id TEXT PRIMARY KEY,
14524
+ name TEXT NOT NULL,
14525
+ role TEXT DEFAULT 'worker',
14526
+ permissions TEXT DEFAULT '{"read":["*"],"write":[],"delete":false}',
14527
+ status TEXT DEFAULT 'active',
14528
+ provider TEXT,
14529
+ connected_at INTEGER DEFAULT (unixepoch()),
14530
+ last_seen INTEGER DEFAULT (unixepoch()),
14531
+ metadata TEXT DEFAULT '{}'
14532
+ );
14533
+
14534
+ -- QUEUE (Agent waitlist for locked atoms)
14535
+ CREATE TABLE IF NOT EXISTS queue (
14536
+ id TEXT PRIMARY KEY,
14537
+ atom_id TEXT NOT NULL REFERENCES atoms(id) ON DELETE CASCADE,
14538
+ assistant_id TEXT NOT NULL REFERENCES assistants(id) ON DELETE CASCADE,
14539
+ requested_at INTEGER DEFAULT (unixepoch()),
14540
+ priority INTEGER DEFAULT 5,
14541
+ status TEXT DEFAULT 'waiting',
14542
+ reason TEXT
14543
+ );
14544
+
14545
+ -- INDICES
14546
+ CREATE INDEX IF NOT EXISTS idx_atoms_project ON atoms(project_id);
14547
+ CREATE INDEX IF NOT EXISTS idx_atoms_parent ON atoms(parent_id);
14548
+ CREATE INDEX IF NOT EXISTS idx_atoms_locked ON atoms(locked_by) WHERE locked_by IS NOT NULL;
14549
+ -- idx_atoms_path_project is created by migration after auto_path column is added
14550
+ CREATE INDEX IF NOT EXISTS idx_blocks_atom ON blocks(atom_id);
14551
+ CREATE INDEX IF NOT EXISTS idx_bonds_source ON bonds(source_id);
14552
+ CREATE INDEX IF NOT EXISTS idx_bonds_target ON bonds(target_id);
14553
+ CREATE INDEX IF NOT EXISTS idx_event_log_time ON event_log(timestamp);
14554
+ CREATE INDEX IF NOT EXISTS idx_event_log_atom ON event_log(atom_id);
14555
+ CREATE INDEX IF NOT EXISTS idx_queue_atom ON queue(atom_id);
14556
+ CREATE INDEX IF NOT EXISTS idx_attachments_hash ON attachments(file_hash);
14557
+
14558
+ -- Auto-update block_count and bond_count triggers
14559
+ CREATE TRIGGER IF NOT EXISTS update_block_count_insert AFTER INSERT ON blocks BEGIN
14560
+ UPDATE atoms SET block_count = block_count + 1 WHERE id = NEW.atom_id;
14561
+ END;
14562
+
14563
+ CREATE TRIGGER IF NOT EXISTS update_block_count_delete AFTER DELETE ON blocks BEGIN
14564
+ UPDATE atoms SET block_count = block_count - 1 WHERE id = OLD.atom_id;
14565
+ END;
14566
+
14567
+ CREATE TRIGGER IF NOT EXISTS update_bond_count_insert AFTER INSERT ON bonds BEGIN
14568
+ UPDATE atoms SET bond_count = bond_count + 1 WHERE id = NEW.source_id OR id = NEW.target_id;
14569
+ END;
14570
+
14571
+ CREATE TRIGGER IF NOT EXISTS update_bond_count_delete AFTER DELETE ON bonds BEGIN
14572
+ UPDATE atoms SET bond_count = bond_count - 1 WHERE id = OLD.source_id OR id = OLD.target_id;
14573
+ END;
14574
+
14575
+ -- FTS5 FULL-TEXT SEARCH
14576
+ -- Separate tables to avoid rowid collisions between atoms and blocks
14577
+
14578
+ CREATE VIRTUAL TABLE IF NOT EXISTS search_atoms USING fts5(
14579
+ title, summary,
14580
+ content='atoms', content_rowid='rowid'
14581
+ );
14582
+
14583
+ CREATE VIRTUAL TABLE IF NOT EXISTS search_blocks USING fts5(
14584
+ content,
14585
+ content='blocks', content_rowid='rowid'
14586
+ );
14587
+
14588
+ -- Triggers to keep search_atoms in sync
14589
+ CREATE TRIGGER IF NOT EXISTS trig_search_atoms_insert AFTER INSERT ON atoms BEGIN
14590
+ INSERT INTO search_atoms(rowid, title, summary) VALUES (new.rowid, new.title, COALESCE(new.summary, ''));
14591
+ END;
14592
+
14593
+ CREATE TRIGGER IF NOT EXISTS trig_search_atoms_update AFTER UPDATE ON atoms BEGIN
14594
+ UPDATE search_atoms SET title = new.title, summary = COALESCE(new.summary, '') WHERE rowid = new.rowid;
14595
+ END;
14596
+
14597
+ CREATE TRIGGER IF NOT EXISTS trig_search_atoms_delete AFTER DELETE ON atoms BEGIN
14598
+ DELETE FROM search_atoms WHERE rowid = old.rowid;
14599
+ END;
14600
+
14601
+ -- Triggers to keep search_blocks in sync
14602
+ CREATE TRIGGER IF NOT EXISTS trig_search_blocks_insert AFTER INSERT ON blocks BEGIN
14603
+ INSERT INTO search_blocks(rowid, content) VALUES (new.rowid, COALESCE(new.content, ''));
14604
+ END;
14605
+
14606
+ CREATE TRIGGER IF NOT EXISTS trig_search_blocks_update AFTER UPDATE ON blocks BEGIN
14607
+ UPDATE search_blocks SET content = COALESCE(new.content, '') WHERE rowid = new.rowid;
14608
+ END;
14609
+
14610
+ CREATE TRIGGER IF NOT EXISTS trig_search_blocks_delete AFTER DELETE ON blocks BEGIN
14611
+ DELETE FROM search_blocks WHERE rowid = old.rowid;
14612
+ END;
14613
+
14614
+
14615
+ -- PER-ATOM PERMISSIONS (Granular access control)
14616
+ CREATE TABLE IF NOT EXISTS atom_permissions (
14617
+ id TEXT PRIMARY KEY,
14618
+ atom_id TEXT NOT NULL REFERENCES atoms(id) ON DELETE CASCADE,
14619
+ assistant_id TEXT NOT NULL REFERENCES assistants(id) ON DELETE CASCADE,
14620
+ level TEXT NOT NULL DEFAULT 'view',
14621
+ granted_by TEXT,
14622
+ granted_at INTEGER DEFAULT (unixepoch()),
14623
+ metadata TEXT DEFAULT '{}',
14624
+ UNIQUE(atom_id, assistant_id)
14625
+ );
14626
+
14627
+ -- sqlite-vec virtual table for semantic embeddings
14628
+ -- Created dynamically by connection.ts after loading the extension
14629
+ -- CREATE VIRTUAL TABLE IF NOT EXISTS atom_vectors USING vec0(atom_id TEXT PRIMARY KEY, embedding float[384]);
14630
+ `;
14631
+
14389
14632
  // src/core/Mnemosyne.ts
14390
14633
  var Mnemosyne = class {
14391
14634
  store;
@@ -14393,7 +14636,7 @@ var Mnemosyne = class {
14393
14636
  vecEnabled;
14394
14637
  db;
14395
14638
  constructor(options = {}) {
14396
- this.config = new MnemosyneConfig({ configPath: options.configPath });
14639
+ this.config = new MnemosyneConfig({ configPath: options.configPath, baseDir: options.baseDir });
14397
14640
  const cfg = this.config.config;
14398
14641
  const dbPath = options.dbPath || this.config.dbPath;
14399
14642
  this.db = new import_better_sqlite32.default(dbPath);
@@ -14402,17 +14645,21 @@ var Mnemosyne = class {
14402
14645
  this.db.pragma("synchronous = NORMAL");
14403
14646
  this.vecEnabled = false;
14404
14647
  try {
14405
- const vecPath = (0, import_path5.resolve)(process.cwd(), cfg.database.vec_extension_path);
14648
+ let vecPath;
14649
+ try {
14650
+ const sqliteVec = require("sqlite-vec");
14651
+ vecPath = sqliteVec.getLoadablePath();
14652
+ } catch {
14653
+ vecPath = (0, import_path5.resolve)(this.config.baseDirPath || process.cwd(), cfg.database.vec_extension_path);
14654
+ }
14406
14655
  this.db.loadExtension(vecPath);
14407
14656
  this.vecEnabled = true;
14408
14657
  console.log("[DB] sqlite-vec extension loaded");
14409
14658
  } catch (err) {
14410
14659
  console.warn("[DB] sqlite-vec not available:", err.message);
14411
14660
  }
14412
- const schemaPath = (0, import_path5.resolve)(process.cwd(), "src", "db", "schema.sql");
14413
14661
  try {
14414
- const schema = (0, import_fs5.readFileSync)(schemaPath, "utf-8");
14415
- this.db.exec(schema);
14662
+ this.db.exec(SCHEMA_SQL);
14416
14663
  } catch (err) {
14417
14664
  console.error("[DB] Failed to load schema:", err.message);
14418
14665
  }
@@ -14456,7 +14703,7 @@ var Mnemosyne = class {
14456
14703
 
14457
14704
  // src/server/MnemosyneServer.ts
14458
14705
  var import_http = require("http");
14459
- var import_fs8 = require("fs");
14706
+ var import_fs6 = require("fs");
14460
14707
  var import_path8 = require("path");
14461
14708
 
14462
14709
  // node_modules/ws/wrapper.mjs
@@ -15611,21 +15858,21 @@ function handleFiles(store, pathname, method, req, res, maxFileSizeMb) {
15611
15858
  // src/server/export-format.ts
15612
15859
  var import_adm_zip2 = __toESM(require("adm-zip"));
15613
15860
  var import_crypto2 = require("crypto");
15614
- var import_fs6 = require("fs");
15861
+ var import_fs5 = require("fs");
15615
15862
  var import_path6 = require("path");
15616
15863
  var DB_PATH = (0, import_path6.resolve)(process.cwd(), "data", "nexus.db");
15617
15864
  var FILES_DIR2 = (0, import_path6.resolve)(process.cwd(), "data", "files");
15618
15865
  function sha256File(path) {
15619
- return (0, import_crypto2.createHash)("sha256").update((0, import_fs6.readFileSync)(path)).digest("hex");
15866
+ return (0, import_crypto2.createHash)("sha256").update((0, import_fs5.readFileSync)(path)).digest("hex");
15620
15867
  }
15621
15868
  function sha256Dir(dir) {
15622
15869
  const hash = (0, import_crypto2.createHash)("sha256");
15623
15870
  function walk(p) {
15624
- const stat = (0, import_fs6.statSync)(p);
15871
+ const stat = (0, import_fs5.statSync)(p);
15625
15872
  if (stat.isFile()) {
15626
- hash.update((0, import_fs6.readFileSync)(p));
15873
+ hash.update((0, import_fs5.readFileSync)(p));
15627
15874
  } else if (stat.isDirectory()) {
15628
- for (const child of (0, import_fs6.readdirSync)(p).sort()) walk((0, import_path6.resolve)(p, child));
15875
+ for (const child of (0, import_fs5.readdirSync)(p).sort()) walk((0, import_path6.resolve)(p, child));
15629
15876
  }
15630
15877
  }
15631
15878
  walk(dir);
@@ -15634,11 +15881,11 @@ function sha256Dir(dir) {
15634
15881
  function buildMnemosyneExport(projectId, projectName) {
15635
15882
  const zip = new import_adm_zip2.default();
15636
15883
  zip.addLocalFile(DB_PATH, "", "nexus.db");
15637
- if ((0, import_fs6.existsSync)(FILES_DIR2)) {
15884
+ if ((0, import_fs5.existsSync)(FILES_DIR2)) {
15638
15885
  zip.addLocalFolder(FILES_DIR2, "files");
15639
15886
  }
15640
15887
  const dbChecksum = sha256File(DB_PATH);
15641
- const filesChecksum = (0, import_fs6.existsSync)(FILES_DIR2) ? sha256Dir(FILES_DIR2) : "";
15888
+ const filesChecksum = (0, import_fs5.existsSync)(FILES_DIR2) ? sha256Dir(FILES_DIR2) : "";
15642
15889
  const manifest = {
15643
15890
  version: "1.1",
15644
15891
  app: "Mnemosyne",
@@ -15764,12 +16011,20 @@ function handleEvents(store, pathname, method, res, searchParams) {
15764
16011
  }
15765
16012
 
15766
16013
  // src/api/routes/health.ts
16014
+ var PKG_VERSION = (() => {
16015
+ try {
16016
+ const pkg = JSON.parse(require("fs").readFileSync(require("path").resolve(__dirname, "../../../package.json"), "utf-8"));
16017
+ return pkg.version;
16018
+ } catch {
16019
+ return "2.0.1";
16020
+ }
16021
+ })();
15767
16022
  function handleHealth(store, pathname, method, res) {
15768
- if (pathname === "/health" && method === "GET") {
16023
+ if ((pathname === "/health" || pathname === "/api/v1/health") && method === "GET") {
15769
16024
  const stats = store.getStats();
15770
16025
  json(res, 200, {
15771
16026
  status: "ok",
15772
- version: "2.0.0",
16027
+ version: PKG_VERSION,
15773
16028
  storage: "sqlite",
15774
16029
  database: store.config.database.path,
15775
16030
  uptime: process.uptime(),
@@ -15994,7 +16249,6 @@ var WebSocketHandler = class {
15994
16249
 
15995
16250
  // src/db/connection.ts
15996
16251
  var import_better_sqlite33 = __toESM(require("better-sqlite3"));
15997
- var import_fs7 = require("fs");
15998
16252
  var import_path7 = require("path");
15999
16253
  init_config();
16000
16254
  var DB_PATH2 = process.env.MNEMOSYNE_DB_PATH || (0, import_path7.resolve)(process.cwd(), CONFIG.database.path);
@@ -16015,8 +16269,7 @@ function getDb() {
16015
16269
  console.warn("[DB] sqlite-vec not available:", err.message);
16016
16270
  vecEnabled = false;
16017
16271
  }
16018
- const schema = (0, import_fs7.readFileSync)((0, import_path7.resolve)(process.cwd(), "src", "db", "schema.sql"), "utf-8");
16019
- db.exec(schema);
16272
+ db.exec(SCHEMA_SQL);
16020
16273
  if (vecEnabled) {
16021
16274
  try {
16022
16275
  db.exec(`CREATE VIRTUAL TABLE IF NOT EXISTS atom_vectors USING vec0(atom_id TEXT PRIMARY KEY, embedding float[${CONFIG.embeddings.dimension}])`);
@@ -16048,7 +16301,6 @@ var Store2 = class extends Store {
16048
16301
  };
16049
16302
 
16050
16303
  // src/server/MnemosyneServer.ts
16051
- init_config();
16052
16304
  var MnemosyneServer = class {
16053
16305
  store;
16054
16306
  api;
@@ -16056,8 +16308,9 @@ var MnemosyneServer = class {
16056
16308
  httpServer;
16057
16309
  brain;
16058
16310
  constructor(options = {}, brain) {
16059
- const port = options.port ?? CONFIG.server.port;
16060
- const host = options.host ?? CONFIG.server.host;
16311
+ const cfg = brain?.config?.config;
16312
+ const port = options.port ?? cfg?.server?.port ?? 7321;
16313
+ const host = options.host ?? cfg?.server?.host ?? "localhost";
16061
16314
  const enableDashboard = options.dashboard !== false;
16062
16315
  const enableWebsocket = options.websocket !== false;
16063
16316
  process.on("uncaughtException", (err) => {
@@ -16085,8 +16338,9 @@ var MnemosyneServer = class {
16085
16338
  const wss = new import_websocket_server.default({ server: this.httpServer });
16086
16339
  this.wsHandler = new WebSocketHandler(wss, this.store);
16087
16340
  }
16341
+ const version = cfg?.server?.version || "2.0.1";
16088
16342
  this.httpServer.listen(port, () => {
16089
- console.log(`Mnemosyne v${CONFIG.server.version} \u2014 port ${port}`);
16343
+ console.log(`Mnemosyne v${version} \u2014 port ${port}`);
16090
16344
  console.log(`Dashboard: http://${host}:${port}/dashboard`);
16091
16345
  console.log(`API: http://${host}:${port}/api/v1`);
16092
16346
  console.log(`MCP: http://${host}:${port}/mcp/manifest`);
@@ -16111,12 +16365,13 @@ var MnemosyneServer = class {
16111
16365
  };
16112
16366
  const dirs = [
16113
16367
  (0, import_path8.resolve)(process.cwd(), "src/dashboard"),
16114
- (0, import_path8.resolve)(process.cwd(), "dashboard")
16368
+ (0, import_path8.resolve)(process.cwd(), "dashboard"),
16369
+ (0, import_path8.resolve)(__dirname, "../dashboard")
16115
16370
  ];
16116
16371
  for (const dir of dirs) {
16117
16372
  const filePath = (0, import_path8.resolve)(dir, urlPath);
16118
- if ((0, import_fs8.existsSync)(filePath)) {
16119
- const data = (0, import_fs8.readFileSync)(filePath);
16373
+ if ((0, import_fs6.existsSync)(filePath)) {
16374
+ const data = (0, import_fs6.readFileSync)(filePath);
16120
16375
  res.writeHead(200, { "Content-Type": mime[ext] || "application/octet-stream" });
16121
16376
  res.end(data);
16122
16377
  return;
@@ -16138,7 +16393,7 @@ var MnemosyneServer = class {
16138
16393
  async function startCommand(options) {
16139
16394
  const dataDir = (0, import_path9.resolve)(options.dataDir);
16140
16395
  const dbPath = (0, import_path9.resolve)(dataDir, "nexus.db");
16141
- const brain = new Mnemosyne({ dbPath, configPath: options.config });
16396
+ const brain = new Mnemosyne({ dbPath, configPath: options.config, baseDir: dataDir });
16142
16397
  await brain.init();
16143
16398
  if (options.mcpTransport === "stdio" && options.mcp) {
16144
16399
  if (options.verbose) {
@@ -16182,7 +16437,7 @@ ${signal} received. Shutting down...`);
16182
16437
 
16183
16438
  // src/cli/commands/init.ts
16184
16439
  var import_path10 = require("path");
16185
- var import_fs9 = require("fs");
16440
+ var import_fs7 = require("fs");
16186
16441
  var DEFAULT_CONFIG = `database:
16187
16442
  path: ./data/nexus.db
16188
16443
  wal: true
@@ -16207,28 +16462,28 @@ server:
16207
16462
  async function initCommand(options) {
16208
16463
  const dataDir = (0, import_path10.resolve)(options.dataDir);
16209
16464
  const configPath = options.config ? (0, import_path10.resolve)(options.config) : (0, import_path10.resolve)(dataDir, "config.yaml");
16210
- if ((0, import_fs9.existsSync)(dataDir)) {
16465
+ if ((0, import_fs7.existsSync)(dataDir)) {
16211
16466
  console.log(`\u{1F4C1} Data directory already exists: ${dataDir}`);
16212
16467
  } else {
16213
- (0, import_fs9.mkdirSync)(dataDir, { recursive: true });
16468
+ (0, import_fs7.mkdirSync)(dataDir, { recursive: true });
16214
16469
  console.log(`\u2705 Created data directory: ${dataDir}`);
16215
16470
  }
16216
16471
  for (const sub of ["backups", "files", "exports"]) {
16217
16472
  const dir = (0, import_path10.resolve)(dataDir, sub);
16218
- if (!(0, import_fs9.existsSync)(dir)) {
16219
- (0, import_fs9.mkdirSync)(dir, { recursive: true });
16473
+ if (!(0, import_fs7.existsSync)(dir)) {
16474
+ (0, import_fs7.mkdirSync)(dir, { recursive: true });
16220
16475
  console.log(`\u2705 Created ${sub}/`);
16221
16476
  }
16222
16477
  }
16223
- if (!(0, import_fs9.existsSync)(configPath)) {
16224
- (0, import_fs9.writeFileSync)(configPath, DEFAULT_CONFIG, "utf-8");
16478
+ if (!(0, import_fs7.existsSync)(configPath)) {
16479
+ (0, import_fs7.writeFileSync)(configPath, DEFAULT_CONFIG, "utf-8");
16225
16480
  console.log(`\u2705 Created config: ${configPath}`);
16226
16481
  } else {
16227
16482
  console.log(`\u{1F4C4} Config already exists: ${configPath}`);
16228
16483
  }
16229
16484
  const dbPath = (0, import_path10.resolve)(dataDir, "nexus.db");
16230
- if (!(0, import_fs9.existsSync)(dbPath)) {
16231
- const brain = new Mnemosyne({ dbPath, configPath });
16485
+ if (!(0, import_fs7.existsSync)(dbPath)) {
16486
+ const brain = new Mnemosyne({ dbPath, configPath, baseDir: dataDir });
16232
16487
  await brain.init();
16233
16488
  await brain.close();
16234
16489
  console.log(`\u2705 Initialized database: ${dbPath}`);
@@ -16242,14 +16497,14 @@ async function initCommand(options) {
16242
16497
 
16243
16498
  // src/cli/commands/migrate.ts
16244
16499
  var import_path11 = require("path");
16245
- var import_fs10 = require("fs");
16500
+ var import_fs8 = require("fs");
16246
16501
  async function migrateCommand(options) {
16247
16502
  const fromPath = (0, import_path11.resolve)(options.from);
16248
16503
  const toPath = (0, import_path11.resolve)(options.to);
16249
16504
  console.log(`\u{1F504} Migrating v1.0 JSON \u2192 v2.0 SQLite`);
16250
16505
  console.log(` From: ${fromPath}`);
16251
16506
  console.log(` To: ${toPath}`);
16252
- const raw = (0, import_fs10.readFileSync)(fromPath, "utf-8");
16507
+ const raw = (0, import_fs8.readFileSync)(fromPath, "utf-8");
16253
16508
  const v1 = JSON.parse(raw);
16254
16509
  const brain = new Mnemosyne({ dbPath: toPath });
16255
16510
  await brain.init();
@@ -16300,7 +16555,7 @@ async function migrateCommand(options) {
16300
16555
 
16301
16556
  // src/cli/commands/export.ts
16302
16557
  var import_path12 = require("path");
16303
- var import_fs11 = require("fs");
16558
+ var import_fs9 = require("fs");
16304
16559
  async function exportCommand(options) {
16305
16560
  const dataDir = (0, import_path12.resolve)(options.dataDir || "./data");
16306
16561
  const format = options.format || "mnemosyne";
@@ -16316,12 +16571,12 @@ async function exportCommand(options) {
16316
16571
  if (format === "mnemosyne") {
16317
16572
  const buffer = buildMnemosyneExport(project.id, project.name);
16318
16573
  const outPath = output || (0, import_path12.resolve)(`${project.name}.mnemosyne`);
16319
- (0, import_fs11.writeFileSync)(outPath, buffer);
16574
+ (0, import_fs9.writeFileSync)(outPath, buffer);
16320
16575
  console.log(`\u2705 Exported to ${outPath} (${buffer.length} bytes)`);
16321
16576
  } else if (format === "markdown") {
16322
16577
  const md = exportMarkdown(brain.store, project.id);
16323
16578
  const outPath = output || (0, import_path12.resolve)(`${project.name}.md`);
16324
- (0, import_fs11.writeFileSync)(outPath, md, "utf-8");
16579
+ (0, import_fs9.writeFileSync)(outPath, md, "utf-8");
16325
16580
  console.log(`\u2705 Exported to ${outPath} (${md.length} chars)`);
16326
16581
  } else {
16327
16582
  console.error(`\u274C Unsupported format: ${format}`);