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.
@@ -1,111 +1,8 @@
1
- import * as node_events from 'node:events';
2
- import * as node_stream_promises from 'node:stream/promises';
3
- import * as node_stream from 'node:stream';
4
- import * as node_stream_web from 'node:stream/web';
5
- import * as node_http from 'node:http';
6
- import { C as Config, S as Store, P as Project, A as Atom } from '../Store-N3j0Vaj6.mjs';
1
+ export { c as MnemosyneServer, S as ServerOptions } from '../index-B8PTQKy9.mjs';
2
+ import 'node:events';
3
+ import 'node:stream/promises';
4
+ import 'node:stream';
5
+ import 'node:stream/web';
6
+ import 'node:http';
7
+ import '../Store-BtdYuiUx.mjs';
7
8
  import 'better-sqlite3';
8
-
9
- /**
10
- * Mnemosyne Configuration
11
- * Loads config.yaml with a minimal parser. Supports env overrides.
12
- */
13
-
14
- declare class MnemosyneConfig {
15
- readonly config: Config;
16
- constructor(options?: {
17
- configPath?: string;
18
- overrides?: Partial<Config>;
19
- });
20
- get dbPath(): string;
21
- get filesDir(): string;
22
- get backupsDir(): string;
23
- }
24
-
25
- /**
26
- * Mnemosyne Core Engine
27
- * Main orchestrator class. Owns lifecycle (init, close).
28
- * Store owns SQLite operations. Config owns settings.
29
- */
30
-
31
- interface MnemosyneOptions {
32
- dbPath?: string;
33
- configPath?: string;
34
- autoBackup?: boolean;
35
- }
36
- declare class Mnemosyne {
37
- store: Store;
38
- config: MnemosyneConfig;
39
- vecEnabled: boolean;
40
- private db;
41
- constructor(options?: MnemosyneOptions);
42
- init(): Promise<void>;
43
- close(): Promise<void>;
44
- createProject(name: string, description?: string): Project;
45
- createAtom(projectId: string, title: string, type: string, createdBy: string, opts?: Parameters<Store["createAtom"]>[4]): Atom;
46
- }
47
-
48
- interface ServerOptions {
49
- port?: number;
50
- host?: string;
51
- dashboard?: boolean;
52
- mcp?: boolean;
53
- websocket?: boolean;
54
- }
55
- declare class MnemosyneServer {
56
- store: Store;
57
- private api;
58
- private wsHandler?;
59
- private httpServer;
60
- private brain?;
61
- constructor(options?: ServerOptions, brain?: Mnemosyne);
62
- private serveDashboard;
63
- getHandler(): node_http.Server<typeof node_http.IncomingMessage, {
64
- new (req: node_http.IncomingMessage): node_http.ServerResponse<node_http.IncomingMessage>;
65
- fromWeb(writableStream: node_stream_web.WritableStream, options?: Pick<node_stream.WritableOptions, "decodeStrings" | "highWaterMark" | "objectMode" | "signal">): node_stream.Writable;
66
- toWeb(streamWritable: NodeJS.WritableStream): node_stream_web.WritableStream;
67
- promises: typeof node_stream_promises;
68
- Stream: typeof node_stream;
69
- duplexPair(options?: node_stream.DuplexOptions): [node_stream.Duplex, node_stream.Duplex];
70
- addAbortSignal<T extends NodeJS.ReadableStream | NodeJS.WritableStream | node_stream_web.ReadableStream | node_stream_web.WritableStream>(signal: AbortSignal, stream: T): T;
71
- getDefaultHighWaterMark(objectMode: boolean): number;
72
- setDefaultHighWaterMark(objectMode: boolean, value: number): void;
73
- finished: typeof node_stream.finished;
74
- pipeline: typeof node_stream.pipeline;
75
- compose(stream: node_stream.ComposeSource<any> | node_stream.ComposeDestination<any>): node_stream.Duplex;
76
- compose<S extends node_stream.ComposeSource<any> | node_stream.ComposeTransform<any, any>, D extends node_stream.ComposeTransform<S, any> | node_stream.ComposeDestination<S>>(source: S, destination: D): node_stream.Duplex;
77
- compose<S extends node_stream.ComposeSource<any> | node_stream.ComposeTransform<any, any>, T extends node_stream.ComposeTransform<S, any>, D extends node_stream.ComposeTransform<T, any> | node_stream.ComposeDestination<T>>(source: S, transform: T, destination: D): node_stream.Duplex;
78
- compose<S extends node_stream.ComposeSource<any> | node_stream.ComposeTransform<any, any>, T1 extends node_stream.ComposeTransform<S, any>, T2 extends node_stream.ComposeTransform<T1, any>, D extends node_stream.ComposeTransform<T2, any> | node_stream.ComposeDestination<T2>>(source: S, transform1: T1, transform2: T2, destination: D): node_stream.Duplex;
79
- compose<S extends node_stream.ComposeSource<any> | node_stream.ComposeTransform<any, any>, T1 extends node_stream.ComposeTransform<S, any>, T2 extends node_stream.ComposeTransform<T1, any>, T3 extends node_stream.ComposeTransform<T2, any>, D extends node_stream.ComposeTransform<T3, any> | node_stream.ComposeDestination<T3>>(source: S, transform1: T1, transform2: T2, transform3: T3, destination: D): node_stream.Duplex;
80
- compose<S extends node_stream.ComposeSource<any> | node_stream.ComposeTransform<any, any>, T1 extends node_stream.ComposeTransform<S, any>, T2 extends node_stream.ComposeTransform<T1, any>, T3 extends node_stream.ComposeTransform<T2, any>, T4 extends node_stream.ComposeTransform<T3, any>, D extends node_stream.ComposeTransform<T4, any> | node_stream.ComposeDestination<T4>>(source: S, transform1: T1, transform2: T2, transform3: T3, transform4: T4, destination: D): node_stream.Duplex;
81
- compose(...streams: [node_stream.ComposeSource<any>, ...node_stream.ComposeTransform<any, any>[], node_stream.ComposeDestination<any>]): node_stream.Duplex;
82
- isErrored(stream: NodeJS.ReadableStream | NodeJS.WritableStream | node_stream_web.ReadableStream | node_stream_web.WritableStream): boolean;
83
- isReadable(stream: NodeJS.ReadableStream | node_stream_web.ReadableStream): boolean | null;
84
- isWritable(stream: NodeJS.WritableStream | node_stream_web.WritableStream): boolean | null;
85
- Readable: typeof node_stream.Readable;
86
- Writable: typeof node_stream.Writable;
87
- Duplex: typeof node_stream.Duplex;
88
- Transform: typeof node_stream.Transform;
89
- PassThrough: typeof node_stream.PassThrough;
90
- EventEmitter: typeof node_events;
91
- addAbortListener(signal: AbortSignal, resource: (event: Event) => void): Disposable;
92
- getEventListeners(emitter: node_events, name: string | symbol): ((...args: any[]) => void)[];
93
- getEventListeners(emitter: EventTarget, name: string): ((...args: any[]) => void)[];
94
- getMaxListeners(emitter: node_events | EventTarget): number;
95
- listenerCount(emitter: node_events, eventName: string | symbol): number;
96
- listenerCount(emitter: EventTarget, eventName: string): number;
97
- on(emitter: node_events, eventName: string | symbol, options?: node_events.OnOptions): NodeJS.AsyncIterator<any[]>;
98
- on(emitter: EventTarget, eventName: string, options?: node_events.OnOptions): NodeJS.AsyncIterator<any[]>;
99
- once(emitter: node_events, eventName: string | symbol, options?: node_events.OnceOptions): Promise<any[]>;
100
- once(emitter: EventTarget, eventName: string, options?: node_events.OnceOptions): Promise<any[]>;
101
- setMaxListeners(n: number, ...eventTargets: ReadonlyArray<node_events | EventTarget>): void;
102
- readonly captureRejectionSymbol: typeof node_events.captureRejectionSymbol;
103
- captureRejections: boolean;
104
- defaultMaxListeners: number;
105
- readonly errorMonitor: typeof node_events.errorMonitor;
106
- EventEmitterAsyncResource: typeof node_events.EventEmitterAsyncResource;
107
- }>;
108
- close(): Promise<void>;
109
- }
110
-
111
- export { MnemosyneServer, type ServerOptions };
@@ -1,111 +1,8 @@
1
- import * as node_events from 'node:events';
2
- import * as node_stream_promises from 'node:stream/promises';
3
- import * as node_stream from 'node:stream';
4
- import * as node_stream_web from 'node:stream/web';
5
- import * as node_http from 'node:http';
6
- import { C as Config, S as Store, P as Project, A as Atom } from '../Store-N3j0Vaj6.js';
1
+ export { c as MnemosyneServer, S as ServerOptions } from '../index-B2oTMNlL.js';
2
+ import 'node:events';
3
+ import 'node:stream/promises';
4
+ import 'node:stream';
5
+ import 'node:stream/web';
6
+ import 'node:http';
7
+ import '../Store-BtdYuiUx.js';
7
8
  import 'better-sqlite3';
8
-
9
- /**
10
- * Mnemosyne Configuration
11
- * Loads config.yaml with a minimal parser. Supports env overrides.
12
- */
13
-
14
- declare class MnemosyneConfig {
15
- readonly config: Config;
16
- constructor(options?: {
17
- configPath?: string;
18
- overrides?: Partial<Config>;
19
- });
20
- get dbPath(): string;
21
- get filesDir(): string;
22
- get backupsDir(): string;
23
- }
24
-
25
- /**
26
- * Mnemosyne Core Engine
27
- * Main orchestrator class. Owns lifecycle (init, close).
28
- * Store owns SQLite operations. Config owns settings.
29
- */
30
-
31
- interface MnemosyneOptions {
32
- dbPath?: string;
33
- configPath?: string;
34
- autoBackup?: boolean;
35
- }
36
- declare class Mnemosyne {
37
- store: Store;
38
- config: MnemosyneConfig;
39
- vecEnabled: boolean;
40
- private db;
41
- constructor(options?: MnemosyneOptions);
42
- init(): Promise<void>;
43
- close(): Promise<void>;
44
- createProject(name: string, description?: string): Project;
45
- createAtom(projectId: string, title: string, type: string, createdBy: string, opts?: Parameters<Store["createAtom"]>[4]): Atom;
46
- }
47
-
48
- interface ServerOptions {
49
- port?: number;
50
- host?: string;
51
- dashboard?: boolean;
52
- mcp?: boolean;
53
- websocket?: boolean;
54
- }
55
- declare class MnemosyneServer {
56
- store: Store;
57
- private api;
58
- private wsHandler?;
59
- private httpServer;
60
- private brain?;
61
- constructor(options?: ServerOptions, brain?: Mnemosyne);
62
- private serveDashboard;
63
- getHandler(): node_http.Server<typeof node_http.IncomingMessage, {
64
- new (req: node_http.IncomingMessage): node_http.ServerResponse<node_http.IncomingMessage>;
65
- fromWeb(writableStream: node_stream_web.WritableStream, options?: Pick<node_stream.WritableOptions, "decodeStrings" | "highWaterMark" | "objectMode" | "signal">): node_stream.Writable;
66
- toWeb(streamWritable: NodeJS.WritableStream): node_stream_web.WritableStream;
67
- promises: typeof node_stream_promises;
68
- Stream: typeof node_stream;
69
- duplexPair(options?: node_stream.DuplexOptions): [node_stream.Duplex, node_stream.Duplex];
70
- addAbortSignal<T extends NodeJS.ReadableStream | NodeJS.WritableStream | node_stream_web.ReadableStream | node_stream_web.WritableStream>(signal: AbortSignal, stream: T): T;
71
- getDefaultHighWaterMark(objectMode: boolean): number;
72
- setDefaultHighWaterMark(objectMode: boolean, value: number): void;
73
- finished: typeof node_stream.finished;
74
- pipeline: typeof node_stream.pipeline;
75
- compose(stream: node_stream.ComposeSource<any> | node_stream.ComposeDestination<any>): node_stream.Duplex;
76
- compose<S extends node_stream.ComposeSource<any> | node_stream.ComposeTransform<any, any>, D extends node_stream.ComposeTransform<S, any> | node_stream.ComposeDestination<S>>(source: S, destination: D): node_stream.Duplex;
77
- compose<S extends node_stream.ComposeSource<any> | node_stream.ComposeTransform<any, any>, T extends node_stream.ComposeTransform<S, any>, D extends node_stream.ComposeTransform<T, any> | node_stream.ComposeDestination<T>>(source: S, transform: T, destination: D): node_stream.Duplex;
78
- compose<S extends node_stream.ComposeSource<any> | node_stream.ComposeTransform<any, any>, T1 extends node_stream.ComposeTransform<S, any>, T2 extends node_stream.ComposeTransform<T1, any>, D extends node_stream.ComposeTransform<T2, any> | node_stream.ComposeDestination<T2>>(source: S, transform1: T1, transform2: T2, destination: D): node_stream.Duplex;
79
- compose<S extends node_stream.ComposeSource<any> | node_stream.ComposeTransform<any, any>, T1 extends node_stream.ComposeTransform<S, any>, T2 extends node_stream.ComposeTransform<T1, any>, T3 extends node_stream.ComposeTransform<T2, any>, D extends node_stream.ComposeTransform<T3, any> | node_stream.ComposeDestination<T3>>(source: S, transform1: T1, transform2: T2, transform3: T3, destination: D): node_stream.Duplex;
80
- compose<S extends node_stream.ComposeSource<any> | node_stream.ComposeTransform<any, any>, T1 extends node_stream.ComposeTransform<S, any>, T2 extends node_stream.ComposeTransform<T1, any>, T3 extends node_stream.ComposeTransform<T2, any>, T4 extends node_stream.ComposeTransform<T3, any>, D extends node_stream.ComposeTransform<T4, any> | node_stream.ComposeDestination<T4>>(source: S, transform1: T1, transform2: T2, transform3: T3, transform4: T4, destination: D): node_stream.Duplex;
81
- compose(...streams: [node_stream.ComposeSource<any>, ...node_stream.ComposeTransform<any, any>[], node_stream.ComposeDestination<any>]): node_stream.Duplex;
82
- isErrored(stream: NodeJS.ReadableStream | NodeJS.WritableStream | node_stream_web.ReadableStream | node_stream_web.WritableStream): boolean;
83
- isReadable(stream: NodeJS.ReadableStream | node_stream_web.ReadableStream): boolean | null;
84
- isWritable(stream: NodeJS.WritableStream | node_stream_web.WritableStream): boolean | null;
85
- Readable: typeof node_stream.Readable;
86
- Writable: typeof node_stream.Writable;
87
- Duplex: typeof node_stream.Duplex;
88
- Transform: typeof node_stream.Transform;
89
- PassThrough: typeof node_stream.PassThrough;
90
- EventEmitter: typeof node_events;
91
- addAbortListener(signal: AbortSignal, resource: (event: Event) => void): Disposable;
92
- getEventListeners(emitter: node_events, name: string | symbol): ((...args: any[]) => void)[];
93
- getEventListeners(emitter: EventTarget, name: string): ((...args: any[]) => void)[];
94
- getMaxListeners(emitter: node_events | EventTarget): number;
95
- listenerCount(emitter: node_events, eventName: string | symbol): number;
96
- listenerCount(emitter: EventTarget, eventName: string): number;
97
- on(emitter: node_events, eventName: string | symbol, options?: node_events.OnOptions): NodeJS.AsyncIterator<any[]>;
98
- on(emitter: EventTarget, eventName: string, options?: node_events.OnOptions): NodeJS.AsyncIterator<any[]>;
99
- once(emitter: node_events, eventName: string | symbol, options?: node_events.OnceOptions): Promise<any[]>;
100
- once(emitter: EventTarget, eventName: string, options?: node_events.OnceOptions): Promise<any[]>;
101
- setMaxListeners(n: number, ...eventTargets: ReadonlyArray<node_events | EventTarget>): void;
102
- readonly captureRejectionSymbol: typeof node_events.captureRejectionSymbol;
103
- captureRejections: boolean;
104
- defaultMaxListeners: number;
105
- readonly errorMonitor: typeof node_events.errorMonitor;
106
- EventEmitterAsyncResource: typeof node_events.EventEmitterAsyncResource;
107
- }>;
108
- close(): Promise<void>;
109
- }
110
-
111
- export { MnemosyneServer, type ServerOptions };
@@ -3730,9 +3730,22 @@ function loadConfig() {
3730
3730
  return defaultConfig();
3731
3731
  }
3732
3732
  }
3733
+ function getVersion() {
3734
+ try {
3735
+ const pkg = JSON.parse((0, import_fs.readFileSync)((0, import_path.resolve)(__dirname, "../package.json"), "utf-8"));
3736
+ return pkg.version;
3737
+ } catch {
3738
+ try {
3739
+ const pkg = JSON.parse((0, import_fs.readFileSync)((0, import_path.resolve)(process.cwd(), "package.json"), "utf-8"));
3740
+ return pkg.version;
3741
+ } catch {
3742
+ return "2.0.1";
3743
+ }
3744
+ }
3745
+ }
3733
3746
  function defaultConfig() {
3734
3747
  return {
3735
- server: { port: 7321, host: "localhost", version: "2.0.0" },
3748
+ server: { port: 7321, host: "localhost", version: getVersion() },
3736
3749
  database: { path: "data/nexus.db", wal_mode: true, vec_extension_path: "data/vec0" },
3737
3750
  storage: { files_dir: "data/files", max_file_size_mb: 50, backups_dir: "data/backups", backup_interval_hours: 24, max_backups: 7 },
3738
3751
  limits: { max_atoms_per_project: 1e4, rate_limit_requests: 100, rate_limit_window_ms: 6e4 },
@@ -4533,7 +4546,7 @@ var require_filesystem = __commonJS({
4533
4546
  var LDD_PATH = "/usr/bin/ldd";
4534
4547
  var SELF_PATH = "/proc/self/exe";
4535
4548
  var MAX_LENGTH = 2048;
4536
- var readFileSync6 = (path) => {
4549
+ var readFileSync5 = (path) => {
4537
4550
  const fd = fs.openSync(path, "r");
4538
4551
  const buffer = Buffer.alloc(MAX_LENGTH);
4539
4552
  const bytesRead = fs.readSync(fd, buffer, 0, MAX_LENGTH, 0);
@@ -4558,7 +4571,7 @@ var require_filesystem = __commonJS({
4558
4571
  module2.exports = {
4559
4572
  LDD_PATH,
4560
4573
  SELF_PATH,
4561
- readFileSync: readFileSync6,
4574
+ readFileSync: readFileSync5,
4562
4575
  readFile
4563
4576
  };
4564
4577
  }
@@ -4607,7 +4620,7 @@ var require_detect_libc = __commonJS({
4607
4620
  "use strict";
4608
4621
  var childProcess = require("child_process");
4609
4622
  var { isLinux, getReport } = require_process();
4610
- var { LDD_PATH, SELF_PATH, readFile, readFileSync: readFileSync6 } = require_filesystem();
4623
+ var { LDD_PATH, SELF_PATH, readFile, readFileSync: readFileSync5 } = require_filesystem();
4611
4624
  var { interpreterPath } = require_elf();
4612
4625
  var cachedFamilyInterpreter;
4613
4626
  var cachedFamilyFilesystem;
@@ -4699,7 +4712,7 @@ var require_detect_libc = __commonJS({
4699
4712
  }
4700
4713
  cachedFamilyFilesystem = null;
4701
4714
  try {
4702
- const lddContent = readFileSync6(LDD_PATH);
4715
+ const lddContent = readFileSync5(LDD_PATH);
4703
4716
  cachedFamilyFilesystem = getFamilyFromLddContent(lddContent);
4704
4717
  } catch (e) {
4705
4718
  }
@@ -4724,7 +4737,7 @@ var require_detect_libc = __commonJS({
4724
4737
  }
4725
4738
  cachedFamilyInterpreter = null;
4726
4739
  try {
4727
- const selfContent = readFileSync6(SELF_PATH);
4740
+ const selfContent = readFileSync5(SELF_PATH);
4728
4741
  const path = interpreterPath(selfContent);
4729
4742
  cachedFamilyInterpreter = familyFromInterpreterPath(path);
4730
4743
  } catch (e) {
@@ -4788,7 +4801,7 @@ var require_detect_libc = __commonJS({
4788
4801
  }
4789
4802
  cachedVersionFilesystem = null;
4790
4803
  try {
4791
- const lddContent = readFileSync6(LDD_PATH);
4804
+ const lddContent = readFileSync5(LDD_PATH);
4792
4805
  const versionMatch = lddContent.match(RE_GLIBC_VERSION);
4793
4806
  if (versionMatch) {
4794
4807
  cachedVersionFilesystem = versionMatch[1];
@@ -9605,7 +9618,7 @@ module.exports = __toCommonJS(server_exports);
9605
9618
 
9606
9619
  // src/server/MnemosyneServer.ts
9607
9620
  var import_http = require("http");
9608
- var import_fs6 = require("fs");
9621
+ var import_fs5 = require("fs");
9609
9622
  var import_path6 = require("path");
9610
9623
 
9611
9624
  // node_modules/ws/wrapper.mjs
@@ -10910,12 +10923,20 @@ function handleEvents(store, pathname, method, res, searchParams) {
10910
10923
  }
10911
10924
 
10912
10925
  // src/api/routes/health.ts
10926
+ var PKG_VERSION = (() => {
10927
+ try {
10928
+ const pkg = JSON.parse(require("fs").readFileSync(require("path").resolve(__dirname, "../../../package.json"), "utf-8"));
10929
+ return pkg.version;
10930
+ } catch {
10931
+ return "2.0.1";
10932
+ }
10933
+ })();
10913
10934
  function handleHealth(store, pathname, method, res) {
10914
- if (pathname === "/health" && method === "GET") {
10935
+ if ((pathname === "/health" || pathname === "/api/v1/health") && method === "GET") {
10915
10936
  const stats = store.getStats();
10916
10937
  json(res, 200, {
10917
10938
  status: "ok",
10918
- version: "2.0.0",
10939
+ version: PKG_VERSION,
10919
10940
  storage: "sqlite",
10920
10941
  database: store.config.database.path,
10921
10942
  uptime: process.uptime(),
@@ -12300,9 +12321,219 @@ ${JSON.stringify(analysis.metadata, null, 2)}
12300
12321
 
12301
12322
  // src/db/connection.ts
12302
12323
  var import_better_sqlite32 = __toESM(require("better-sqlite3"));
12303
- var import_fs5 = require("fs");
12304
12324
  var import_path5 = require("path");
12305
12325
  init_config();
12326
+
12327
+ // src/db/schema.ts
12328
+ var SCHEMA_SQL = `-- Mnemosyne v1.1 Database Schema
12329
+ -- SQLite with sqlite-vec extension for semantic search
12330
+
12331
+ -- PROJECTS (Spaces)
12332
+ CREATE TABLE IF NOT EXISTS projects (
12333
+ id TEXT PRIMARY KEY,
12334
+ name TEXT NOT NULL UNIQUE,
12335
+ description TEXT,
12336
+ icon TEXT DEFAULT '\u25C9',
12337
+ color TEXT DEFAULT '#6366f1',
12338
+ created_at INTEGER DEFAULT (unixepoch()),
12339
+ updated_at INTEGER DEFAULT (unixepoch()),
12340
+ owner TEXT DEFAULT 'human',
12341
+ metadata TEXT DEFAULT '{}'
12342
+ );
12343
+
12344
+ -- ATOMS (Ideas/Nodes)
12345
+ CREATE TABLE IF NOT EXISTS atoms (
12346
+ id TEXT PRIMARY KEY,
12347
+ project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
12348
+ parent_id TEXT REFERENCES atoms(id) ON DELETE CASCADE,
12349
+ title TEXT NOT NULL,
12350
+ summary TEXT,
12351
+ icon TEXT DEFAULT '\u25CF',
12352
+ color TEXT,
12353
+ x REAL,
12354
+ y REAL,
12355
+ auto_path TEXT,
12356
+ path_overridden INTEGER DEFAULT 0,
12357
+ status TEXT DEFAULT 'draft',
12358
+ status_updated_at INTEGER DEFAULT (unixepoch()),
12359
+ embedding_status TEXT DEFAULT 'pending',
12360
+ embedding_error TEXT,
12361
+ block_count INTEGER DEFAULT 0,
12362
+ bond_count INTEGER DEFAULT 0,
12363
+ template_id TEXT,
12364
+ created_at INTEGER DEFAULT (unixepoch()),
12365
+ updated_at INTEGER DEFAULT (unixepoch()),
12366
+ version INTEGER DEFAULT 1,
12367
+ locked_by TEXT,
12368
+ locked_at INTEGER,
12369
+ locked_reason TEXT,
12370
+ owner TEXT DEFAULT 'human',
12371
+ metadata TEXT DEFAULT '{}'
12372
+ );
12373
+
12374
+ -- BLOCKS (Content pieces inside atoms)
12375
+ CREATE TABLE IF NOT EXISTS blocks (
12376
+ id TEXT PRIMARY KEY,
12377
+ atom_id TEXT NOT NULL REFERENCES atoms(id) ON DELETE CASCADE,
12378
+ type TEXT NOT NULL DEFAULT 'text',
12379
+ content TEXT,
12380
+ order_index INTEGER DEFAULT 0,
12381
+ created_at INTEGER DEFAULT (unixepoch()),
12382
+ updated_at INTEGER DEFAULT (unixepoch()),
12383
+ metadata TEXT DEFAULT '{}'
12384
+ );
12385
+
12386
+ -- BONDS (Graph connections between atoms)
12387
+ CREATE TABLE IF NOT EXISTS bonds (
12388
+ id TEXT PRIMARY KEY,
12389
+ source_id TEXT NOT NULL REFERENCES atoms(id) ON DELETE CASCADE,
12390
+ target_id TEXT NOT NULL REFERENCES atoms(id) ON DELETE CASCADE,
12391
+ label TEXT DEFAULT 'connects',
12392
+ color TEXT,
12393
+ created_at INTEGER DEFAULT (unixepoch()),
12394
+ UNIQUE(source_id, target_id)
12395
+ );
12396
+
12397
+ -- ATTACHMENTS (Files in CAS)
12398
+ CREATE TABLE IF NOT EXISTS attachments (
12399
+ id TEXT PRIMARY KEY,
12400
+ block_id TEXT REFERENCES blocks(id) ON DELETE CASCADE,
12401
+ file_name TEXT NOT NULL,
12402
+ file_hash TEXT NOT NULL,
12403
+ file_size INTEGER,
12404
+ mime_type TEXT,
12405
+ created_at INTEGER DEFAULT (unixepoch()),
12406
+ UNIQUE(file_hash)
12407
+ );
12408
+
12409
+ -- EVENT LOG (Immutable audit trail)
12410
+ CREATE TABLE IF NOT EXISTS event_log (
12411
+ id TEXT PRIMARY KEY,
12412
+ timestamp INTEGER DEFAULT (unixepoch()),
12413
+ event_type TEXT NOT NULL,
12414
+ project_id TEXT,
12415
+ atom_id TEXT,
12416
+ block_id TEXT,
12417
+ bond_id TEXT,
12418
+ actor TEXT NOT NULL DEFAULT 'system',
12419
+ actor_type TEXT DEFAULT 'system',
12420
+ diff TEXT,
12421
+ trigger TEXT,
12422
+ metadata TEXT DEFAULT '{}'
12423
+ );
12424
+
12425
+ -- ASSISTANTS (AI Agents)
12426
+ CREATE TABLE IF NOT EXISTS assistants (
12427
+ id TEXT PRIMARY KEY,
12428
+ name TEXT NOT NULL,
12429
+ role TEXT DEFAULT 'worker',
12430
+ permissions TEXT DEFAULT '{"read":["*"],"write":[],"delete":false}',
12431
+ status TEXT DEFAULT 'active',
12432
+ provider TEXT,
12433
+ connected_at INTEGER DEFAULT (unixepoch()),
12434
+ last_seen INTEGER DEFAULT (unixepoch()),
12435
+ metadata TEXT DEFAULT '{}'
12436
+ );
12437
+
12438
+ -- QUEUE (Agent waitlist for locked atoms)
12439
+ CREATE TABLE IF NOT EXISTS queue (
12440
+ id TEXT PRIMARY KEY,
12441
+ atom_id TEXT NOT NULL REFERENCES atoms(id) ON DELETE CASCADE,
12442
+ assistant_id TEXT NOT NULL REFERENCES assistants(id) ON DELETE CASCADE,
12443
+ requested_at INTEGER DEFAULT (unixepoch()),
12444
+ priority INTEGER DEFAULT 5,
12445
+ status TEXT DEFAULT 'waiting',
12446
+ reason TEXT
12447
+ );
12448
+
12449
+ -- INDICES
12450
+ CREATE INDEX IF NOT EXISTS idx_atoms_project ON atoms(project_id);
12451
+ CREATE INDEX IF NOT EXISTS idx_atoms_parent ON atoms(parent_id);
12452
+ CREATE INDEX IF NOT EXISTS idx_atoms_locked ON atoms(locked_by) WHERE locked_by IS NOT NULL;
12453
+ -- idx_atoms_path_project is created by migration after auto_path column is added
12454
+ CREATE INDEX IF NOT EXISTS idx_blocks_atom ON blocks(atom_id);
12455
+ CREATE INDEX IF NOT EXISTS idx_bonds_source ON bonds(source_id);
12456
+ CREATE INDEX IF NOT EXISTS idx_bonds_target ON bonds(target_id);
12457
+ CREATE INDEX IF NOT EXISTS idx_event_log_time ON event_log(timestamp);
12458
+ CREATE INDEX IF NOT EXISTS idx_event_log_atom ON event_log(atom_id);
12459
+ CREATE INDEX IF NOT EXISTS idx_queue_atom ON queue(atom_id);
12460
+ CREATE INDEX IF NOT EXISTS idx_attachments_hash ON attachments(file_hash);
12461
+
12462
+ -- Auto-update block_count and bond_count triggers
12463
+ CREATE TRIGGER IF NOT EXISTS update_block_count_insert AFTER INSERT ON blocks BEGIN
12464
+ UPDATE atoms SET block_count = block_count + 1 WHERE id = NEW.atom_id;
12465
+ END;
12466
+
12467
+ CREATE TRIGGER IF NOT EXISTS update_block_count_delete AFTER DELETE ON blocks BEGIN
12468
+ UPDATE atoms SET block_count = block_count - 1 WHERE id = OLD.atom_id;
12469
+ END;
12470
+
12471
+ CREATE TRIGGER IF NOT EXISTS update_bond_count_insert AFTER INSERT ON bonds BEGIN
12472
+ UPDATE atoms SET bond_count = bond_count + 1 WHERE id = NEW.source_id OR id = NEW.target_id;
12473
+ END;
12474
+
12475
+ CREATE TRIGGER IF NOT EXISTS update_bond_count_delete AFTER DELETE ON bonds BEGIN
12476
+ UPDATE atoms SET bond_count = bond_count - 1 WHERE id = OLD.source_id OR id = OLD.target_id;
12477
+ END;
12478
+
12479
+ -- FTS5 FULL-TEXT SEARCH
12480
+ -- Separate tables to avoid rowid collisions between atoms and blocks
12481
+
12482
+ CREATE VIRTUAL TABLE IF NOT EXISTS search_atoms USING fts5(
12483
+ title, summary,
12484
+ content='atoms', content_rowid='rowid'
12485
+ );
12486
+
12487
+ CREATE VIRTUAL TABLE IF NOT EXISTS search_blocks USING fts5(
12488
+ content,
12489
+ content='blocks', content_rowid='rowid'
12490
+ );
12491
+
12492
+ -- Triggers to keep search_atoms in sync
12493
+ CREATE TRIGGER IF NOT EXISTS trig_search_atoms_insert AFTER INSERT ON atoms BEGIN
12494
+ INSERT INTO search_atoms(rowid, title, summary) VALUES (new.rowid, new.title, COALESCE(new.summary, ''));
12495
+ END;
12496
+
12497
+ CREATE TRIGGER IF NOT EXISTS trig_search_atoms_update AFTER UPDATE ON atoms BEGIN
12498
+ UPDATE search_atoms SET title = new.title, summary = COALESCE(new.summary, '') WHERE rowid = new.rowid;
12499
+ END;
12500
+
12501
+ CREATE TRIGGER IF NOT EXISTS trig_search_atoms_delete AFTER DELETE ON atoms BEGIN
12502
+ DELETE FROM search_atoms WHERE rowid = old.rowid;
12503
+ END;
12504
+
12505
+ -- Triggers to keep search_blocks in sync
12506
+ CREATE TRIGGER IF NOT EXISTS trig_search_blocks_insert AFTER INSERT ON blocks BEGIN
12507
+ INSERT INTO search_blocks(rowid, content) VALUES (new.rowid, COALESCE(new.content, ''));
12508
+ END;
12509
+
12510
+ CREATE TRIGGER IF NOT EXISTS trig_search_blocks_update AFTER UPDATE ON blocks BEGIN
12511
+ UPDATE search_blocks SET content = COALESCE(new.content, '') WHERE rowid = new.rowid;
12512
+ END;
12513
+
12514
+ CREATE TRIGGER IF NOT EXISTS trig_search_blocks_delete AFTER DELETE ON blocks BEGIN
12515
+ DELETE FROM search_blocks WHERE rowid = old.rowid;
12516
+ END;
12517
+
12518
+
12519
+ -- PER-ATOM PERMISSIONS (Granular access control)
12520
+ CREATE TABLE IF NOT EXISTS atom_permissions (
12521
+ id TEXT PRIMARY KEY,
12522
+ atom_id TEXT NOT NULL REFERENCES atoms(id) ON DELETE CASCADE,
12523
+ assistant_id TEXT NOT NULL REFERENCES assistants(id) ON DELETE CASCADE,
12524
+ level TEXT NOT NULL DEFAULT 'view',
12525
+ granted_by TEXT,
12526
+ granted_at INTEGER DEFAULT (unixepoch()),
12527
+ metadata TEXT DEFAULT '{}',
12528
+ UNIQUE(atom_id, assistant_id)
12529
+ );
12530
+
12531
+ -- sqlite-vec virtual table for semantic embeddings
12532
+ -- Created dynamically by connection.ts after loading the extension
12533
+ -- CREATE VIRTUAL TABLE IF NOT EXISTS atom_vectors USING vec0(atom_id TEXT PRIMARY KEY, embedding float[384]);
12534
+ `;
12535
+
12536
+ // src/db/connection.ts
12306
12537
  var DB_PATH2 = process.env.MNEMOSYNE_DB_PATH || (0, import_path5.resolve)(process.cwd(), CONFIG.database.path);
12307
12538
  var db = null;
12308
12539
  var vecEnabled = false;
@@ -12321,8 +12552,7 @@ function getDb() {
12321
12552
  console.warn("[DB] sqlite-vec not available:", err.message);
12322
12553
  vecEnabled = false;
12323
12554
  }
12324
- const schema = (0, import_fs5.readFileSync)((0, import_path5.resolve)(process.cwd(), "src", "db", "schema.sql"), "utf-8");
12325
- db.exec(schema);
12555
+ db.exec(SCHEMA_SQL);
12326
12556
  if (vecEnabled) {
12327
12557
  try {
12328
12558
  db.exec(`CREATE VIRTUAL TABLE IF NOT EXISTS atom_vectors USING vec0(atom_id TEXT PRIMARY KEY, embedding float[${CONFIG.embeddings.dimension}])`);
@@ -12354,7 +12584,6 @@ var Store2 = class extends Store {
12354
12584
  };
12355
12585
 
12356
12586
  // src/server/MnemosyneServer.ts
12357
- init_config();
12358
12587
  var MnemosyneServer = class {
12359
12588
  store;
12360
12589
  api;
@@ -12362,8 +12591,9 @@ var MnemosyneServer = class {
12362
12591
  httpServer;
12363
12592
  brain;
12364
12593
  constructor(options = {}, brain) {
12365
- const port = options.port ?? CONFIG.server.port;
12366
- const host = options.host ?? CONFIG.server.host;
12594
+ const cfg = brain?.config?.config;
12595
+ const port = options.port ?? cfg?.server?.port ?? 7321;
12596
+ const host = options.host ?? cfg?.server?.host ?? "localhost";
12367
12597
  const enableDashboard = options.dashboard !== false;
12368
12598
  const enableWebsocket = options.websocket !== false;
12369
12599
  process.on("uncaughtException", (err) => {
@@ -12391,8 +12621,9 @@ var MnemosyneServer = class {
12391
12621
  const wss = new import_websocket_server.default({ server: this.httpServer });
12392
12622
  this.wsHandler = new WebSocketHandler(wss, this.store);
12393
12623
  }
12624
+ const version = cfg?.server?.version || "2.0.1";
12394
12625
  this.httpServer.listen(port, () => {
12395
- console.log(`Mnemosyne v${CONFIG.server.version} \u2014 port ${port}`);
12626
+ console.log(`Mnemosyne v${version} \u2014 port ${port}`);
12396
12627
  console.log(`Dashboard: http://${host}:${port}/dashboard`);
12397
12628
  console.log(`API: http://${host}:${port}/api/v1`);
12398
12629
  console.log(`MCP: http://${host}:${port}/mcp/manifest`);
@@ -12417,12 +12648,13 @@ var MnemosyneServer = class {
12417
12648
  };
12418
12649
  const dirs = [
12419
12650
  (0, import_path6.resolve)(process.cwd(), "src/dashboard"),
12420
- (0, import_path6.resolve)(process.cwd(), "dashboard")
12651
+ (0, import_path6.resolve)(process.cwd(), "dashboard"),
12652
+ (0, import_path6.resolve)(__dirname, "../dashboard")
12421
12653
  ];
12422
12654
  for (const dir of dirs) {
12423
12655
  const filePath = (0, import_path6.resolve)(dir, urlPath);
12424
- if ((0, import_fs6.existsSync)(filePath)) {
12425
- const data = (0, import_fs6.readFileSync)(filePath);
12656
+ if ((0, import_fs5.existsSync)(filePath)) {
12657
+ const data = (0, import_fs5.readFileSync)(filePath);
12426
12658
  res.writeHead(200, { "Content-Type": mime[ext] || "application/octet-stream" });
12427
12659
  res.end(data);
12428
12660
  return;