tsunami-memory 1.0.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 (54) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +501 -0
  3. package/README.zh-CN.md +485 -0
  4. package/package.json +46 -0
  5. package/server/api.ts +125 -0
  6. package/server/mcp.ts +221 -0
  7. package/src/bun_memory_store.ts +340 -0
  8. package/src/classifier_keywords.ts +115 -0
  9. package/src/core/project_state.ts +88 -0
  10. package/src/index.ts +54 -0
  11. package/src/legacy_compat/tsunami_compat.ts +22 -0
  12. package/src/legacy_compat/tsunami_legacy_identity.ts +13 -0
  13. package/src/legacy_compat/tsunami_legacy_taxonomy.ts +197 -0
  14. package/src/memory_audit.ts +32 -0
  15. package/src/memory_conflict_resolver.ts +14 -0
  16. package/src/memory_fabric.ts +31 -0
  17. package/src/memory_manager.ts +10 -0
  18. package/src/memory_promotion.ts +22 -0
  19. package/src/memory_recovery.ts +14 -0
  20. package/src/memory_runtime.ts +7 -0
  21. package/src/migration.ts +163 -0
  22. package/src/provider.ts +68 -0
  23. package/src/runtime/checkpoints/durable_recovery.ts +24 -0
  24. package/src/runtime/paths.ts +11 -0
  25. package/src/storm/basins.ts +57 -0
  26. package/src/storm/boundary.ts +52 -0
  27. package/src/storm/budget.ts +42 -0
  28. package/src/storm/center.ts +396 -0
  29. package/src/storm/confidence.ts +88 -0
  30. package/src/storm/coverage.ts +44 -0
  31. package/src/storm/directive.ts +94 -0
  32. package/src/storm/gate.ts +43 -0
  33. package/src/storm/helpers.ts +172 -0
  34. package/src/storm/horizon.ts +52 -0
  35. package/src/storm/intake.ts +80 -0
  36. package/src/storm/mode.ts +21 -0
  37. package/src/storm/pressure.ts +56 -0
  38. package/src/storm/readiness.ts +29 -0
  39. package/src/storm/saturation.ts +45 -0
  40. package/src/storm/selection.ts +49 -0
  41. package/src/storm/signals.ts +105 -0
  42. package/src/storm/types.ts +216 -0
  43. package/src/tsunami_bun_backend.ts +705 -0
  44. package/src/tsunami_chinese_dialect.ts +19 -0
  45. package/src/tsunami_classifier.ts +137 -0
  46. package/src/tsunami_client.ts +710 -0
  47. package/src/tsunami_execution_gate.ts +232 -0
  48. package/src/tsunami_graph_runtime.ts +359 -0
  49. package/src/tsunami_identity.ts +35 -0
  50. package/src/tsunami_routing.ts +169 -0
  51. package/src/tsunami_runtime_graph_sync.ts +17 -0
  52. package/src/tsunami_schema.ts +403 -0
  53. package/src/tsunami_storage_paths.ts +8 -0
  54. package/src/tsunami_storm_center.ts +53 -0
@@ -0,0 +1,88 @@
1
+ /**
2
+ * TSUNAMI project state stubs
3
+ *
4
+ * Provides project-level state queries for the storm center.
5
+ * Returns null/empty defaults; the storm center handles these gracefully.
6
+ */
7
+
8
+ export interface ProjectTaskThread {
9
+ id: string;
10
+ title: string;
11
+ status: string;
12
+ summary?: string;
13
+ nextStep?: string;
14
+ featureId?: string;
15
+ }
16
+
17
+ export interface ProjectHandoffRecord {
18
+ id: string;
19
+ task: string;
20
+ summary?: string;
21
+ nextStep?: string;
22
+ progressStatus?: string;
23
+ progressFeatureId?: string;
24
+ }
25
+
26
+ export interface ProjectStateStatus {
27
+ activeFeature?: {
28
+ id?: string;
29
+ title?: string;
30
+ status?: string;
31
+ detail?: string;
32
+ } | null;
33
+ }
34
+
35
+ export interface ProjectWikiPage {
36
+ pageId: string;
37
+ title: string;
38
+ summary: string;
39
+ confidence: number;
40
+ tags: string[];
41
+ sourceRefs: string[];
42
+ updatedAt: number;
43
+ }
44
+
45
+ export interface ProjectWikiEvidence {
46
+ snippetId: string;
47
+ pageId: string;
48
+ title: string;
49
+ sourcePath: string;
50
+ sourceRef: string;
51
+ quote: string;
52
+ tags: string[];
53
+ }
54
+
55
+ export interface ProjectWikiQueryResult {
56
+ evidence: ProjectWikiEvidence[];
57
+ }
58
+
59
+ export function getProjectStateStatus(_projectDir: string): ProjectStateStatus {
60
+ return { activeFeature: null };
61
+ }
62
+
63
+ export function resolveProjectTaskThread(
64
+ _projectDir: string,
65
+ _query: string,
66
+ _limit?: number,
67
+ ): { thread: ProjectTaskThread | null; match: string | null } {
68
+ return { thread: null, match: null };
69
+ }
70
+
71
+ export function getProjectLatestHandoff(
72
+ _projectDir: string,
73
+ _opts?: { sessionId?: string; featureId?: string },
74
+ ): ProjectHandoffRecord | null {
75
+ return null;
76
+ }
77
+
78
+ export function listProjectWikiPages(_projectDir: string, _limit?: number): ProjectWikiPage[] {
79
+ return [];
80
+ }
81
+
82
+ export function queryProjectWiki(
83
+ _projectDir: string,
84
+ _query: string,
85
+ _limit?: number,
86
+ ): ProjectWikiQueryResult {
87
+ return { evidence: [] };
88
+ }
package/src/index.ts ADDED
@@ -0,0 +1,54 @@
1
+ /**
2
+ * TSUNAMI Memory System — Public API
3
+ *
4
+ * Bun-native oceanic memory with basin/current flow, storm center,
5
+ * hot+cold retrieval, knowledge graph sync, and evidence linking.
6
+ *
7
+ * Usage:
8
+ * import { tsunamiSearch, tsunamiAdd, tsunamiStatus } from 'tsunami-memory';
9
+ * */
10
+
11
+ // ── Core Memory Operations ──────────────────────────────────
12
+ export {
13
+ tsunamiAdd,
14
+ tsunamiSearch,
15
+ tsunamiRecall,
16
+ tsunamiWakeUp,
17
+ tsunamiDiary,
18
+ tsunamiStatus,
19
+ tsunamiTimeline,
20
+ tsunamiListWings,
21
+ } from './tsunami_client';
22
+
23
+ // ── Knowledge Graph ────────────────────────────────────────
24
+ export {
25
+ tsunamiKgQuery,
26
+ tsunamiKgAdd,
27
+ tsunamiKgAddTyped,
28
+ tsunamiKgStats,
29
+ tsunamiKgTimeline,
30
+ } from './tsunami_client';
31
+
32
+ // ── Storm Center ────────────────────────────────────────────
33
+ export {
34
+ buildTsunamiStormCenter,
35
+ formatTsunamiStormCenterText,
36
+ } from './tsunami_storm_center';
37
+
38
+ // ── Execution Gate ──────────────────────────────────────────
39
+ export {
40
+ buildTsunamiExecutionGate,
41
+ deriveTsunamiLoopStepLimit,
42
+ applyTsunamiExecutionGateToTool,
43
+ formatTsunamiExecutionGateSummary,
44
+ } from './tsunami_execution_gate';
45
+
46
+ // ── Classification & Routing ────────────────────────────────
47
+ export { classifyMemory } from './tsunami_classifier';
48
+
49
+ // ── Types ───────────────────────────────────────────────────
50
+ export type { TsunamiBasin, TsunamiCurrent } from './tsunami_schema';
51
+ export type { TsunamiStormCenter } from './tsunami_storm_center';
52
+ export type { TsunamiExecutionGate } from './tsunami_execution_gate';
53
+
54
+ export type { TsunamiAddOptions } from './tsunami_client';
@@ -0,0 +1,22 @@
1
+ /**
2
+ * TSUNAMI legacy compatibility stubs
3
+ *
4
+ * @deprecated These stubs exist to preserve compile-time compatibility with code
5
+ * extracted from a larger Python-based monorepo. They provide fallback/opt-in paths
6
+ * that are disabled by default. Scheduled for removal in v2.0.
7
+ */
8
+
9
+ export const TSUNAMI_COMPAT_WRAPPER = '';
10
+ export const TSUNAMI_DEFAULT_LEGACY_ROOM = 'ats/general';
11
+
12
+ export function normalizeTsunamiCompatRoom(room: string): string {
13
+ return String(room || TSUNAMI_DEFAULT_LEGACY_ROOM).trim().toLowerCase().replace(/\s+/g, '_');
14
+ }
15
+
16
+ export function isTsunamiLegacyWrapperExplicitlyEnabled(_req: Record<string, unknown>): boolean {
17
+ return false;
18
+ }
19
+
20
+ export function listTsunamiCompatPythonCandidates(): string[] {
21
+ return ['python3', 'python'];
22
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * TSUNAMI legacy identity stub
3
+ *
4
+ * Provides legacy identity text replacements and detection.
5
+ * All replacements are empty by default; the Bun-native runtime
6
+ * handles identity normalization directly.
7
+ */
8
+
9
+ export const TSUNAMI_LEGACY_IDENTITY_REPLACEMENTS: Array<[RegExp, string]> = [];
10
+
11
+ export function hasTsunamiLegacyIdentityTerms(_raw: string): boolean {
12
+ return false;
13
+ }
@@ -0,0 +1,197 @@
1
+ /**
2
+ * TSUNAMI legacy taxonomy mapping
3
+ *
4
+ * Maps legacy wing/room identifiers to the current basin/current taxonomy.
5
+ *
6
+ * Legacy wings are mapped as follows:
7
+ * ats -> epicenter (core identity, memory operations)
8
+ * brain -> surface (model, tools, architecture)
9
+ * decision -> faultline (choices, direction, strategy)
10
+ * memory -> abyss (deep storage, retrieval, compression)
11
+ * task -> surge (execution, projects, routines)
12
+ * people -> harbor (users, partners, team)
13
+ */
14
+
15
+ export const TSUNAMI_LEGACY_TAXONOMY_ENTRIES = [
16
+ // --- epicenter (legacy: ats) ---
17
+ {
18
+ legacyWing: 'ats',
19
+ legacyRoom: 'ats/signature',
20
+ basin: 'epicenter',
21
+ current: 'epicenter/signature',
22
+ description: 'Core identity signature and positioning',
23
+ },
24
+ {
25
+ legacyWing: 'ats',
26
+ legacyRoom: 'ats/crest',
27
+ basin: 'epicenter',
28
+ current: 'epicenter/crest',
29
+ description: 'Peak identity states and high-confidence role affirmations',
30
+ },
31
+ {
32
+ legacyWing: 'ats',
33
+ legacyRoom: 'ats/law',
34
+ basin: 'epicenter',
35
+ current: 'epicenter/law',
36
+ description: 'Immutable rules, principles, and hard boundaries',
37
+ },
38
+ // --- surface (legacy: brain) ---
39
+ {
40
+ legacyWing: 'brain',
41
+ legacyRoom: 'brain/bridge',
42
+ basin: 'surface',
43
+ current: 'surface/bridge',
44
+ description: 'Model provider bridge and engine configuration',
45
+ },
46
+ {
47
+ legacyWing: 'brain',
48
+ legacyRoom: 'brain/helm',
49
+ basin: 'surface',
50
+ current: 'surface/helm',
51
+ description: 'Active control plane, execution loop, and orchestration',
52
+ },
53
+ {
54
+ legacyWing: 'brain',
55
+ legacyRoom: 'brain/rigging',
56
+ basin: 'surface',
57
+ current: 'surface/rigging',
58
+ description: 'Tool rigging, registration, and executor wiring',
59
+ },
60
+ {
61
+ legacyWing: 'brain',
62
+ legacyRoom: 'brain/hull',
63
+ basin: 'surface',
64
+ current: 'surface/hull',
65
+ description: 'Architecture, modules, and structural integrity',
66
+ },
67
+ {
68
+ legacyWing: 'brain',
69
+ legacyRoom: 'brain/chart',
70
+ basin: 'surface',
71
+ current: 'surface/chart',
72
+ description: 'Directory layout, paths, and project navigation',
73
+ },
74
+ {
75
+ legacyWing: 'brain',
76
+ legacyRoom: 'brain/echo',
77
+ basin: 'surface',
78
+ current: 'surface/echo',
79
+ description: 'TTS, voice, audio, and speech synthesis',
80
+ },
81
+ // --- faultline (legacy: decision) ---
82
+ {
83
+ legacyWing: 'decision',
84
+ legacyRoom: 'decision/choice',
85
+ basin: 'faultline',
86
+ current: 'faultline/choice',
87
+ description: 'Technical decisions, architecture selection, and approach finalization',
88
+ },
89
+ {
90
+ legacyWing: 'decision',
91
+ legacyRoom: 'decision/course',
92
+ basin: 'faultline',
93
+ current: 'faultline/course',
94
+ description: 'Strategic direction, priorities, and product decisions',
95
+ },
96
+ {
97
+ legacyWing: 'decision',
98
+ legacyRoom: 'decision/drift',
99
+ basin: 'faultline',
100
+ current: 'faultline/drift',
101
+ description: 'Conflicts, abandoned approaches, and course corrections',
102
+ },
103
+ // --- abyss (legacy: memory) ---
104
+ {
105
+ legacyWing: 'memory',
106
+ legacyRoom: 'memory/archive',
107
+ basin: 'abyss',
108
+ current: 'abyss/archive',
109
+ description: 'Long-term memory storage, compression, and archival',
110
+ },
111
+ {
112
+ legacyWing: 'memory',
113
+ legacyRoom: 'memory/mesh',
114
+ basin: 'abyss',
115
+ current: 'abyss/mesh',
116
+ description: 'Knowledge graph, relationships, and semantic connections',
117
+ },
118
+ {
119
+ legacyWing: 'memory',
120
+ legacyRoom: 'memory/wake',
121
+ basin: 'abyss',
122
+ current: 'abyss/wake',
123
+ description: 'Memory retrieval, wake signals, and activation patterns',
124
+ },
125
+ {
126
+ legacyWing: 'memory',
127
+ legacyRoom: 'memory/anchors',
128
+ basin: 'abyss',
129
+ current: 'abyss/anchors',
130
+ description: 'Recovery anchors, checkpoints, and persistent reference points',
131
+ },
132
+ {
133
+ legacyWing: 'memory',
134
+ legacyRoom: 'memory/evidence',
135
+ basin: 'abyss',
136
+ current: 'abyss/evidence',
137
+ description: 'Evidence snippets, citations, and supporting context',
138
+ },
139
+ // --- surge (legacy: task) ---
140
+ {
141
+ legacyWing: 'task',
142
+ legacyRoom: 'task/expedition',
143
+ basin: 'surge',
144
+ current: 'surge/expedition',
145
+ description: 'Active projects, features, and implementation work',
146
+ },
147
+ {
148
+ legacyWing: 'task',
149
+ legacyRoom: 'task/tide',
150
+ basin: 'surge',
151
+ current: 'surge/tide',
152
+ description: 'Scheduled routines, daily tasks, and recurring checks',
153
+ },
154
+ {
155
+ legacyWing: 'task',
156
+ legacyRoom: 'task/queue',
157
+ basin: 'surge',
158
+ current: 'surge/queue',
159
+ description: 'Task backlog, pending items, and work queue',
160
+ },
161
+ {
162
+ legacyWing: 'task',
163
+ legacyRoom: 'task/blockers',
164
+ basin: 'surge',
165
+ current: 'surge/blockers',
166
+ description: 'Blockers, issues, and impediments to progress',
167
+ },
168
+ // --- harbor (legacy: people) ---
169
+ {
170
+ legacyWing: 'people',
171
+ legacyRoom: 'people/crew',
172
+ basin: 'harbor',
173
+ current: 'harbor/crew',
174
+ description: 'Users, team members, and collaboration context',
175
+ },
176
+ {
177
+ legacyWing: 'people',
178
+ legacyRoom: 'people/research',
179
+ basin: 'harbor',
180
+ current: 'harbor/research',
181
+ description: 'Research findings, explorations, and investigations',
182
+ },
183
+ {
184
+ legacyWing: 'people',
185
+ legacyRoom: 'people/liu-lie',
186
+ basin: 'harbor',
187
+ current: 'harbor/liu-lie',
188
+ description: 'Partner context and shared understanding',
189
+ },
190
+ {
191
+ legacyWing: 'people',
192
+ legacyRoom: 'people/dandan',
193
+ basin: 'harbor',
194
+ current: 'harbor/dandan',
195
+ description: 'Companion and adjacent agent context',
196
+ },
197
+ ];
@@ -0,0 +1,32 @@
1
+ /**
2
+ * TSUNAMI memory audit stub
3
+ *
4
+ * Provides memory fabric auditing functions expected by the storm center.
5
+ * Returns empty results; the storm center handles these gracefully.
6
+ */
7
+
8
+ export interface MemoryAuditIssue {
9
+ code: string;
10
+ severity: 'low' | 'medium' | 'high';
11
+ detail?: string;
12
+ }
13
+
14
+ export interface MemoryAuditRepairSuggestion {
15
+ title: string;
16
+ priority: 'P0' | 'P1' | 'P2' | 'P3';
17
+ detail?: string;
18
+ }
19
+
20
+ export interface MemoryAuditResult {
21
+ issues: MemoryAuditIssue[];
22
+ repairSuggestions: MemoryAuditRepairSuggestion[];
23
+ issueCount: number;
24
+ }
25
+
26
+ export function auditMemoryFabric(_projectDir: string): MemoryAuditResult {
27
+ return { issues: [], repairSuggestions: [], issueCount: 0 };
28
+ }
29
+
30
+ export function buildMemoryAuditContext(): Record<string, unknown> {
31
+ return {};
32
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * TSUNAMI memory conflict resolver stub
3
+ *
4
+ * Provides memory conflict resolution functions.
5
+ * Returns empty/unchanged by default.
6
+ */
7
+
8
+ export function resolveMemoryConflicts(): null {
9
+ return null;
10
+ }
11
+
12
+ export function buildMemoryConflictContext(): Record<string, unknown> {
13
+ return {};
14
+ }
@@ -0,0 +1,31 @@
1
+ export { memoryFabric, memoryManager } from './memory_manager';
2
+ export {
3
+ auditMemoryFabric,
4
+ buildMemoryAuditContext,
5
+ } from './memory_audit';
6
+ export {
7
+ promoteConversationTurn,
8
+ promoteHandoffToMemory,
9
+ promoteWorklogSnapshot,
10
+ queueMemoryPromotion,
11
+ } from './memory_promotion';
12
+ export { memoryRuntime } from './memory_runtime';
13
+ export {
14
+ buildCrossSessionRecoveryBlock,
15
+ searchCrossSessionRecovery,
16
+ } from './memory_recovery';
17
+ export {
18
+ resolveMemoryConflicts,
19
+ buildMemoryConflictContext,
20
+ } from './memory_conflict_resolver';
21
+ export type {
22
+ MemoryAddOptions,
23
+ MemoryCompactOptions,
24
+ MemoryPrefetchOptions,
25
+ MemoryProvider,
26
+ MemoryQueryIntent,
27
+ MemoryRecallOptions,
28
+ MemorySearchOptions,
29
+ MemorySyncOptions,
30
+ MemoryWakeOptions,
31
+ } from './provider';
@@ -0,0 +1,10 @@
1
+ /**
2
+ * TSUNAMI memory manager stub
3
+ *
4
+ * Provides the memoryFabric and memoryManager exports expected by memory_fabric.ts.
5
+ * These are placeholder stubs for future full implementations.
6
+ */
7
+
8
+ export const memoryFabric = {};
9
+
10
+ export const memoryManager = {};
@@ -0,0 +1,22 @@
1
+ /**
2
+ * TSUNAMI memory promotion stubs
3
+ *
4
+ * Provides memory promotion functions for promoting conversation turns,
5
+ * handoffs, and worklog snapshots into durable memory.
6
+ */
7
+
8
+ export function promoteConversationTurn(): null {
9
+ return null;
10
+ }
11
+
12
+ export function promoteHandoffToMemory(): null {
13
+ return null;
14
+ }
15
+
16
+ export function promoteWorklogSnapshot(): null {
17
+ return null;
18
+ }
19
+
20
+ export function queueMemoryPromotion(): null {
21
+ return null;
22
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * TSUNAMI memory recovery stubs
3
+ *
4
+ * Provides cross-session recovery block builders and search functions.
5
+ * Returns null/empty by default.
6
+ */
7
+
8
+ export function buildCrossSessionRecoveryBlock(): null {
9
+ return null;
10
+ }
11
+
12
+ export function searchCrossSessionRecovery(): null {
13
+ return null;
14
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * TSUNAMI memory runtime stub
3
+ *
4
+ * Provides the memoryRuntime export expected by memory_fabric.ts.
5
+ */
6
+
7
+ export const memoryRuntime = {};
@@ -0,0 +1,163 @@
1
+ /**
2
+ * TSUNAMI Schema Migration System
3
+ *
4
+ * Versioned, idempotent migrations for the SQLite database.
5
+ * Each migration has a version number and an `up` function.
6
+ * The `schema_version` table tracks which migrations have been applied.
7
+ *
8
+ * Usage:
9
+ * import { runMigrations } from './migration';
10
+ * const db = new Database(path);
11
+ * const applied = runMigrations(db, getMigrations());
12
+ */
13
+
14
+ import type { Database } from 'bun:sqlite';
15
+
16
+ export interface Migration {
17
+ version: number;
18
+ name: string;
19
+ up: (db: Database) => void;
20
+ }
21
+
22
+ const SCHEMA_TABLE = 'schema_version';
23
+
24
+ /** Ensure the schema_version tracking table exists. */
25
+ function ensureVersionTable(db: Database): void {
26
+ db.run(`
27
+ CREATE TABLE IF NOT EXISTS ${SCHEMA_TABLE} (
28
+ version INTEGER PRIMARY KEY,
29
+ name TEXT NOT NULL,
30
+ appliedAt INTEGER NOT NULL DEFAULT (unixepoch() * 1000)
31
+ )
32
+ `);
33
+ }
34
+
35
+ /** Get the highest applied migration version. */
36
+ function currentVersion(db: Database): number {
37
+ ensureVersionTable(db);
38
+ const row = db.prepare(
39
+ `SELECT MAX(version) as v FROM ${SCHEMA_TABLE}`
40
+ ).get() as { v: number | null } | undefined;
41
+ return row?.v ?? 0;
42
+ }
43
+
44
+ /** Apply a single migration if not already applied. */
45
+ function applyMigration(db: Database, m: Migration): boolean {
46
+ const existing = db.prepare(
47
+ `SELECT 1 FROM ${SCHEMA_TABLE} WHERE version = ?`
48
+ ).get(m.version);
49
+ if (existing) return false;
50
+
51
+ m.up(db);
52
+ db.prepare(
53
+ `INSERT INTO ${SCHEMA_TABLE} (version, name) VALUES (?, ?)`
54
+ ).run(m.version, m.name);
55
+ return true;
56
+ }
57
+
58
+ /** Run all pending migrations in order. Returns count of newly applied. */
59
+ export function runMigrations(db: Database, migrations: Migration[]): number {
60
+ ensureVersionTable(db);
61
+ const current = currentVersion(db);
62
+ const pending = migrations
63
+ .filter(m => m.version > current)
64
+ .sort((a, b) => a.version - b.version);
65
+
66
+ let applied = 0;
67
+ for (const m of pending) {
68
+ if (applyMigration(db, m)) applied++;
69
+ }
70
+ return applied;
71
+ }
72
+
73
+ // ═══════════════════════════════════════════════════════════
74
+ // Migration definitions
75
+ // ═══════════════════════════════════════════════════════════
76
+
77
+ /** v1 — Initial schema: memory entries + FTS5 + knowledge graph. */
78
+ const v1_initial_schema: Migration = {
79
+ version: 1,
80
+ name: 'initial_schema',
81
+ up(db) {
82
+ // Memory entries
83
+ db.run(`
84
+ CREATE TABLE IF NOT EXISTS memory_entries (
85
+ id TEXT PRIMARY KEY,
86
+ wing TEXT NOT NULL DEFAULT 'general',
87
+ room TEXT NOT NULL DEFAULT 'inbox',
88
+ content TEXT NOT NULL,
89
+ importance INTEGER NOT NULL DEFAULT 3,
90
+ source TEXT DEFAULT 'direct',
91
+ session_id TEXT,
92
+ project_dir TEXT,
93
+ fingerprint TEXT,
94
+ created_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000),
95
+ updated_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000)
96
+ )
97
+ `);
98
+
99
+ // FTS5 virtual table
100
+ db.run(`
101
+ CREATE VIRTUAL TABLE IF NOT EXISTS memory_fts USING fts5(
102
+ content, wing, room,
103
+ content='memory_entries',
104
+ content_rowid='rowid'
105
+ )
106
+ `);
107
+
108
+ // FTS sync triggers
109
+ db.run(`
110
+ CREATE TRIGGER IF NOT EXISTS memory_ai AFTER INSERT ON memory_entries BEGIN
111
+ INSERT INTO memory_fts(rowid, content, wing, room)
112
+ VALUES (new.rowid, new.content, new.wing, new.room);
113
+ END
114
+ `);
115
+ db.run(`
116
+ CREATE TRIGGER IF NOT EXISTS memory_ad AFTER DELETE ON memory_entries BEGIN
117
+ INSERT INTO memory_fts(memory_fts, rowid, content, wing, room)
118
+ VALUES ('delete', old.rowid, old.content, old.wing, old.room);
119
+ END
120
+ `);
121
+ db.run(`
122
+ CREATE TRIGGER IF NOT EXISTS memory_au AFTER UPDATE ON memory_entries BEGIN
123
+ INSERT INTO memory_fts(memory_fts, rowid, content, wing, room)
124
+ VALUES ('delete', old.rowid, old.content, old.wing, old.room);
125
+ INSERT INTO memory_fts(rowid, content, wing, room)
126
+ VALUES (new.rowid, new.content, new.wing, new.room);
127
+ END
128
+ `);
129
+
130
+ // Indexes
131
+ db.run(`CREATE INDEX IF NOT EXISTS idx_mem_wing ON memory_entries(wing)`);
132
+ db.run(`CREATE INDEX IF NOT EXISTS idx_mem_room ON memory_entries(room)`);
133
+ db.run(`CREATE INDEX IF NOT EXISTS idx_mem_created ON memory_entries(created_at)`);
134
+
135
+ // Knowledge graph
136
+ db.run(`
137
+ CREATE TABLE IF NOT EXISTS graph_triples (
138
+ id TEXT PRIMARY KEY,
139
+ subject TEXT NOT NULL,
140
+ predicate TEXT NOT NULL,
141
+ object TEXT NOT NULL,
142
+ subject_type TEXT,
143
+ object_type TEXT,
144
+ subject_properties TEXT DEFAULT '{}',
145
+ object_properties TEXT DEFAULT '{}',
146
+ confidence REAL NOT NULL DEFAULT 1.0,
147
+ valid_from TEXT,
148
+ valid_to TEXT,
149
+ source_file TEXT,
150
+ created_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000)
151
+ )
152
+ `);
153
+
154
+ db.run(`CREATE INDEX IF NOT EXISTS idx_graph_subject ON graph_triples(subject)`);
155
+ db.run(`CREATE INDEX IF NOT EXISTS idx_graph_object ON graph_triples(object)`);
156
+ db.run(`CREATE INDEX IF NOT EXISTS idx_graph_predicate ON graph_triples(predicate)`);
157
+ },
158
+ };
159
+
160
+ /** All migrations in version order. Add new entries at the end. */
161
+ export function getMigrations(): Migration[] {
162
+ return [v1_initial_schema];
163
+ }