@velvetmonkey/vault-core 2.0.119 → 2.0.121

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/sqlite.d.ts CHANGED
@@ -75,7 +75,7 @@ export interface StateDb {
75
75
  close: () => void;
76
76
  }
77
77
  /** Current schema version - bump when schema changes */
78
- export declare const SCHEMA_VERSION = 28;
78
+ export declare const SCHEMA_VERSION = 30;
79
79
  /** State database filename */
80
80
  export declare const STATE_DB_FILENAME = "state.db";
81
81
  /** Directory for flywheel state */
package/dist/sqlite.js CHANGED
@@ -16,7 +16,7 @@ import * as path from 'path';
16
16
  // Constants
17
17
  // =============================================================================
18
18
  /** Current schema version - bump when schema changes */
19
- export const SCHEMA_VERSION = 28;
19
+ export const SCHEMA_VERSION = 30;
20
20
  /** State database filename */
21
21
  export const STATE_DB_FILENAME = 'state.db';
22
22
  /** Directory for flywheel state */
@@ -164,6 +164,7 @@ CREATE TABLE IF NOT EXISTS wikilink_feedback (
164
164
  created_at TEXT DEFAULT (datetime('now'))
165
165
  );
166
166
  CREATE INDEX IF NOT EXISTS idx_wl_feedback_entity ON wikilink_feedback(entity);
167
+ CREATE INDEX IF NOT EXISTS idx_wl_feedback_note_path ON wikilink_feedback(note_path);
167
168
 
168
169
  -- Wikilink suppressions (v4: auto-suppress false positives)
169
170
  CREATE TABLE IF NOT EXISTS wikilink_suppressions (
@@ -205,7 +206,9 @@ CREATE TABLE IF NOT EXISTS tool_invocations (
205
206
  session_id TEXT,
206
207
  note_paths TEXT,
207
208
  duration_ms INTEGER,
208
- success INTEGER NOT NULL DEFAULT 1
209
+ success INTEGER NOT NULL DEFAULT 1,
210
+ response_tokens INTEGER,
211
+ baseline_tokens INTEGER
209
212
  );
210
213
  CREATE INDEX IF NOT EXISTS idx_tool_inv_ts ON tool_invocations(timestamp);
211
214
  CREATE INDEX IF NOT EXISTS idx_tool_inv_tool ON tool_invocations(tool_name, timestamp);
@@ -424,6 +427,19 @@ CREATE TABLE IF NOT EXISTS session_summaries (
424
427
  ended_at INTEGER NOT NULL,
425
428
  tool_count INTEGER
426
429
  );
430
+
431
+ -- Retrieval co-occurrence (v30): notes retrieved together build implicit edges
432
+ CREATE TABLE IF NOT EXISTS retrieval_cooccurrence (
433
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
434
+ note_a TEXT NOT NULL,
435
+ note_b TEXT NOT NULL,
436
+ session_id TEXT NOT NULL,
437
+ timestamp INTEGER NOT NULL,
438
+ weight REAL NOT NULL DEFAULT 1.0,
439
+ UNIQUE(note_a, note_b, session_id)
440
+ );
441
+ CREATE INDEX IF NOT EXISTS idx_retcooc_notes ON retrieval_cooccurrence(note_a, note_b);
442
+ CREATE INDEX IF NOT EXISTS idx_retcooc_ts ON retrieval_cooccurrence(timestamp);
427
443
  `;
428
444
  // =============================================================================
429
445
  // Database Initialization
@@ -565,6 +581,16 @@ function initSchema(db) {
565
581
  // (created by SCHEMA_SQL above via CREATE TABLE IF NOT EXISTS)
566
582
  // v28: content_hashes table (persist watcher content hashes across restarts)
567
583
  // (created by SCHEMA_SQL above via CREATE TABLE IF NOT EXISTS)
584
+ // v29: index on wikilink_feedback(note_path) for temporal analysis queries
585
+ // (created by SCHEMA_SQL above via CREATE INDEX IF NOT EXISTS)
586
+ // v30: token economics columns on tool_invocations
587
+ if (currentVersion < 30) {
588
+ const hasResponseTokens = db.prepare(`SELECT COUNT(*) as cnt FROM pragma_table_info('tool_invocations') WHERE name = 'response_tokens'`).get();
589
+ if (hasResponseTokens.cnt === 0) {
590
+ db.exec('ALTER TABLE tool_invocations ADD COLUMN response_tokens INTEGER');
591
+ db.exec('ALTER TABLE tool_invocations ADD COLUMN baseline_tokens INTEGER');
592
+ }
593
+ }
568
594
  db.prepare('INSERT OR IGNORE INTO schema_version (version) VALUES (?)').run(SCHEMA_VERSION);
569
595
  }
570
596
  }
@@ -575,6 +601,32 @@ function deleteStateDbFiles(dbPath) {
575
601
  fs.unlinkSync(p);
576
602
  }
577
603
  }
604
+ /** Back up state.db before opening (skip if missing or 0 bytes). */
605
+ function backupStateDb(dbPath) {
606
+ try {
607
+ if (!fs.existsSync(dbPath))
608
+ return;
609
+ const stat = fs.statSync(dbPath);
610
+ if (stat.size === 0)
611
+ return;
612
+ fs.copyFileSync(dbPath, dbPath + '.backup');
613
+ }
614
+ catch (err) {
615
+ console.error(`[vault-core] Failed to back up state.db: ${err instanceof Error ? err.message : err}`);
616
+ }
617
+ }
618
+ /** Preserve a corrupted database for inspection before deleting. */
619
+ function preserveCorruptedDb(dbPath) {
620
+ try {
621
+ if (fs.existsSync(dbPath)) {
622
+ fs.copyFileSync(dbPath, dbPath + '.corrupt');
623
+ console.error(`[vault-core] Corrupted database preserved at ${dbPath}.corrupt`);
624
+ }
625
+ }
626
+ catch {
627
+ // Best effort — don't block recovery
628
+ }
629
+ }
578
630
  /**
579
631
  * Open or create the state database for a vault
580
632
  *
@@ -583,6 +635,8 @@ function deleteStateDbFiles(dbPath) {
583
635
  */
584
636
  export function openStateDb(vaultPath) {
585
637
  const dbPath = getStateDbPath(vaultPath);
638
+ // Back up existing database before any mutations
639
+ backupStateDb(dbPath);
586
640
  // Guard: Delete corrupted 0-byte database files
587
641
  // This can happen when better-sqlite3 fails to compile (e.g., Node 24)
588
642
  // and creates an empty file instead of a valid SQLite database
@@ -599,10 +653,11 @@ export function openStateDb(vaultPath) {
599
653
  initSchema(db);
600
654
  }
601
655
  catch (err) {
602
- // Corrupted database (e.g., "file is not a database") — delete and retry once
656
+ // Corrupted database (e.g., "file is not a database") — preserve, delete, and retry once
603
657
  if (fs.existsSync(dbPath)) {
604
658
  const msg = err instanceof Error ? err.message : String(err);
605
659
  console.error(`[vault-core] Corrupted state.db (${msg}) — deleting and recreating`);
660
+ preserveCorruptedDb(dbPath);
606
661
  try {
607
662
  db?.close();
608
663
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@velvetmonkey/vault-core",
3
- "version": "2.0.119",
3
+ "version": "2.0.121",
4
4
  "description": "Shared vault utilities for Flywheel ecosystem (entity scanning, wikilinks, protected zones)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",