teleton 0.8.4 → 0.8.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/README.md +40 -17
  2. package/dist/{bootstrap-NNEI3Z5H.js → bootstrap-PFBH6ALD.js} +11 -8
  3. package/dist/bridge-guards-HZTNH7IB.js +9 -0
  4. package/dist/{chunk-NH2CNRKJ.js → chunk-2UUGRY5B.js} +151 -159
  5. package/dist/{chunk-UMUONAD6.js → chunk-4MFN75ZK.js} +5941 -2716
  6. package/dist/{chunk-LC4TV3KL.js → chunk-4MG2AROG.js} +5 -7
  7. package/dist/{chunk-LZQOX6YY.js → chunk-6IFNQWIM.js} +7714 -8748
  8. package/dist/chunk-7KI25UJU.js +215 -0
  9. package/dist/chunk-AX5NBEHX.js +12 -0
  10. package/dist/{chunk-5LOHRZYY.js → chunk-BLUES3FJ.js} +80 -101
  11. package/dist/{chunk-CUE4UZXR.js → chunk-BT2I3ETV.js} +3 -3
  12. package/dist/chunk-CXTZPOTA.js +107 -0
  13. package/dist/{chunk-LVTKJQ7O.js → chunk-D3GT6YIY.js} +59 -7
  14. package/dist/chunk-EKCXKL5M.js +53 -0
  15. package/dist/{chunk-XDZDOKIF.js → chunk-F6S3L3OV.js} +3 -3
  16. package/dist/{chunk-C4NKJT2Z.js → chunk-J4WDJ7XS.js} +1 -1
  17. package/dist/{chunk-G7PCW63M.js → chunk-JYF2MM5I.js} +147 -113
  18. package/dist/{chunk-NVKBBTI6.js → chunk-K3QSIIMZ.js} +9 -6
  19. package/dist/{chunk-EYWNOHMJ.js → chunk-L653KKCR.js} +1 -0
  20. package/dist/chunk-OMQIAWEU.js +273 -0
  21. package/dist/chunk-PCT7GYBP.js +274 -0
  22. package/dist/chunk-QYZBWU2D.js +139 -0
  23. package/dist/{chunk-WTDAICGT.js → chunk-R6W4DJRK.js} +7 -7
  24. package/dist/{chunk-5SEMA47R.js → chunk-RILOEIK6.js} +1 -1
  25. package/dist/{chunk-6OOHHJ4N.js → chunk-TFTNZZDH.js} +20 -20
  26. package/dist/chunk-TTOZCZWE.js +96 -0
  27. package/dist/chunk-UJ54YT2T.js +12 -0
  28. package/dist/{chunk-GHMXWAXI.js → chunk-ULVL2W3D.js} +211 -445
  29. package/dist/{chunk-NQ6FZKCE.js → chunk-V3S3NXBQ.js} +3 -1
  30. package/dist/{chunk-H7MFXJZK.js → chunk-WSL4KIOI.js} +31 -26
  31. package/dist/{chunk-35MX4ZUI.js → chunk-Z5WY7BSB.js} +5 -5
  32. package/dist/{chunk-ALKAAG4O.js → chunk-ZGKE3OTA.js} +112 -49
  33. package/dist/{chunk-JROBTXWY.js → chunk-ZHRDETCX.js} +38 -4
  34. package/dist/cli/index.d.ts +2 -0
  35. package/dist/cli/index.js +272 -159
  36. package/dist/{client-5KD25NOP.js → client-S5UIK6OG.js} +10 -8
  37. package/dist/daily-logs-3WXGYAQF.js +25 -0
  38. package/dist/{get-my-gifts-Y7EN7RK4.js → get-my-gifts-3YSYM3LI.js} +3 -2
  39. package/dist/harden-permissions-PV5SGV5D.js +100 -0
  40. package/dist/index.d.ts +923 -0
  41. package/dist/index.js +29 -20
  42. package/dist/knowledge-RRWUIO3G.js +19 -0
  43. package/dist/{local-IHKJFQJS.js → local-MSZAXWUL.js} +3 -3
  44. package/dist/mcp-loader-OELDFR63.js +15 -0
  45. package/dist/{memory-QMJRM3XJ.js → memory-6U6HGRK2.js} +23 -12
  46. package/dist/memory-hook-T7Y235KY.js +19 -0
  47. package/dist/messages-KV5ADNJB.js +17 -0
  48. package/dist/{migrate-5VBAP52B.js → migrate-AX3HOKOO.js} +10 -7
  49. package/dist/{paths-XA2RJH4S.js → paths-WMVV7ZAJ.js} +1 -1
  50. package/dist/{server-WWGVDFPW.js → server-MFRYOGHR.js} +21 -23
  51. package/dist/{server-AJCOURH7.js → server-SFLCAZFR.js} +221 -27
  52. package/dist/{setup-server-VDY64CWW.js → setup-server-YWAPKZVE.js} +26 -26
  53. package/dist/{store-BY7S6IFN.js → store-PGHQASBC.js} +11 -8
  54. package/dist/{task-dependency-resolver-L6UUMTHK.js → task-dependency-resolver-YQKADDEU.js} +24 -10
  55. package/dist/{task-executor-XBNJLUCS.js → task-executor-LWAWD225.js} +4 -4
  56. package/dist/{tool-adapter-IVX2XQJE.js → tool-adapter-VKLUZSQS.js} +1 -1
  57. package/dist/{tool-index-FTERJSZK.js → tool-index-YEWDF5CK.js} +5 -5
  58. package/dist/{transcript-IM7G25OS.js → transcript-4Y3Z2BJ3.js} +3 -3
  59. package/dist/web/assets/Config-MNxA69ib.js +1 -0
  60. package/dist/web/assets/Conversations-Dk958paA.js +1 -0
  61. package/dist/web/assets/Dashboard-dM18fGOm.js +1 -0
  62. package/dist/web/assets/Hooks-D2griQnI.js +1 -0
  63. package/dist/web/assets/Mcp-CtWNzwsz.js +1 -0
  64. package/dist/web/assets/Memory-CfLwH45G.js +1 -0
  65. package/dist/web/assets/Plugins-3hoJprFo.js +1 -0
  66. package/dist/web/assets/SearchInput-CpcETdpE.js +1 -0
  67. package/dist/web/assets/Soul-BSxE73aK.js +1 -0
  68. package/dist/web/assets/Tasks-DkCkfu3A.js +1 -0
  69. package/dist/web/assets/TelegramSettingsPanel-BRzc5G6e.js +1 -0
  70. package/dist/web/assets/Tools-Du8B8Mb4.js +1 -0
  71. package/dist/web/assets/Wallet-BLILP2Gn.js +1 -0
  72. package/dist/web/assets/Workspace-qklcXpXV.js +1 -0
  73. package/dist/web/assets/index-BwEPTTKp.js +90 -0
  74. package/dist/web/assets/index-noejUsK7.css +1 -0
  75. package/dist/web/assets/{index.es-DitvF-9H.js → index.es-DdpKlnGb.js} +1 -1
  76. package/dist/web/assets/useToolManager-tdxkKn3H.js +1 -0
  77. package/dist/web/assets/utils-CnsbSMo4.js +1 -0
  78. package/dist/web/index.html +2 -2
  79. package/package.json +7 -12
  80. package/src/templates/HEARTBEAT.md +5 -0
  81. package/dist/memory-hook-VUNWZ3NY.js +0 -19
  82. package/dist/web/assets/index-BfYCdwLI.js +0 -80
  83. package/dist/web/assets/index-DmlyQVhR.css +0 -1
  84. package/dist/{chunk-WFTC3JJW.js → chunk-3NO7QU7W.js} +1 -1
@@ -1,160 +1,40 @@
1
+ import {
2
+ JOURNAL_SCHEMA
3
+ } from "./chunk-QYZBWU2D.js";
4
+ import {
5
+ KnowledgeIndexer
6
+ } from "./chunk-OMQIAWEU.js";
7
+ import {
8
+ MessageStore
9
+ } from "./chunk-TTOZCZWE.js";
1
10
  import {
2
11
  CachedEmbeddingProvider,
3
12
  createEmbeddingProvider,
4
13
  hashText,
5
14
  serializeEmbedding
6
- } from "./chunk-35MX4ZUI.js";
15
+ } from "./chunk-Z5WY7BSB.js";
7
16
  import {
8
17
  FEED_MESSAGE_MAX_CHARS,
9
18
  HYBRID_SEARCH_MIN_SCORE,
10
- KNOWLEDGE_CHUNK_SIZE,
11
19
  RECENCY_DECAY_FACTOR,
12
20
  RECENCY_WEIGHT,
13
21
  SECONDS_PER_DAY,
14
22
  SECONDS_PER_HOUR,
15
23
  SQLITE_CACHE_SIZE_KB,
16
24
  SQLITE_MMAP_SIZE
17
- } from "./chunk-C4NKJT2Z.js";
18
- import {
19
- TELETON_ROOT
20
- } from "./chunk-EYWNOHMJ.js";
25
+ } from "./chunk-J4WDJ7XS.js";
21
26
  import {
22
27
  createLogger
23
- } from "./chunk-NQ6FZKCE.js";
28
+ } from "./chunk-V3S3NXBQ.js";
24
29
 
25
30
  // src/memory/database.ts
26
- import Database2 from "better-sqlite3";
27
- import { existsSync as existsSync2, mkdirSync as mkdirSync2, chmodSync as chmodSync2 } from "fs";
28
- import { dirname as dirname2 } from "path";
29
- import * as sqliteVec from "sqlite-vec";
30
-
31
- // src/utils/module-db.ts
32
31
  import Database from "better-sqlite3";
33
32
  import { existsSync, mkdirSync, chmodSync } from "fs";
34
- import { dirname, join } from "path";
35
- var log = createLogger("Utils");
36
- var JOURNAL_SCHEMA = `
37
- CREATE TABLE IF NOT EXISTS journal (
38
- id INTEGER PRIMARY KEY AUTOINCREMENT,
39
- timestamp INTEGER NOT NULL DEFAULT (unixepoch()),
40
- type TEXT NOT NULL CHECK(type IN ('trade', 'gift', 'middleman', 'kol')),
41
- action TEXT NOT NULL,
42
- asset_from TEXT,
43
- asset_to TEXT,
44
- amount_from REAL,
45
- amount_to REAL,
46
- price_ton REAL,
47
- counterparty TEXT,
48
- platform TEXT,
49
- reasoning TEXT,
50
- outcome TEXT CHECK(outcome IN ('pending', 'profit', 'loss', 'neutral', 'cancelled')),
51
- pnl_ton REAL,
52
- pnl_pct REAL,
53
- tx_hash TEXT,
54
- tool_used TEXT,
55
- chat_id TEXT,
56
- user_id INTEGER,
57
- closed_at INTEGER,
58
- created_at INTEGER NOT NULL DEFAULT (unixepoch())
59
- );
60
-
61
- CREATE INDEX IF NOT EXISTS idx_journal_type ON journal(type);
62
- CREATE INDEX IF NOT EXISTS idx_journal_timestamp ON journal(timestamp DESC);
63
- CREATE INDEX IF NOT EXISTS idx_journal_asset_from ON journal(asset_from);
64
- CREATE INDEX IF NOT EXISTS idx_journal_outcome ON journal(outcome);
65
- CREATE INDEX IF NOT EXISTS idx_journal_type_timestamp ON journal(type, timestamp DESC);
66
- `;
67
- var USED_TRANSACTIONS_SCHEMA = `
68
- CREATE TABLE IF NOT EXISTS used_transactions (
69
- tx_hash TEXT PRIMARY KEY,
70
- user_id TEXT NOT NULL,
71
- amount REAL NOT NULL,
72
- game_type TEXT NOT NULL,
73
- used_at INTEGER NOT NULL DEFAULT (unixepoch())
74
- );
75
-
76
- CREATE INDEX IF NOT EXISTS idx_used_tx_user ON used_transactions(user_id);
77
- CREATE INDEX IF NOT EXISTS idx_used_tx_used_at ON used_transactions(used_at);
78
- `;
79
- function openModuleDb(path) {
80
- const dir = dirname(path);
81
- if (!existsSync(dir)) {
82
- mkdirSync(dir, { recursive: true });
83
- }
84
- const db = new Database(path);
85
- try {
86
- chmodSync(path, 384);
87
- } catch {
88
- }
89
- db.pragma("journal_mode = WAL");
90
- return db;
91
- }
92
- function createDbWrapper(getDb, moduleName) {
93
- return function withDb(executor) {
94
- return (params, context) => {
95
- const moduleDb = getDb();
96
- if (!moduleDb) {
97
- return Promise.resolve({
98
- success: false,
99
- error: `${moduleName} module not started`
100
- });
101
- }
102
- return executor(params, { ...context, db: moduleDb });
103
- };
104
- };
105
- }
106
- var MAIN_DB_PATH = join(TELETON_ROOT, "memory.db");
107
- function migrateFromMainDb(moduleDb, tables) {
108
- let totalMigrated = 0;
109
- for (const table of tables) {
110
- if (!/^[a-z_]+$/.test(table)) {
111
- throw new Error(`Invalid table name for migration: "${table}"`);
112
- }
113
- }
114
- for (const table of tables) {
115
- try {
116
- const row = moduleDb.prepare(`SELECT COUNT(*) as c FROM ${table}`).get();
117
- if (row.c > 0) return 0;
118
- } catch {
119
- continue;
120
- }
121
- }
122
- if (!existsSync(MAIN_DB_PATH)) return 0;
123
- try {
124
- moduleDb.exec(`ATTACH DATABASE '${MAIN_DB_PATH}' AS main_db`);
125
- for (const table of tables) {
126
- try {
127
- const exists = moduleDb.prepare(`SELECT name FROM main_db.sqlite_master WHERE type='table' AND name=?`).get(table);
128
- if (!exists) continue;
129
- const src = moduleDb.prepare(`SELECT COUNT(*) as c FROM main_db.${table}`).get();
130
- if (src.c === 0) continue;
131
- const dstCols = moduleDb.prepare(`PRAGMA table_info(${table})`).all().map((r) => r.name);
132
- const srcCols = moduleDb.prepare(`PRAGMA main_db.table_info(${table})`).all().map((r) => r.name);
133
- const shared = dstCols.filter((c) => srcCols.includes(c));
134
- if (shared.length === 0) continue;
135
- const cols = shared.join(", ");
136
- moduleDb.exec(
137
- `INSERT OR IGNORE INTO ${table} (${cols}) SELECT ${cols} FROM main_db.${table}`
138
- );
139
- totalMigrated += src.c;
140
- log.info(`Migrated ${src.c} rows from memory.db \u2192 ${table}`);
141
- } catch (e) {
142
- log.warn({ err: e }, `Could not migrate table ${table}`);
143
- }
144
- }
145
- moduleDb.exec(`DETACH DATABASE main_db`);
146
- } catch (e) {
147
- log.warn({ err: e }, `Migration from memory.db failed`);
148
- try {
149
- moduleDb.exec(`DETACH DATABASE main_db`);
150
- } catch {
151
- }
152
- }
153
- return totalMigrated;
154
- }
33
+ import { dirname } from "path";
34
+ import * as sqliteVec from "sqlite-vec";
155
35
 
156
36
  // src/memory/schema.ts
157
- var log2 = createLogger("Memory");
37
+ var log = createLogger("Memory");
158
38
  function compareSemver(a, b) {
159
39
  const parseVersion = (v) => {
160
40
  const parts = v.split("-")[0].split(".").map(Number);
@@ -371,16 +251,16 @@ function ensureSchema(db) {
371
251
  );
372
252
 
373
253
  -- FTS triggers for messages
374
- CREATE TRIGGER IF NOT EXISTS tg_messages_fts_insert AFTER INSERT ON tg_messages BEGIN
254
+ CREATE TRIGGER IF NOT EXISTS tg_messages_fts_insert AFTER INSERT ON tg_messages WHEN new.text IS NOT NULL BEGIN
375
255
  INSERT INTO tg_messages_fts(rowid, text, id, chat_id, sender_id, timestamp)
376
256
  VALUES (new.rowid, new.text, new.id, new.chat_id, new.sender_id, new.timestamp);
377
257
  END;
378
258
 
379
- CREATE TRIGGER IF NOT EXISTS tg_messages_fts_delete AFTER DELETE ON tg_messages BEGIN
259
+ CREATE TRIGGER IF NOT EXISTS tg_messages_fts_delete AFTER DELETE ON tg_messages WHEN old.text IS NOT NULL BEGIN
380
260
  DELETE FROM tg_messages_fts WHERE rowid = old.rowid;
381
261
  END;
382
262
 
383
- CREATE TRIGGER IF NOT EXISTS tg_messages_fts_update AFTER UPDATE ON tg_messages BEGIN
263
+ CREATE TRIGGER IF NOT EXISTS tg_messages_fts_update AFTER UPDATE ON tg_messages WHEN old.text IS NOT NULL OR new.text IS NOT NULL BEGIN
384
264
  DELETE FROM tg_messages_fts WHERE rowid = old.rowid;
385
265
  INSERT INTO tg_messages_fts(rowid, text, id, chat_id, sender_id, timestamp)
386
266
  VALUES (new.rowid, new.text, new.id, new.chat_id, new.sender_id, new.timestamp);
@@ -492,15 +372,15 @@ function setSchemaVersion(db, version) {
492
372
  `
493
373
  ).run(version);
494
374
  }
495
- var CURRENT_SCHEMA_VERSION = "1.15.0";
375
+ var CURRENT_SCHEMA_VERSION = "1.18.0";
496
376
  function runMigrations(db) {
497
377
  const currentVersion = getSchemaVersion(db);
498
378
  if (!currentVersion || versionLessThan(currentVersion, "1.1.0")) {
499
- log2.info("Running migration: Adding scheduled task columns...");
379
+ log.info("Running migration: Adding scheduled task columns...");
500
380
  try {
501
381
  const tableExists = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='tasks'").get();
502
382
  if (!tableExists) {
503
- log2.info("Tasks table doesn't exist yet, skipping column migration");
383
+ log.info("Tasks table doesn't exist yet, skipping column migration");
504
384
  setSchemaVersion(db, CURRENT_SCHEMA_VERSION);
505
385
  return;
506
386
  }
@@ -533,21 +413,21 @@ function runMigrations(db) {
533
413
  CREATE INDEX IF NOT EXISTS idx_task_deps_task ON task_dependencies(task_id);
534
414
  CREATE INDEX IF NOT EXISTS idx_task_deps_parent ON task_dependencies(depends_on_task_id);
535
415
  `);
536
- log2.info("Migration 1.1.0 complete: Scheduled tasks support added");
416
+ log.info("Migration 1.1.0 complete: Scheduled tasks support added");
537
417
  } catch (error) {
538
- log2.error({ err: error }, "Migration 1.1.0 failed");
418
+ log.error({ err: error }, "Migration 1.1.0 failed");
539
419
  throw error;
540
420
  }
541
421
  }
542
422
  if (!currentVersion || versionLessThan(currentVersion, "1.2.0")) {
543
423
  try {
544
- log2.info("Running migration 1.2.0: Extend sessions table for SQLite backend");
424
+ log.info("Running migration 1.2.0: Extend sessions table for SQLite backend");
545
425
  const addColumnIfNotExists = (table, column, type) => {
546
426
  try {
547
427
  db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${type}`);
548
- } catch (e) {
549
- if (!(e instanceof Error) || !e.message.includes("duplicate column name")) {
550
- throw e;
428
+ } catch (error) {
429
+ if (!(error instanceof Error) || !error.message.includes("duplicate column name")) {
430
+ throw error;
551
431
  }
552
432
  }
553
433
  };
@@ -570,14 +450,14 @@ function runMigrations(db) {
570
450
  );
571
451
  }
572
452
  db.exec("CREATE INDEX IF NOT EXISTS idx_sessions_updated ON sessions(updated_at DESC)");
573
- log2.info("Migration 1.2.0 complete: Sessions table extended");
453
+ log.info("Migration 1.2.0 complete: Sessions table extended");
574
454
  } catch (error) {
575
- log2.error({ err: error }, "Migration 1.2.0 failed");
455
+ log.error({ err: error }, "Migration 1.2.0 failed");
576
456
  throw error;
577
457
  }
578
458
  }
579
459
  if (!currentVersion || versionLessThan(currentVersion, "1.9.0")) {
580
- log2.info("Running migration 1.9.0: Upgrade embedding_cache to BLOB storage");
460
+ log.info("Running migration 1.9.0: Upgrade embedding_cache to BLOB storage");
581
461
  try {
582
462
  db.exec(`DROP TABLE IF EXISTS embedding_cache`);
583
463
  db.exec(`
@@ -593,14 +473,14 @@ function runMigrations(db) {
593
473
  );
594
474
  CREATE INDEX IF NOT EXISTS idx_embedding_cache_accessed ON embedding_cache(accessed_at);
595
475
  `);
596
- log2.info("Migration 1.9.0 complete: embedding_cache upgraded to BLOB storage");
476
+ log.info("Migration 1.9.0 complete: embedding_cache upgraded to BLOB storage");
597
477
  } catch (error) {
598
- log2.error({ err: error }, "Migration 1.9.0 failed");
478
+ log.error({ err: error }, "Migration 1.9.0 failed");
599
479
  throw error;
600
480
  }
601
481
  }
602
482
  if (!currentVersion || versionLessThan(currentVersion, "1.10.0")) {
603
- log2.info("Running migration 1.10.0: Add tool_config table for runtime tool management");
483
+ log.info("Running migration 1.10.0: Add tool_config table for runtime tool management");
604
484
  try {
605
485
  db.exec(`
606
486
  CREATE TABLE IF NOT EXISTS tool_config (
@@ -611,14 +491,14 @@ function runMigrations(db) {
611
491
  updated_by INTEGER
612
492
  );
613
493
  `);
614
- log2.info("Migration 1.10.0 complete: tool_config table created");
494
+ log.info("Migration 1.10.0 complete: tool_config table created");
615
495
  } catch (error) {
616
- log2.error({ err: error }, "Migration 1.10.0 failed");
496
+ log.error({ err: error }, "Migration 1.10.0 failed");
617
497
  throw error;
618
498
  }
619
499
  }
620
500
  if (!currentVersion || versionLessThan(currentVersion, "1.10.1")) {
621
- log2.info("Running migration 1.10.1: Fix tool_config scope CHECK constraint (add admin-only)");
501
+ log.info("Running migration 1.10.1: Fix tool_config scope CHECK constraint (add admin-only)");
622
502
  try {
623
503
  db.transaction(() => {
624
504
  db.exec(`
@@ -634,14 +514,14 @@ function runMigrations(db) {
634
514
  ALTER TABLE tool_config_new RENAME TO tool_config;
635
515
  `);
636
516
  })();
637
- log2.info("Migration 1.10.1 complete: tool_config CHECK constraint updated");
517
+ log.info("Migration 1.10.1 complete: tool_config CHECK constraint updated");
638
518
  } catch (error) {
639
- log2.error({ err: error }, "Migration 1.10.1 failed");
519
+ log.error({ err: error }, "Migration 1.10.1 failed");
640
520
  throw error;
641
521
  }
642
522
  }
643
523
  if (!currentVersion || versionLessThan(currentVersion, "1.11.0")) {
644
- log2.info("Running migration 1.11.0: Add tool_index tables for Tool RAG");
524
+ log.info("Running migration 1.11.0: Add tool_index tables for Tool RAG");
645
525
  try {
646
526
  db.exec(`
647
527
  CREATE TABLE IF NOT EXISTS tool_index (
@@ -673,14 +553,14 @@ function runMigrations(db) {
673
553
  VALUES (new.rowid, new.search_text, new.name);
674
554
  END;
675
555
  `);
676
- log2.info("Migration 1.11.0 complete: tool_index tables created");
556
+ log.info("Migration 1.11.0 complete: tool_index tables created");
677
557
  } catch (error) {
678
- log2.error({ err: error }, "Migration 1.11.0 failed");
558
+ log.error({ err: error }, "Migration 1.11.0 failed");
679
559
  throw error;
680
560
  }
681
561
  }
682
562
  if (!currentVersion || versionLessThan(currentVersion, "1.12.0")) {
683
- log2.info("Running migration 1.12.0: Add exec_audit table");
563
+ log.info("Running migration 1.12.0: Add exec_audit table");
684
564
  try {
685
565
  db.exec(`
686
566
  CREATE TABLE IF NOT EXISTS exec_audit (
@@ -702,34 +582,34 @@ function runMigrations(db) {
702
582
  CREATE INDEX IF NOT EXISTS idx_exec_audit_timestamp ON exec_audit(timestamp DESC);
703
583
  CREATE INDEX IF NOT EXISTS idx_exec_audit_user ON exec_audit(user_id);
704
584
  `);
705
- log2.info("Migration 1.12.0 complete: exec_audit table created");
585
+ log.info("Migration 1.12.0 complete: exec_audit table created");
706
586
  } catch (error) {
707
- log2.error({ err: error }, "Migration 1.12.0 failed");
587
+ log.error({ err: error }, "Migration 1.12.0 failed");
708
588
  throw error;
709
589
  }
710
590
  }
711
591
  if (!currentVersion || versionLessThan(currentVersion, "1.13.0")) {
712
- log2.info("Running migration 1.13.0: Add token usage columns to sessions");
592
+ log.info("Running migration 1.13.0: Add token usage columns to sessions");
713
593
  try {
714
594
  const addColumnIfNotExists = (table, column, type) => {
715
595
  try {
716
596
  db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${type}`);
717
- } catch (e) {
718
- if (!(e instanceof Error) || !e.message.includes("duplicate column name")) {
719
- throw e;
597
+ } catch (error) {
598
+ if (!(error instanceof Error) || !error.message.includes("duplicate column name")) {
599
+ throw error;
720
600
  }
721
601
  }
722
602
  };
723
603
  addColumnIfNotExists("sessions", "input_tokens", "INTEGER DEFAULT 0");
724
604
  addColumnIfNotExists("sessions", "output_tokens", "INTEGER DEFAULT 0");
725
- log2.info("Migration 1.13.0 complete: Token usage columns added to sessions");
605
+ log.info("Migration 1.13.0 complete: Token usage columns added to sessions");
726
606
  } catch (error) {
727
- log2.error({ err: error }, "Migration 1.13.0 failed");
607
+ log.error({ err: error }, "Migration 1.13.0 failed");
728
608
  throw error;
729
609
  }
730
610
  }
731
611
  if (!currentVersion || versionLessThan(currentVersion, "1.14.0")) {
732
- log2.info("Running migration 1.14.0: Add plugin_config table for plugin priority");
612
+ log.info("Running migration 1.14.0: Add plugin_config table for plugin priority");
733
613
  try {
734
614
  db.exec(`
735
615
  CREATE TABLE IF NOT EXISTS plugin_config (
@@ -738,14 +618,14 @@ function runMigrations(db) {
738
618
  updated_at TEXT NOT NULL DEFAULT (datetime('now'))
739
619
  );
740
620
  `);
741
- log2.info("Migration 1.14.0 complete: plugin_config table created");
621
+ log.info("Migration 1.14.0 complete: plugin_config table created");
742
622
  } catch (error) {
743
- log2.error({ err: error }, "Migration 1.14.0 failed");
623
+ log.error({ err: error }, "Migration 1.14.0 failed");
744
624
  throw error;
745
625
  }
746
626
  }
747
627
  if (!currentVersion || versionLessThan(currentVersion, "1.15.0")) {
748
- log2.info("Running migration 1.15.0: Add user_hook_config table");
628
+ log.info("Running migration 1.15.0: Add user_hook_config table");
749
629
  try {
750
630
  db.exec(`
751
631
  CREATE TABLE IF NOT EXISTS user_hook_config (
@@ -754,9 +634,101 @@ function runMigrations(db) {
754
634
  updated_at TEXT NOT NULL DEFAULT (datetime('now'))
755
635
  );
756
636
  `);
757
- log2.info("Migration 1.15.0 complete: user_hook_config table created");
637
+ log.info("Migration 1.15.0 complete: user_hook_config table created");
638
+ } catch (error) {
639
+ log.error({ err: error }, "Migration 1.15.0 failed");
640
+ throw error;
641
+ }
642
+ }
643
+ if (!currentVersion || versionLessThan(currentVersion, "1.16.0")) {
644
+ log.info("Running migration 1.16.0: Fix tg_messages FTS triggers to skip NULL text rows");
645
+ try {
646
+ db.exec(`
647
+ DROP TRIGGER IF EXISTS tg_messages_fts_insert;
648
+ CREATE TRIGGER tg_messages_fts_insert AFTER INSERT ON tg_messages WHEN new.text IS NOT NULL BEGIN
649
+ INSERT INTO tg_messages_fts(rowid, text, id, chat_id, sender_id, timestamp)
650
+ VALUES (new.rowid, new.text, new.id, new.chat_id, new.sender_id, new.timestamp);
651
+ END;
652
+
653
+ DROP TRIGGER IF EXISTS tg_messages_fts_delete;
654
+ CREATE TRIGGER tg_messages_fts_delete AFTER DELETE ON tg_messages WHEN old.text IS NOT NULL BEGIN
655
+ DELETE FROM tg_messages_fts WHERE rowid = old.rowid;
656
+ END;
657
+
658
+ DROP TRIGGER IF EXISTS tg_messages_fts_update;
659
+ CREATE TRIGGER tg_messages_fts_update AFTER UPDATE ON tg_messages WHEN old.text IS NOT NULL OR new.text IS NOT NULL BEGIN
660
+ DELETE FROM tg_messages_fts WHERE rowid = old.rowid;
661
+ INSERT INTO tg_messages_fts(rowid, text, id, chat_id, sender_id, timestamp)
662
+ VALUES (new.rowid, new.text, new.id, new.chat_id, new.sender_id, new.timestamp);
663
+ END;
664
+ `);
665
+ log.info("Migration 1.16.0 complete: tg_messages FTS triggers updated");
758
666
  } catch (error) {
759
- log2.error({ err: error }, "Migration 1.15.0 failed");
667
+ log.error({ err: error }, "Migration 1.16.0 failed");
668
+ throw error;
669
+ }
670
+ }
671
+ if (!currentVersion || versionLessThan(currentVersion, "1.17.0")) {
672
+ log.info(
673
+ "Running migration 1.17.0: Add importance, access tracking, and lifecycle columns to knowledge"
674
+ );
675
+ try {
676
+ const addColumnIfNotExists = (table, column, type) => {
677
+ try {
678
+ db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${type}`);
679
+ } catch (error) {
680
+ if (!(error instanceof Error) || !error.message.includes("duplicate column name")) {
681
+ throw error;
682
+ }
683
+ }
684
+ };
685
+ addColumnIfNotExists("knowledge", "importance", "REAL DEFAULT 0.5");
686
+ addColumnIfNotExists("knowledge", "access_count", "INTEGER DEFAULT 0");
687
+ addColumnIfNotExists("knowledge", "last_accessed_at", "INTEGER");
688
+ addColumnIfNotExists("knowledge", "status", "TEXT DEFAULT 'active'");
689
+ addColumnIfNotExists("knowledge", "memory_type", "TEXT DEFAULT 'semantic'");
690
+ db.exec(`CREATE INDEX IF NOT EXISTS idx_knowledge_status ON knowledge(status)`);
691
+ log.info("Migration 1.17.0 complete: importance/access/lifecycle columns added to knowledge");
692
+ } catch (error) {
693
+ log.error({ err: error }, "Migration 1.17.0 failed");
694
+ throw error;
695
+ }
696
+ }
697
+ if (!currentVersion || versionLessThan(currentVersion, "1.18.0")) {
698
+ log.info(
699
+ "Running migration 1.18.0: Extend tool_config scope CHECK constraint for new scope values"
700
+ );
701
+ try {
702
+ const tableExists = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='tool_config'").get();
703
+ if (tableExists) {
704
+ db.transaction(() => {
705
+ db.exec(`
706
+ CREATE TABLE IF NOT EXISTS tool_config_new (
707
+ tool_name TEXT PRIMARY KEY,
708
+ enabled INTEGER NOT NULL DEFAULT 1 CHECK(enabled IN (0, 1)),
709
+ scope TEXT CHECK(scope IN ('always', 'open', 'dm-only', 'group-only', 'admin-only', 'allowlist', 'disabled')),
710
+ updated_at INTEGER NOT NULL DEFAULT (unixepoch()),
711
+ updated_by INTEGER
712
+ );
713
+ INSERT OR IGNORE INTO tool_config_new SELECT * FROM tool_config;
714
+ DROP TABLE tool_config;
715
+ ALTER TABLE tool_config_new RENAME TO tool_config;
716
+ `);
717
+ })();
718
+ } else {
719
+ db.exec(`
720
+ CREATE TABLE IF NOT EXISTS tool_config (
721
+ tool_name TEXT PRIMARY KEY,
722
+ enabled INTEGER NOT NULL DEFAULT 1 CHECK(enabled IN (0, 1)),
723
+ scope TEXT CHECK(scope IN ('always', 'open', 'dm-only', 'group-only', 'admin-only', 'allowlist', 'disabled')),
724
+ updated_at INTEGER NOT NULL DEFAULT (unixepoch()),
725
+ updated_by INTEGER
726
+ );
727
+ `);
728
+ }
729
+ log.info("Migration 1.18.0 complete: tool_config scope CHECK constraint extended");
730
+ } catch (error) {
731
+ log.error({ err: error }, "Migration 1.18.0 failed");
760
732
  throw error;
761
733
  }
762
734
  }
@@ -764,7 +736,7 @@ function runMigrations(db) {
764
736
  }
765
737
 
766
738
  // src/memory/database.ts
767
- var log3 = createLogger("Memory");
739
+ var log2 = createLogger("Memory");
768
740
  var MemoryDatabase = class {
769
741
  db;
770
742
  config;
@@ -772,17 +744,17 @@ var MemoryDatabase = class {
772
744
  _dimensionsChanged = false;
773
745
  constructor(config) {
774
746
  this.config = config;
775
- const dir = dirname2(config.path);
776
- if (!existsSync2(dir)) {
777
- mkdirSync2(dir, { recursive: true });
747
+ const dir = dirname(config.path);
748
+ if (!existsSync(dir)) {
749
+ mkdirSync(dir, { recursive: true });
778
750
  }
779
- this.db = new Database2(config.path, {
780
- verbose: process.env.DEBUG_SQL ? (msg) => log3.debug(String(msg)) : void 0
751
+ this.db = new Database(config.path, {
752
+ verbose: process.env.DEBUG_SQL ? (msg) => log2.debug(String(msg)) : void 0
781
753
  });
782
754
  try {
783
- chmodSync2(config.path, 384);
784
- } catch (err) {
785
- log3.warn({ err, path: config.path }, "Failed to set DB file permissions to 0o600");
755
+ chmodSync(config.path, 384);
756
+ } catch (error) {
757
+ log2.warn({ err: error, path: config.path }, "Failed to set DB file permissions to 0o600");
786
758
  }
787
759
  this.db.pragma("journal_mode = WAL");
788
760
  this.db.pragma("synchronous = NORMAL");
@@ -796,8 +768,8 @@ var MemoryDatabase = class {
796
768
  let currentVersion = null;
797
769
  try {
798
770
  currentVersion = getSchemaVersion(this.db);
799
- } catch (err) {
800
- log3.warn({ err }, "Could not read schema version, assuming fresh database");
771
+ } catch (error) {
772
+ log2.warn({ err: error }, "Could not read schema version, assuming fresh database");
801
773
  currentVersion = null;
802
774
  }
803
775
  if (!currentVersion) {
@@ -819,16 +791,16 @@ var MemoryDatabase = class {
819
791
  this._dimensionsChanged = ensureVectorTables(this.db, dims);
820
792
  this.vectorReady = true;
821
793
  } catch (error) {
822
- log3.warn(`sqlite-vec not available, vector search disabled: ${error.message}`);
823
- log3.warn("Falling back to keyword-only search");
794
+ log2.warn(`sqlite-vec not available, vector search disabled: ${error.message}`);
795
+ log2.warn("Falling back to keyword-only search");
824
796
  this.config.enableVectorSearch = false;
825
797
  }
826
798
  }
827
799
  migrate(from, to) {
828
- log3.info(`Migrating database from ${from} to ${to}...`);
800
+ log2.info(`Migrating database from ${from} to ${to}...`);
829
801
  runMigrations(this.db);
830
802
  ensureSchema(this.db);
831
- log3.info("Migration complete");
803
+ log2.info("Migration complete");
832
804
  }
833
805
  getDb() {
834
806
  return this.db;
@@ -935,160 +907,9 @@ function closeDatabase() {
935
907
  }
936
908
  }
937
909
 
938
- // src/memory/agent/knowledge.ts
939
- import { readFileSync, existsSync as existsSync3, readdirSync, statSync } from "fs";
940
- import { join as join2 } from "path";
941
- var KnowledgeIndexer = class {
942
- constructor(db, workspaceDir, embedder, vectorEnabled) {
943
- this.db = db;
944
- this.workspaceDir = workspaceDir;
945
- this.embedder = embedder;
946
- this.vectorEnabled = vectorEnabled;
947
- }
948
- async indexAll(options) {
949
- const files = this.listMemoryFiles();
950
- let indexed = 0;
951
- let skipped = 0;
952
- for (const file of files) {
953
- const wasIndexed = await this.indexFile(file, options?.force);
954
- if (wasIndexed) {
955
- indexed++;
956
- } else {
957
- skipped++;
958
- }
959
- }
960
- return { indexed, skipped };
961
- }
962
- async indexFile(absPath, force) {
963
- if (!existsSync3(absPath) || !absPath.endsWith(".md")) {
964
- return false;
965
- }
966
- const content = readFileSync(absPath, "utf-8");
967
- const relPath = absPath.replace(this.workspaceDir + "/", "");
968
- const fileHash = hashText(content);
969
- if (!force) {
970
- const existing = this.db.prepare(`SELECT hash FROM knowledge WHERE path = ? AND source = 'memory' LIMIT 1`).get(relPath);
971
- if (existing?.hash === fileHash) {
972
- return false;
973
- }
974
- }
975
- const chunks = this.chunkMarkdown(content, relPath);
976
- const texts = chunks.map((c) => c.text);
977
- const embeddings = await this.embedder.embedBatch(texts);
978
- this.db.transaction(() => {
979
- if (this.vectorEnabled) {
980
- this.db.prepare(
981
- `DELETE FROM knowledge_vec WHERE id IN (
982
- SELECT id FROM knowledge WHERE path = ? AND source = 'memory'
983
- )`
984
- ).run(relPath);
985
- }
986
- this.db.prepare(`DELETE FROM knowledge WHERE path = ? AND source = 'memory'`).run(relPath);
987
- const insert = this.db.prepare(`
988
- INSERT INTO knowledge (id, source, path, text, embedding, start_line, end_line, hash)
989
- VALUES (?, 'memory', ?, ?, ?, ?, ?, ?)
990
- `);
991
- const insertVec = this.vectorEnabled ? this.db.prepare(`INSERT INTO knowledge_vec (id, embedding) VALUES (?, ?)`) : null;
992
- for (let i = 0; i < chunks.length; i++) {
993
- const chunk = chunks[i];
994
- const embedding = embeddings[i] ?? [];
995
- insert.run(
996
- chunk.id,
997
- chunk.path,
998
- chunk.text,
999
- serializeEmbedding(embedding),
1000
- chunk.startLine,
1001
- chunk.endLine,
1002
- fileHash
1003
- );
1004
- if (insertVec && embedding.length > 0) {
1005
- insertVec.run(chunk.id, serializeEmbedding(embedding));
1006
- }
1007
- }
1008
- })();
1009
- return true;
1010
- }
1011
- listMemoryFiles() {
1012
- const files = [];
1013
- const memoryMd = join2(this.workspaceDir, "MEMORY.md");
1014
- if (existsSync3(memoryMd)) {
1015
- files.push(memoryMd);
1016
- }
1017
- const memoryDir = join2(this.workspaceDir, "memory");
1018
- if (existsSync3(memoryDir)) {
1019
- const entries = readdirSync(memoryDir);
1020
- for (const entry of entries) {
1021
- const absPath = join2(memoryDir, entry);
1022
- if (statSync(absPath).isFile() && entry.endsWith(".md")) {
1023
- files.push(absPath);
1024
- }
1025
- }
1026
- }
1027
- return files;
1028
- }
1029
- /**
1030
- * Chunk markdown content with structure awareness.
1031
- * Respects heading boundaries, code blocks, and list groups.
1032
- * Target: KNOWLEDGE_CHUNK_SIZE chars, hard max: 2x target.
1033
- */
1034
- chunkMarkdown(content, path) {
1035
- const lines = content.split("\n");
1036
- const chunks = [];
1037
- const targetSize = KNOWLEDGE_CHUNK_SIZE;
1038
- const hardMax = targetSize * 2;
1039
- let currentChunk = "";
1040
- let startLine = 1;
1041
- let currentLine = 1;
1042
- let inCodeBlock = false;
1043
- let overlapPrefix = "";
1044
- const flushChunk = () => {
1045
- const text = currentChunk.trim();
1046
- if (text.length > 0) {
1047
- chunks.push({
1048
- id: hashText(`${path}:${startLine}:${currentLine - 1}`),
1049
- source: "memory",
1050
- path,
1051
- text,
1052
- startLine,
1053
- endLine: currentLine - 1,
1054
- hash: hashText(text)
1055
- });
1056
- const nonEmpty = text.split("\n").filter((l) => l.trim());
1057
- overlapPrefix = nonEmpty.length > 0 ? nonEmpty.slice(-2).join("\n") + "\n" : "";
1058
- }
1059
- currentChunk = overlapPrefix;
1060
- startLine = currentLine;
1061
- };
1062
- for (const line of lines) {
1063
- if (line.trimStart().startsWith("```")) {
1064
- inCodeBlock = !inCodeBlock;
1065
- }
1066
- if (!inCodeBlock && currentChunk.length >= targetSize) {
1067
- const isHeading = /^#{1,6}\s/.test(line);
1068
- const isBlankLine = line.trim() === "";
1069
- const isHorizontalRule = /^(-{3,}|\*{3,}|_{3,})\s*$/.test(line.trim());
1070
- if (isHeading) {
1071
- flushChunk();
1072
- } else if ((isBlankLine || isHorizontalRule) && currentChunk.length >= targetSize) {
1073
- currentChunk += line + "\n";
1074
- currentLine++;
1075
- flushChunk();
1076
- continue;
1077
- } else if (currentChunk.length >= hardMax) {
1078
- flushChunk();
1079
- }
1080
- }
1081
- currentChunk += line + "\n";
1082
- currentLine++;
1083
- }
1084
- flushChunk();
1085
- return chunks;
1086
- }
1087
- };
1088
-
1089
910
  // src/memory/agent/sessions.ts
1090
911
  import { randomUUID } from "crypto";
1091
- var log4 = createLogger("Memory");
912
+ var log3 = createLogger("Memory");
1092
913
  var SessionStore = class {
1093
914
  constructor(db, embedder, vectorEnabled) {
1094
915
  this.db = db;
@@ -1212,9 +1033,9 @@ ${session.summary}`;
1212
1033
  this.db.prepare(`DELETE FROM knowledge_vec WHERE id = ?`).run(knowledgeId);
1213
1034
  this.db.prepare(`INSERT INTO knowledge_vec (id, embedding) VALUES (?, ?)`).run(knowledgeId, embeddingBuffer);
1214
1035
  }
1215
- log4.info(`Indexed session ${sessionId} to knowledge base`);
1036
+ log3.info(`Indexed session ${sessionId} to knowledge base`);
1216
1037
  } catch (error) {
1217
- log4.error({ err: error }, "Error indexing session");
1038
+ log3.error({ err: error }, "Error indexing session");
1218
1039
  }
1219
1040
  }
1220
1041
  deleteSession(sessionId) {
@@ -1227,84 +1048,6 @@ ${session.summary}`;
1227
1048
  }
1228
1049
  };
1229
1050
 
1230
- // src/memory/feed/messages.ts
1231
- var MessageStore = class {
1232
- constructor(db, embedder, vectorEnabled) {
1233
- this.db = db;
1234
- this.embedder = embedder;
1235
- this.vectorEnabled = vectorEnabled;
1236
- }
1237
- ensureChat(chatId, isGroup = false) {
1238
- const existing = this.db.prepare(`SELECT id FROM tg_chats WHERE id = ?`).get(chatId);
1239
- if (!existing) {
1240
- this.db.prepare(`INSERT INTO tg_chats (id, type, is_monitored) VALUES (?, ?, 1)`).run(chatId, isGroup ? "group" : "dm");
1241
- }
1242
- }
1243
- ensureUser(userId) {
1244
- if (!userId) return;
1245
- const existing = this.db.prepare(`SELECT id FROM tg_users WHERE id = ?`).get(userId);
1246
- if (!existing) {
1247
- this.db.prepare(`INSERT INTO tg_users (id) VALUES (?)`).run(userId);
1248
- }
1249
- }
1250
- async storeMessage(message) {
1251
- this.ensureChat(message.chatId);
1252
- if (message.senderId) {
1253
- this.ensureUser(message.senderId);
1254
- }
1255
- const embedding = this.vectorEnabled && message.text ? await this.embedder.embedQuery(message.text) : [];
1256
- const embeddingBuffer = serializeEmbedding(embedding);
1257
- this.db.transaction(() => {
1258
- this.db.prepare(
1259
- `
1260
- INSERT OR REPLACE INTO tg_messages (
1261
- id, chat_id, sender_id, text, embedding, reply_to_id,
1262
- is_from_agent, has_media, media_type, timestamp
1263
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
1264
- `
1265
- ).run(
1266
- message.id,
1267
- message.chatId,
1268
- message.senderId,
1269
- message.text,
1270
- embeddingBuffer,
1271
- message.replyToId,
1272
- message.isFromAgent ? 1 : 0,
1273
- message.hasMedia ? 1 : 0,
1274
- message.mediaType,
1275
- message.timestamp
1276
- );
1277
- if (this.vectorEnabled && embedding.length > 0 && message.text) {
1278
- this.db.prepare(`DELETE FROM tg_messages_vec WHERE id = ?`).run(message.id);
1279
- this.db.prepare(`INSERT INTO tg_messages_vec (id, embedding) VALUES (?, ?)`).run(message.id, embeddingBuffer);
1280
- }
1281
- this.db.prepare(`UPDATE tg_chats SET last_message_at = ?, last_message_id = ? WHERE id = ?`).run(message.timestamp, message.id, message.chatId);
1282
- })();
1283
- }
1284
- getRecentMessages(chatId, limit = 20) {
1285
- const rows = this.db.prepare(
1286
- `
1287
- SELECT id, chat_id, sender_id, text, reply_to_id, is_from_agent, has_media, media_type, timestamp
1288
- FROM tg_messages
1289
- WHERE chat_id = ?
1290
- ORDER BY timestamp DESC
1291
- LIMIT ?
1292
- `
1293
- ).all(chatId, limit);
1294
- return rows.reverse().map((row) => ({
1295
- id: row.id,
1296
- chatId: row.chat_id,
1297
- senderId: row.sender_id,
1298
- text: row.text,
1299
- replyToId: row.reply_to_id ?? void 0,
1300
- isFromAgent: Boolean(row.is_from_agent),
1301
- hasMedia: Boolean(row.has_media),
1302
- mediaType: row.media_type ?? void 0,
1303
- timestamp: row.timestamp
1304
- }));
1305
- }
1306
- };
1307
-
1308
1051
  // src/memory/feed/chats.ts
1309
1052
  var ChatStore = class {
1310
1053
  constructor(db) {
@@ -1579,7 +1322,7 @@ var UserStore = class {
1579
1322
  };
1580
1323
 
1581
1324
  // src/memory/search/hybrid.ts
1582
- var log5 = createLogger("Memory");
1325
+ var log4 = createLogger("Memory");
1583
1326
  var UNIT_SECONDS = {
1584
1327
  hour: SECONDS_PER_HOUR,
1585
1328
  day: SECONDS_PER_DAY,
@@ -1621,7 +1364,26 @@ var HybridSearch = class {
1621
1364
  const keywordWeight = options.keywordWeight ?? 0.5;
1622
1365
  const vectorResults = this.vectorEnabled ? this.vectorSearchKnowledge(queryEmbedding, Math.ceil(limit * 3)) : [];
1623
1366
  const keywordResults = this.keywordSearchKnowledge(query, Math.ceil(limit * 3));
1624
- return this.mergeResults(vectorResults, keywordResults, vectorWeight, keywordWeight, limit);
1367
+ const results = this.mergeResults(
1368
+ vectorResults,
1369
+ keywordResults,
1370
+ vectorWeight,
1371
+ keywordWeight,
1372
+ limit
1373
+ );
1374
+ if (results.length > 0) {
1375
+ const ids = results.map((r) => r.id);
1376
+ setImmediate(() => {
1377
+ try {
1378
+ const ph = ids.map(() => "?").join(", ");
1379
+ this.db.prepare(
1380
+ `UPDATE knowledge SET access_count = access_count + 1, last_accessed_at = unixepoch() WHERE id IN (${ph})`
1381
+ ).run(...ids);
1382
+ } catch {
1383
+ }
1384
+ });
1385
+ }
1386
+ return results;
1625
1387
  }
1626
1388
  async searchMessages(query, queryEmbedding, options = {}) {
1627
1389
  const limit = options.limit ?? 10;
@@ -1647,13 +1409,14 @@ var HybridSearch = class {
1647
1409
  const embeddingBuffer = serializeEmbedding(embedding);
1648
1410
  const rows = this.db.prepare(
1649
1411
  `
1650
- SELECT kv.id, k.text, k.source, kv.distance, k.created_at
1412
+ SELECT kv.id, k.text, k.source, kv.distance, k.created_at, k.importance, k.last_accessed_at
1651
1413
  FROM (
1652
1414
  SELECT id, distance
1653
1415
  FROM knowledge_vec
1654
1416
  WHERE embedding MATCH ? AND k = ?
1655
1417
  ) kv
1656
1418
  JOIN knowledge k ON k.id = kv.id
1419
+ WHERE (k.status = 'active' OR k.status IS NULL)
1657
1420
  `
1658
1421
  ).all(embeddingBuffer, limit);
1659
1422
  return rows.map((row) => ({
@@ -1662,10 +1425,12 @@ var HybridSearch = class {
1662
1425
  source: row.source,
1663
1426
  score: 1 - row.distance,
1664
1427
  vectorScore: 1 - row.distance,
1665
- createdAt: row.created_at ?? void 0
1428
+ createdAt: row.created_at ?? void 0,
1429
+ importance: row.importance ?? 0.5,
1430
+ lastAccessedAt: row.last_accessed_at ?? void 0
1666
1431
  }));
1667
1432
  } catch (error) {
1668
- log5.error({ err: error }, "Vector search error (knowledge)");
1433
+ log4.error({ err: error }, "Vector search error (knowledge)");
1669
1434
  return [];
1670
1435
  }
1671
1436
  }
@@ -1675,10 +1440,11 @@ var HybridSearch = class {
1675
1440
  try {
1676
1441
  const rows = this.db.prepare(
1677
1442
  `
1678
- SELECT k.id, k.text, k.source, rank as score, k.created_at
1443
+ SELECT k.id, k.text, k.source, rank as score, k.created_at, k.importance, k.last_accessed_at
1679
1444
  FROM knowledge_fts kf
1680
1445
  JOIN knowledge k ON k.rowid = kf.rowid
1681
1446
  WHERE knowledge_fts MATCH ?
1447
+ AND (k.status = 'active' OR k.status IS NULL)
1682
1448
  ORDER BY rank
1683
1449
  LIMIT ?
1684
1450
  `
@@ -1686,10 +1452,12 @@ var HybridSearch = class {
1686
1452
  return rows.map((row) => ({
1687
1453
  ...row,
1688
1454
  keywordScore: this.bm25ToScore(row.score),
1689
- createdAt: row.created_at ?? void 0
1455
+ createdAt: row.created_at ?? void 0,
1456
+ importance: row.importance ?? 0.5,
1457
+ lastAccessedAt: row.last_accessed_at ?? void 0
1690
1458
  }));
1691
1459
  } catch (error) {
1692
- log5.error({ err: error }, "FTS5 search error (knowledge)");
1460
+ log4.error({ err: error }, "FTS5 search error (knowledge)");
1693
1461
  return [];
1694
1462
  }
1695
1463
  }
@@ -1728,7 +1496,7 @@ var HybridSearch = class {
1728
1496
  createdAt: row.timestamp ?? void 0
1729
1497
  }));
1730
1498
  } catch (error) {
1731
- log5.error({ err: error }, "Vector search error (messages)");
1499
+ log4.error({ err: error }, "Vector search error (messages)");
1732
1500
  return [];
1733
1501
  }
1734
1502
  }
@@ -1763,7 +1531,7 @@ var HybridSearch = class {
1763
1531
  createdAt: row.timestamp ?? void 0
1764
1532
  }));
1765
1533
  } catch (error) {
1766
- log5.error({ err: error }, "FTS5 search error (messages)");
1534
+ log4.error({ err: error }, "FTS5 search error (messages)");
1767
1535
  return [];
1768
1536
  }
1769
1537
  }
@@ -1784,7 +1552,12 @@ var HybridSearch = class {
1784
1552
  const now = Math.floor(Date.now() / 1e3);
1785
1553
  const results = Array.from(byId.values());
1786
1554
  for (const r of results) {
1787
- if (r.createdAt) {
1555
+ if (r.source !== "message" && r.importance !== void 0) {
1556
+ const refTime = r.lastAccessedAt ?? r.createdAt ?? now;
1557
+ const hoursSince = Math.max(0, (now - refTime) / SECONDS_PER_HOUR);
1558
+ const recency = Math.pow(0.995, hoursSince);
1559
+ r.score = 0.4 * r.score + 0.3 * r.importance + 0.3 * recency;
1560
+ } else if (r.createdAt) {
1788
1561
  const ageDays = Math.max(0, (now - r.createdAt) / SECONDS_PER_DAY);
1789
1562
  const boost = 1 / (1 + ageDays * RECENCY_DECAY_FACTOR);
1790
1563
  r.score *= 1 - RECENCY_WEIGHT + RECENCY_WEIGHT * boost;
@@ -1802,7 +1575,7 @@ var HybridSearch = class {
1802
1575
  };
1803
1576
 
1804
1577
  // src/memory/search/context.ts
1805
- var log6 = createLogger("Memory");
1578
+ var log5 = createLogger("Memory");
1806
1579
  function reorderForEdges(items) {
1807
1580
  if (items.length <= 2) return items;
1808
1581
  const result = new Array(items.length);
@@ -1851,7 +1624,7 @@ var ContextBuilder = class {
1851
1624
  recentTgMessages.filter((m) => m.text && m.text.length > 0).map((m) => m.text)
1852
1625
  );
1853
1626
  const knowledgePromise = includeAgentMemory ? this.hybridSearch.searchKnowledge(query, queryEmbedding, { limit: maxRelevantChunks }).catch((error) => {
1854
- log6.warn({ err: error }, "Knowledge search failed");
1627
+ log5.warn({ err: error }, "Knowledge search failed");
1855
1628
  return [];
1856
1629
  }) : Promise.resolve([]);
1857
1630
  const { afterTimestamp } = parseTemporalIntent(query);
@@ -1860,7 +1633,7 @@ var ContextBuilder = class {
1860
1633
  limit: maxRelevantChunks,
1861
1634
  afterTimestamp
1862
1635
  }).catch((error) => {
1863
- log6.warn({ err: error }, "Feed search failed");
1636
+ log5.warn({ err: error }, "Feed search failed");
1864
1637
  return [];
1865
1638
  }) : Promise.resolve([]);
1866
1639
  const [knowledgeResults, feedResults] = await Promise.all([knowledgePromise, feedPromise]);
@@ -1888,7 +1661,7 @@ var ContextBuilder = class {
1888
1661
  }
1889
1662
  }
1890
1663
  } catch (error) {
1891
- log6.warn({ err: error }, "Global feed search failed");
1664
+ log5.warn({ err: error }, "Global feed search failed");
1892
1665
  }
1893
1666
  }
1894
1667
  if (relevantFeed.length === 0 && recentTgMessages.length > 0) {
@@ -1927,11 +1700,6 @@ function initializeMemory(config) {
1927
1700
  }
1928
1701
 
1929
1702
  export {
1930
- JOURNAL_SCHEMA,
1931
- USED_TRANSACTIONS_SCHEMA,
1932
- openModuleDb,
1933
- createDbWrapper,
1934
- migrateFromMainDb,
1935
1703
  ensureSchema,
1936
1704
  ensureVectorTables,
1937
1705
  getSchemaVersion,
@@ -1941,9 +1709,7 @@ export {
1941
1709
  MemoryDatabase,
1942
1710
  getDatabase,
1943
1711
  closeDatabase,
1944
- KnowledgeIndexer,
1945
1712
  SessionStore,
1946
- MessageStore,
1947
1713
  ChatStore,
1948
1714
  UserStore,
1949
1715
  parseTemporalIntent,