@spool-lab/core 0.3.3
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/LICENSE +21 -0
- package/README.md +39 -0
- package/dist/connectors/capabilities/cookies-chrome.d.ts +19 -0
- package/dist/connectors/capabilities/cookies-chrome.d.ts.map +1 -0
- package/dist/connectors/capabilities/cookies-chrome.js +199 -0
- package/dist/connectors/capabilities/cookies-chrome.js.map +1 -0
- package/dist/connectors/capabilities/exec-impl.d.ts +3 -0
- package/dist/connectors/capabilities/exec-impl.d.ts.map +1 -0
- package/dist/connectors/capabilities/exec-impl.js +108 -0
- package/dist/connectors/capabilities/exec-impl.js.map +1 -0
- package/dist/connectors/capabilities/fetch-impl.d.ts +3 -0
- package/dist/connectors/capabilities/fetch-impl.d.ts.map +1 -0
- package/dist/connectors/capabilities/fetch-impl.js +4 -0
- package/dist/connectors/capabilities/fetch-impl.js.map +1 -0
- package/dist/connectors/capabilities/index.d.ts +6 -0
- package/dist/connectors/capabilities/index.d.ts.map +1 -0
- package/dist/connectors/capabilities/index.js +6 -0
- package/dist/connectors/capabilities/index.js.map +1 -0
- package/dist/connectors/capabilities/log-impl.d.ts +3 -0
- package/dist/connectors/capabilities/log-impl.d.ts.map +1 -0
- package/dist/connectors/capabilities/log-impl.js +26 -0
- package/dist/connectors/capabilities/log-impl.js.map +1 -0
- package/dist/connectors/capabilities/sqlite-impl.d.ts +3 -0
- package/dist/connectors/capabilities/sqlite-impl.d.ts.map +1 -0
- package/dist/connectors/capabilities/sqlite-impl.js +19 -0
- package/dist/connectors/capabilities/sqlite-impl.js.map +1 -0
- package/dist/connectors/loader.d.ts +47 -0
- package/dist/connectors/loader.d.ts.map +1 -0
- package/dist/connectors/loader.js +328 -0
- package/dist/connectors/loader.js.map +1 -0
- package/dist/connectors/npm-install.d.ts +26 -0
- package/dist/connectors/npm-install.d.ts.map +1 -0
- package/dist/connectors/npm-install.js +71 -0
- package/dist/connectors/npm-install.js.map +1 -0
- package/dist/connectors/prerequisites.d.ts +14 -0
- package/dist/connectors/prerequisites.d.ts.map +1 -0
- package/dist/connectors/prerequisites.js +109 -0
- package/dist/connectors/prerequisites.js.map +1 -0
- package/dist/connectors/registry-fetch.d.ts +22 -0
- package/dist/connectors/registry-fetch.d.ts.map +1 -0
- package/dist/connectors/registry-fetch.js +54 -0
- package/dist/connectors/registry-fetch.js.map +1 -0
- package/dist/connectors/registry.d.ts +23 -0
- package/dist/connectors/registry.d.ts.map +1 -0
- package/dist/connectors/registry.js +59 -0
- package/dist/connectors/registry.js.map +1 -0
- package/dist/connectors/sync-engine.d.ts +30 -0
- package/dist/connectors/sync-engine.d.ts.map +1 -0
- package/dist/connectors/sync-engine.js +589 -0
- package/dist/connectors/sync-engine.js.map +1 -0
- package/dist/connectors/sync-scheduler.d.ts +56 -0
- package/dist/connectors/sync-scheduler.d.ts.map +1 -0
- package/dist/connectors/sync-scheduler.js +238 -0
- package/dist/connectors/sync-scheduler.js.map +1 -0
- package/dist/connectors/trust-store.d.ts +13 -0
- package/dist/connectors/trust-store.d.ts.map +1 -0
- package/dist/connectors/trust-store.js +48 -0
- package/dist/connectors/trust-store.js.map +1 -0
- package/dist/connectors/types.d.ts +111 -0
- package/dist/connectors/types.d.ts.map +1 -0
- package/dist/connectors/types.js +50 -0
- package/dist/connectors/types.js.map +1 -0
- package/dist/db/db.d.ts +6 -0
- package/dist/db/db.d.ts.map +1 -0
- package/dist/db/db.js +347 -0
- package/dist/db/db.js.map +1 -0
- package/dist/db/queries.d.ts +68 -0
- package/dist/db/queries.d.ts.map +1 -0
- package/dist/db/queries.js +828 -0
- package/dist/db/queries.js.map +1 -0
- package/dist/db/search-query.d.ts +13 -0
- package/dist/db/search-query.d.ts.map +1 -0
- package/dist/db/search-query.js +62 -0
- package/dist/db/search-query.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/parsers/claude.d.ts +9 -0
- package/dist/parsers/claude.d.ts.map +1 -0
- package/dist/parsers/claude.js +153 -0
- package/dist/parsers/claude.js.map +1 -0
- package/dist/parsers/codex.d.ts +5 -0
- package/dist/parsers/codex.d.ts.map +1 -0
- package/dist/parsers/codex.js +192 -0
- package/dist/parsers/codex.js.map +1 -0
- package/dist/parsers/gemini.d.ts +4 -0
- package/dist/parsers/gemini.d.ts.map +1 -0
- package/dist/parsers/gemini.js +149 -0
- package/dist/parsers/gemini.js.map +1 -0
- package/dist/sync/source-paths.d.ts +5 -0
- package/dist/sync/source-paths.d.ts.map +1 -0
- package/dist/sync/source-paths.js +119 -0
- package/dist/sync/source-paths.js.map +1 -0
- package/dist/sync/syncer.d.ts +19 -0
- package/dist/sync/syncer.d.ts.map +1 -0
- package/dist/sync/syncer.js +308 -0
- package/dist/sync/syncer.js.map +1 -0
- package/dist/sync/watcher.d.ts +19 -0
- package/dist/sync/watcher.d.ts.map +1 -0
- package/dist/sync/watcher.js +67 -0
- package/dist/sync/watcher.js.map +1 -0
- package/dist/types.d.ts +112 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/util/resolve-bin.d.ts +6 -0
- package/dist/util/resolve-bin.d.ts.map +1 -0
- package/dist/util/resolve-bin.js +66 -0
- package/dist/util/resolve-bin.js.map +1 -0
- package/package.json +43 -0
package/dist/db/db.js
ADDED
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
import Database from 'better-sqlite3';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { mkdirSync, statSync } from 'node:fs';
|
|
5
|
+
export const SPOOL_DIR = process.env['SPOOL_DATA_DIR'] ?? join(homedir(), '.spool');
|
|
6
|
+
export const DB_PATH = join(SPOOL_DIR, 'spool.db');
|
|
7
|
+
let _db = null;
|
|
8
|
+
export function getDB(_readonly = false) {
|
|
9
|
+
if (_db)
|
|
10
|
+
return _db;
|
|
11
|
+
mkdirSync(SPOOL_DIR, { recursive: true });
|
|
12
|
+
const db = new Database(DB_PATH);
|
|
13
|
+
db.pragma('journal_mode = WAL');
|
|
14
|
+
db.pragma('foreign_keys = ON');
|
|
15
|
+
db.pragma('busy_timeout = 5000');
|
|
16
|
+
runMigrations(db);
|
|
17
|
+
_db = db;
|
|
18
|
+
return db;
|
|
19
|
+
}
|
|
20
|
+
export function getDBSize() {
|
|
21
|
+
try {
|
|
22
|
+
return statSync(DB_PATH).size;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return 0;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function runMigrations(db) {
|
|
29
|
+
db.exec(`
|
|
30
|
+
CREATE TABLE IF NOT EXISTS sources (
|
|
31
|
+
id INTEGER PRIMARY KEY,
|
|
32
|
+
name TEXT NOT NULL UNIQUE,
|
|
33
|
+
base_path TEXT NOT NULL,
|
|
34
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
INSERT OR IGNORE INTO sources (name, base_path) VALUES
|
|
38
|
+
('claude', '~/.claude/projects'),
|
|
39
|
+
('codex', '~/.codex/sessions'),
|
|
40
|
+
('gemini', '~/.gemini/tmp'),
|
|
41
|
+
('connector', '<plugin>');
|
|
42
|
+
|
|
43
|
+
CREATE TABLE IF NOT EXISTS projects (
|
|
44
|
+
id INTEGER PRIMARY KEY,
|
|
45
|
+
source_id INTEGER NOT NULL REFERENCES sources(id),
|
|
46
|
+
slug TEXT NOT NULL,
|
|
47
|
+
display_path TEXT NOT NULL,
|
|
48
|
+
display_name TEXT NOT NULL,
|
|
49
|
+
last_synced TEXT,
|
|
50
|
+
UNIQUE (source_id, slug)
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
CREATE TABLE IF NOT EXISTS sessions (
|
|
54
|
+
id INTEGER PRIMARY KEY,
|
|
55
|
+
project_id INTEGER NOT NULL REFERENCES projects(id),
|
|
56
|
+
source_id INTEGER NOT NULL REFERENCES sources(id),
|
|
57
|
+
session_uuid TEXT NOT NULL UNIQUE,
|
|
58
|
+
file_path TEXT NOT NULL UNIQUE,
|
|
59
|
+
title TEXT,
|
|
60
|
+
started_at TEXT NOT NULL,
|
|
61
|
+
ended_at TEXT NOT NULL,
|
|
62
|
+
message_count INTEGER NOT NULL DEFAULT 0,
|
|
63
|
+
has_tool_use INTEGER NOT NULL DEFAULT 0,
|
|
64
|
+
cwd TEXT,
|
|
65
|
+
model TEXT,
|
|
66
|
+
raw_file_mtime TEXT,
|
|
67
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_project ON sessions(project_id);
|
|
71
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_started ON sessions(started_at DESC);
|
|
72
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_source ON sessions(source_id);
|
|
73
|
+
|
|
74
|
+
CREATE TABLE IF NOT EXISTS messages (
|
|
75
|
+
id INTEGER PRIMARY KEY,
|
|
76
|
+
session_id INTEGER NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
|
77
|
+
source_id INTEGER NOT NULL REFERENCES sources(id),
|
|
78
|
+
msg_uuid TEXT,
|
|
79
|
+
parent_uuid TEXT,
|
|
80
|
+
role TEXT NOT NULL,
|
|
81
|
+
content_text TEXT NOT NULL DEFAULT '',
|
|
82
|
+
timestamp TEXT NOT NULL,
|
|
83
|
+
is_sidechain INTEGER NOT NULL DEFAULT 0,
|
|
84
|
+
tool_names TEXT NOT NULL DEFAULT '[]',
|
|
85
|
+
seq INTEGER NOT NULL
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
CREATE INDEX IF NOT EXISTS idx_messages_session ON messages(session_id);
|
|
89
|
+
CREATE INDEX IF NOT EXISTS idx_messages_timestamp ON messages(timestamp);
|
|
90
|
+
|
|
91
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS messages_fts USING fts5(
|
|
92
|
+
content_text,
|
|
93
|
+
content='messages',
|
|
94
|
+
content_rowid='id',
|
|
95
|
+
tokenize='unicode61 remove_diacritics 1'
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS messages_fts_trigram USING fts5(
|
|
99
|
+
content_text,
|
|
100
|
+
content='messages',
|
|
101
|
+
content_rowid='id',
|
|
102
|
+
tokenize='trigram'
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
CREATE TABLE IF NOT EXISTS sync_log (
|
|
106
|
+
id INTEGER PRIMARY KEY,
|
|
107
|
+
source_id INTEGER NOT NULL REFERENCES sources(id),
|
|
108
|
+
file_path TEXT NOT NULL,
|
|
109
|
+
status TEXT NOT NULL,
|
|
110
|
+
message TEXT,
|
|
111
|
+
synced_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
CREATE TABLE IF NOT EXISTS session_search (
|
|
115
|
+
session_id INTEGER PRIMARY KEY REFERENCES sessions(id) ON DELETE CASCADE,
|
|
116
|
+
title TEXT NOT NULL DEFAULT '',
|
|
117
|
+
user_text TEXT NOT NULL DEFAULT '',
|
|
118
|
+
assistant_text TEXT NOT NULL DEFAULT '',
|
|
119
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS session_search_fts USING fts5(
|
|
123
|
+
title,
|
|
124
|
+
user_text,
|
|
125
|
+
assistant_text,
|
|
126
|
+
content='session_search',
|
|
127
|
+
content_rowid='session_id',
|
|
128
|
+
tokenize='unicode61 remove_diacritics 1'
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS session_search_fts_trigram USING fts5(
|
|
132
|
+
title,
|
|
133
|
+
user_text,
|
|
134
|
+
assistant_text,
|
|
135
|
+
content='session_search',
|
|
136
|
+
content_rowid='session_id',
|
|
137
|
+
tokenize='trigram'
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
-- ── Captures (connector items) ─────────────────────────────────────────
|
|
141
|
+
|
|
142
|
+
CREATE TABLE IF NOT EXISTS captures (
|
|
143
|
+
id INTEGER PRIMARY KEY,
|
|
144
|
+
source_id INTEGER NOT NULL REFERENCES sources(id),
|
|
145
|
+
capture_uuid TEXT NOT NULL UNIQUE,
|
|
146
|
+
url TEXT NOT NULL,
|
|
147
|
+
title TEXT NOT NULL DEFAULT '',
|
|
148
|
+
content_text TEXT NOT NULL DEFAULT '',
|
|
149
|
+
author TEXT,
|
|
150
|
+
platform TEXT NOT NULL,
|
|
151
|
+
platform_id TEXT,
|
|
152
|
+
content_type TEXT NOT NULL DEFAULT 'page',
|
|
153
|
+
thumbnail_url TEXT,
|
|
154
|
+
metadata TEXT NOT NULL DEFAULT '{}',
|
|
155
|
+
captured_at TEXT NOT NULL,
|
|
156
|
+
indexed_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
157
|
+
raw_json TEXT
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
CREATE INDEX IF NOT EXISTS idx_captures_platform ON captures(platform);
|
|
161
|
+
CREATE INDEX IF NOT EXISTS idx_captures_url ON captures(url);
|
|
162
|
+
CREATE INDEX IF NOT EXISTS idx_captures_captured ON captures(captured_at DESC);
|
|
163
|
+
|
|
164
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS captures_fts USING fts5(
|
|
165
|
+
title,
|
|
166
|
+
content_text,
|
|
167
|
+
content='captures',
|
|
168
|
+
content_rowid='id',
|
|
169
|
+
tokenize='unicode61 remove_diacritics 1'
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS captures_fts_trigram USING fts5(
|
|
173
|
+
title,
|
|
174
|
+
content_text,
|
|
175
|
+
content='captures',
|
|
176
|
+
content_rowid='id',
|
|
177
|
+
tokenize='trigram'
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
-- ── Connector sync state ────────────────────────────────────────────────
|
|
181
|
+
|
|
182
|
+
CREATE TABLE IF NOT EXISTS capture_connectors (
|
|
183
|
+
capture_id INTEGER NOT NULL REFERENCES captures(id) ON DELETE CASCADE,
|
|
184
|
+
connector_id TEXT NOT NULL,
|
|
185
|
+
PRIMARY KEY (capture_id, connector_id)
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
CREATE INDEX IF NOT EXISTS idx_capture_connectors_connector
|
|
189
|
+
ON capture_connectors(connector_id);
|
|
190
|
+
|
|
191
|
+
CREATE TABLE IF NOT EXISTS connector_sync_state (
|
|
192
|
+
connector_id TEXT PRIMARY KEY,
|
|
193
|
+
head_cursor TEXT,
|
|
194
|
+
head_item_id TEXT,
|
|
195
|
+
tail_cursor TEXT,
|
|
196
|
+
tail_complete INTEGER NOT NULL DEFAULT 0,
|
|
197
|
+
last_forward_sync_at TEXT,
|
|
198
|
+
last_backfill_sync_at TEXT,
|
|
199
|
+
total_synced INTEGER NOT NULL DEFAULT 0,
|
|
200
|
+
consecutive_errors INTEGER NOT NULL DEFAULT 0,
|
|
201
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
202
|
+
config_json TEXT NOT NULL DEFAULT '{}',
|
|
203
|
+
last_error_at TEXT,
|
|
204
|
+
last_error_code TEXT,
|
|
205
|
+
last_error_message TEXT
|
|
206
|
+
);
|
|
207
|
+
`);
|
|
208
|
+
db.exec(`
|
|
209
|
+
DROP TRIGGER IF EXISTS messages_fts_insert;
|
|
210
|
+
DROP TRIGGER IF EXISTS messages_fts_delete;
|
|
211
|
+
DROP TRIGGER IF EXISTS captures_fts_insert;
|
|
212
|
+
DROP TRIGGER IF EXISTS captures_fts_delete;
|
|
213
|
+
DROP TRIGGER IF EXISTS session_search_fts_insert;
|
|
214
|
+
DROP TRIGGER IF EXISTS session_search_fts_update;
|
|
215
|
+
DROP TRIGGER IF EXISTS session_search_fts_delete;
|
|
216
|
+
|
|
217
|
+
CREATE TRIGGER messages_fts_insert
|
|
218
|
+
AFTER INSERT ON messages BEGIN
|
|
219
|
+
INSERT INTO messages_fts(rowid, content_text)
|
|
220
|
+
VALUES(NEW.id, NEW.content_text);
|
|
221
|
+
INSERT INTO messages_fts_trigram(rowid, content_text)
|
|
222
|
+
VALUES(NEW.id, NEW.content_text);
|
|
223
|
+
END;
|
|
224
|
+
|
|
225
|
+
CREATE TRIGGER messages_fts_delete
|
|
226
|
+
AFTER DELETE ON messages BEGIN
|
|
227
|
+
INSERT INTO messages_fts(messages_fts, rowid, content_text)
|
|
228
|
+
VALUES('delete', OLD.id, OLD.content_text);
|
|
229
|
+
INSERT INTO messages_fts_trigram(messages_fts_trigram, rowid, content_text)
|
|
230
|
+
VALUES('delete', OLD.id, OLD.content_text);
|
|
231
|
+
END;
|
|
232
|
+
|
|
233
|
+
CREATE TRIGGER captures_fts_insert
|
|
234
|
+
AFTER INSERT ON captures BEGIN
|
|
235
|
+
INSERT INTO captures_fts(rowid, title, content_text)
|
|
236
|
+
VALUES(NEW.id, NEW.title, NEW.content_text);
|
|
237
|
+
INSERT INTO captures_fts_trigram(rowid, title, content_text)
|
|
238
|
+
VALUES(NEW.id, NEW.title, NEW.content_text);
|
|
239
|
+
END;
|
|
240
|
+
|
|
241
|
+
CREATE TRIGGER captures_fts_delete
|
|
242
|
+
AFTER DELETE ON captures BEGIN
|
|
243
|
+
INSERT INTO captures_fts(captures_fts, rowid, title, content_text)
|
|
244
|
+
VALUES('delete', OLD.id, OLD.title, OLD.content_text);
|
|
245
|
+
INSERT INTO captures_fts_trigram(captures_fts_trigram, rowid, title, content_text)
|
|
246
|
+
VALUES('delete', OLD.id, OLD.title, OLD.content_text);
|
|
247
|
+
END;
|
|
248
|
+
|
|
249
|
+
CREATE TRIGGER session_search_fts_insert
|
|
250
|
+
AFTER INSERT ON session_search BEGIN
|
|
251
|
+
INSERT INTO session_search_fts(rowid, title, user_text, assistant_text)
|
|
252
|
+
VALUES(NEW.session_id, NEW.title, NEW.user_text, NEW.assistant_text);
|
|
253
|
+
INSERT INTO session_search_fts_trigram(rowid, title, user_text, assistant_text)
|
|
254
|
+
VALUES(NEW.session_id, NEW.title, NEW.user_text, NEW.assistant_text);
|
|
255
|
+
END;
|
|
256
|
+
|
|
257
|
+
CREATE TRIGGER session_search_fts_update
|
|
258
|
+
AFTER UPDATE ON session_search BEGIN
|
|
259
|
+
INSERT INTO session_search_fts(session_search_fts, rowid, title, user_text, assistant_text)
|
|
260
|
+
VALUES('delete', OLD.session_id, OLD.title, OLD.user_text, OLD.assistant_text);
|
|
261
|
+
INSERT INTO session_search_fts(rowid, title, user_text, assistant_text)
|
|
262
|
+
VALUES(NEW.session_id, NEW.title, NEW.user_text, NEW.assistant_text);
|
|
263
|
+
INSERT INTO session_search_fts_trigram(session_search_fts_trigram, rowid, title, user_text, assistant_text)
|
|
264
|
+
VALUES('delete', OLD.session_id, OLD.title, OLD.user_text, OLD.assistant_text);
|
|
265
|
+
INSERT INTO session_search_fts_trigram(rowid, title, user_text, assistant_text)
|
|
266
|
+
VALUES(NEW.session_id, NEW.title, NEW.user_text, NEW.assistant_text);
|
|
267
|
+
END;
|
|
268
|
+
|
|
269
|
+
CREATE TRIGGER session_search_fts_delete
|
|
270
|
+
AFTER DELETE ON session_search BEGIN
|
|
271
|
+
INSERT INTO session_search_fts(session_search_fts, rowid, title, user_text, assistant_text)
|
|
272
|
+
VALUES('delete', OLD.session_id, OLD.title, OLD.user_text, OLD.assistant_text);
|
|
273
|
+
INSERT INTO session_search_fts_trigram(session_search_fts_trigram, rowid, title, user_text, assistant_text)
|
|
274
|
+
VALUES('delete', OLD.session_id, OLD.title, OLD.user_text, OLD.assistant_text);
|
|
275
|
+
END;
|
|
276
|
+
`);
|
|
277
|
+
// ── Incremental migrations ──────────────────────────────────────────────
|
|
278
|
+
// Use SQLite's built-in user_version pragma to track schema version.
|
|
279
|
+
// Each migration runs exactly once. Add new migrations at the end with
|
|
280
|
+
// the next sequential version number.
|
|
281
|
+
const version = db.pragma('user_version')[0].user_version;
|
|
282
|
+
if (version < 1) {
|
|
283
|
+
// v1: add last_error_at for accurate backoff timing
|
|
284
|
+
try {
|
|
285
|
+
db.exec('ALTER TABLE connector_sync_state ADD COLUMN last_error_at TEXT');
|
|
286
|
+
}
|
|
287
|
+
catch {
|
|
288
|
+
// Column may already exist if user ran a dev build before this migration
|
|
289
|
+
}
|
|
290
|
+
db.pragma('user_version = 1');
|
|
291
|
+
}
|
|
292
|
+
if (version < 2) {
|
|
293
|
+
// v2: rebuild captures FTS indexes to fix corruption from old opencli data
|
|
294
|
+
// that causes DELETE triggers to fail with SQLITE_CORRUPT
|
|
295
|
+
try {
|
|
296
|
+
db.exec("INSERT INTO captures_fts(captures_fts) VALUES('rebuild')");
|
|
297
|
+
db.exec("INSERT INTO captures_fts_trigram(captures_fts_trigram) VALUES('rebuild')");
|
|
298
|
+
}
|
|
299
|
+
catch {
|
|
300
|
+
// FTS tables may not exist yet on fresh installs — safe to skip
|
|
301
|
+
}
|
|
302
|
+
db.pragma('user_version = 2');
|
|
303
|
+
}
|
|
304
|
+
if (version < 3) {
|
|
305
|
+
// v3: migrate connector provenance from metadata.connectorId (single-valued,
|
|
306
|
+
// clobbered on UPSERT) to the M:N capture_connectors table, and stop
|
|
307
|
+
// claiming connector captures came from source_id=claude.
|
|
308
|
+
db.transaction(() => {
|
|
309
|
+
// Backfill M:N from existing metadata.connectorId.
|
|
310
|
+
db.exec(`
|
|
311
|
+
INSERT OR IGNORE INTO capture_connectors (capture_id, connector_id)
|
|
312
|
+
SELECT id, json_extract(metadata, '$.connectorId')
|
|
313
|
+
FROM captures
|
|
314
|
+
WHERE json_extract(metadata, '$.connectorId') IS NOT NULL
|
|
315
|
+
`);
|
|
316
|
+
// Strip the now-redundant field from metadata.
|
|
317
|
+
db.exec(`
|
|
318
|
+
UPDATE captures
|
|
319
|
+
SET metadata = json_remove(metadata, '$.connectorId')
|
|
320
|
+
WHERE json_extract(metadata, '$.connectorId') IS NOT NULL
|
|
321
|
+
`);
|
|
322
|
+
// Point connector captures at the 'connector' source row instead of claude.
|
|
323
|
+
db.exec(`
|
|
324
|
+
UPDATE captures
|
|
325
|
+
SET source_id = (SELECT id FROM sources WHERE name = 'connector')
|
|
326
|
+
WHERE id IN (SELECT capture_id FROM capture_connectors)
|
|
327
|
+
`);
|
|
328
|
+
// idx_captures_source was never used by any query — drop it.
|
|
329
|
+
db.exec(`DROP INDEX IF EXISTS idx_captures_source`);
|
|
330
|
+
})();
|
|
331
|
+
db.pragma('user_version = 3');
|
|
332
|
+
}
|
|
333
|
+
rebuildFtsTableIfEmpty(db, 'messages', 'messages_fts_trigram');
|
|
334
|
+
rebuildFtsTableIfEmpty(db, 'captures', 'captures_fts_trigram');
|
|
335
|
+
rebuildFtsTableIfEmpty(db, 'session_search', 'session_search_fts');
|
|
336
|
+
rebuildFtsTableIfEmpty(db, 'session_search', 'session_search_fts_trigram');
|
|
337
|
+
}
|
|
338
|
+
function rebuildFtsTableIfEmpty(db, contentTable, ftsTable) {
|
|
339
|
+
const sourceCount = db.prepare(`SELECT COUNT(*) AS count FROM ${contentTable}`).get().count;
|
|
340
|
+
if (sourceCount === 0)
|
|
341
|
+
return;
|
|
342
|
+
const indexCount = db.prepare(`SELECT COUNT(*) AS count FROM ${ftsTable}`).get().count;
|
|
343
|
+
if (indexCount > 0)
|
|
344
|
+
return;
|
|
345
|
+
db.exec(`INSERT INTO ${ftsTable}(${ftsTable}) VALUES('rebuild')`);
|
|
346
|
+
}
|
|
347
|
+
//# sourceMappingURL=db.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/db/db.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type Database from 'better-sqlite3';
|
|
2
|
+
import type { Session, Message, FragmentResult, StatusInfo, CaptureResult, SearchResult, Source, SessionSource } from '../types.js';
|
|
3
|
+
import type { CapturedItem } from '../connectors/types.js';
|
|
4
|
+
export declare function getOrCreateProject(db: Database.Database, sourceId: number, slug: string, displayPath: string, displayName: string): number;
|
|
5
|
+
export declare function getSourceId(db: Database.Database, name: SessionSource): number;
|
|
6
|
+
export declare function getSessionMtime(db: Database.Database, filePath: string): string | null;
|
|
7
|
+
export declare function deleteSessionByFilePath(db: Database.Database, filePath: string): boolean;
|
|
8
|
+
export declare function getAllSessionMtimes(db: Database.Database): Map<string, string>;
|
|
9
|
+
export declare function upsertSession(db: Database.Database, opts: {
|
|
10
|
+
projectId: number;
|
|
11
|
+
sourceId: number;
|
|
12
|
+
sessionUuid: string;
|
|
13
|
+
filePath: string;
|
|
14
|
+
title: string;
|
|
15
|
+
startedAt: string;
|
|
16
|
+
endedAt: string;
|
|
17
|
+
messageCount: number;
|
|
18
|
+
hasToolUse: boolean;
|
|
19
|
+
cwd: string;
|
|
20
|
+
model: string;
|
|
21
|
+
rawFileMtime: string;
|
|
22
|
+
}): number;
|
|
23
|
+
export declare function upsertSessionSearch(db: Database.Database, opts: {
|
|
24
|
+
sessionId: number;
|
|
25
|
+
title: string;
|
|
26
|
+
userText: string;
|
|
27
|
+
assistantText: string;
|
|
28
|
+
}): void;
|
|
29
|
+
export declare function insertMessages(db: Database.Database, sessionId: number, sourceId: number, messages: Array<{
|
|
30
|
+
uuid: string;
|
|
31
|
+
parentUuid: string | null;
|
|
32
|
+
role: string;
|
|
33
|
+
contentText: string;
|
|
34
|
+
timestamp: string;
|
|
35
|
+
isSidechain: boolean;
|
|
36
|
+
toolNames: string[];
|
|
37
|
+
seq: number;
|
|
38
|
+
}>): void;
|
|
39
|
+
export declare function listRecentSessions(db: Database.Database, limit?: number): Session[];
|
|
40
|
+
export declare function getSessionWithMessages(db: Database.Database, sessionUuid: string): {
|
|
41
|
+
session: Session;
|
|
42
|
+
messages: Message[];
|
|
43
|
+
} | null;
|
|
44
|
+
export declare function searchFragments(db: Database.Database, query: string, opts?: {
|
|
45
|
+
limit?: number;
|
|
46
|
+
source?: SessionSource;
|
|
47
|
+
since?: string;
|
|
48
|
+
}): FragmentResult[];
|
|
49
|
+
export declare function searchSessionPreview(db: Database.Database, query: string, opts?: {
|
|
50
|
+
limit?: number;
|
|
51
|
+
source?: SessionSource;
|
|
52
|
+
since?: string;
|
|
53
|
+
}): FragmentResult[];
|
|
54
|
+
export declare function buildLikeSnippet(text: string, terms: string[]): string;
|
|
55
|
+
export declare function getStatus(db: Database.Database): StatusInfo;
|
|
56
|
+
export declare function insertCapture(db: Database.Database, sourceId: number, item: CapturedItem): number;
|
|
57
|
+
export declare function searchCaptures(db: Database.Database, query: string, opts?: {
|
|
58
|
+
limit?: number;
|
|
59
|
+
platform?: string;
|
|
60
|
+
since?: string;
|
|
61
|
+
}): CaptureResult[];
|
|
62
|
+
export declare function searchAll(db: Database.Database, query: string, opts?: {
|
|
63
|
+
limit?: number;
|
|
64
|
+
source?: Source;
|
|
65
|
+
since?: string;
|
|
66
|
+
}): SearchResult[];
|
|
67
|
+
export declare function getCaptureCount(db: Database.Database, platform?: string): number;
|
|
68
|
+
//# sourceMappingURL=queries.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../src/db/queries.ts"],"names":[],"mappings":"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"}
|