@tznthou/ccrecall 0.4.7 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +73 -57
  2. package/README_ZH.md +73 -58
  3. package/dist/api/routes.d.ts +0 -10
  4. package/dist/api/routes.d.ts.map +1 -1
  5. package/dist/api/routes.js +4 -354
  6. package/dist/api/routes.js.map +1 -1
  7. package/dist/api/server.js +3 -3
  8. package/dist/api/server.js.map +1 -1
  9. package/dist/core/database.d.ts +14 -49
  10. package/dist/core/database.d.ts.map +1 -1
  11. package/dist/core/database.js +113 -225
  12. package/dist/core/database.js.map +1 -1
  13. package/dist/core/indexer.d.ts.map +1 -1
  14. package/dist/core/indexer.js +0 -1
  15. package/dist/core/indexer.js.map +1 -1
  16. package/dist/core/maintenance-coordinator.d.ts +3 -9
  17. package/dist/core/maintenance-coordinator.d.ts.map +1 -1
  18. package/dist/core/maintenance-coordinator.js +4 -24
  19. package/dist/core/maintenance-coordinator.js.map +1 -1
  20. package/dist/core/summarizer.d.ts.map +1 -1
  21. package/dist/core/summarizer.js +0 -22
  22. package/dist/core/summarizer.js.map +1 -1
  23. package/dist/core/types.d.ts +0 -87
  24. package/dist/core/types.d.ts.map +1 -1
  25. package/dist/core/types.js.map +1 -1
  26. package/dist/index.js +0 -16
  27. package/dist/index.js.map +1 -1
  28. package/package.json +1 -1
  29. package/dist/cli/journal.d.ts +0 -11
  30. package/dist/cli/journal.d.ts.map +0 -1
  31. package/dist/cli/journal.js +0 -111
  32. package/dist/cli/journal.js.map +0 -1
  33. package/dist/core/lint.d.ts +0 -17
  34. package/dist/core/lint.d.ts.map +0 -1
  35. package/dist/core/lint.js +0 -51
  36. package/dist/core/lint.js.map +0 -1
  37. package/dist/core/outcome-extractor.d.ts +0 -6
  38. package/dist/core/outcome-extractor.d.ts.map +0 -1
  39. package/dist/core/outcome-extractor.js +0 -39
  40. package/dist/core/outcome-extractor.js.map +0 -1
  41. package/dist/core/outcome-scorer.d.ts +0 -8
  42. package/dist/core/outcome-scorer.d.ts.map +0 -1
  43. package/dist/core/outcome-scorer.js +0 -103
  44. package/dist/core/outcome-scorer.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/core/database.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/core/database.ts"],"names":[],"mappings":"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"}
@@ -4,10 +4,21 @@ import { createHash } from 'node:crypto';
4
4
  import { copyFileSync, existsSync, mkdirSync } from 'node:fs';
5
5
  import path from 'node:path';
6
6
  import { scrubErrorMessage } from './log-safe.js';
7
+ /** 64-bit signed hash for message_uuids (v24 dual-hash schema). First 8 bytes
8
+ * of SHA-256 read as a signed BigInt — exactly the SQLite INTEGER range, so
9
+ * uuid_hash doubles as the rowid (zero autoindex). Collision odds at ~400k
10
+ * rows ≈ 4e-9; a collision merely makes one replayed message skip indexing.
11
+ *
12
+ * ⚠️ Reading these values back REQUIRES `.safeIntegers(true)` on the statement:
13
+ * better-sqlite3 otherwise returns a lossy JS number for |v| > 2^53 and any
14
+ * Map<bigint, …> reverse lookup silently misses (dedup would silently die). */
15
+ export function hash64(s) {
16
+ return createHash('sha256').update(s).digest().readBigInt64BE(0);
17
+ }
7
18
  /** sessions 資料表的完整欄位 SELECT 子句(getSessions / getSessionById 共用) */
8
19
  const SESSION_SELECT_COLUMNS = `id, project_id, title, message_count, started_at, ended_at, archived,
9
20
  summary_text, intent_text, outcome_status, duration_seconds, active_duration_seconds, summary_version,
10
- tags, files_touched, tools_used, total_input_tokens, total_output_tokens, harvest_text`;
21
+ tags, files_touched, tools_used, total_input_tokens, total_output_tokens`;
11
22
  function mapSessionRow(r) {
12
23
  return {
13
24
  id: r.id,
@@ -28,7 +39,6 @@ function mapSessionRow(r) {
28
39
  toolsUsed: r.tools_used,
29
40
  totalInputTokens: r.total_input_tokens,
30
41
  totalOutputTokens: r.total_output_tokens,
31
- harvestText: r.harvest_text,
32
42
  };
33
43
  }
34
44
  function mapMemoryRow(r) {
@@ -51,42 +61,6 @@ function mapTopicRow(r) {
51
61
  lastTouched: r.last_touched,
52
62
  };
53
63
  }
54
- function mapCheckpointRow(r) {
55
- return {
56
- id: r.id,
57
- sessionId: r.session_id,
58
- projectId: r.project_id,
59
- snapshotText: r.snapshot_text,
60
- createdAt: r.created_at,
61
- };
62
- }
63
- function mapJournalRow(r) {
64
- return {
65
- id: r.id,
66
- sessionId: r.session_id,
67
- messageId: r.message_id,
68
- content: r.content,
69
- contentHash: r.content_hash,
70
- score: r.score,
71
- reasonsJson: r.reasons_json,
72
- status: r.status,
73
- expiresAt: r.expires_at,
74
- promotedMemoryId: r.promoted_memory_id,
75
- projectId: r.project_id,
76
- createdAt: r.created_at,
77
- };
78
- }
79
- function mapJournalPreviewRow(r) {
80
- return {
81
- id: r.id,
82
- sessionId: r.session_id,
83
- score: r.score,
84
- reasonsJson: r.reasons_json,
85
- contentPreview: r.content_preview,
86
- projectId: r.project_id,
87
- createdAt: r.created_at,
88
- };
89
- }
90
64
  /** 重建 message_content / message_archive 表,修正 FK 指向 messages */
91
65
  function rebuildSideTables(db) {
92
66
  db.exec(`
@@ -655,6 +629,48 @@ const migrations = [
655
629
  `);
656
630
  },
657
631
  },
632
+ {
633
+ version: 24,
634
+ description: 'knife-field (v0.5.0): drop session_journal/session_checkpoints/sessions.harvest_text; rebuild message_uuids as dual 64-bit hash (73.6MB → ~14MB)',
635
+ up: (db) => {
636
+ // Dead-pipeline tables — the journal DLQ recorded 0 promotions in its
637
+ // entire history (2026-06-10 audit) and /session/checkpoint had no caller.
638
+ db.exec(`
639
+ DROP TABLE IF EXISTS session_journal;
640
+ DROP TABLE IF EXISTS session_checkpoints;
641
+ `);
642
+ const sessionCols = db.prepare('PRAGMA table_info(sessions)').all();
643
+ if (sessionCols.some(c => c.name === 'harvest_text')) {
644
+ db.exec('ALTER TABLE sessions DROP COLUMN harvest_text;');
645
+ }
646
+ // message_uuids: TEXT uuid PK (36 chars ×3 b-trees) → dual 64-bit hash.
647
+ // uuid_hash INTEGER PRIMARY KEY is the rowid alias — zero autoindex.
648
+ // Skip when already dual-hash (idempotency; also covers a repaired DB
649
+ // where initSchema recreated the table in its final shape).
650
+ const uuidCols = db.prepare('PRAGMA table_info(message_uuids)').all();
651
+ if (uuidCols.some(c => c.name === 'uuid_hash'))
652
+ return;
653
+ db.exec(`
654
+ CREATE TABLE message_uuids_new (
655
+ uuid_hash INTEGER PRIMARY KEY,
656
+ session_hash INTEGER NOT NULL
657
+ );
658
+ `);
659
+ // JS-side rehash: hash64 lives here, not in SQLite. ~400k rows over the
660
+ // sync API completes in seconds. INSERT OR IGNORE keeps first-writer-wins
661
+ // on the astronomically unlikely 64-bit collision.
662
+ const insert = db.prepare('INSERT OR IGNORE INTO message_uuids_new (uuid_hash, session_hash) VALUES (?, ?)');
663
+ const rows = db.prepare('SELECT uuid, session_id FROM message_uuids').all();
664
+ for (const r of rows) {
665
+ insert.run(hash64(r.uuid), hash64(r.session_id));
666
+ }
667
+ db.exec(`
668
+ DROP TABLE message_uuids;
669
+ ALTER TABLE message_uuids_new RENAME TO message_uuids;
670
+ CREATE INDEX idx_message_uuids_session ON message_uuids(session_hash);
671
+ `);
672
+ },
673
+ },
658
674
  ];
659
675
  export class Database {
660
676
  db;
@@ -872,14 +888,24 @@ export class Database {
872
888
  }
873
889
  }
874
890
  else {
875
- // v20+ baseline — message_uuids carries the UUID dedup set.
891
+ // v20+ baseline — message_uuids carries the UUID dedup set. DDL is the
892
+ // v24 dual-hash shape: on a v20–v23 DB the table already exists so this
893
+ // is a no-op (v24 migration handles the rebuild); it only materialises
894
+ // when repairing a DB whose table went missing, and then the v24
895
+ // migration's shape check skips the rebuild.
876
896
  this.db.exec(`
877
897
  CREATE TABLE IF NOT EXISTS message_uuids (
878
- uuid TEXT PRIMARY KEY,
879
- session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE
898
+ uuid_hash INTEGER PRIMARY KEY,
899
+ session_hash INTEGER NOT NULL
880
900
  );
881
- CREATE INDEX IF NOT EXISTS idx_message_uuids_session ON message_uuids(session_id);
882
901
  `);
902
+ // Index only when the table is dual-hash: a v20–v23 table awaiting the
903
+ // v24 rebuild has no session_hash column, and indexing it here would
904
+ // throw. The rebuild recreates the index itself.
905
+ const uuidCols = this.db.prepare('PRAGMA table_info(message_uuids)').all();
906
+ if (uuidCols.some(c => c.name === 'session_hash')) {
907
+ this.db.exec('CREATE INDEX IF NOT EXISTS idx_message_uuids_session ON message_uuids(session_hash);');
908
+ }
883
909
  }
884
910
  }
885
911
  /** 依序執行尚未套用的 migrations */
@@ -956,18 +982,31 @@ export class Database {
956
982
  return row?.file_mtime ?? null;
957
983
  }
958
984
  getSessions(projectId) {
985
+ // instr(id,'/') mirrors getLastSession's registry-timing guard (v0.4.8):
986
+ // a subagent row can momentarily lack its subagent_sessions registration,
987
+ // and composite "<parent>/agent-…" ids are never main sessions.
959
988
  const rows = this.db.prepare(`SELECT ${SESSION_SELECT_COLUMNS}
960
989
  FROM sessions
961
990
  WHERE project_id = ?
962
991
  AND id ${Database.EXCLUDE_SUBAGENTS}
992
+ AND instr(id, '/') = 0
963
993
  ORDER BY started_at DESC`).all(projectId);
964
994
  return rows.map(mapSessionRow);
965
995
  }
966
996
  getLastSession(projectId) {
997
+ // instr(id,'/') guards the registry-timing window (observed 2026-07-13):
998
+ // a subagent row can exist in sessions while its subagent_sessions row is
999
+ // momentarily absent, so EXCLUDE_SUBAGENTS alone lets "<parent>/agent-…"
1000
+ // shadow the real last session. Composite ids are never main sessions —
1001
+ // main ids come from top-level JSONL filenames, which cannot contain '/'.
1002
+ // archived rows are excluded too: their JSONL is gone from disk, so they
1003
+ // cannot be "the session that just closed" this endpoint exists to find.
967
1004
  const row = this.db.prepare(`SELECT ${SESSION_SELECT_COLUMNS}
968
1005
  FROM sessions
969
1006
  WHERE project_id = ?
970
1007
  AND id ${Database.EXCLUDE_SUBAGENTS}
1008
+ AND instr(id, '/') = 0
1009
+ AND archived = 0
971
1010
  ORDER BY started_at DESC
972
1011
  LIMIT 1`).get(projectId);
973
1012
  return row ? mapSessionRow(row) : null;
@@ -1037,11 +1076,12 @@ export class Database {
1037
1076
  deleteSubagentSessions(parentSessionId) {
1038
1077
  this.db.prepare('DELETE FROM subagent_sessions WHERE parent_session_id = ?').run(parentSessionId);
1039
1078
  }
1040
- /** 刪除單一 subagent session(session_files / message_uuids 會經 FK CASCADE 清除) */
1079
+ /** 刪除單一 subagent session。v24: message_uuids 無 FK CASCADE,手動清除。 */
1041
1080
  deleteSubagentSession(subagentId) {
1042
1081
  const doDelete = this.db.transaction(() => {
1043
1082
  this.db.prepare('DELETE FROM session_files WHERE session_id = ?').run(subagentId);
1044
1083
  this.db.prepare('DELETE FROM sessions WHERE id = ?').run(subagentId);
1084
+ this.db.prepare('DELETE FROM message_uuids WHERE session_hash = ?').run(hash64(subagentId));
1045
1085
  this.db.prepare('DELETE FROM subagent_sessions WHERE id = ?').run(subagentId);
1046
1086
  });
1047
1087
  doDelete();
@@ -1067,15 +1107,27 @@ export class Database {
1067
1107
  return map;
1068
1108
  }
1069
1109
  // ── UUID dedup helper ──
1070
- /** 查詢 DB 中已存在的 uuid(用於跨 session 去重 resumed session replay) */
1110
+ /** 查詢 DB 中已存在的 uuid(用於跨 session 去重 resumed session replay)。
1111
+ * v24: message_uuids 只存 64-bit hash,查詢以 hash 比對、以 Map 反查還原
1112
+ * 原 uuid — 簽名與回傳不變,indexer 端零改動。 */
1071
1113
  getExistingUuids(uuids, excludeSessionId) {
1072
1114
  const result = new Set();
1115
+ const excludeHash = hash64(excludeSessionId);
1073
1116
  for (let i = 0; i < uuids.length; i += 500) {
1074
1117
  const chunk = uuids.slice(i, i + 500);
1075
- const placeholders = chunk.map(() => '?').join(',');
1076
- const rows = this.db.prepare(`SELECT uuid FROM message_uuids WHERE session_id != ? AND uuid IN (${placeholders})`).all(excludeSessionId, ...chunk);
1077
- for (const r of rows)
1078
- result.add(r.uuid);
1118
+ const byHash = new Map();
1119
+ for (const u of chunk)
1120
+ byHash.set(hash64(u), u);
1121
+ const hashes = [...byHash.keys()];
1122
+ const placeholders = hashes.map(() => '?').join(',');
1123
+ // safeIntegers is load-bearing: without it uuid_hash values beyond 2^53
1124
+ // come back as lossy numbers and the Map lookup misses every row.
1125
+ const rows = this.db.prepare(`SELECT uuid_hash FROM message_uuids WHERE session_hash != ? AND uuid_hash IN (${placeholders})`).safeIntegers(true).all(excludeHash, ...hashes);
1126
+ for (const r of rows) {
1127
+ const uuid = byHash.get(r.uuid_hash);
1128
+ if (uuid !== undefined)
1129
+ result.add(uuid);
1130
+ }
1079
1131
  }
1080
1132
  return result;
1081
1133
  }
@@ -1089,6 +1141,10 @@ export class Database {
1089
1141
  }
1090
1142
  this.db.prepare('DELETE FROM session_files WHERE session_id = ?').run(params.sessionId);
1091
1143
  this.db.prepare('DELETE FROM sessions WHERE id = ?').run(params.sessionId);
1144
+ // v24: message_uuids no longer has an FK to sessions (hash columns can't
1145
+ // reference TEXT ids) — clear this session's registrations manually so a
1146
+ // reindex re-registers from scratch instead of stacking stale hashes.
1147
+ this.db.prepare('DELETE FROM message_uuids WHERE session_hash = ?').run(hash64(params.sessionId));
1092
1148
  this.upsertProject(params.projectId, params.projectDisplayName);
1093
1149
  // 計算 token 彙總
1094
1150
  let totalInput = 0;
@@ -1102,9 +1158,9 @@ export class Database {
1102
1158
  const insertResult = this.db.prepare(`
1103
1159
  INSERT INTO sessions (id, project_id, title, message_count, file_path, file_size, file_mtime, started_at, ended_at,
1104
1160
  summary_text, intent_text, outcome_status, outcome_signals, duration_seconds, active_duration_seconds, summary_version,
1105
- tags, files_touched, tools_used, total_input_tokens, total_output_tokens, harvest_text)
1106
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
1107
- `).run(params.sessionId, params.projectId, params.title, params.messageCount, params.filePath, params.fileSize, params.fileMtime, params.startedAt, params.endedAt, params.summaryText ?? null, params.intentText ?? null, params.outcomeStatus ?? null, params.outcomeSignals ?? null, params.durationSeconds ?? null, params.activeDurationSeconds ?? null, params.summaryVersion ?? null, params.tags ?? null, params.filesTouched ?? null, params.toolsUsed ?? null, totalInput || null, totalOutput || null, params.harvestText ?? null);
1161
+ tags, files_touched, tools_used, total_input_tokens, total_output_tokens)
1162
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
1163
+ `).run(params.sessionId, params.projectId, params.title, params.messageCount, params.filePath, params.fileSize, params.fileMtime, params.startedAt, params.endedAt, params.summaryText ?? null, params.intentText ?? null, params.outcomeStatus ?? null, params.outcomeSignals ?? null, params.durationSeconds ?? null, params.activeDurationSeconds ?? null, params.summaryVersion ?? null, params.tags ?? null, params.filesTouched ?? null, params.toolsUsed ?? null, totalInput || null, totalOutput || null);
1108
1164
  // 新增 sessions_fts 條目(用 INSERT 回傳的 rowid 避免多餘查詢)
1109
1165
  this.db.prepare('INSERT INTO sessions_fts(rowid, title, tags, files_touched, summary_text, intent_text) VALUES (?, ?, ?, ?, ?, ?)').run(insertResult.lastInsertRowid, params.title ?? '', params.tags ?? '', params.filesTouched ?? '', params.summaryText ?? '', params.intentText ?? '');
1110
1166
  // 寫入 session_files
@@ -1117,12 +1173,14 @@ export class Database {
1117
1173
  insertFile.run(params.sessionId, f.filePath, f.operation, f.count, f.firstSeenSeq, f.lastSeenSeq);
1118
1174
  }
1119
1175
  }
1120
- // message_uuids: 寫入 uuid 登記表,供跨 session replay dedup 查詢。
1121
- // 舊 session row 已由上面的 DELETE FROM sessions 透過 FK CASCADE 自動清除。
1122
- const insertUuid = this.db.prepare('INSERT OR IGNORE INTO message_uuids (uuid, session_id) VALUES (?, ?)');
1176
+ // message_uuids: 寫入 uuid 登記表(雙 hash),供跨 session replay dedup 查詢。
1177
+ // 舊登記已在本 transaction 開頭手動 DELETE。INSERT OR IGNORE 保持「先寫者
1178
+ // 擁有 uuid」語義(uuid_hash 為 PK;他 session 已登記或本 session 重複皆略過)。
1179
+ const insertUuid = this.db.prepare('INSERT OR IGNORE INTO message_uuids (uuid_hash, session_hash) VALUES (?, ?)');
1180
+ const sessionHash = hash64(params.sessionId);
1123
1181
  for (const m of params.messages) {
1124
1182
  if (m.uuid != null) {
1125
- insertUuid.run(m.uuid, params.sessionId);
1183
+ insertUuid.run(hash64(m.uuid), sessionHash);
1126
1184
  }
1127
1185
  }
1128
1186
  });
@@ -1386,101 +1444,6 @@ export class Database {
1386
1444
  `).run(input.sessionId, input.messageId, input.content, input.type, input.confidence ?? 0.8, projectId, key);
1387
1445
  return Number(info.lastInsertRowid);
1388
1446
  }
1389
- // ─────────────────────────────────────────────────────────────
1390
- // session_journal DAO (issue #21 P1)
1391
- // 低信任 harvest 候選的寫入入口; manual recall_save 仍走 saveMemory()。
1392
- //
1393
- // Trust boundary: queryMemories / getMemoriesByTopics 故意只查 memories table,
1394
- // 不 union session_journal — unpromoted journal entries 是 low-trust,不該污染
1395
- // recall 結果。promote 路徑 (C4) 把 journal entry 搬到 memories 後才會被 recall
1396
- // 看到。若未來修改 query 邏輯需動到 journal,務必保持這條 invariant。
1397
- // ─────────────────────────────────────────────────────────────
1398
- /** 寫入 journal 條目。content_hash 內部以 SHA-256 計算; 同 hash 第二次 INSERT
1399
- * 會被 UNIQUE INDEX 擋下並回傳 0 (idempotency)。
1400
- *
1401
- * 注意: better-sqlite3 的 INSERT OR IGNORE 在 IGNORE'd 時, lastInsertRowid
1402
- * 不會歸零 (保留前次成功 insert 的 rowid)。所以用 info.changes 判 dedup。 */
1403
- saveJournalEntry(input) {
1404
- const hash = createHash('sha256').update(input.content).digest('hex');
1405
- const info = this.db.prepare(`
1406
- INSERT OR IGNORE INTO session_journal
1407
- (session_id, message_id, content, content_hash, score, reasons_json, project_id)
1408
- VALUES (?, ?, ?, ?, ?, ?, ?)
1409
- `).run(input.sessionId ?? null, input.messageId ?? null, input.content, hash, input.score, input.reasonsJson ?? null, input.projectId ?? null);
1410
- return info.changes === 0 ? 0 : Number(info.lastInsertRowid);
1411
- }
1412
- /** 給 /health endpoint 用; promotion path manual-only,user 看 pending 數決定是否 invoke。 */
1413
- getJournalPendingCount() {
1414
- const row = this.db.prepare("SELECT COUNT(*) AS c FROM session_journal WHERE status = 'pending'").get();
1415
- return row.c;
1416
- }
1417
- getJournalEntry(id) {
1418
- const row = this.db.prepare(`
1419
- SELECT id, session_id, message_id, content, content_hash, score,
1420
- reasons_json, status, expires_at, promoted_memory_id,
1421
- project_id, created_at
1422
- FROM session_journal WHERE id = ?
1423
- `).get(id);
1424
- return row ? mapJournalRow(row) : null;
1425
- }
1426
- /** 升級 journal entry 為 promoted; caller 已透過 saveMemory 寫入 memories table
1427
- * 並拿到 memoryId,本方法只更新 journal 的 status + 回填 promoted_memory_id。
1428
- * 回 false 表示 entry 不存在或已不在 'pending' 狀態 (idempotent)。 */
1429
- promoteJournalEntry(id, memoryId) {
1430
- const info = this.db.prepare(`
1431
- UPDATE session_journal
1432
- SET status = 'promoted', promoted_memory_id = ?
1433
- WHERE id = ? AND status = 'pending'
1434
- `).run(memoryId, id);
1435
- return info.changes > 0;
1436
- }
1437
- /** List pending journal entries (newest first) with content preview for
1438
- * surfacing on the manual promotion path. content 截 200 chars 避免 response
1439
- * blob 過大; caller 想看完整內容可走 promote 看 memories 或直接 sqlite3。 */
1440
- getPendingJournalEntries(limit) {
1441
- const cappedLimit = Math.min(Math.max(limit, 1), 100);
1442
- const rows = this.db.prepare(`
1443
- SELECT id, session_id, score, reasons_json,
1444
- substr(content, 1, 200) AS content_preview,
1445
- project_id, created_at
1446
- FROM session_journal
1447
- WHERE status = 'pending'
1448
- ORDER BY created_at DESC, id DESC
1449
- LIMIT ?
1450
- `).all(cappedLimit);
1451
- return rows.map(mapJournalPreviewRow);
1452
- }
1453
- /** 標記 entry 為 rejected, expires_at 設為 now+7d (decay sweep 才真的刪除)。
1454
- * caller 傳 expiresAt ISO string; 回 false 表示 entry 不存在或非 pending。 */
1455
- rejectJournalEntry(id, expiresAt) {
1456
- const info = this.db.prepare(`
1457
- UPDATE session_journal
1458
- SET status = 'rejected', expires_at = ?
1459
- WHERE id = ? AND status = 'pending'
1460
- `).run(expiresAt, id);
1461
- return info.changes > 0;
1462
- }
1463
- /** Decay sweep (P1 step 7):
1464
- * - rejected entries past expires_at → DELETE
1465
- * - pending entries older than 30 days → DELETE
1466
- * promoted entries 留著作 audit trail (有 promoted_memory_id 指 memories.id)。
1467
- * manual memories 在 memories table,本方法完全不碰。 */
1468
- sweepJournal(now = new Date()) {
1469
- const nowIso = now.toISOString();
1470
- const thirtyDaysAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000).toISOString();
1471
- const rejectedInfo = this.db.prepare(`
1472
- DELETE FROM session_journal
1473
- WHERE status = 'rejected' AND expires_at IS NOT NULL AND expires_at < ?
1474
- `).run(nowIso);
1475
- const pendingInfo = this.db.prepare(`
1476
- DELETE FROM session_journal
1477
- WHERE status = 'pending' AND created_at < ?
1478
- `).run(thirtyDaysAgo);
1479
- return {
1480
- rejectedDeleted: rejectedInfo.changes,
1481
- pendingDeleted: pendingInfo.changes,
1482
- };
1483
- }
1484
1447
  queryMemories(query, limit, projectId) {
1485
1448
  const rawQuery = query;
1486
1449
  const q = Database.fts5QuoteIfNeeded(query);
@@ -1901,23 +1864,6 @@ export class Database {
1901
1864
  });
1902
1865
  run();
1903
1866
  }
1904
- static TOPIC_ORDER_BY = {
1905
- mention: 'mention_count DESC, last_touched DESC',
1906
- recent: 'last_touched DESC',
1907
- stale: 'last_touched ASC',
1908
- };
1909
- getKnowledgeMap(projectId, opts = {}) {
1910
- const { limit = 50, sortBy = 'mention' } = opts;
1911
- const cappedLimit = Math.min(limit, 500);
1912
- const rows = this.db.prepare(`
1913
- SELECT topic_key, project_id, mention_count, last_touched
1914
- FROM knowledge_map
1915
- WHERE project_id = ?
1916
- ORDER BY ${Database.TOPIC_ORDER_BY[sortBy]}
1917
- LIMIT ?
1918
- `).all(projectId, cappedLimit);
1919
- return rows.map(mapTopicRow);
1920
- }
1921
1867
  getMemoriesByTopics(projectId, topicKeys, limit) {
1922
1868
  if (topicKeys.length === 0)
1923
1869
  return [];
@@ -1954,63 +1900,5 @@ export class Database {
1954
1900
  `).get(topicKey, projectId);
1955
1901
  return row ? mapTopicRow(row) : null;
1956
1902
  }
1957
- /** 共現 topics(與目標共享 session 或 memory),按共現次數排序。
1958
- project_id 透過 JOIN sessions 決定,避免 memory_topics 過時的 project_id 汙染。 */
1959
- getRelatedTopics(topicKey, projectId, limit) {
1960
- const cappedLimit = Math.min(limit, 50);
1961
- const rows = this.db.prepare(`
1962
- SELECT k, COUNT(*) AS c FROM (
1963
- SELECT st2.topic_key AS k
1964
- FROM session_topics st1
1965
- JOIN session_topics st2 ON st1.session_id = st2.session_id AND st2.topic_key != st1.topic_key
1966
- JOIN sessions s ON s.id = st1.session_id
1967
- WHERE st1.topic_key = ? AND s.project_id = ? AND s.id ${Database.EXCLUDE_SUBAGENTS}
1968
- UNION ALL
1969
- SELECT mt2.topic_key AS k
1970
- FROM memory_topics mt1
1971
- JOIN memory_topics mt2 ON mt1.memory_id = mt2.memory_id AND mt2.topic_key != mt1.topic_key
1972
- JOIN memories m ON m.id = mt1.memory_id
1973
- JOIN sessions s ON s.id = m.session_id
1974
- WHERE mt1.topic_key = ? AND s.project_id = ? AND s.id ${Database.EXCLUDE_SUBAGENTS}
1975
- )
1976
- GROUP BY k ORDER BY c DESC, k ASC LIMIT ?
1977
- `).all(topicKey, projectId, topicKey, projectId, cappedLimit);
1978
- return rows.map(r => r.k);
1979
- }
1980
- getKnowledgeMapCounts(projectId) {
1981
- const topics = this.db.prepare('SELECT COUNT(*) AS c FROM knowledge_map WHERE project_id = ?').get(projectId);
1982
- const mems = this.db.prepare(`
1983
- SELECT COUNT(*) AS c FROM memories m
1984
- JOIN sessions s ON s.id = m.session_id
1985
- WHERE s.project_id = ? AND s.id ${Database.EXCLUDE_SUBAGENTS}
1986
- `).get(projectId);
1987
- const sess = this.db.prepare(`
1988
- SELECT COUNT(*) AS c FROM sessions WHERE project_id = ? AND id ${Database.EXCLUDE_SUBAGENTS}
1989
- `).get(projectId);
1990
- return { totalTopics: topics.c, totalMemories: mems.c, totalSessions: sess.c };
1991
- }
1992
- // ── Session Checkpoints (Phase 3d) ──
1993
- saveCheckpoint(sessionId, projectId, snapshotText) {
1994
- const info = this.db.prepare(`
1995
- INSERT INTO session_checkpoints (session_id, project_id, snapshot_text)
1996
- VALUES (?, ?, ?)
1997
- `).run(sessionId, projectId, snapshotText);
1998
- return Number(info.lastInsertRowid);
1999
- }
2000
- getCheckpointById(id) {
2001
- const row = this.db.prepare(`
2002
- SELECT id, session_id, project_id, snapshot_text, created_at
2003
- FROM session_checkpoints WHERE id = ?
2004
- `).get(id);
2005
- return row ? mapCheckpointRow(row) : null;
2006
- }
2007
- getCheckpointsBySessionId(sessionId) {
2008
- const rows = this.db.prepare(`
2009
- SELECT id, session_id, project_id, snapshot_text, created_at
2010
- FROM session_checkpoints WHERE session_id = ?
2011
- ORDER BY created_at DESC, id DESC
2012
- `).all(sessionId);
2013
- return rows.map(mapCheckpointRow);
2014
- }
2015
1903
  }
2016
1904
  //# sourceMappingURL=database.js.map