@velvetmonkey/vault-core 2.0.138 → 2.0.139
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/migrations.js +116 -0
- package/dist/queries.d.ts +2 -2
- package/dist/queries.js +12 -3
- package/dist/schema.d.ts +2 -2
- package/dist/schema.js +19 -6
- package/dist/sqlite.js +6 -3
- package/package.json +3 -3
package/dist/migrations.js
CHANGED
|
@@ -162,6 +162,122 @@ export function initSchema(db) {
|
|
|
162
162
|
db.exec('ALTER TABLE tool_invocations ADD COLUMN baseline_tokens INTEGER');
|
|
163
163
|
}
|
|
164
164
|
}
|
|
165
|
+
// v32: Drop composite PRIMARY KEY on entity_changes (was causing UNIQUE constraint
|
|
166
|
+
// crashes when two changes hit the same entity+field within one second).
|
|
167
|
+
// Recreate as rowid table — audit log doesn't need dedup.
|
|
168
|
+
if (currentVersion < 32) {
|
|
169
|
+
const hasTable = db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='entity_changes'`).get();
|
|
170
|
+
if (hasTable) {
|
|
171
|
+
db.exec(`
|
|
172
|
+
CREATE TABLE IF NOT EXISTS entity_changes_new (
|
|
173
|
+
entity TEXT NOT NULL,
|
|
174
|
+
field TEXT NOT NULL,
|
|
175
|
+
old_value TEXT,
|
|
176
|
+
new_value TEXT,
|
|
177
|
+
changed_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
178
|
+
);
|
|
179
|
+
INSERT INTO entity_changes_new SELECT entity, field, old_value, new_value, changed_at FROM entity_changes;
|
|
180
|
+
DROP TABLE entity_changes;
|
|
181
|
+
ALTER TABLE entity_changes_new RENAME TO entity_changes;
|
|
182
|
+
`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// v33: performance_benchmarks table (longitudinal tracking)
|
|
186
|
+
if (currentVersion < 33) {
|
|
187
|
+
const hasTable = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='performance_benchmarks'").get();
|
|
188
|
+
if (!hasTable) {
|
|
189
|
+
db.exec(`
|
|
190
|
+
CREATE TABLE performance_benchmarks (
|
|
191
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
192
|
+
timestamp INTEGER NOT NULL,
|
|
193
|
+
version TEXT NOT NULL,
|
|
194
|
+
benchmark TEXT NOT NULL,
|
|
195
|
+
mean_ms REAL NOT NULL,
|
|
196
|
+
p50_ms REAL,
|
|
197
|
+
p95_ms REAL,
|
|
198
|
+
iterations INTEGER NOT NULL DEFAULT 1
|
|
199
|
+
);
|
|
200
|
+
CREATE INDEX idx_perf_bench_ts ON performance_benchmarks(timestamp);
|
|
201
|
+
CREATE INDEX idx_perf_bench_name ON performance_benchmarks(benchmark, timestamp);
|
|
202
|
+
`);
|
|
203
|
+
}
|
|
204
|
+
db.prepare('INSERT OR REPLACE INTO schema_version (version) VALUES (?)').run(33);
|
|
205
|
+
}
|
|
206
|
+
// v34: Fix entities_fts — switch from content='entities' to contentless
|
|
207
|
+
// The old FTS5 declared content='entities' with column 'aliases', but the entities
|
|
208
|
+
// table has 'aliases_json'. This caused "no such column: T.aliases" on every query.
|
|
209
|
+
// Contentless FTS5 eliminates the column name dependency; triggers handle sync.
|
|
210
|
+
if (currentVersion < 34) {
|
|
211
|
+
// Drop old FTS5 and shadow tables
|
|
212
|
+
db.exec(`DROP TABLE IF EXISTS entities_fts`);
|
|
213
|
+
db.exec(`DROP TABLE IF EXISTS entities_fts_data`);
|
|
214
|
+
db.exec(`DROP TABLE IF EXISTS entities_fts_idx`);
|
|
215
|
+
db.exec(`DROP TABLE IF EXISTS entities_fts_docsize`);
|
|
216
|
+
db.exec(`DROP TABLE IF EXISTS entities_fts_config`);
|
|
217
|
+
// Recreate as contentless
|
|
218
|
+
db.exec(`
|
|
219
|
+
CREATE VIRTUAL TABLE entities_fts USING fts5(
|
|
220
|
+
name, aliases, category,
|
|
221
|
+
content='',
|
|
222
|
+
tokenize='porter unicode61'
|
|
223
|
+
)
|
|
224
|
+
`);
|
|
225
|
+
// Drop and recreate triggers (unchanged logic, now targeting contentless table)
|
|
226
|
+
db.exec(`DROP TRIGGER IF EXISTS entities_ai`);
|
|
227
|
+
db.exec(`DROP TRIGGER IF EXISTS entities_ad`);
|
|
228
|
+
db.exec(`DROP TRIGGER IF EXISTS entities_au`);
|
|
229
|
+
db.exec(`
|
|
230
|
+
CREATE TRIGGER entities_ai AFTER INSERT ON entities BEGIN
|
|
231
|
+
INSERT INTO entities_fts(rowid, name, aliases, category)
|
|
232
|
+
VALUES (
|
|
233
|
+
new.id,
|
|
234
|
+
new.name,
|
|
235
|
+
COALESCE((SELECT group_concat(value, ' ') FROM json_each(new.aliases_json)), ''),
|
|
236
|
+
new.category
|
|
237
|
+
);
|
|
238
|
+
END
|
|
239
|
+
`);
|
|
240
|
+
db.exec(`
|
|
241
|
+
CREATE TRIGGER entities_ad AFTER DELETE ON entities BEGIN
|
|
242
|
+
INSERT INTO entities_fts(entities_fts, rowid, name, aliases, category)
|
|
243
|
+
VALUES (
|
|
244
|
+
'delete',
|
|
245
|
+
old.id,
|
|
246
|
+
old.name,
|
|
247
|
+
COALESCE((SELECT group_concat(value, ' ') FROM json_each(old.aliases_json)), ''),
|
|
248
|
+
old.category
|
|
249
|
+
);
|
|
250
|
+
END
|
|
251
|
+
`);
|
|
252
|
+
db.exec(`
|
|
253
|
+
CREATE TRIGGER entities_au AFTER UPDATE ON entities BEGIN
|
|
254
|
+
INSERT INTO entities_fts(entities_fts, rowid, name, aliases, category)
|
|
255
|
+
VALUES (
|
|
256
|
+
'delete',
|
|
257
|
+
old.id,
|
|
258
|
+
old.name,
|
|
259
|
+
COALESCE((SELECT group_concat(value, ' ') FROM json_each(old.aliases_json)), ''),
|
|
260
|
+
old.category
|
|
261
|
+
);
|
|
262
|
+
INSERT INTO entities_fts(rowid, name, aliases, category)
|
|
263
|
+
VALUES (
|
|
264
|
+
new.id,
|
|
265
|
+
new.name,
|
|
266
|
+
COALESCE((SELECT group_concat(value, ' ') FROM json_each(new.aliases_json)), ''),
|
|
267
|
+
new.category
|
|
268
|
+
);
|
|
269
|
+
END
|
|
270
|
+
`);
|
|
271
|
+
// Populate FTS from existing entities
|
|
272
|
+
db.exec(`
|
|
273
|
+
INSERT INTO entities_fts(rowid, name, aliases, category)
|
|
274
|
+
SELECT id, name,
|
|
275
|
+
COALESCE((SELECT group_concat(value, ' ') FROM json_each(aliases_json)), ''),
|
|
276
|
+
category
|
|
277
|
+
FROM entities
|
|
278
|
+
`);
|
|
279
|
+
db.prepare('INSERT OR REPLACE INTO schema_version (version) VALUES (?)').run(34);
|
|
280
|
+
}
|
|
165
281
|
db.prepare('INSERT OR IGNORE INTO schema_version (version) VALUES (?)').run(SCHEMA_VERSION);
|
|
166
282
|
}
|
|
167
283
|
}
|
package/dist/queries.d.ts
CHANGED
|
@@ -120,8 +120,8 @@ export declare function isEntityDataStale(stateDb: StateDb, thresholdMs?: number
|
|
|
120
120
|
export declare function escapeFts5Query(query: string): string;
|
|
121
121
|
/**
|
|
122
122
|
* Rebuild the entities_fts index from the entities table.
|
|
123
|
-
*
|
|
124
|
-
*
|
|
123
|
+
* Contentless FTS5 tables don't support the 'rebuild' command,
|
|
124
|
+
* so we manually delete all entries and re-insert from the entities table.
|
|
125
125
|
*/
|
|
126
126
|
export declare function rebuildEntitiesFts(stateDb: StateDb): void;
|
|
127
127
|
/**
|
package/dist/queries.js
CHANGED
|
@@ -339,11 +339,20 @@ export function escapeFts5Query(query) {
|
|
|
339
339
|
}
|
|
340
340
|
/**
|
|
341
341
|
* Rebuild the entities_fts index from the entities table.
|
|
342
|
-
*
|
|
343
|
-
*
|
|
342
|
+
* Contentless FTS5 tables don't support the 'rebuild' command,
|
|
343
|
+
* so we manually delete all entries and re-insert from the entities table.
|
|
344
344
|
*/
|
|
345
345
|
export function rebuildEntitiesFts(stateDb) {
|
|
346
|
-
stateDb.db.
|
|
346
|
+
stateDb.db.transaction(() => {
|
|
347
|
+
stateDb.db.exec(`DELETE FROM entities_fts`);
|
|
348
|
+
stateDb.db.exec(`
|
|
349
|
+
INSERT INTO entities_fts(rowid, name, aliases, category)
|
|
350
|
+
SELECT id, name,
|
|
351
|
+
COALESCE((SELECT group_concat(value, ' ') FROM json_each(aliases_json)), ''),
|
|
352
|
+
category
|
|
353
|
+
FROM entities
|
|
354
|
+
`);
|
|
355
|
+
})();
|
|
347
356
|
}
|
|
348
357
|
/**
|
|
349
358
|
* Check if the state database exists for a vault
|
package/dist/schema.d.ts
CHANGED
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
* for the flywheel state database.
|
|
6
6
|
*/
|
|
7
7
|
/** Current schema version - bump when schema changes */
|
|
8
|
-
export declare const SCHEMA_VERSION =
|
|
8
|
+
export declare const SCHEMA_VERSION = 34;
|
|
9
9
|
/** State database filename */
|
|
10
10
|
export declare const STATE_DB_FILENAME = "state.db";
|
|
11
11
|
/** Directory for flywheel state */
|
|
12
12
|
export declare const FLYWHEEL_DIR = ".flywheel";
|
|
13
|
-
export declare const SCHEMA_SQL = "\n-- Schema version tracking\nCREATE TABLE IF NOT EXISTS schema_version (\n version INTEGER PRIMARY KEY,\n applied_at TEXT DEFAULT (datetime('now'))\n);\n\n-- Metadata key-value store\nCREATE TABLE IF NOT EXISTS metadata (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL,\n updated_at TEXT DEFAULT (datetime('now'))\n);\n\n-- Entity index (replaces wikilink-entities.json)\nCREATE TABLE IF NOT EXISTS entities (\n id INTEGER PRIMARY KEY,\n name TEXT NOT NULL,\n name_lower TEXT NOT NULL,\n path TEXT NOT NULL,\n category TEXT NOT NULL,\n aliases_json TEXT,\n hub_score INTEGER DEFAULT 0,\n description TEXT\n);\nCREATE INDEX IF NOT EXISTS idx_entities_name_lower ON entities(name_lower);\nCREATE INDEX IF NOT EXISTS idx_entities_category ON entities(category);\n\n-- FTS5 for entity search with porter stemmer\nCREATE VIRTUAL TABLE IF NOT EXISTS entities_fts USING fts5(\n name, aliases, category,\n content='entities', content_rowid='id',\n tokenize='porter unicode61'\n);\n\n-- Auto-sync triggers for entities_fts\nCREATE TRIGGER IF NOT EXISTS entities_ai AFTER INSERT ON entities BEGIN\n INSERT INTO entities_fts(rowid, name, aliases, category)\n VALUES (\n new.id,\n new.name,\n COALESCE((SELECT group_concat(value, ' ') FROM json_each(new.aliases_json)), ''),\n new.category\n );\nEND;\n\nCREATE TRIGGER IF NOT EXISTS entities_ad AFTER DELETE ON entities BEGIN\n INSERT INTO entities_fts(entities_fts, rowid, name, aliases, category)\n VALUES (\n 'delete',\n old.id,\n old.name,\n COALESCE((SELECT group_concat(value, ' ') FROM json_each(old.aliases_json)), ''),\n old.category\n );\nEND;\n\nCREATE TRIGGER IF NOT EXISTS entities_au AFTER UPDATE ON entities BEGIN\n INSERT INTO entities_fts(entities_fts, rowid, name, aliases, category)\n VALUES (\n 'delete',\n old.id,\n old.name,\n COALESCE((SELECT group_concat(value, ' ') FROM json_each(old.aliases_json)), ''),\n old.category\n );\n INSERT INTO entities_fts(rowid, name, aliases, category)\n VALUES (\n new.id,\n new.name,\n COALESCE((SELECT group_concat(value, ' ') FROM json_each(new.aliases_json)), ''),\n new.category\n );\nEND;\n\n-- Recency tracking (replaces entity-recency.json)\nCREATE TABLE IF NOT EXISTS recency (\n entity_name_lower TEXT PRIMARY KEY,\n last_mentioned_at INTEGER NOT NULL,\n mention_count INTEGER DEFAULT 1\n);\n\n-- Write state (replaces last-commit.json and other write state)\nCREATE TABLE IF NOT EXISTS write_state (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL,\n updated_at TEXT DEFAULT (datetime('now'))\n);\n\n-- Content search FTS5 (migrated from vault-search.db)\n-- v11: Added frontmatter column for weighted search (path, title, frontmatter, content)\nCREATE VIRTUAL TABLE IF NOT EXISTS notes_fts USING fts5(\n path, title, frontmatter, content,\n tokenize='porter'\n);\n\n-- FTS5 build metadata (consolidated from vault-search.db)\nCREATE TABLE IF NOT EXISTS fts_metadata (\n key TEXT PRIMARY KEY,\n value TEXT\n);\n\n-- Vault index cache (for fast startup)\n-- Stores serialized VaultIndex to avoid full rebuild on startup\nCREATE TABLE IF NOT EXISTS vault_index_cache (\n id INTEGER PRIMARY KEY CHECK (id = 1),\n data BLOB NOT NULL,\n built_at INTEGER NOT NULL,\n note_count INTEGER NOT NULL,\n version INTEGER DEFAULT 1\n);\n\n-- Flywheel configuration (replaces .flywheel.json)\nCREATE TABLE IF NOT EXISTS flywheel_config (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL,\n updated_at TEXT DEFAULT (datetime('now'))\n);\n\n-- Vault metrics (v4: growth tracking)\nCREATE TABLE IF NOT EXISTS vault_metrics (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n timestamp INTEGER NOT NULL,\n metric TEXT NOT NULL,\n value REAL NOT NULL\n);\nCREATE INDEX IF NOT EXISTS idx_vault_metrics_ts ON vault_metrics(timestamp);\nCREATE INDEX IF NOT EXISTS idx_vault_metrics_m ON vault_metrics(metric, timestamp);\n\n-- Wikilink feedback (v4: quality tracking)\nCREATE TABLE IF NOT EXISTS wikilink_feedback (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n entity TEXT NOT NULL,\n context TEXT NOT NULL,\n note_path TEXT NOT NULL,\n correct INTEGER NOT NULL,\n confidence REAL NOT NULL DEFAULT 1.0,\n created_at TEXT DEFAULT (datetime('now'))\n);\nCREATE INDEX IF NOT EXISTS idx_wl_feedback_entity ON wikilink_feedback(entity);\nCREATE INDEX IF NOT EXISTS idx_wl_feedback_note_path ON wikilink_feedback(note_path);\n\n-- Wikilink suppressions (v4: auto-suppress false positives)\nCREATE TABLE IF NOT EXISTS wikilink_suppressions (\n entity TEXT PRIMARY KEY,\n false_positive_rate REAL NOT NULL,\n updated_at TEXT DEFAULT (datetime('now'))\n);\n\n-- Wikilink applications tracking (v5: implicit feedback)\nCREATE TABLE IF NOT EXISTS wikilink_applications (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n entity TEXT NOT NULL,\n note_path TEXT NOT NULL,\n applied_at TEXT DEFAULT (datetime('now')),\n status TEXT DEFAULT 'applied'\n);\nCREATE UNIQUE INDEX IF NOT EXISTS idx_wl_apps_unique ON wikilink_applications(entity COLLATE NOCASE, note_path);\n\n-- Index events tracking (v6: index activity history)\nCREATE TABLE IF NOT EXISTS index_events (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n timestamp INTEGER NOT NULL,\n trigger TEXT NOT NULL,\n duration_ms INTEGER NOT NULL,\n success INTEGER NOT NULL DEFAULT 1,\n note_count INTEGER,\n files_changed INTEGER,\n changed_paths TEXT,\n error TEXT,\n steps TEXT\n);\nCREATE INDEX IF NOT EXISTS idx_index_events_ts ON index_events(timestamp);\n\n-- Tool invocation tracking (v7: usage analytics)\nCREATE TABLE IF NOT EXISTS tool_invocations (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n timestamp INTEGER NOT NULL,\n tool_name TEXT NOT NULL,\n session_id TEXT,\n note_paths TEXT,\n duration_ms INTEGER,\n success INTEGER NOT NULL DEFAULT 1,\n response_tokens INTEGER,\n baseline_tokens INTEGER\n);\nCREATE INDEX IF NOT EXISTS idx_tool_inv_ts ON tool_invocations(timestamp);\nCREATE INDEX IF NOT EXISTS idx_tool_inv_tool ON tool_invocations(tool_name, timestamp);\nCREATE INDEX IF NOT EXISTS idx_tool_inv_session ON tool_invocations(session_id, timestamp);\n\n-- Graph topology snapshots (v8: structural evolution)\nCREATE TABLE IF NOT EXISTS graph_snapshots (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n timestamp INTEGER NOT NULL,\n metric TEXT NOT NULL,\n value REAL NOT NULL,\n details TEXT\n);\nCREATE INDEX IF NOT EXISTS idx_graph_snap_ts ON graph_snapshots(timestamp);\nCREATE INDEX IF NOT EXISTS idx_graph_snap_m ON graph_snapshots(metric, timestamp);\n\n-- Note embeddings for semantic search (v9)\nCREATE TABLE IF NOT EXISTS note_embeddings (\n path TEXT PRIMARY KEY,\n embedding BLOB NOT NULL,\n content_hash TEXT NOT NULL,\n model TEXT NOT NULL,\n updated_at INTEGER NOT NULL\n);\n\n-- Entity embeddings for semantic entity search (v10)\nCREATE TABLE IF NOT EXISTS entity_embeddings (\n entity_name TEXT PRIMARY KEY,\n embedding BLOB NOT NULL,\n source_hash TEXT NOT NULL,\n model TEXT NOT NULL,\n updated_at INTEGER NOT NULL\n);\n\n-- Task cache for fast task queries (v12)\nCREATE TABLE IF NOT EXISTS tasks (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n path TEXT NOT NULL,\n line INTEGER NOT NULL,\n text TEXT NOT NULL,\n status TEXT NOT NULL,\n raw TEXT NOT NULL,\n context TEXT,\n tags_json TEXT,\n due_date TEXT,\n UNIQUE(path, line)\n);\nCREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status);\nCREATE INDEX IF NOT EXISTS idx_tasks_path ON tasks(path);\nCREATE INDEX IF NOT EXISTS idx_tasks_due ON tasks(due_date);\n\n-- Merge dismissals (v13: persistent merge pair suppression)\nCREATE TABLE IF NOT EXISTS merge_dismissals (\n pair_key TEXT PRIMARY KEY,\n source_path TEXT NOT NULL,\n target_path TEXT NOT NULL,\n source_name TEXT NOT NULL,\n target_name TEXT NOT NULL,\n reason TEXT NOT NULL,\n dismissed_at TEXT DEFAULT (datetime('now'))\n);\n\n-- Suggestion events audit log (v15: pipeline observability)\nCREATE TABLE IF NOT EXISTS suggestion_events (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n timestamp INTEGER NOT NULL,\n note_path TEXT NOT NULL,\n entity TEXT NOT NULL,\n total_score REAL NOT NULL,\n breakdown_json TEXT NOT NULL,\n threshold REAL NOT NULL,\n passed INTEGER NOT NULL,\n strictness TEXT NOT NULL,\n applied INTEGER DEFAULT 0,\n pipeline_event_id INTEGER,\n UNIQUE(timestamp, note_path, entity)\n);\nCREATE INDEX IF NOT EXISTS idx_suggestion_entity ON suggestion_events(entity);\nCREATE INDEX IF NOT EXISTS idx_suggestion_note ON suggestion_events(note_path);\n\n-- Forward-link persistence for diff-based feedback (v16), edge weights (v22)\nCREATE TABLE IF NOT EXISTS note_links (\n note_path TEXT NOT NULL,\n target TEXT NOT NULL,\n weight REAL NOT NULL DEFAULT 1.0,\n weight_updated_at INTEGER,\n PRIMARY KEY (note_path, target)\n);\n\n-- Entity field change audit log (v17)\nCREATE TABLE IF NOT EXISTS entity_changes (\n entity TEXT NOT NULL,\n field TEXT NOT NULL,\n old_value TEXT,\n new_value TEXT,\n changed_at TEXT NOT NULL DEFAULT (datetime('now')),\n PRIMARY KEY (entity, field, changed_at)\n);\n\n-- Note tag persistence for diff-based feedback (v18)\nCREATE TABLE IF NOT EXISTS note_tags (\n note_path TEXT NOT NULL,\n tag TEXT NOT NULL,\n PRIMARY KEY (note_path, tag)\n);\n\n-- Wikilink survival tracking for positive feedback signals (v19)\nCREATE TABLE IF NOT EXISTS note_link_history (\n note_path TEXT NOT NULL,\n target TEXT NOT NULL,\n first_seen_at TEXT NOT NULL DEFAULT (datetime('now')),\n edits_survived INTEGER NOT NULL DEFAULT 0,\n last_positive_at TEXT,\n PRIMARY KEY (note_path, target)\n);\n\n-- Note move history (v20): records when files are moved/renamed to a different folder\nCREATE TABLE IF NOT EXISTS note_moves (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n old_path TEXT NOT NULL,\n new_path TEXT NOT NULL,\n moved_at TEXT NOT NULL DEFAULT (datetime('now')),\n old_folder TEXT,\n new_folder TEXT\n);\nCREATE INDEX IF NOT EXISTS idx_note_moves_old_path ON note_moves(old_path);\nCREATE INDEX IF NOT EXISTS idx_note_moves_new_path ON note_moves(new_path);\nCREATE INDEX IF NOT EXISTS idx_note_moves_moved_at ON note_moves(moved_at);\n\n-- Corrections (v24): persistent correction records from user/engine feedback\nCREATE TABLE IF NOT EXISTS corrections (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n entity TEXT,\n note_path TEXT,\n correction_type TEXT NOT NULL,\n description TEXT NOT NULL,\n source TEXT NOT NULL DEFAULT 'user',\n status TEXT DEFAULT 'pending',\n created_at TEXT DEFAULT (datetime('now')),\n resolved_at TEXT\n);\nCREATE INDEX IF NOT EXISTS idx_corrections_status ON corrections(status);\nCREATE INDEX IF NOT EXISTS idx_corrections_entity ON corrections(entity);\n\n-- Memories (v26): lightweight key-value working memory for agents\nCREATE TABLE IF NOT EXISTS memories (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n key TEXT NOT NULL,\n value TEXT NOT NULL,\n memory_type TEXT NOT NULL,\n entity TEXT,\n entities_json TEXT,\n source_agent_id TEXT,\n source_session_id TEXT,\n confidence REAL NOT NULL DEFAULT 1.0,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n accessed_at INTEGER NOT NULL,\n ttl_days INTEGER,\n superseded_by INTEGER REFERENCES memories(id),\n visibility TEXT NOT NULL DEFAULT 'shared'\n);\nCREATE INDEX IF NOT EXISTS idx_memories_key ON memories(key);\nCREATE INDEX IF NOT EXISTS idx_memories_entity ON memories(entity);\nCREATE INDEX IF NOT EXISTS idx_memories_type ON memories(memory_type);\n\nCREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(\n key, value,\n content=memories, content_rowid=id,\n tokenize='porter unicode61'\n);\n\n-- Auto-sync triggers for memories_fts\nCREATE TRIGGER IF NOT EXISTS memories_ai AFTER INSERT ON memories BEGIN\n INSERT INTO memories_fts(rowid, key, value)\n VALUES (new.id, new.key, new.value);\nEND;\n\nCREATE TRIGGER IF NOT EXISTS memories_ad AFTER DELETE ON memories BEGIN\n INSERT INTO memories_fts(memories_fts, rowid, key, value)\n VALUES ('delete', old.id, old.key, old.value);\nEND;\n\nCREATE TRIGGER IF NOT EXISTS memories_au AFTER UPDATE ON memories BEGIN\n INSERT INTO memories_fts(memories_fts, rowid, key, value)\n VALUES ('delete', old.id, old.key, old.value);\n INSERT INTO memories_fts(rowid, key, value)\n VALUES (new.id, new.key, new.value);\nEND;\n\n-- Co-occurrence cache (v27): persist co-occurrence index to avoid full vault scan on restart\nCREATE TABLE IF NOT EXISTS cooccurrence_cache (\n id INTEGER PRIMARY KEY CHECK (id = 1),\n data TEXT NOT NULL,\n built_at INTEGER NOT NULL,\n entity_count INTEGER NOT NULL,\n association_count INTEGER NOT NULL\n);\n\n-- Content hashes (v28): persist watcher content hashes across restarts\nCREATE TABLE IF NOT EXISTS content_hashes (\n path TEXT PRIMARY KEY,\n hash TEXT NOT NULL,\n updated_at INTEGER NOT NULL\n);\n\n-- Session summaries (v26): agent session tracking\nCREATE TABLE IF NOT EXISTS session_summaries (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n session_id TEXT NOT NULL UNIQUE,\n summary TEXT NOT NULL,\n topics_json TEXT,\n notes_modified_json TEXT,\n agent_id TEXT,\n started_at INTEGER,\n ended_at INTEGER NOT NULL,\n tool_count INTEGER\n);\n\n-- Retrieval co-occurrence (v30): notes retrieved together build implicit edges\nCREATE TABLE IF NOT EXISTS retrieval_cooccurrence (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n note_a TEXT NOT NULL,\n note_b TEXT NOT NULL,\n session_id TEXT NOT NULL,\n timestamp INTEGER NOT NULL,\n weight REAL NOT NULL DEFAULT 1.0,\n UNIQUE(note_a, note_b, session_id)\n);\nCREATE INDEX IF NOT EXISTS idx_retcooc_notes ON retrieval_cooccurrence(note_a, note_b);\nCREATE INDEX IF NOT EXISTS idx_retcooc_ts ON retrieval_cooccurrence(timestamp);\n\n-- Deferred proactive linking queue (v31)\nCREATE TABLE IF NOT EXISTS proactive_queue (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n note_path TEXT NOT NULL,\n entity TEXT NOT NULL,\n score REAL NOT NULL,\n confidence TEXT NOT NULL,\n queued_at INTEGER NOT NULL,\n expires_at INTEGER NOT NULL,\n status TEXT NOT NULL DEFAULT 'pending',\n applied_at INTEGER,\n UNIQUE(note_path, entity)\n);\nCREATE INDEX IF NOT EXISTS idx_pq_status ON proactive_queue(status, expires_at);\n";
|
|
13
|
+
export declare const SCHEMA_SQL = "\n-- Schema version tracking\nCREATE TABLE IF NOT EXISTS schema_version (\n version INTEGER PRIMARY KEY,\n applied_at TEXT DEFAULT (datetime('now'))\n);\n\n-- Metadata key-value store\nCREATE TABLE IF NOT EXISTS metadata (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL,\n updated_at TEXT DEFAULT (datetime('now'))\n);\n\n-- Entity index (replaces wikilink-entities.json)\nCREATE TABLE IF NOT EXISTS entities (\n id INTEGER PRIMARY KEY,\n name TEXT NOT NULL,\n name_lower TEXT NOT NULL,\n path TEXT NOT NULL,\n category TEXT NOT NULL,\n aliases_json TEXT,\n hub_score INTEGER DEFAULT 0,\n description TEXT\n);\nCREATE INDEX IF NOT EXISTS idx_entities_name_lower ON entities(name_lower);\nCREATE INDEX IF NOT EXISTS idx_entities_category ON entities(category);\n\n-- FTS5 for entity search with porter stemmer (contentless \u2014 triggers handle sync)\nCREATE VIRTUAL TABLE IF NOT EXISTS entities_fts USING fts5(\n name, aliases, category,\n content='',\n tokenize='porter unicode61'\n);\n\n-- Auto-sync triggers for entities_fts\nCREATE TRIGGER IF NOT EXISTS entities_ai AFTER INSERT ON entities BEGIN\n INSERT INTO entities_fts(rowid, name, aliases, category)\n VALUES (\n new.id,\n new.name,\n COALESCE((SELECT group_concat(value, ' ') FROM json_each(new.aliases_json)), ''),\n new.category\n );\nEND;\n\nCREATE TRIGGER IF NOT EXISTS entities_ad AFTER DELETE ON entities BEGIN\n INSERT INTO entities_fts(entities_fts, rowid, name, aliases, category)\n VALUES (\n 'delete',\n old.id,\n old.name,\n COALESCE((SELECT group_concat(value, ' ') FROM json_each(old.aliases_json)), ''),\n old.category\n );\nEND;\n\nCREATE TRIGGER IF NOT EXISTS entities_au AFTER UPDATE ON entities BEGIN\n INSERT INTO entities_fts(entities_fts, rowid, name, aliases, category)\n VALUES (\n 'delete',\n old.id,\n old.name,\n COALESCE((SELECT group_concat(value, ' ') FROM json_each(old.aliases_json)), ''),\n old.category\n );\n INSERT INTO entities_fts(rowid, name, aliases, category)\n VALUES (\n new.id,\n new.name,\n COALESCE((SELECT group_concat(value, ' ') FROM json_each(new.aliases_json)), ''),\n new.category\n );\nEND;\n\n-- Recency tracking (replaces entity-recency.json)\nCREATE TABLE IF NOT EXISTS recency (\n entity_name_lower TEXT PRIMARY KEY,\n last_mentioned_at INTEGER NOT NULL,\n mention_count INTEGER DEFAULT 1\n);\n\n-- Write state (replaces last-commit.json and other write state)\nCREATE TABLE IF NOT EXISTS write_state (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL,\n updated_at TEXT DEFAULT (datetime('now'))\n);\n\n-- Content search FTS5 (migrated from vault-search.db)\n-- v11: Added frontmatter column for weighted search (path, title, frontmatter, content)\nCREATE VIRTUAL TABLE IF NOT EXISTS notes_fts USING fts5(\n path, title, frontmatter, content,\n tokenize='porter'\n);\n\n-- FTS5 build metadata (consolidated from vault-search.db)\nCREATE TABLE IF NOT EXISTS fts_metadata (\n key TEXT PRIMARY KEY,\n value TEXT\n);\n\n-- Vault index cache (for fast startup)\n-- Stores serialized VaultIndex to avoid full rebuild on startup\nCREATE TABLE IF NOT EXISTS vault_index_cache (\n id INTEGER PRIMARY KEY CHECK (id = 1),\n data BLOB NOT NULL,\n built_at INTEGER NOT NULL,\n note_count INTEGER NOT NULL,\n version INTEGER DEFAULT 1\n);\n\n-- Flywheel configuration (replaces .flywheel.json)\nCREATE TABLE IF NOT EXISTS flywheel_config (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL,\n updated_at TEXT DEFAULT (datetime('now'))\n);\n\n-- Vault metrics (v4: growth tracking)\nCREATE TABLE IF NOT EXISTS vault_metrics (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n timestamp INTEGER NOT NULL,\n metric TEXT NOT NULL,\n value REAL NOT NULL\n);\nCREATE INDEX IF NOT EXISTS idx_vault_metrics_ts ON vault_metrics(timestamp);\nCREATE INDEX IF NOT EXISTS idx_vault_metrics_m ON vault_metrics(metric, timestamp);\n\n-- Wikilink feedback (v4: quality tracking)\nCREATE TABLE IF NOT EXISTS wikilink_feedback (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n entity TEXT NOT NULL,\n context TEXT NOT NULL,\n note_path TEXT NOT NULL,\n correct INTEGER NOT NULL,\n confidence REAL NOT NULL DEFAULT 1.0,\n created_at TEXT DEFAULT (datetime('now'))\n);\nCREATE INDEX IF NOT EXISTS idx_wl_feedback_entity ON wikilink_feedback(entity);\nCREATE INDEX IF NOT EXISTS idx_wl_feedback_note_path ON wikilink_feedback(note_path);\n\n-- Wikilink suppressions (v4: auto-suppress false positives)\nCREATE TABLE IF NOT EXISTS wikilink_suppressions (\n entity TEXT PRIMARY KEY,\n false_positive_rate REAL NOT NULL,\n updated_at TEXT DEFAULT (datetime('now'))\n);\n\n-- Wikilink applications tracking (v5: implicit feedback)\nCREATE TABLE IF NOT EXISTS wikilink_applications (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n entity TEXT NOT NULL,\n note_path TEXT NOT NULL,\n applied_at TEXT DEFAULT (datetime('now')),\n status TEXT DEFAULT 'applied'\n);\nCREATE UNIQUE INDEX IF NOT EXISTS idx_wl_apps_unique ON wikilink_applications(entity COLLATE NOCASE, note_path);\n\n-- Index events tracking (v6: index activity history)\nCREATE TABLE IF NOT EXISTS index_events (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n timestamp INTEGER NOT NULL,\n trigger TEXT NOT NULL,\n duration_ms INTEGER NOT NULL,\n success INTEGER NOT NULL DEFAULT 1,\n note_count INTEGER,\n files_changed INTEGER,\n changed_paths TEXT,\n error TEXT,\n steps TEXT\n);\nCREATE INDEX IF NOT EXISTS idx_index_events_ts ON index_events(timestamp);\n\n-- Tool invocation tracking (v7: usage analytics)\nCREATE TABLE IF NOT EXISTS tool_invocations (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n timestamp INTEGER NOT NULL,\n tool_name TEXT NOT NULL,\n session_id TEXT,\n note_paths TEXT,\n duration_ms INTEGER,\n success INTEGER NOT NULL DEFAULT 1,\n response_tokens INTEGER,\n baseline_tokens INTEGER\n);\nCREATE INDEX IF NOT EXISTS idx_tool_inv_ts ON tool_invocations(timestamp);\nCREATE INDEX IF NOT EXISTS idx_tool_inv_tool ON tool_invocations(tool_name, timestamp);\nCREATE INDEX IF NOT EXISTS idx_tool_inv_session ON tool_invocations(session_id, timestamp);\n\n-- Graph topology snapshots (v8: structural evolution)\nCREATE TABLE IF NOT EXISTS graph_snapshots (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n timestamp INTEGER NOT NULL,\n metric TEXT NOT NULL,\n value REAL NOT NULL,\n details TEXT\n);\nCREATE INDEX IF NOT EXISTS idx_graph_snap_ts ON graph_snapshots(timestamp);\nCREATE INDEX IF NOT EXISTS idx_graph_snap_m ON graph_snapshots(metric, timestamp);\n\n-- Note embeddings for semantic search (v9)\nCREATE TABLE IF NOT EXISTS note_embeddings (\n path TEXT PRIMARY KEY,\n embedding BLOB NOT NULL,\n content_hash TEXT NOT NULL,\n model TEXT NOT NULL,\n updated_at INTEGER NOT NULL\n);\n\n-- Entity embeddings for semantic entity search (v10)\nCREATE TABLE IF NOT EXISTS entity_embeddings (\n entity_name TEXT PRIMARY KEY,\n embedding BLOB NOT NULL,\n source_hash TEXT NOT NULL,\n model TEXT NOT NULL,\n updated_at INTEGER NOT NULL\n);\n\n-- Task cache for fast task queries (v12)\nCREATE TABLE IF NOT EXISTS tasks (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n path TEXT NOT NULL,\n line INTEGER NOT NULL,\n text TEXT NOT NULL,\n status TEXT NOT NULL,\n raw TEXT NOT NULL,\n context TEXT,\n tags_json TEXT,\n due_date TEXT,\n UNIQUE(path, line)\n);\nCREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status);\nCREATE INDEX IF NOT EXISTS idx_tasks_path ON tasks(path);\nCREATE INDEX IF NOT EXISTS idx_tasks_due ON tasks(due_date);\n\n-- Merge dismissals (v13: persistent merge pair suppression)\nCREATE TABLE IF NOT EXISTS merge_dismissals (\n pair_key TEXT PRIMARY KEY,\n source_path TEXT NOT NULL,\n target_path TEXT NOT NULL,\n source_name TEXT NOT NULL,\n target_name TEXT NOT NULL,\n reason TEXT NOT NULL,\n dismissed_at TEXT DEFAULT (datetime('now'))\n);\n\n-- Suggestion events audit log (v15: pipeline observability)\nCREATE TABLE IF NOT EXISTS suggestion_events (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n timestamp INTEGER NOT NULL,\n note_path TEXT NOT NULL,\n entity TEXT NOT NULL,\n total_score REAL NOT NULL,\n breakdown_json TEXT NOT NULL,\n threshold REAL NOT NULL,\n passed INTEGER NOT NULL,\n strictness TEXT NOT NULL,\n applied INTEGER DEFAULT 0,\n pipeline_event_id INTEGER,\n UNIQUE(timestamp, note_path, entity)\n);\nCREATE INDEX IF NOT EXISTS idx_suggestion_entity ON suggestion_events(entity);\nCREATE INDEX IF NOT EXISTS idx_suggestion_note ON suggestion_events(note_path);\n\n-- Forward-link persistence for diff-based feedback (v16), edge weights (v22)\nCREATE TABLE IF NOT EXISTS note_links (\n note_path TEXT NOT NULL,\n target TEXT NOT NULL,\n weight REAL NOT NULL DEFAULT 1.0,\n weight_updated_at INTEGER,\n PRIMARY KEY (note_path, target)\n);\n\n-- Entity field change audit log (v17, rowid PK since v32)\nCREATE TABLE IF NOT EXISTS entity_changes (\n entity TEXT NOT NULL,\n field TEXT NOT NULL,\n old_value TEXT,\n new_value TEXT,\n changed_at TEXT NOT NULL DEFAULT (datetime('now'))\n);\n\n-- Note tag persistence for diff-based feedback (v18)\nCREATE TABLE IF NOT EXISTS note_tags (\n note_path TEXT NOT NULL,\n tag TEXT NOT NULL,\n PRIMARY KEY (note_path, tag)\n);\n\n-- Wikilink survival tracking for positive feedback signals (v19)\nCREATE TABLE IF NOT EXISTS note_link_history (\n note_path TEXT NOT NULL,\n target TEXT NOT NULL,\n first_seen_at TEXT NOT NULL DEFAULT (datetime('now')),\n edits_survived INTEGER NOT NULL DEFAULT 0,\n last_positive_at TEXT,\n PRIMARY KEY (note_path, target)\n);\n\n-- Note move history (v20): records when files are moved/renamed to a different folder\nCREATE TABLE IF NOT EXISTS note_moves (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n old_path TEXT NOT NULL,\n new_path TEXT NOT NULL,\n moved_at TEXT NOT NULL DEFAULT (datetime('now')),\n old_folder TEXT,\n new_folder TEXT\n);\nCREATE INDEX IF NOT EXISTS idx_note_moves_old_path ON note_moves(old_path);\nCREATE INDEX IF NOT EXISTS idx_note_moves_new_path ON note_moves(new_path);\nCREATE INDEX IF NOT EXISTS idx_note_moves_moved_at ON note_moves(moved_at);\n\n-- Corrections (v24): persistent correction records from user/engine feedback\nCREATE TABLE IF NOT EXISTS corrections (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n entity TEXT,\n note_path TEXT,\n correction_type TEXT NOT NULL,\n description TEXT NOT NULL,\n source TEXT NOT NULL DEFAULT 'user',\n status TEXT DEFAULT 'pending',\n created_at TEXT DEFAULT (datetime('now')),\n resolved_at TEXT\n);\nCREATE INDEX IF NOT EXISTS idx_corrections_status ON corrections(status);\nCREATE INDEX IF NOT EXISTS idx_corrections_entity ON corrections(entity);\n\n-- Memories (v26): lightweight key-value working memory for agents\nCREATE TABLE IF NOT EXISTS memories (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n key TEXT NOT NULL,\n value TEXT NOT NULL,\n memory_type TEXT NOT NULL,\n entity TEXT,\n entities_json TEXT,\n source_agent_id TEXT,\n source_session_id TEXT,\n confidence REAL NOT NULL DEFAULT 1.0,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n accessed_at INTEGER NOT NULL,\n ttl_days INTEGER,\n superseded_by INTEGER REFERENCES memories(id),\n visibility TEXT NOT NULL DEFAULT 'shared'\n);\nCREATE INDEX IF NOT EXISTS idx_memories_key ON memories(key);\nCREATE INDEX IF NOT EXISTS idx_memories_entity ON memories(entity);\nCREATE INDEX IF NOT EXISTS idx_memories_type ON memories(memory_type);\n\nCREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(\n key, value,\n content=memories, content_rowid=id,\n tokenize='porter unicode61'\n);\n\n-- Auto-sync triggers for memories_fts\nCREATE TRIGGER IF NOT EXISTS memories_ai AFTER INSERT ON memories BEGIN\n INSERT INTO memories_fts(rowid, key, value)\n VALUES (new.id, new.key, new.value);\nEND;\n\nCREATE TRIGGER IF NOT EXISTS memories_ad AFTER DELETE ON memories BEGIN\n INSERT INTO memories_fts(memories_fts, rowid, key, value)\n VALUES ('delete', old.id, old.key, old.value);\nEND;\n\nCREATE TRIGGER IF NOT EXISTS memories_au AFTER UPDATE ON memories BEGIN\n INSERT INTO memories_fts(memories_fts, rowid, key, value)\n VALUES ('delete', old.id, old.key, old.value);\n INSERT INTO memories_fts(rowid, key, value)\n VALUES (new.id, new.key, new.value);\nEND;\n\n-- Co-occurrence cache (v27): persist co-occurrence index to avoid full vault scan on restart\nCREATE TABLE IF NOT EXISTS cooccurrence_cache (\n id INTEGER PRIMARY KEY CHECK (id = 1),\n data TEXT NOT NULL,\n built_at INTEGER NOT NULL,\n entity_count INTEGER NOT NULL,\n association_count INTEGER NOT NULL\n);\n\n-- Content hashes (v28): persist watcher content hashes across restarts\nCREATE TABLE IF NOT EXISTS content_hashes (\n path TEXT PRIMARY KEY,\n hash TEXT NOT NULL,\n updated_at INTEGER NOT NULL\n);\n\n-- Session summaries (v26): agent session tracking\nCREATE TABLE IF NOT EXISTS session_summaries (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n session_id TEXT NOT NULL UNIQUE,\n summary TEXT NOT NULL,\n topics_json TEXT,\n notes_modified_json TEXT,\n agent_id TEXT,\n started_at INTEGER,\n ended_at INTEGER NOT NULL,\n tool_count INTEGER\n);\n\n-- Retrieval co-occurrence (v30): notes retrieved together build implicit edges\nCREATE TABLE IF NOT EXISTS retrieval_cooccurrence (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n note_a TEXT NOT NULL,\n note_b TEXT NOT NULL,\n session_id TEXT NOT NULL,\n timestamp INTEGER NOT NULL,\n weight REAL NOT NULL DEFAULT 1.0,\n UNIQUE(note_a, note_b, session_id)\n);\nCREATE INDEX IF NOT EXISTS idx_retcooc_notes ON retrieval_cooccurrence(note_a, note_b);\nCREATE INDEX IF NOT EXISTS idx_retcooc_ts ON retrieval_cooccurrence(timestamp);\n\n-- Deferred proactive linking queue (v31)\nCREATE TABLE IF NOT EXISTS proactive_queue (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n note_path TEXT NOT NULL,\n entity TEXT NOT NULL,\n score REAL NOT NULL,\n confidence TEXT NOT NULL,\n queued_at INTEGER NOT NULL,\n expires_at INTEGER NOT NULL,\n status TEXT NOT NULL DEFAULT 'pending',\n applied_at INTEGER,\n UNIQUE(note_path, entity)\n);\nCREATE INDEX IF NOT EXISTS idx_pq_status ON proactive_queue(status, expires_at);\n\n-- Performance benchmarks (v33: longitudinal tracking)\nCREATE TABLE IF NOT EXISTS performance_benchmarks (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n timestamp INTEGER NOT NULL,\n version TEXT NOT NULL,\n benchmark TEXT NOT NULL,\n mean_ms REAL NOT NULL,\n p50_ms REAL,\n p95_ms REAL,\n iterations INTEGER NOT NULL DEFAULT 1\n);\nCREATE INDEX IF NOT EXISTS idx_perf_bench_ts ON performance_benchmarks(timestamp);\nCREATE INDEX IF NOT EXISTS idx_perf_bench_name ON performance_benchmarks(benchmark, timestamp);\n";
|
|
14
14
|
//# sourceMappingURL=schema.d.ts.map
|
package/dist/schema.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// Constants
|
|
9
9
|
// =============================================================================
|
|
10
10
|
/** Current schema version - bump when schema changes */
|
|
11
|
-
export const SCHEMA_VERSION =
|
|
11
|
+
export const SCHEMA_VERSION = 34;
|
|
12
12
|
/** State database filename */
|
|
13
13
|
export const STATE_DB_FILENAME = 'state.db';
|
|
14
14
|
/** Directory for flywheel state */
|
|
@@ -44,10 +44,10 @@ CREATE TABLE IF NOT EXISTS entities (
|
|
|
44
44
|
CREATE INDEX IF NOT EXISTS idx_entities_name_lower ON entities(name_lower);
|
|
45
45
|
CREATE INDEX IF NOT EXISTS idx_entities_category ON entities(category);
|
|
46
46
|
|
|
47
|
-
-- FTS5 for entity search with porter stemmer
|
|
47
|
+
-- FTS5 for entity search with porter stemmer (contentless — triggers handle sync)
|
|
48
48
|
CREATE VIRTUAL TABLE IF NOT EXISTS entities_fts USING fts5(
|
|
49
49
|
name, aliases, category,
|
|
50
|
-
content='
|
|
50
|
+
content='',
|
|
51
51
|
tokenize='porter unicode61'
|
|
52
52
|
);
|
|
53
53
|
|
|
@@ -290,14 +290,13 @@ CREATE TABLE IF NOT EXISTS note_links (
|
|
|
290
290
|
PRIMARY KEY (note_path, target)
|
|
291
291
|
);
|
|
292
292
|
|
|
293
|
-
-- Entity field change audit log (v17)
|
|
293
|
+
-- Entity field change audit log (v17, rowid PK since v32)
|
|
294
294
|
CREATE TABLE IF NOT EXISTS entity_changes (
|
|
295
295
|
entity TEXT NOT NULL,
|
|
296
296
|
field TEXT NOT NULL,
|
|
297
297
|
old_value TEXT,
|
|
298
298
|
new_value TEXT,
|
|
299
|
-
changed_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
300
|
-
PRIMARY KEY (entity, field, changed_at)
|
|
299
|
+
changed_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
301
300
|
);
|
|
302
301
|
|
|
303
302
|
-- Note tag persistence for diff-based feedback (v18)
|
|
@@ -447,5 +446,19 @@ CREATE TABLE IF NOT EXISTS proactive_queue (
|
|
|
447
446
|
UNIQUE(note_path, entity)
|
|
448
447
|
);
|
|
449
448
|
CREATE INDEX IF NOT EXISTS idx_pq_status ON proactive_queue(status, expires_at);
|
|
449
|
+
|
|
450
|
+
-- Performance benchmarks (v33: longitudinal tracking)
|
|
451
|
+
CREATE TABLE IF NOT EXISTS performance_benchmarks (
|
|
452
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
453
|
+
timestamp INTEGER NOT NULL,
|
|
454
|
+
version TEXT NOT NULL,
|
|
455
|
+
benchmark TEXT NOT NULL,
|
|
456
|
+
mean_ms REAL NOT NULL,
|
|
457
|
+
p50_ms REAL,
|
|
458
|
+
p95_ms REAL,
|
|
459
|
+
iterations INTEGER NOT NULL DEFAULT 1
|
|
460
|
+
);
|
|
461
|
+
CREATE INDEX IF NOT EXISTS idx_perf_bench_ts ON performance_benchmarks(timestamp);
|
|
462
|
+
CREATE INDEX IF NOT EXISTS idx_perf_bench_name ON performance_benchmarks(benchmark, timestamp);
|
|
450
463
|
`;
|
|
451
464
|
//# sourceMappingURL=schema.js.map
|
package/dist/sqlite.js
CHANGED
|
@@ -48,9 +48,10 @@ export function openStateDb(vaultPath) {
|
|
|
48
48
|
initSchema(db);
|
|
49
49
|
}
|
|
50
50
|
catch (err) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
52
|
+
// Only nuke-and-rebuild for actual SQLite corruption, not recoverable errors
|
|
53
|
+
const isActualCorruption = /file is not a database|disk image is malformed|database or disk is full/i.test(msg);
|
|
54
|
+
if (isActualCorruption && fs.existsSync(dbPath)) {
|
|
54
55
|
console.error(`[vault-core] Corrupted state.db (${msg}) — deleting and recreating`);
|
|
55
56
|
preserveCorruptedDb(dbPath);
|
|
56
57
|
try {
|
|
@@ -62,6 +63,8 @@ export function openStateDb(vaultPath) {
|
|
|
62
63
|
initSchema(db);
|
|
63
64
|
}
|
|
64
65
|
else {
|
|
66
|
+
// Recoverable error (constraint violation, migration issue, etc.) — don't destroy the DB
|
|
67
|
+
console.error(`[vault-core] state.db error (${msg}) — NOT deleting (recoverable)`);
|
|
65
68
|
throw err;
|
|
66
69
|
}
|
|
67
70
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@velvetmonkey/vault-core",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.139",
|
|
4
4
|
"description": "Shared vault utilities for Flywheel ecosystem (entity scanning, wikilinks, protected zones)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"prepublishOnly": "npm run build"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"better-sqlite3": "^
|
|
39
|
+
"better-sqlite3": "^12.0.0",
|
|
40
40
|
"esbuild": "0.27.4",
|
|
41
41
|
"mdast-util-from-markdown": "^2.0.0",
|
|
42
42
|
"mdast-util-frontmatter": "^2.0.0",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"vitest": "^4.1.1"
|
|
55
55
|
},
|
|
56
56
|
"engines": {
|
|
57
|
-
"node": ">=
|
|
57
|
+
"node": ">=22.0.0"
|
|
58
58
|
},
|
|
59
59
|
"license": "AGPL-3.0-only",
|
|
60
60
|
"files": [
|