@psiclawops/hypermem 0.1.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +4 -3
- package/README.md +457 -174
- package/package.json +15 -5
- package/dist/background-indexer.d.ts +0 -117
- package/dist/background-indexer.d.ts.map +0 -1
- package/dist/background-indexer.js +0 -732
- package/dist/compaction-fence.d.ts +0 -89
- package/dist/compaction-fence.d.ts.map +0 -1
- package/dist/compaction-fence.js +0 -153
- package/dist/compositor.d.ts +0 -139
- package/dist/compositor.d.ts.map +0 -1
- package/dist/compositor.js +0 -1109
- package/dist/cross-agent.d.ts +0 -57
- package/dist/cross-agent.d.ts.map +0 -1
- package/dist/cross-agent.js +0 -254
- package/dist/db.d.ts +0 -131
- package/dist/db.d.ts.map +0 -1
- package/dist/db.js +0 -398
- package/dist/desired-state-store.d.ts +0 -100
- package/dist/desired-state-store.d.ts.map +0 -1
- package/dist/desired-state-store.js +0 -212
- package/dist/doc-chunk-store.d.ts +0 -115
- package/dist/doc-chunk-store.d.ts.map +0 -1
- package/dist/doc-chunk-store.js +0 -278
- package/dist/doc-chunker.d.ts +0 -99
- package/dist/doc-chunker.d.ts.map +0 -1
- package/dist/doc-chunker.js +0 -324
- package/dist/episode-store.d.ts +0 -48
- package/dist/episode-store.d.ts.map +0 -1
- package/dist/episode-store.js +0 -135
- package/dist/fact-store.d.ts +0 -57
- package/dist/fact-store.d.ts.map +0 -1
- package/dist/fact-store.js +0 -175
- package/dist/fleet-store.d.ts +0 -144
- package/dist/fleet-store.d.ts.map +0 -1
- package/dist/fleet-store.js +0 -276
- package/dist/hybrid-retrieval.d.ts +0 -60
- package/dist/hybrid-retrieval.d.ts.map +0 -1
- package/dist/hybrid-retrieval.js +0 -340
- package/dist/index.d.ts +0 -611
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -1042
- package/dist/knowledge-graph.d.ts +0 -110
- package/dist/knowledge-graph.d.ts.map +0 -1
- package/dist/knowledge-graph.js +0 -305
- package/dist/knowledge-store.d.ts +0 -72
- package/dist/knowledge-store.d.ts.map +0 -1
- package/dist/knowledge-store.js +0 -241
- package/dist/library-schema.d.ts +0 -22
- package/dist/library-schema.d.ts.map +0 -1
- package/dist/library-schema.js +0 -717
- package/dist/message-store.d.ts +0 -76
- package/dist/message-store.d.ts.map +0 -1
- package/dist/message-store.js +0 -273
- package/dist/preference-store.d.ts +0 -54
- package/dist/preference-store.d.ts.map +0 -1
- package/dist/preference-store.js +0 -109
- package/dist/preservation-gate.d.ts +0 -82
- package/dist/preservation-gate.d.ts.map +0 -1
- package/dist/preservation-gate.js +0 -150
- package/dist/provider-translator.d.ts +0 -40
- package/dist/provider-translator.d.ts.map +0 -1
- package/dist/provider-translator.js +0 -349
- package/dist/rate-limiter.d.ts +0 -76
- package/dist/rate-limiter.d.ts.map +0 -1
- package/dist/rate-limiter.js +0 -179
- package/dist/redis.d.ts +0 -188
- package/dist/redis.d.ts.map +0 -1
- package/dist/redis.js +0 -534
- package/dist/schema.d.ts +0 -15
- package/dist/schema.d.ts.map +0 -1
- package/dist/schema.js +0 -203
- package/dist/secret-scanner.d.ts +0 -51
- package/dist/secret-scanner.d.ts.map +0 -1
- package/dist/secret-scanner.js +0 -248
- package/dist/seed.d.ts +0 -108
- package/dist/seed.d.ts.map +0 -1
- package/dist/seed.js +0 -177
- package/dist/system-store.d.ts +0 -73
- package/dist/system-store.d.ts.map +0 -1
- package/dist/system-store.js +0 -182
- package/dist/topic-store.d.ts +0 -45
- package/dist/topic-store.d.ts.map +0 -1
- package/dist/topic-store.js +0 -136
- package/dist/types.d.ts +0 -329
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -9
- package/dist/vector-store.d.ts +0 -132
- package/dist/vector-store.d.ts.map +0 -1
- package/dist/vector-store.js +0 -498
- package/dist/work-store.d.ts +0 -112
- package/dist/work-store.d.ts.map +0 -1
- package/dist/work-store.js +0 -273
package/dist/library-schema.js
DELETED
|
@@ -1,717 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* HyperMem Library Schema — Fleet-Wide Structured Knowledge
|
|
3
|
-
*
|
|
4
|
-
* Single database: ~/.openclaw/hypermem/library.db
|
|
5
|
-
* The "crown jewel" — durable, backed up, low-write-frequency.
|
|
6
|
-
*
|
|
7
|
-
* Collections:
|
|
8
|
-
* 1. Library entries (versioned docs, specs, reference material)
|
|
9
|
-
* 2. Facts (agent-learned truths)
|
|
10
|
-
* 3. Preferences (behavioral patterns)
|
|
11
|
-
* 4. Knowledge (structured domain knowledge, supersedable)
|
|
12
|
-
* 5. Episodes (significant events)
|
|
13
|
-
* 6. Fleet registry (agents, orgs)
|
|
14
|
-
* 7. System registry (server state, config)
|
|
15
|
-
* 8. Session registry (lifecycle tracking)
|
|
16
|
-
* 9. Work items (fleet kanban)
|
|
17
|
-
* 10. Topics (cross-session thread tracking)
|
|
18
|
-
*/
|
|
19
|
-
export const LIBRARY_SCHEMA_VERSION = 7;
|
|
20
|
-
function nowIso() {
|
|
21
|
-
return new Date().toISOString();
|
|
22
|
-
}
|
|
23
|
-
// ── V1: Original library + subscriptions + changelog ──────────
|
|
24
|
-
function applyV1Schema(db) {
|
|
25
|
-
db.exec(`
|
|
26
|
-
CREATE TABLE IF NOT EXISTS library_entries (
|
|
27
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
28
|
-
domain TEXT NOT NULL,
|
|
29
|
-
key TEXT NOT NULL,
|
|
30
|
-
content TEXT NOT NULL,
|
|
31
|
-
content_hash TEXT,
|
|
32
|
-
version INTEGER DEFAULT 1,
|
|
33
|
-
source TEXT,
|
|
34
|
-
agent_id TEXT,
|
|
35
|
-
visibility TEXT DEFAULT 'fleet',
|
|
36
|
-
tags TEXT,
|
|
37
|
-
created_at TEXT NOT NULL,
|
|
38
|
-
updated_at TEXT NOT NULL,
|
|
39
|
-
superseded_at TEXT,
|
|
40
|
-
superseded_by INTEGER,
|
|
41
|
-
UNIQUE(domain, key, version)
|
|
42
|
-
)
|
|
43
|
-
`);
|
|
44
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_lib_entries_domain ON library_entries(domain, key)');
|
|
45
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_lib_entries_active ON library_entries(domain, key, superseded_by)');
|
|
46
|
-
db.exec(`
|
|
47
|
-
CREATE TABLE IF NOT EXISTS library_changelog (
|
|
48
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
49
|
-
library_entry_id INTEGER NOT NULL REFERENCES library_entries(id),
|
|
50
|
-
change_type TEXT NOT NULL,
|
|
51
|
-
changed_by TEXT NOT NULL,
|
|
52
|
-
diff_summary TEXT,
|
|
53
|
-
version INTEGER NOT NULL,
|
|
54
|
-
created_at TEXT NOT NULL
|
|
55
|
-
)
|
|
56
|
-
`);
|
|
57
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_lib_changelog_item ON library_changelog(library_entry_id, created_at DESC)');
|
|
58
|
-
db.exec(`
|
|
59
|
-
CREATE TABLE IF NOT EXISTS library_subscriptions (
|
|
60
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
61
|
-
agent_id TEXT NOT NULL,
|
|
62
|
-
domain TEXT,
|
|
63
|
-
item_type TEXT,
|
|
64
|
-
created_at TEXT NOT NULL,
|
|
65
|
-
UNIQUE(agent_id, domain, item_type)
|
|
66
|
-
)
|
|
67
|
-
`);
|
|
68
|
-
// FTS on library content
|
|
69
|
-
db.exec(`
|
|
70
|
-
CREATE VIRTUAL TABLE IF NOT EXISTS library_fts USING fts5(
|
|
71
|
-
key,
|
|
72
|
-
content,
|
|
73
|
-
content='library_entries',
|
|
74
|
-
content_rowid='id'
|
|
75
|
-
)
|
|
76
|
-
`);
|
|
77
|
-
db.exec(`
|
|
78
|
-
CREATE TRIGGER IF NOT EXISTS lib_fts_ai AFTER INSERT ON library_entries BEGIN
|
|
79
|
-
INSERT INTO library_fts(rowid, key, content) VALUES (new.id, new.key, new.content);
|
|
80
|
-
END
|
|
81
|
-
`);
|
|
82
|
-
db.exec(`
|
|
83
|
-
CREATE TRIGGER IF NOT EXISTS lib_fts_ad AFTER DELETE ON library_entries BEGIN
|
|
84
|
-
INSERT INTO library_fts(library_fts, rowid, key, content) VALUES('delete', old.id, old.key, old.content);
|
|
85
|
-
END
|
|
86
|
-
`);
|
|
87
|
-
db.exec(`
|
|
88
|
-
CREATE TRIGGER IF NOT EXISTS lib_fts_au AFTER UPDATE ON library_entries BEGIN
|
|
89
|
-
INSERT INTO library_fts(library_fts, rowid, key, content) VALUES('delete', old.id, old.key, old.content);
|
|
90
|
-
INSERT INTO library_fts(rowid, key, content) VALUES (new.id, new.key, new.content);
|
|
91
|
-
END
|
|
92
|
-
`);
|
|
93
|
-
}
|
|
94
|
-
// ── V2: Session registry ──────────────────────────────────────
|
|
95
|
-
function applyV2SessionRegistry(db) {
|
|
96
|
-
db.exec(`
|
|
97
|
-
CREATE TABLE IF NOT EXISTS session_registry (
|
|
98
|
-
id TEXT PRIMARY KEY,
|
|
99
|
-
agent_id TEXT NOT NULL,
|
|
100
|
-
channel TEXT,
|
|
101
|
-
channel_type TEXT,
|
|
102
|
-
started_at TEXT NOT NULL,
|
|
103
|
-
ended_at TEXT,
|
|
104
|
-
status TEXT DEFAULT 'active',
|
|
105
|
-
summary TEXT,
|
|
106
|
-
decisions_made INTEGER DEFAULT 0,
|
|
107
|
-
facts_extracted INTEGER DEFAULT 0,
|
|
108
|
-
messages_count INTEGER DEFAULT 0
|
|
109
|
-
)
|
|
110
|
-
`);
|
|
111
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_session_agent ON session_registry(agent_id, status, started_at DESC)');
|
|
112
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_session_status ON session_registry(status, started_at DESC)');
|
|
113
|
-
db.exec(`
|
|
114
|
-
CREATE TABLE IF NOT EXISTS session_events (
|
|
115
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
116
|
-
session_id TEXT NOT NULL REFERENCES session_registry(id),
|
|
117
|
-
event_type TEXT NOT NULL,
|
|
118
|
-
timestamp TEXT NOT NULL,
|
|
119
|
-
payload TEXT
|
|
120
|
-
)
|
|
121
|
-
`);
|
|
122
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_session_events ON session_events(session_id, timestamp DESC)');
|
|
123
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_session_events_type ON session_events(event_type, timestamp DESC)');
|
|
124
|
-
db.exec(`
|
|
125
|
-
CREATE VIRTUAL TABLE IF NOT EXISTS session_fts USING fts5(
|
|
126
|
-
summary,
|
|
127
|
-
content='session_registry',
|
|
128
|
-
content_rowid='rowid'
|
|
129
|
-
)
|
|
130
|
-
`);
|
|
131
|
-
}
|
|
132
|
-
// ── V3: Centralized collections ───────────────────────────────
|
|
133
|
-
// Facts, preferences, knowledge, episodes, topics move here from per-agent DBs.
|
|
134
|
-
// Fleet registry, system registry, work items are new.
|
|
135
|
-
function applyV3Collections(db) {
|
|
136
|
-
// ── Facts (agent-learned truths) ──
|
|
137
|
-
db.exec(`
|
|
138
|
-
CREATE TABLE IF NOT EXISTS facts (
|
|
139
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
140
|
-
agent_id TEXT NOT NULL,
|
|
141
|
-
scope TEXT NOT NULL DEFAULT 'agent',
|
|
142
|
-
domain TEXT,
|
|
143
|
-
content TEXT NOT NULL,
|
|
144
|
-
confidence REAL DEFAULT 1.0,
|
|
145
|
-
visibility TEXT NOT NULL DEFAULT 'private',
|
|
146
|
-
source_type TEXT DEFAULT 'conversation',
|
|
147
|
-
source_session_key TEXT,
|
|
148
|
-
source_ref TEXT,
|
|
149
|
-
created_at TEXT NOT NULL,
|
|
150
|
-
updated_at TEXT NOT NULL,
|
|
151
|
-
expires_at TEXT,
|
|
152
|
-
superseded_by INTEGER,
|
|
153
|
-
decay_score REAL DEFAULT 0.0
|
|
154
|
-
)
|
|
155
|
-
`);
|
|
156
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_facts_agent ON facts(agent_id, scope, domain)');
|
|
157
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_facts_visibility ON facts(visibility, agent_id)');
|
|
158
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_facts_active ON facts(agent_id, superseded_by, decay_score, confidence DESC)');
|
|
159
|
-
db.exec(`
|
|
160
|
-
CREATE VIRTUAL TABLE IF NOT EXISTS facts_fts USING fts5(
|
|
161
|
-
content,
|
|
162
|
-
domain,
|
|
163
|
-
content='facts',
|
|
164
|
-
content_rowid='id'
|
|
165
|
-
)
|
|
166
|
-
`);
|
|
167
|
-
db.exec(`
|
|
168
|
-
CREATE TRIGGER IF NOT EXISTS facts_fts_ai AFTER INSERT ON facts BEGIN
|
|
169
|
-
INSERT INTO facts_fts(rowid, content, domain) VALUES (new.id, new.content, new.domain);
|
|
170
|
-
END
|
|
171
|
-
`);
|
|
172
|
-
db.exec(`
|
|
173
|
-
CREATE TRIGGER IF NOT EXISTS facts_fts_ad AFTER DELETE ON facts BEGIN
|
|
174
|
-
INSERT INTO facts_fts(facts_fts, rowid, content, domain) VALUES('delete', old.id, old.content, old.domain);
|
|
175
|
-
END
|
|
176
|
-
`);
|
|
177
|
-
db.exec(`
|
|
178
|
-
CREATE TRIGGER IF NOT EXISTS facts_fts_au AFTER UPDATE ON facts BEGIN
|
|
179
|
-
INSERT INTO facts_fts(facts_fts, rowid, content, domain) VALUES('delete', old.id, old.content, old.domain);
|
|
180
|
-
INSERT INTO facts_fts(rowid, content, domain) VALUES (new.id, new.content, new.domain);
|
|
181
|
-
END
|
|
182
|
-
`);
|
|
183
|
-
// ── Preferences (behavioral patterns) ──
|
|
184
|
-
db.exec(`
|
|
185
|
-
CREATE TABLE IF NOT EXISTS preferences (
|
|
186
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
187
|
-
subject TEXT NOT NULL,
|
|
188
|
-
domain TEXT NOT NULL DEFAULT 'general',
|
|
189
|
-
key TEXT NOT NULL,
|
|
190
|
-
value TEXT NOT NULL,
|
|
191
|
-
agent_id TEXT NOT NULL,
|
|
192
|
-
confidence REAL DEFAULT 1.0,
|
|
193
|
-
visibility TEXT NOT NULL DEFAULT 'fleet',
|
|
194
|
-
source_type TEXT DEFAULT 'observation',
|
|
195
|
-
source_ref TEXT,
|
|
196
|
-
created_at TEXT NOT NULL,
|
|
197
|
-
updated_at TEXT NOT NULL,
|
|
198
|
-
UNIQUE(subject, domain, key)
|
|
199
|
-
)
|
|
200
|
-
`);
|
|
201
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_prefs_subject ON preferences(subject, domain)');
|
|
202
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_prefs_agent ON preferences(agent_id)');
|
|
203
|
-
// ── Knowledge (structured domain knowledge, supersedable) ──
|
|
204
|
-
db.exec(`
|
|
205
|
-
CREATE TABLE IF NOT EXISTS knowledge (
|
|
206
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
207
|
-
agent_id TEXT NOT NULL,
|
|
208
|
-
domain TEXT NOT NULL,
|
|
209
|
-
key TEXT NOT NULL,
|
|
210
|
-
content TEXT NOT NULL,
|
|
211
|
-
confidence REAL DEFAULT 1.0,
|
|
212
|
-
visibility TEXT NOT NULL DEFAULT 'private',
|
|
213
|
-
source_type TEXT NOT NULL DEFAULT 'manual',
|
|
214
|
-
source_ref TEXT,
|
|
215
|
-
created_at TEXT NOT NULL,
|
|
216
|
-
updated_at TEXT NOT NULL,
|
|
217
|
-
expires_at TEXT,
|
|
218
|
-
superseded_by INTEGER,
|
|
219
|
-
UNIQUE(agent_id, domain, key)
|
|
220
|
-
)
|
|
221
|
-
`);
|
|
222
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_knowledge_agent ON knowledge(agent_id, domain)');
|
|
223
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_knowledge_visibility ON knowledge(visibility, agent_id)');
|
|
224
|
-
db.exec(`
|
|
225
|
-
CREATE VIRTUAL TABLE IF NOT EXISTS knowledge_fts USING fts5(
|
|
226
|
-
key,
|
|
227
|
-
content,
|
|
228
|
-
domain,
|
|
229
|
-
content='knowledge',
|
|
230
|
-
content_rowid='id'
|
|
231
|
-
)
|
|
232
|
-
`);
|
|
233
|
-
db.exec(`
|
|
234
|
-
CREATE TRIGGER IF NOT EXISTS knowledge_fts_ai AFTER INSERT ON knowledge BEGIN
|
|
235
|
-
INSERT INTO knowledge_fts(rowid, key, content, domain) VALUES (new.id, new.key, new.content, new.domain);
|
|
236
|
-
END
|
|
237
|
-
`);
|
|
238
|
-
db.exec(`
|
|
239
|
-
CREATE TRIGGER IF NOT EXISTS knowledge_fts_ad AFTER DELETE ON knowledge BEGIN
|
|
240
|
-
INSERT INTO knowledge_fts(knowledge_fts, rowid, key, content, domain) VALUES('delete', old.id, old.key, old.content, old.domain);
|
|
241
|
-
END
|
|
242
|
-
`);
|
|
243
|
-
db.exec(`
|
|
244
|
-
CREATE TRIGGER IF NOT EXISTS knowledge_fts_au AFTER UPDATE ON knowledge BEGIN
|
|
245
|
-
INSERT INTO knowledge_fts(knowledge_fts, rowid, key, content, domain) VALUES('delete', old.id, old.key, old.content, old.domain);
|
|
246
|
-
INSERT INTO knowledge_fts(rowid, key, content, domain) VALUES (new.id, new.key, new.content, new.domain);
|
|
247
|
-
END
|
|
248
|
-
`);
|
|
249
|
-
// ── Knowledge relationships (DAG edges) ──
|
|
250
|
-
db.exec(`
|
|
251
|
-
CREATE TABLE IF NOT EXISTS knowledge_links (
|
|
252
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
253
|
-
from_type TEXT NOT NULL,
|
|
254
|
-
from_id INTEGER NOT NULL,
|
|
255
|
-
to_type TEXT NOT NULL,
|
|
256
|
-
to_id INTEGER NOT NULL,
|
|
257
|
-
link_type TEXT NOT NULL,
|
|
258
|
-
created_at TEXT NOT NULL,
|
|
259
|
-
UNIQUE(from_type, from_id, to_type, to_id, link_type)
|
|
260
|
-
)
|
|
261
|
-
`);
|
|
262
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_klinks_from ON knowledge_links(from_type, from_id)');
|
|
263
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_klinks_to ON knowledge_links(to_type, to_id)');
|
|
264
|
-
// ── Episodes (significant events) ──
|
|
265
|
-
db.exec(`
|
|
266
|
-
CREATE TABLE IF NOT EXISTS episodes (
|
|
267
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
268
|
-
agent_id TEXT NOT NULL,
|
|
269
|
-
event_type TEXT NOT NULL,
|
|
270
|
-
summary TEXT NOT NULL,
|
|
271
|
-
significance REAL NOT NULL DEFAULT 0.5,
|
|
272
|
-
visibility TEXT NOT NULL DEFAULT 'org',
|
|
273
|
-
participants TEXT,
|
|
274
|
-
session_key TEXT,
|
|
275
|
-
created_at TEXT NOT NULL,
|
|
276
|
-
decay_score REAL DEFAULT 0.0
|
|
277
|
-
)
|
|
278
|
-
`);
|
|
279
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_episodes_agent ON episodes(agent_id, significance DESC, created_at DESC)');
|
|
280
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_episodes_visibility ON episodes(visibility, agent_id)');
|
|
281
|
-
db.exec(`
|
|
282
|
-
CREATE VIRTUAL TABLE IF NOT EXISTS episodes_fts USING fts5(
|
|
283
|
-
summary,
|
|
284
|
-
event_type,
|
|
285
|
-
content='episodes',
|
|
286
|
-
content_rowid='id'
|
|
287
|
-
)
|
|
288
|
-
`);
|
|
289
|
-
db.exec(`
|
|
290
|
-
CREATE TRIGGER IF NOT EXISTS episodes_fts_ai AFTER INSERT ON episodes BEGIN
|
|
291
|
-
INSERT INTO episodes_fts(rowid, summary, event_type) VALUES (new.id, new.summary, new.event_type);
|
|
292
|
-
END
|
|
293
|
-
`);
|
|
294
|
-
db.exec(`
|
|
295
|
-
CREATE TRIGGER IF NOT EXISTS episodes_fts_ad AFTER DELETE ON episodes BEGIN
|
|
296
|
-
INSERT INTO episodes_fts(episodes_fts, rowid, summary, event_type) VALUES('delete', old.id, old.summary, old.event_type);
|
|
297
|
-
END
|
|
298
|
-
`);
|
|
299
|
-
db.exec(`
|
|
300
|
-
CREATE TRIGGER IF NOT EXISTS episodes_fts_au AFTER UPDATE ON episodes BEGIN
|
|
301
|
-
INSERT INTO episodes_fts(episodes_fts, rowid, summary, event_type) VALUES('delete', old.id, old.summary, old.event_type);
|
|
302
|
-
INSERT INTO episodes_fts(rowid, summary, event_type) VALUES (new.id, new.summary, new.event_type);
|
|
303
|
-
END
|
|
304
|
-
`);
|
|
305
|
-
// ── Topics (cross-session thread tracking) ──
|
|
306
|
-
db.exec(`
|
|
307
|
-
CREATE TABLE IF NOT EXISTS topics (
|
|
308
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
309
|
-
agent_id TEXT NOT NULL,
|
|
310
|
-
name TEXT NOT NULL,
|
|
311
|
-
description TEXT,
|
|
312
|
-
status TEXT DEFAULT 'active',
|
|
313
|
-
visibility TEXT NOT NULL DEFAULT 'org',
|
|
314
|
-
last_session_key TEXT,
|
|
315
|
-
message_count INTEGER DEFAULT 0,
|
|
316
|
-
created_at TEXT NOT NULL,
|
|
317
|
-
updated_at TEXT NOT NULL
|
|
318
|
-
)
|
|
319
|
-
`);
|
|
320
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_topics_agent ON topics(agent_id, status, updated_at DESC)');
|
|
321
|
-
// ── Fleet registry ──
|
|
322
|
-
db.exec(`
|
|
323
|
-
CREATE TABLE IF NOT EXISTS fleet_agents (
|
|
324
|
-
id TEXT PRIMARY KEY,
|
|
325
|
-
display_name TEXT NOT NULL,
|
|
326
|
-
tier TEXT NOT NULL DEFAULT 'unknown',
|
|
327
|
-
org_id TEXT,
|
|
328
|
-
reports_to TEXT,
|
|
329
|
-
domains TEXT,
|
|
330
|
-
session_keys TEXT,
|
|
331
|
-
status TEXT DEFAULT 'active',
|
|
332
|
-
last_seen TEXT,
|
|
333
|
-
created_at TEXT NOT NULL,
|
|
334
|
-
updated_at TEXT NOT NULL,
|
|
335
|
-
metadata TEXT
|
|
336
|
-
)
|
|
337
|
-
`);
|
|
338
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_fleet_agents_tier ON fleet_agents(tier, status)');
|
|
339
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_fleet_agents_org ON fleet_agents(org_id)');
|
|
340
|
-
db.exec(`
|
|
341
|
-
CREATE TABLE IF NOT EXISTS fleet_orgs (
|
|
342
|
-
id TEXT PRIMARY KEY,
|
|
343
|
-
name TEXT NOT NULL,
|
|
344
|
-
lead_agent_id TEXT REFERENCES fleet_agents(id),
|
|
345
|
-
mission TEXT,
|
|
346
|
-
created_at TEXT NOT NULL
|
|
347
|
-
)
|
|
348
|
-
`);
|
|
349
|
-
// ── System registry ──
|
|
350
|
-
db.exec(`
|
|
351
|
-
CREATE TABLE IF NOT EXISTS system_state (
|
|
352
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
353
|
-
category TEXT NOT NULL,
|
|
354
|
-
key TEXT NOT NULL,
|
|
355
|
-
value TEXT NOT NULL,
|
|
356
|
-
updated_at TEXT NOT NULL,
|
|
357
|
-
updated_by TEXT,
|
|
358
|
-
ttl TEXT,
|
|
359
|
-
UNIQUE(category, key)
|
|
360
|
-
)
|
|
361
|
-
`);
|
|
362
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_system_state_cat ON system_state(category)');
|
|
363
|
-
db.exec(`
|
|
364
|
-
CREATE TABLE IF NOT EXISTS system_events (
|
|
365
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
366
|
-
category TEXT NOT NULL,
|
|
367
|
-
key TEXT NOT NULL,
|
|
368
|
-
event_type TEXT NOT NULL,
|
|
369
|
-
old_value TEXT,
|
|
370
|
-
new_value TEXT,
|
|
371
|
-
agent_id TEXT,
|
|
372
|
-
created_at TEXT NOT NULL,
|
|
373
|
-
metadata TEXT
|
|
374
|
-
)
|
|
375
|
-
`);
|
|
376
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_system_events ON system_events(category, key, created_at DESC)');
|
|
377
|
-
// ── Work items (fleet kanban) ──
|
|
378
|
-
db.exec(`
|
|
379
|
-
CREATE TABLE IF NOT EXISTS work_items (
|
|
380
|
-
id TEXT PRIMARY KEY,
|
|
381
|
-
title TEXT NOT NULL,
|
|
382
|
-
description TEXT,
|
|
383
|
-
status TEXT NOT NULL DEFAULT 'incoming',
|
|
384
|
-
priority INTEGER NOT NULL DEFAULT 3,
|
|
385
|
-
agent_id TEXT,
|
|
386
|
-
created_by TEXT NOT NULL,
|
|
387
|
-
domain TEXT,
|
|
388
|
-
parent_id TEXT,
|
|
389
|
-
blocked_by TEXT,
|
|
390
|
-
session_key TEXT,
|
|
391
|
-
created_at TEXT NOT NULL,
|
|
392
|
-
updated_at TEXT NOT NULL,
|
|
393
|
-
started_at TEXT,
|
|
394
|
-
completed_at TEXT,
|
|
395
|
-
due_at TEXT,
|
|
396
|
-
metadata TEXT
|
|
397
|
-
)
|
|
398
|
-
`);
|
|
399
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_work_status ON work_items(status, priority)');
|
|
400
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_work_agent ON work_items(agent_id, status)');
|
|
401
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_work_domain ON work_items(domain, status)');
|
|
402
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_work_parent ON work_items(parent_id)');
|
|
403
|
-
db.exec(`
|
|
404
|
-
CREATE TABLE IF NOT EXISTS work_events (
|
|
405
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
406
|
-
work_item_id TEXT NOT NULL REFERENCES work_items(id),
|
|
407
|
-
event_type TEXT NOT NULL,
|
|
408
|
-
old_status TEXT,
|
|
409
|
-
new_status TEXT,
|
|
410
|
-
agent_id TEXT,
|
|
411
|
-
comment TEXT,
|
|
412
|
-
created_at TEXT NOT NULL
|
|
413
|
-
)
|
|
414
|
-
`);
|
|
415
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_work_events ON work_events(work_item_id, created_at DESC)');
|
|
416
|
-
db.exec(`
|
|
417
|
-
CREATE VIRTUAL TABLE IF NOT EXISTS work_items_fts USING fts5(
|
|
418
|
-
title,
|
|
419
|
-
description,
|
|
420
|
-
content='work_items',
|
|
421
|
-
content_rowid='rowid'
|
|
422
|
-
)
|
|
423
|
-
`);
|
|
424
|
-
db.exec(`
|
|
425
|
-
CREATE TRIGGER IF NOT EXISTS work_fts_ai AFTER INSERT ON work_items BEGIN
|
|
426
|
-
INSERT INTO work_items_fts(rowid, title, description) VALUES (new.rowid, new.title, new.description);
|
|
427
|
-
END
|
|
428
|
-
`);
|
|
429
|
-
db.exec(`
|
|
430
|
-
CREATE TRIGGER IF NOT EXISTS work_fts_ad AFTER DELETE ON work_items BEGIN
|
|
431
|
-
INSERT INTO work_items_fts(work_items_fts, rowid, title, description) VALUES('delete', old.rowid, old.title, old.description);
|
|
432
|
-
END
|
|
433
|
-
`);
|
|
434
|
-
db.exec(`
|
|
435
|
-
CREATE TRIGGER IF NOT EXISTS work_fts_au AFTER UPDATE ON work_items BEGIN
|
|
436
|
-
INSERT INTO work_items_fts(work_items_fts, rowid, title, description) VALUES('delete', old.rowid, old.title, old.description);
|
|
437
|
-
INSERT INTO work_items_fts(rowid, title, description) VALUES (new.rowid, new.title, new.description);
|
|
438
|
-
END
|
|
439
|
-
`);
|
|
440
|
-
}
|
|
441
|
-
// ── V4: Agent capabilities ────────────────────────────────────
|
|
442
|
-
// Skills, tools, MCP servers registered per agent for fleet-wide discoverability.
|
|
443
|
-
function applyV4Capabilities(db) {
|
|
444
|
-
// Add capabilities column to fleet_agents
|
|
445
|
-
db.exec('ALTER TABLE fleet_agents ADD COLUMN capabilities TEXT');
|
|
446
|
-
// Structured capabilities table for queryable skill/tool lookups
|
|
447
|
-
db.exec(`
|
|
448
|
-
CREATE TABLE IF NOT EXISTS agent_capabilities (
|
|
449
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
450
|
-
agent_id TEXT NOT NULL REFERENCES fleet_agents(id),
|
|
451
|
-
cap_type TEXT NOT NULL,
|
|
452
|
-
name TEXT NOT NULL,
|
|
453
|
-
version TEXT,
|
|
454
|
-
source TEXT,
|
|
455
|
-
config TEXT,
|
|
456
|
-
status TEXT DEFAULT 'active',
|
|
457
|
-
last_verified TEXT,
|
|
458
|
-
created_at TEXT NOT NULL,
|
|
459
|
-
updated_at TEXT NOT NULL,
|
|
460
|
-
UNIQUE(agent_id, cap_type, name)
|
|
461
|
-
)
|
|
462
|
-
`);
|
|
463
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_agent_caps_agent ON agent_capabilities(agent_id, cap_type)');
|
|
464
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_agent_caps_type ON agent_capabilities(cap_type, name)');
|
|
465
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_agent_caps_status ON agent_capabilities(status, cap_type)');
|
|
466
|
-
}
|
|
467
|
-
// ── V5: Agent desired state ───────────────────────────────────
|
|
468
|
-
// Stores intended configuration for each agent: model, thinking, provider, etc.
|
|
469
|
-
// Enables drift detection (desired vs actual) and fleet-wide config visibility.
|
|
470
|
-
function applyV5DesiredState(db) {
|
|
471
|
-
db.exec(`
|
|
472
|
-
CREATE TABLE IF NOT EXISTS agent_desired_state (
|
|
473
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
474
|
-
agent_id TEXT NOT NULL,
|
|
475
|
-
config_key TEXT NOT NULL,
|
|
476
|
-
desired_value TEXT NOT NULL,
|
|
477
|
-
actual_value TEXT,
|
|
478
|
-
source TEXT NOT NULL DEFAULT 'operator',
|
|
479
|
-
set_by TEXT,
|
|
480
|
-
drift_status TEXT DEFAULT 'unknown',
|
|
481
|
-
last_checked TEXT,
|
|
482
|
-
created_at TEXT NOT NULL,
|
|
483
|
-
updated_at TEXT NOT NULL,
|
|
484
|
-
notes TEXT,
|
|
485
|
-
UNIQUE(agent_id, config_key)
|
|
486
|
-
)
|
|
487
|
-
`);
|
|
488
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_desired_agent ON agent_desired_state(agent_id)');
|
|
489
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_desired_drift ON agent_desired_state(drift_status)');
|
|
490
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_desired_key ON agent_desired_state(config_key)');
|
|
491
|
-
// Change log for desired state modifications
|
|
492
|
-
db.exec(`
|
|
493
|
-
CREATE TABLE IF NOT EXISTS agent_config_events (
|
|
494
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
495
|
-
agent_id TEXT NOT NULL,
|
|
496
|
-
config_key TEXT NOT NULL,
|
|
497
|
-
event_type TEXT NOT NULL,
|
|
498
|
-
old_value TEXT,
|
|
499
|
-
new_value TEXT,
|
|
500
|
-
changed_by TEXT,
|
|
501
|
-
created_at TEXT NOT NULL
|
|
502
|
-
)
|
|
503
|
-
`);
|
|
504
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_config_events_agent ON agent_config_events(agent_id, config_key, created_at DESC)');
|
|
505
|
-
}
|
|
506
|
-
// ── V6: Document chunks ───────────────────────────────────────
|
|
507
|
-
// Stores chunked ACA workspace documents for semantic retrieval.
|
|
508
|
-
// Enables ACA offload: governance docs, identity files, memory → demand-loaded.
|
|
509
|
-
//
|
|
510
|
-
// Key design:
|
|
511
|
-
// - Each chunk has a source_hash — atomic re-indexing via hash-based swap
|
|
512
|
-
// - collection path mirrors ACA_COLLECTIONS (governance/policy, etc.)
|
|
513
|
-
// - scope: shared-fleet | per-tier | per-agent
|
|
514
|
-
// - FTS5 virtual table for keyword fallback when no embedder configured
|
|
515
|
-
function applyV6DocChunks(db) {
|
|
516
|
-
db.exec(`
|
|
517
|
-
CREATE TABLE IF NOT EXISTS doc_chunks (
|
|
518
|
-
id TEXT PRIMARY KEY,
|
|
519
|
-
collection TEXT NOT NULL,
|
|
520
|
-
section_path TEXT NOT NULL,
|
|
521
|
-
depth INTEGER NOT NULL DEFAULT 2,
|
|
522
|
-
content TEXT NOT NULL,
|
|
523
|
-
token_estimate INTEGER NOT NULL DEFAULT 0,
|
|
524
|
-
source_hash TEXT NOT NULL,
|
|
525
|
-
source_path TEXT NOT NULL,
|
|
526
|
-
scope TEXT NOT NULL DEFAULT 'shared-fleet',
|
|
527
|
-
tier TEXT,
|
|
528
|
-
agent_id TEXT,
|
|
529
|
-
parent_path TEXT,
|
|
530
|
-
created_at TEXT NOT NULL,
|
|
531
|
-
updated_at TEXT NOT NULL
|
|
532
|
-
)
|
|
533
|
-
`);
|
|
534
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_doc_chunks_collection ON doc_chunks(collection, scope)');
|
|
535
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_doc_chunks_agent ON doc_chunks(agent_id, collection)');
|
|
536
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_doc_chunks_hash ON doc_chunks(source_hash)');
|
|
537
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_doc_chunks_source ON doc_chunks(source_path)');
|
|
538
|
-
// Source file tracking: one row per indexed file
|
|
539
|
-
// Used to detect when a file has changed and needs re-indexing
|
|
540
|
-
db.exec(`
|
|
541
|
-
CREATE TABLE IF NOT EXISTS doc_sources (
|
|
542
|
-
source_path TEXT NOT NULL,
|
|
543
|
-
collection TEXT NOT NULL,
|
|
544
|
-
scope TEXT NOT NULL DEFAULT 'shared-fleet',
|
|
545
|
-
agent_id TEXT,
|
|
546
|
-
source_hash TEXT NOT NULL,
|
|
547
|
-
chunk_count INTEGER NOT NULL DEFAULT 0,
|
|
548
|
-
indexed_at TEXT NOT NULL,
|
|
549
|
-
PRIMARY KEY (source_path, collection)
|
|
550
|
-
)
|
|
551
|
-
`);
|
|
552
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_doc_sources_collection ON doc_sources(collection)');
|
|
553
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_doc_sources_agent ON doc_sources(agent_id)');
|
|
554
|
-
// FTS5 for keyword-based fallback retrieval
|
|
555
|
-
db.exec(`
|
|
556
|
-
CREATE VIRTUAL TABLE IF NOT EXISTS doc_chunks_fts USING fts5(
|
|
557
|
-
content,
|
|
558
|
-
section_path,
|
|
559
|
-
collection,
|
|
560
|
-
content='doc_chunks',
|
|
561
|
-
content_rowid='rowid'
|
|
562
|
-
)
|
|
563
|
-
`);
|
|
564
|
-
db.exec(`
|
|
565
|
-
CREATE TRIGGER IF NOT EXISTS doc_chunks_fts_ai AFTER INSERT ON doc_chunks BEGIN
|
|
566
|
-
INSERT INTO doc_chunks_fts(rowid, content, section_path, collection)
|
|
567
|
-
VALUES (new.rowid, new.content, new.section_path, new.collection);
|
|
568
|
-
END
|
|
569
|
-
`);
|
|
570
|
-
db.exec(`
|
|
571
|
-
CREATE TRIGGER IF NOT EXISTS doc_chunks_fts_ad AFTER DELETE ON doc_chunks BEGIN
|
|
572
|
-
INSERT INTO doc_chunks_fts(doc_chunks_fts, rowid, content, section_path, collection)
|
|
573
|
-
VALUES ('delete', old.rowid, old.content, old.section_path, old.collection);
|
|
574
|
-
END
|
|
575
|
-
`);
|
|
576
|
-
db.exec(`
|
|
577
|
-
CREATE TRIGGER IF NOT EXISTS doc_chunks_fts_au AFTER UPDATE ON doc_chunks BEGIN
|
|
578
|
-
INSERT INTO doc_chunks_fts(doc_chunks_fts, rowid, content, section_path, collection)
|
|
579
|
-
VALUES ('delete', old.rowid, old.content, old.section_path, old.collection);
|
|
580
|
-
INSERT INTO doc_chunks_fts(rowid, content, section_path, collection)
|
|
581
|
-
VALUES (new.rowid, new.content, new.section_path, new.collection);
|
|
582
|
-
END
|
|
583
|
-
`);
|
|
584
|
-
}
|
|
585
|
-
// ── V7: Fix knowledge versioning ─────────────────────────────
|
|
586
|
-
// The V1 knowledge table had UNIQUE(agent_id, domain, key) which prevented
|
|
587
|
-
// true versioning — upsert would overwrite in-place, creating self-superseding rows.
|
|
588
|
-
//
|
|
589
|
-
// V7 recreates the knowledge table with:
|
|
590
|
-
// - version INTEGER NOT NULL DEFAULT 1
|
|
591
|
-
// - UNIQUE(agent_id, domain, key, version) — allows multiple versions per key
|
|
592
|
-
// - Preserves existing data (current rows become version 1)
|
|
593
|
-
function applyV7KnowledgeVersioning(db) {
|
|
594
|
-
// Rename existing table
|
|
595
|
-
db.exec('ALTER TABLE knowledge RENAME TO knowledge_v6');
|
|
596
|
-
// Create new table with versioned unique constraint
|
|
597
|
-
db.exec(`
|
|
598
|
-
CREATE TABLE knowledge (
|
|
599
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
600
|
-
agent_id TEXT NOT NULL,
|
|
601
|
-
domain TEXT NOT NULL,
|
|
602
|
-
key TEXT NOT NULL,
|
|
603
|
-
version INTEGER NOT NULL DEFAULT 1,
|
|
604
|
-
content TEXT NOT NULL,
|
|
605
|
-
confidence REAL NOT NULL DEFAULT 1.0,
|
|
606
|
-
visibility TEXT NOT NULL DEFAULT 'private',
|
|
607
|
-
source_type TEXT NOT NULL DEFAULT 'manual',
|
|
608
|
-
source_ref TEXT,
|
|
609
|
-
created_at TEXT NOT NULL,
|
|
610
|
-
updated_at TEXT NOT NULL,
|
|
611
|
-
expires_at TEXT,
|
|
612
|
-
superseded_by INTEGER,
|
|
613
|
-
UNIQUE(agent_id, domain, key, version)
|
|
614
|
-
)
|
|
615
|
-
`);
|
|
616
|
-
// Recreate indexes
|
|
617
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_knowledge_agent ON knowledge(agent_id, domain, key)');
|
|
618
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_knowledge_active ON knowledge(agent_id, superseded_by)');
|
|
619
|
-
// Migrate existing data (all become version 1, preserve visibility)
|
|
620
|
-
db.exec(`
|
|
621
|
-
INSERT INTO knowledge (id, agent_id, domain, key, version, content, confidence, visibility,
|
|
622
|
-
source_type, source_ref, created_at, updated_at, expires_at, superseded_by)
|
|
623
|
-
SELECT id, agent_id, domain, key, 1, content, confidence,
|
|
624
|
-
COALESCE(visibility, 'private'),
|
|
625
|
-
source_type, source_ref, created_at, updated_at, expires_at, superseded_by
|
|
626
|
-
FROM knowledge_v6
|
|
627
|
-
`);
|
|
628
|
-
// Drop old table
|
|
629
|
-
db.exec('DROP TABLE knowledge_v6');
|
|
630
|
-
// Recreate FTS5 virtual table (was created in V3 but references knowledge)
|
|
631
|
-
// FTS tables can't be migrated — drop and recreate
|
|
632
|
-
try {
|
|
633
|
-
db.exec('DROP TABLE IF EXISTS knowledge_fts');
|
|
634
|
-
}
|
|
635
|
-
catch { /* ignore */ }
|
|
636
|
-
db.exec(`
|
|
637
|
-
CREATE VIRTUAL TABLE IF NOT EXISTS knowledge_fts USING fts5(
|
|
638
|
-
content,
|
|
639
|
-
domain,
|
|
640
|
-
key,
|
|
641
|
-
content='knowledge',
|
|
642
|
-
content_rowid='id'
|
|
643
|
-
)
|
|
644
|
-
`);
|
|
645
|
-
// Repopulate FTS index from migrated data
|
|
646
|
-
db.exec(`INSERT INTO knowledge_fts(rowid, content, domain, key) SELECT id, content, domain, key FROM knowledge`);
|
|
647
|
-
// Recreate triggers
|
|
648
|
-
db.exec(`
|
|
649
|
-
CREATE TRIGGER IF NOT EXISTS knowledge_fts_ai AFTER INSERT ON knowledge BEGIN
|
|
650
|
-
INSERT INTO knowledge_fts(rowid, content, domain, key) VALUES (new.id, new.content, new.domain, new.key);
|
|
651
|
-
END
|
|
652
|
-
`);
|
|
653
|
-
db.exec(`
|
|
654
|
-
CREATE TRIGGER IF NOT EXISTS knowledge_fts_au AFTER UPDATE ON knowledge BEGIN
|
|
655
|
-
INSERT INTO knowledge_fts(knowledge_fts, rowid, content, domain, key) VALUES('delete', old.id, old.content, old.domain, old.key);
|
|
656
|
-
INSERT INTO knowledge_fts(rowid, content, domain, key) VALUES (new.id, new.content, new.domain, new.key);
|
|
657
|
-
END
|
|
658
|
-
`);
|
|
659
|
-
db.exec(`
|
|
660
|
-
CREATE TRIGGER IF NOT EXISTS knowledge_fts_ad AFTER DELETE ON knowledge BEGIN
|
|
661
|
-
INSERT INTO knowledge_fts(knowledge_fts, rowid, content, domain, key) VALUES('delete', old.id, old.content, old.domain, old.key);
|
|
662
|
-
END
|
|
663
|
-
`);
|
|
664
|
-
}
|
|
665
|
-
// ── Migration runner ──────────────────────────────────────────
|
|
666
|
-
export function migrateLibrary(db) {
|
|
667
|
-
db.exec(`
|
|
668
|
-
CREATE TABLE IF NOT EXISTS schema_version (
|
|
669
|
-
version INTEGER PRIMARY KEY,
|
|
670
|
-
applied_at TEXT NOT NULL
|
|
671
|
-
)
|
|
672
|
-
`);
|
|
673
|
-
const row = db
|
|
674
|
-
.prepare('SELECT MAX(version) AS version FROM schema_version')
|
|
675
|
-
.get();
|
|
676
|
-
const currentVersion = typeof row?.version === 'number' ? row.version : 0;
|
|
677
|
-
if (currentVersion > LIBRARY_SCHEMA_VERSION) {
|
|
678
|
-
console.warn(`[hypermem-library] Database schema version (${currentVersion}) is newer than this engine (${LIBRARY_SCHEMA_VERSION}).`);
|
|
679
|
-
return;
|
|
680
|
-
}
|
|
681
|
-
if (currentVersion < 1) {
|
|
682
|
-
applyV1Schema(db);
|
|
683
|
-
db.prepare('INSERT INTO schema_version (version, applied_at) VALUES (?, ?)')
|
|
684
|
-
.run(1, nowIso());
|
|
685
|
-
}
|
|
686
|
-
if (currentVersion < 2) {
|
|
687
|
-
applyV2SessionRegistry(db);
|
|
688
|
-
db.prepare('INSERT INTO schema_version (version, applied_at) VALUES (?, ?)')
|
|
689
|
-
.run(2, nowIso());
|
|
690
|
-
}
|
|
691
|
-
if (currentVersion < 3) {
|
|
692
|
-
applyV3Collections(db);
|
|
693
|
-
db.prepare('INSERT INTO schema_version (version, applied_at) VALUES (?, ?)')
|
|
694
|
-
.run(3, nowIso());
|
|
695
|
-
}
|
|
696
|
-
if (currentVersion < 4) {
|
|
697
|
-
applyV4Capabilities(db);
|
|
698
|
-
db.prepare('INSERT INTO schema_version (version, applied_at) VALUES (?, ?)')
|
|
699
|
-
.run(4, nowIso());
|
|
700
|
-
}
|
|
701
|
-
if (currentVersion < 5) {
|
|
702
|
-
applyV5DesiredState(db);
|
|
703
|
-
db.prepare('INSERT INTO schema_version (version, applied_at) VALUES (?, ?)')
|
|
704
|
-
.run(5, nowIso());
|
|
705
|
-
}
|
|
706
|
-
if (currentVersion < 6) {
|
|
707
|
-
applyV6DocChunks(db);
|
|
708
|
-
db.prepare('INSERT INTO schema_version (version, applied_at) VALUES (?, ?)')
|
|
709
|
-
.run(6, nowIso());
|
|
710
|
-
}
|
|
711
|
-
if (currentVersion < 7) {
|
|
712
|
-
applyV7KnowledgeVersioning(db);
|
|
713
|
-
db.prepare('INSERT INTO schema_version (version, applied_at) VALUES (?, ?)')
|
|
714
|
-
.run(7, nowIso());
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
//# sourceMappingURL=library-schema.js.map
|