@vortex-os/memory-extended 0.5.1

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 (181) hide show
  1. package/README.md +244 -0
  2. package/dist/consolidate/index.d.ts +7 -0
  3. package/dist/consolidate/index.d.ts.map +1 -0
  4. package/dist/consolidate/index.js +4 -0
  5. package/dist/consolidate/index.js.map +1 -0
  6. package/dist/consolidate/proposer.d.ts +43 -0
  7. package/dist/consolidate/proposer.d.ts.map +1 -0
  8. package/dist/consolidate/proposer.js +276 -0
  9. package/dist/consolidate/proposer.js.map +1 -0
  10. package/dist/consolidate/query.d.ts +32 -0
  11. package/dist/consolidate/query.d.ts.map +1 -0
  12. package/dist/consolidate/query.js +40 -0
  13. package/dist/consolidate/query.js.map +1 -0
  14. package/dist/consolidate/store.d.ts +21 -0
  15. package/dist/consolidate/store.d.ts.map +1 -0
  16. package/dist/consolidate/store.js +91 -0
  17. package/dist/consolidate/store.js.map +1 -0
  18. package/dist/consolidate/types.d.ts +68 -0
  19. package/dist/consolidate/types.d.ts.map +1 -0
  20. package/dist/consolidate/types.js +2 -0
  21. package/dist/consolidate/types.js.map +1 -0
  22. package/dist/index.d.ts +7 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +7 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/internal/frontmatter.d.ts +6 -0
  27. package/dist/internal/frontmatter.d.ts.map +1 -0
  28. package/dist/internal/frontmatter.js +38 -0
  29. package/dist/internal/frontmatter.js.map +1 -0
  30. package/dist/internal/proactive-curator-helpers.d.ts +171 -0
  31. package/dist/internal/proactive-curator-helpers.d.ts.map +1 -0
  32. package/dist/internal/proactive-curator-helpers.js +162 -0
  33. package/dist/internal/proactive-curator-helpers.js.map +1 -0
  34. package/dist/mcp/document-tools.d.ts +144 -0
  35. package/dist/mcp/document-tools.d.ts.map +1 -0
  36. package/dist/mcp/document-tools.js +319 -0
  37. package/dist/mcp/document-tools.js.map +1 -0
  38. package/dist/mcp/index.d.ts +34 -0
  39. package/dist/mcp/index.d.ts.map +1 -0
  40. package/dist/mcp/index.js +29 -0
  41. package/dist/mcp/index.js.map +1 -0
  42. package/dist/mcp/install.d.ts +72 -0
  43. package/dist/mcp/install.d.ts.map +1 -0
  44. package/dist/mcp/install.js +92 -0
  45. package/dist/mcp/install.js.map +1 -0
  46. package/dist/mcp/memory-tools.d.ts +101 -0
  47. package/dist/mcp/memory-tools.d.ts.map +1 -0
  48. package/dist/mcp/memory-tools.js +105 -0
  49. package/dist/mcp/memory-tools.js.map +1 -0
  50. package/dist/mcp/recall-tool.d.ts +52 -0
  51. package/dist/mcp/recall-tool.d.ts.map +1 -0
  52. package/dist/mcp/recall-tool.js +60 -0
  53. package/dist/mcp/recall-tool.js.map +1 -0
  54. package/dist/mcp/server.d.ts +32 -0
  55. package/dist/mcp/server.d.ts.map +1 -0
  56. package/dist/mcp/server.js +113 -0
  57. package/dist/mcp/server.js.map +1 -0
  58. package/dist/recall/engine.d.ts +38 -0
  59. package/dist/recall/engine.d.ts.map +1 -0
  60. package/dist/recall/engine.js +113 -0
  61. package/dist/recall/engine.js.map +1 -0
  62. package/dist/recall/index.d.ts +22 -0
  63. package/dist/recall/index.d.ts.map +1 -0
  64. package/dist/recall/index.js +20 -0
  65. package/dist/recall/index.js.map +1 -0
  66. package/dist/recall/intent.d.ts +24 -0
  67. package/dist/recall/intent.d.ts.map +1 -0
  68. package/dist/recall/intent.js +95 -0
  69. package/dist/recall/intent.js.map +1 -0
  70. package/dist/recall/render.d.ts +11 -0
  71. package/dist/recall/render.d.ts.map +1 -0
  72. package/dist/recall/render.js +23 -0
  73. package/dist/recall/render.js.map +1 -0
  74. package/dist/recall/types.d.ts +72 -0
  75. package/dist/recall/types.d.ts.map +1 -0
  76. package/dist/recall/types.js +2 -0
  77. package/dist/recall/types.js.map +1 -0
  78. package/dist/sessionArchive/adapters/claude-code.d.ts +3 -0
  79. package/dist/sessionArchive/adapters/claude-code.d.ts.map +1 -0
  80. package/dist/sessionArchive/adapters/claude-code.js +276 -0
  81. package/dist/sessionArchive/adapters/claude-code.js.map +1 -0
  82. package/dist/sessionArchive/adapters/claude-desktop.d.ts +3 -0
  83. package/dist/sessionArchive/adapters/claude-desktop.d.ts.map +1 -0
  84. package/dist/sessionArchive/adapters/claude-desktop.js +234 -0
  85. package/dist/sessionArchive/adapters/claude-desktop.js.map +1 -0
  86. package/dist/sessionArchive/adapters/codex.d.ts +3 -0
  87. package/dist/sessionArchive/adapters/codex.d.ts.map +1 -0
  88. package/dist/sessionArchive/adapters/codex.js +322 -0
  89. package/dist/sessionArchive/adapters/codex.js.map +1 -0
  90. package/dist/sessionArchive/adapters/gemini.d.ts +3 -0
  91. package/dist/sessionArchive/adapters/gemini.d.ts.map +1 -0
  92. package/dist/sessionArchive/adapters/gemini.js +248 -0
  93. package/dist/sessionArchive/adapters/gemini.js.map +1 -0
  94. package/dist/sessionArchive/adapters/index.d.ts +5 -0
  95. package/dist/sessionArchive/adapters/index.d.ts.map +1 -0
  96. package/dist/sessionArchive/adapters/index.js +5 -0
  97. package/dist/sessionArchive/adapters/index.js.map +1 -0
  98. package/dist/sessionArchive/index.d.ts +9 -0
  99. package/dist/sessionArchive/index.d.ts.map +1 -0
  100. package/dist/sessionArchive/index.js +6 -0
  101. package/dist/sessionArchive/index.js.map +1 -0
  102. package/dist/sessionArchive/ingest.d.ts +68 -0
  103. package/dist/sessionArchive/ingest.d.ts.map +1 -0
  104. package/dist/sessionArchive/ingest.js +134 -0
  105. package/dist/sessionArchive/ingest.js.map +1 -0
  106. package/dist/sessionArchive/normalize.d.ts +15 -0
  107. package/dist/sessionArchive/normalize.d.ts.map +1 -0
  108. package/dist/sessionArchive/normalize.js +40 -0
  109. package/dist/sessionArchive/normalize.js.map +1 -0
  110. package/dist/sessionArchive/store.d.ts +118 -0
  111. package/dist/sessionArchive/store.d.ts.map +1 -0
  112. package/dist/sessionArchive/store.js +491 -0
  113. package/dist/sessionArchive/store.js.map +1 -0
  114. package/dist/sessionArchive/types.d.ts +124 -0
  115. package/dist/sessionArchive/types.d.ts.map +1 -0
  116. package/dist/sessionArchive/types.js +24 -0
  117. package/dist/sessionArchive/types.js.map +1 -0
  118. package/dist/sqlite/drift.d.ts +22 -0
  119. package/dist/sqlite/drift.d.ts.map +1 -0
  120. package/dist/sqlite/drift.js +69 -0
  121. package/dist/sqlite/drift.js.map +1 -0
  122. package/dist/sqlite/index.d.ts +22 -0
  123. package/dist/sqlite/index.d.ts.map +1 -0
  124. package/dist/sqlite/index.js +4 -0
  125. package/dist/sqlite/index.js.map +1 -0
  126. package/dist/sqlite/rebuild.d.ts +32 -0
  127. package/dist/sqlite/rebuild.d.ts.map +1 -0
  128. package/dist/sqlite/rebuild.js +80 -0
  129. package/dist/sqlite/rebuild.js.map +1 -0
  130. package/dist/sqlite/schema.d.ts +15 -0
  131. package/dist/sqlite/schema.d.ts.map +1 -0
  132. package/dist/sqlite/schema.js +41 -0
  133. package/dist/sqlite/schema.js.map +1 -0
  134. package/dist/sqlite/store.d.ts +49 -0
  135. package/dist/sqlite/store.d.ts.map +1 -0
  136. package/dist/sqlite/store.js +179 -0
  137. package/dist/sqlite/store.js.map +1 -0
  138. package/dist/sqlite/types.d.ts +57 -0
  139. package/dist/sqlite/types.d.ts.map +1 -0
  140. package/dist/sqlite/types.js +2 -0
  141. package/dist/sqlite/types.js.map +1 -0
  142. package/dist/vector/backend-brute.d.ts +38 -0
  143. package/dist/vector/backend-brute.d.ts.map +1 -0
  144. package/dist/vector/backend-brute.js +112 -0
  145. package/dist/vector/backend-brute.js.map +1 -0
  146. package/dist/vector/embedder.d.ts +59 -0
  147. package/dist/vector/embedder.d.ts.map +1 -0
  148. package/dist/vector/embedder.js +47 -0
  149. package/dist/vector/embedder.js.map +1 -0
  150. package/dist/vector/index.d.ts +24 -0
  151. package/dist/vector/index.d.ts.map +1 -0
  152. package/dist/vector/index.js +7 -0
  153. package/dist/vector/index.js.map +1 -0
  154. package/dist/vector/math.d.ts +21 -0
  155. package/dist/vector/math.d.ts.map +1 -0
  156. package/dist/vector/math.js +34 -0
  157. package/dist/vector/math.js.map +1 -0
  158. package/dist/vector/schema.d.ts +14 -0
  159. package/dist/vector/schema.d.ts.map +1 -0
  160. package/dist/vector/schema.js +24 -0
  161. package/dist/vector/schema.js.map +1 -0
  162. package/dist/vector/segment.d.ts +65 -0
  163. package/dist/vector/segment.d.ts.map +1 -0
  164. package/dist/vector/segment.js +72 -0
  165. package/dist/vector/segment.js.map +1 -0
  166. package/dist/vector/session.d.ts +90 -0
  167. package/dist/vector/session.d.ts.map +1 -0
  168. package/dist/vector/session.js +242 -0
  169. package/dist/vector/session.js.map +1 -0
  170. package/dist/vector/store.d.ts +69 -0
  171. package/dist/vector/store.d.ts.map +1 -0
  172. package/dist/vector/store.js +131 -0
  173. package/dist/vector/store.js.map +1 -0
  174. package/dist/vector/types.d.ts +109 -0
  175. package/dist/vector/types.d.ts.map +1 -0
  176. package/dist/vector/types.js +24 -0
  177. package/dist/vector/types.js.map +1 -0
  178. package/package.json +96 -0
  179. package/scripts/mcp-stdio.mjs +143 -0
  180. package/scripts/rebuild-memory-sqlite.mjs +39 -0
  181. package/scripts/rebuild-memory-vector.mjs +64 -0
@@ -0,0 +1,491 @@
1
+ import Database from "better-sqlite3";
2
+ import { chmodSync, copyFileSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
3
+ import { join, relative, resolve, sep } from "node:path";
4
+ import { MAX_TRANSCRIPT_BYTES } from "./types.js";
5
+ const SCHEMA = `
6
+ CREATE TABLE IF NOT EXISTS ingested_sessions (
7
+ host TEXT NOT NULL,
8
+ session_id TEXT NOT NULL,
9
+ cwd TEXT NOT NULL,
10
+ started_at TEXT NOT NULL,
11
+ ended_at TEXT,
12
+ model TEXT,
13
+ event_count INTEGER NOT NULL,
14
+ raw_path TEXT NOT NULL,
15
+ normalized_path TEXT NOT NULL,
16
+ ingested_at TEXT NOT NULL,
17
+ reviewed_at TEXT,
18
+ source_mtime_ms INTEGER NOT NULL,
19
+ PRIMARY KEY (host, session_id)
20
+ );
21
+
22
+ CREATE TABLE IF NOT EXISTS events (
23
+ host TEXT NOT NULL,
24
+ session_id TEXT NOT NULL,
25
+ idx INTEGER NOT NULL,
26
+ turn_id TEXT,
27
+ kind TEXT NOT NULL,
28
+ at TEXT NOT NULL,
29
+ text TEXT,
30
+ tool_use_id TEXT,
31
+ PRIMARY KEY (host, session_id, idx)
32
+ );
33
+
34
+ CREATE INDEX IF NOT EXISTS events_kind_at ON events(kind, at);
35
+ CREATE INDEX IF NOT EXISTS events_turn ON events(host, session_id, turn_id);
36
+
37
+ CREATE VIRTUAL TABLE IF NOT EXISTS events_fts USING fts5(
38
+ text,
39
+ content = 'events',
40
+ content_rowid = 'rowid'
41
+ );
42
+
43
+ CREATE TRIGGER IF NOT EXISTS events_ai AFTER INSERT ON events BEGIN
44
+ INSERT INTO events_fts(rowid, text) VALUES (new.rowid, new.text);
45
+ END;
46
+
47
+ CREATE TRIGGER IF NOT EXISTS events_ad AFTER DELETE ON events BEGIN
48
+ INSERT INTO events_fts(events_fts, rowid, text) VALUES('delete', old.rowid, old.text);
49
+ END;
50
+
51
+ CREATE TRIGGER IF NOT EXISTS events_au AFTER UPDATE ON events BEGIN
52
+ INSERT INTO events_fts(events_fts, rowid, text) VALUES('delete', old.rowid, old.text);
53
+ INSERT INTO events_fts(rowid, text) VALUES (new.rowid, new.text);
54
+ END;
55
+ `;
56
+ /**
57
+ * Append-only store backing the sessionArchive namespace.
58
+ *
59
+ * Layout under `<dataDir>/_session-archive/`:
60
+ * raw/<host>/<session-id>.{jsonl|json} ← byte-for-byte copy of host file (when available)
61
+ * normalized/YYYY/MM/<session-id>.jsonl ← vortex VortexTranscriptEvent JSONL
62
+ * metadata.sqlite ← ingested_sessions + events + events_fts
63
+ *
64
+ * SQLite indexes are rebuildable from the normalized JSONL — they are derived state, not SoT.
65
+ */
66
+ export class SessionArchiveStore {
67
+ archiveDir;
68
+ rawDir;
69
+ normalizedDir;
70
+ dbPath;
71
+ db;
72
+ constructor(dataDir) {
73
+ this.archiveDir = join(dataDir, "_session-archive");
74
+ this.rawDir = join(this.archiveDir, "raw");
75
+ this.normalizedDir = join(this.archiveDir, "normalized");
76
+ this.dbPath = join(this.archiveDir, "metadata.sqlite");
77
+ // Transcript archives hold verbatim session content; on multi-user POSIX
78
+ // hosts they should not be world/group readable. mode 0o700 (dirs) / 0o600
79
+ // (files) is a no-op on Windows but protects POSIX. Applied as a chmod after
80
+ // creation too, since mkdirSync's mode is masked by umask on first create.
81
+ mkdirSync(this.archiveDir, { recursive: true, mode: 0o700 });
82
+ mkdirSync(this.rawDir, { recursive: true, mode: 0o700 });
83
+ mkdirSync(this.normalizedDir, { recursive: true, mode: 0o700 });
84
+ chmodDirQuietly(this.archiveDir);
85
+ chmodDirQuietly(this.rawDir);
86
+ chmodDirQuietly(this.normalizedDir);
87
+ this.db = new Database(this.dbPath);
88
+ chmodFileQuietly(this.dbPath); // 0o600 — index holds transcript-derived data
89
+ this.db.pragma("journal_mode = WAL");
90
+ this.db.exec(SCHEMA);
91
+ this.migrate();
92
+ }
93
+ /** True iff a session with the same (host, sessionId) is already ingested at or beyond the given mtime. */
94
+ hasIngested(host, sessionId, mtimeMs) {
95
+ const row = this.db
96
+ .prepare("SELECT source_mtime_ms FROM ingested_sessions WHERE host = ? AND session_id = ?")
97
+ .get(host, sessionId);
98
+ return !!row && row.source_mtime_ms >= mtimeMs;
99
+ }
100
+ /** All rows in `ingested_sessions` — used by the orchestrator for incremental re-scan. */
101
+ listIngested() {
102
+ const rows = this.db
103
+ .prepare("SELECT host, session_id, source_mtime_ms FROM ingested_sessions")
104
+ .all();
105
+ return rows.map((r) => ({ host: r.host, sessionId: r.session_id, mtimeMs: r.source_mtime_ms }));
106
+ }
107
+ /**
108
+ * Session metadata — used by consolidate (and any future analyzer) to
109
+ * filter recently-ingested sessions before pulling their event bodies.
110
+ *
111
+ * Ordered newest-ingested first. `sinceMs` is checked against
112
+ * `ingested_at`, not the session's own `started_at`, so a session that
113
+ * was ingested today but happened weeks ago still surfaces on a
114
+ * "consolidate since last run" query.
115
+ */
116
+ listSessions(options) {
117
+ const wheres = [];
118
+ const params = [];
119
+ if (options?.sinceMs !== undefined) {
120
+ wheres.push("ingested_at > ?");
121
+ params.push(options.sinceMs);
122
+ }
123
+ if (options?.hosts && options.hosts.length > 0) {
124
+ wheres.push(`host IN (${options.hosts.map(() => "?").join(", ")})`);
125
+ params.push(...options.hosts);
126
+ }
127
+ if (options?.onlyUnreviewed) {
128
+ wheres.push("reviewed_at IS NULL");
129
+ }
130
+ let sql = `
131
+ SELECT host, session_id, cwd, started_at, ended_at, model, event_count, ingested_at, reviewed_at
132
+ FROM ingested_sessions
133
+ `;
134
+ if (wheres.length > 0)
135
+ sql += ` WHERE ${wheres.join(" AND ")}`;
136
+ sql += ` ORDER BY ingested_at DESC`;
137
+ if (options?.limit !== undefined) {
138
+ sql += ` LIMIT ?`;
139
+ params.push(options.limit);
140
+ }
141
+ const rows = this.db.prepare(sql).all(...params);
142
+ return rows.map((r) => ({
143
+ host: r.host,
144
+ sessionId: r.session_id,
145
+ cwd: r.cwd,
146
+ startedAt: r.started_at,
147
+ endedAt: r.ended_at,
148
+ model: r.model,
149
+ eventCount: r.event_count,
150
+ ingestedAt: r.ingested_at,
151
+ reviewedAt: r.reviewed_at,
152
+ }));
153
+ }
154
+ /**
155
+ * Replay all events of one session, in original order. Useful for analyzers
156
+ * (consolidate, future LLM-driven tooling) that need the actual content,
157
+ * not just metadata.
158
+ */
159
+ readSessionEvents(host, sessionId) {
160
+ const rows = this.db
161
+ .prepare(`
162
+ SELECT idx, turn_id, kind, at, text, tool_use_id
163
+ FROM events
164
+ WHERE host = ? AND session_id = ?
165
+ ORDER BY idx ASC
166
+ `)
167
+ .all(host, sessionId);
168
+ return rows.map((r) => ({
169
+ idx: r.idx,
170
+ turnId: r.turn_id,
171
+ kind: r.kind,
172
+ at: r.at,
173
+ text: r.text,
174
+ toolUseId: r.tool_use_id,
175
+ }));
176
+ }
177
+ /**
178
+ * Persist a normalized session — writes the raw copy (if a source path is provided),
179
+ * writes the normalized JSONL, and replaces metadata + events rows in a single transaction.
180
+ */
181
+ writeSession(session, rawSourcePath, sourceMtimeMs) {
182
+ const rawAbs = rawSourcePath ? this.writeRawCopy(session.host, session.sessionId, rawSourcePath) : "";
183
+ const normalizedAbs = this.writeNormalized(session);
184
+ // writeRawCopy returns "" when the source is a directory or missing — treat as no raw.
185
+ const rawRel = rawAbs ? relative(this.archiveDir, rawAbs).replace(/\\/g, "/") : "";
186
+ const normalizedRel = relative(this.archiveDir, normalizedAbs).replace(/\\/g, "/");
187
+ this.indexSession(session, rawRel, normalizedRel, sourceMtimeMs);
188
+ }
189
+ /**
190
+ * DB-only upsert of a session's metadata + events — no file writes. Shared
191
+ * by {@link writeSession} (fresh ingest, which also writes the raw +
192
+ * normalized files first) and {@link reindexFromNormalized} (a session whose
193
+ * normalized text is already on disk, typically pulled from another machine
194
+ * via git). `INSERT OR REPLACE` intentionally clears `reviewed_at`: a
195
+ * re-indexed session has new content since any prior review, so curate
196
+ * should surface it again.
197
+ */
198
+ indexSession(session, rawRel, normalizedRel, sourceMtimeMs) {
199
+ const deleteOld = this.db.prepare(`DELETE FROM events WHERE host = ? AND session_id = ?`);
200
+ const insertSession = this.db.prepare(`
201
+ INSERT OR REPLACE INTO ingested_sessions
202
+ (host, session_id, cwd, started_at, ended_at, model, event_count,
203
+ raw_path, normalized_path, ingested_at, source_mtime_ms)
204
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
205
+ `);
206
+ const insertEvent = this.db.prepare(`
207
+ INSERT INTO events (host, session_id, idx, turn_id, kind, at, text, tool_use_id)
208
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
209
+ `);
210
+ const tx = this.db.transaction(() => {
211
+ deleteOld.run(session.host, session.sessionId);
212
+ insertSession.run(session.host, session.sessionId, session.cwd, session.startedAt, session.endedAt ?? null, session.model ?? null, session.events.length, rawRel, normalizedRel, new Date().toISOString(), sourceMtimeMs);
213
+ session.events.forEach((ev, idx) => {
214
+ insertEvent.run(session.host, session.sessionId, idx, getTurnId(ev), ev.kind, ev.at, getEventText(ev), getToolUseId(ev));
215
+ });
216
+ });
217
+ tx();
218
+ }
219
+ /**
220
+ * Index any normalized transcript on disk that this DB has not seen yet, and
221
+ * return the session ids newly indexed.
222
+ *
223
+ * The normalized JSONL under `normalized/` is the synced source of truth; the
224
+ * sqlite DB is local, derived, and gitignored. So a session created on another
225
+ * machine arrives here as a normalized file (via git pull) with no DB row
226
+ * until this runs — this is what makes a pulled conversation searchable on
227
+ * this machine. Already-indexed sessions are skipped by `(host, sessionId)`.
228
+ */
229
+ reindexFromNormalized() {
230
+ const known = new Set(this.listIngested().map((r) => `${r.host}${r.sessionId}`));
231
+ const ids = [];
232
+ for (const file of this.listNormalizedFiles()) {
233
+ // Size cap: stat before reading so an oversized normalized file (e.g. one
234
+ // pulled in via git) is never slurped into memory. Skip it on over-cap.
235
+ let mtimeMs = 0;
236
+ try {
237
+ const st = statSync(file);
238
+ if (st.size > MAX_TRANSCRIPT_BYTES)
239
+ continue;
240
+ mtimeMs = st.mtimeMs;
241
+ }
242
+ catch {
243
+ // unreadable stat — index with 0; presence in the table is what matters
244
+ }
245
+ const session = readNormalizedSession(file);
246
+ if (!session)
247
+ continue;
248
+ const key = `${session.host}${session.sessionId}`;
249
+ if (known.has(key))
250
+ continue;
251
+ const normalizedRel = relative(this.archiveDir, file).replace(/\\/g, "/");
252
+ this.indexSession(session, "", normalizedRel, mtimeMs);
253
+ known.add(key);
254
+ ids.push(session.sessionId);
255
+ }
256
+ return { indexed: ids.length, sessionIds: ids };
257
+ }
258
+ /** Every `*.jsonl` under the normalized dir (`normalized/YYYY/MM/<id>.jsonl`). */
259
+ listNormalizedFiles() {
260
+ const out = [];
261
+ const walk = (dir) => {
262
+ let entries;
263
+ try {
264
+ entries = readdirSync(dir, { withFileTypes: true });
265
+ }
266
+ catch {
267
+ return;
268
+ }
269
+ for (const e of entries) {
270
+ const p = join(dir, e.name);
271
+ if (e.isDirectory())
272
+ walk(p);
273
+ else if (e.isFile() && e.name.endsWith(".jsonl"))
274
+ out.push(p);
275
+ }
276
+ };
277
+ walk(this.normalizedDir);
278
+ return out;
279
+ }
280
+ /** Stamp a session as curate-reviewed at the given ISO-8601 time (last write wins). */
281
+ markReviewed(host, sessionId, atIso) {
282
+ this.db
283
+ .prepare("UPDATE ingested_sessions SET reviewed_at = ? WHERE host = ? AND session_id = ?")
284
+ .run(atIso, host, sessionId);
285
+ }
286
+ /**
287
+ * Additive schema migrations for DBs created by an earlier version.
288
+ * `CREATE TABLE IF NOT EXISTS` will not add a column to a table that
289
+ * already exists, so new columns are introduced here, guarded by a
290
+ * column-presence check so the migration is idempotent.
291
+ */
292
+ migrate() {
293
+ const cols = this.db
294
+ .prepare("PRAGMA table_info(ingested_sessions)")
295
+ .all();
296
+ if (!cols.some((c) => c.name === "reviewed_at")) {
297
+ this.db.exec("ALTER TABLE ingested_sessions ADD COLUMN reviewed_at TEXT");
298
+ }
299
+ }
300
+ close() {
301
+ this.db.close();
302
+ }
303
+ writeRawCopy(host, sessionId, sourcePath) {
304
+ // Only copy regular files. Claude Desktop passes a directory path (the LevelDB dir),
305
+ // and tests sometimes pass paths that don't exist on disk — in both cases skip the raw
306
+ // copy and let `writeSession` proceed with normalized-only storage.
307
+ let stat;
308
+ try {
309
+ stat = statSync(sourcePath);
310
+ }
311
+ catch {
312
+ return "";
313
+ }
314
+ if (!stat.isFile())
315
+ return "";
316
+ // host + sessionId are derived from adapter-parsed host fields / transcript
317
+ // filenames (external input). Validate as path segments before interpolating
318
+ // them, then containment-check the resolved target. (mirror base validateSegment)
319
+ validateSegment("host", host);
320
+ validateSegment("sessionId", sessionId);
321
+ const hostDir = join(this.rawDir, host);
322
+ assertContained(hostDir, this.rawDir);
323
+ mkdirSync(hostDir, { recursive: true, mode: 0o700 });
324
+ chmodDirQuietly(hostDir);
325
+ const ext = sourcePath.toLowerCase().endsWith(".json") ? ".json" : ".jsonl";
326
+ const target = join(hostDir, `${sessionId}${ext}`);
327
+ assertContained(target, this.rawDir);
328
+ copyFileSync(sourcePath, target);
329
+ chmodFileQuietly(target); // 0o600 — verbatim copy of the host transcript
330
+ return target;
331
+ }
332
+ writeNormalized(session) {
333
+ // sessionId is external input (adapter-parsed from a transcript filename).
334
+ // Validate it as a path segment, then containment-check the resolved target.
335
+ // (mirror base validateSegment / assertContained)
336
+ validateSegment("sessionId", session.sessionId);
337
+ const started = new Date(session.startedAt);
338
+ const yearDir = String(started.getUTCFullYear());
339
+ const monthDir = String(started.getUTCMonth() + 1).padStart(2, "0");
340
+ const targetDir = join(this.normalizedDir, yearDir, monthDir);
341
+ mkdirSync(targetDir, { recursive: true, mode: 0o700 });
342
+ chmodDirQuietly(targetDir);
343
+ const target = join(targetDir, `${session.sessionId}.jsonl`);
344
+ assertContained(target, this.normalizedDir);
345
+ const headerLine = JSON.stringify({
346
+ kind: "session_header",
347
+ host: session.host,
348
+ sessionId: session.sessionId,
349
+ cwd: session.cwd,
350
+ startedAt: session.startedAt,
351
+ endedAt: session.endedAt,
352
+ model: session.model,
353
+ cliVersion: session.cliVersion,
354
+ });
355
+ const eventLines = session.events.map((ev) => JSON.stringify(ev));
356
+ writeFileSync(target, [headerLine, ...eventLines].join("\n") + "\n", { encoding: "utf8", mode: 0o600 });
357
+ chmodFileQuietly(target); // ensure 0o600 even if the file pre-existed with looser perms
358
+ return target;
359
+ }
360
+ }
361
+ // chmod helpers — best-effort POSIX hardening. On Windows (and other platforms
362
+ // where chmod is unsupported / the path is gone) these are intentional no-ops:
363
+ // archive integrity must never hinge on a permission bit failing to set.
364
+ function chmodDirQuietly(path) {
365
+ try {
366
+ chmodSync(path, 0o700);
367
+ }
368
+ catch {
369
+ /* no-op on Windows / unsupported FS */
370
+ }
371
+ }
372
+ function chmodFileQuietly(path) {
373
+ try {
374
+ chmodSync(path, 0o600);
375
+ }
376
+ catch {
377
+ /* no-op on Windows / unsupported FS */
378
+ }
379
+ }
380
+ /**
381
+ * Reject a path segment (host / sessionId) that could escape the archive
382
+ * directory or smuggle a path into a filename. host + sessionId derive from
383
+ * adapter-parsed transcript filenames / host fields, which are external input,
384
+ * so the same defensive rules as `@vortex-os/base` (worklog/decision-log
385
+ * `validateSegment`) apply: no path separators, no `..` traversal, no
386
+ * absolute paths / drive letters / UNC, no leading `~`, no NUL / control chars,
387
+ * not empty or bare `.`/`..`.
388
+ */
389
+ function validateSegment(label, value) {
390
+ const v = (value ?? "").trim();
391
+ if (v.length === 0)
392
+ throw new Error(`${label} is required`);
393
+ if (v === "." || v === "..")
394
+ throw new Error(`${label} must not be '.' or '..': ${value}`);
395
+ if (v.includes("/") || v.includes("\\"))
396
+ throw new Error(`${label} must not contain path separators: ${value}`);
397
+ if (/(^|[\\/])\.\.([\\/]|$)/.test(v))
398
+ throw new Error(`${label} must not contain '..': ${value}`);
399
+ if (v.startsWith("/") || v.startsWith("\\") || /^[a-zA-Z]:/.test(v))
400
+ throw new Error(`${label} must be a relative name, not an absolute path: ${value}`);
401
+ if (v.startsWith("~"))
402
+ throw new Error(`${label} must not start with '~': ${value}`);
403
+ // eslint-disable-next-line no-control-regex
404
+ if (/[\u0000-\u001f\u007f]/.test(v))
405
+ throw new Error(`${label} must not contain NUL or control characters: ${value}`);
406
+ }
407
+ /**
408
+ * Defense-in-depth containment: the resolved absolute target must live inside
409
+ * `rootDir`. Catches any traversal the segment check missed (symlinks, future
410
+ * callers). Throws on escape. Mirrors worklog/decision-log `assertContained`
411
+ * and the `runWriteDocument` data-root guard in `mcp/document-tools.ts`.
412
+ */
413
+ function assertContained(abs, rootDir) {
414
+ const root = resolve(rootDir);
415
+ const target = resolve(abs);
416
+ if (target !== root && !(target + sep).startsWith(root + sep)) {
417
+ throw new Error(`Refusing to write outside the archive directory: ${abs}`);
418
+ }
419
+ }
420
+ // Helpers — narrow VortexTranscriptEvent's discriminated union without `any`.
421
+ function getTurnId(ev) {
422
+ return ev.kind === "meta" ? null : ev.turnId;
423
+ }
424
+ function getEventText(ev) {
425
+ switch (ev.kind) {
426
+ case "user_message":
427
+ case "assistant_message":
428
+ return ev.text;
429
+ case "tool_result":
430
+ return ev.content;
431
+ default:
432
+ return null;
433
+ }
434
+ }
435
+ function getToolUseId(ev) {
436
+ if (ev.kind === "tool_call" || ev.kind === "tool_result")
437
+ return ev.toolUseId;
438
+ return null;
439
+ }
440
+ /**
441
+ * Reconstruct a session from a normalized JSONL file (the inverse of
442
+ * {@link SessionArchiveStore.writeNormalized}): line 1 is the
443
+ * `session_header`, the rest are one `VortexTranscriptEvent` each. Returns
444
+ * null for an unreadable file or a missing/invalid header; a single malformed
445
+ * event line is skipped rather than discarding the whole session.
446
+ */
447
+ function readNormalizedSession(path) {
448
+ let raw;
449
+ try {
450
+ raw = readFileSync(path, "utf8");
451
+ }
452
+ catch {
453
+ return null;
454
+ }
455
+ const lines = raw.split(/\r?\n/).filter((l) => l.length > 0);
456
+ if (lines.length === 0)
457
+ return null;
458
+ let header;
459
+ try {
460
+ header = JSON.parse(lines[0]);
461
+ }
462
+ catch {
463
+ return null;
464
+ }
465
+ if (header.kind !== "session_header" ||
466
+ !header.host ||
467
+ typeof header.sessionId !== "string" ||
468
+ typeof header.startedAt !== "string") {
469
+ return null;
470
+ }
471
+ const events = [];
472
+ for (let i = 1; i < lines.length; i++) {
473
+ try {
474
+ events.push(JSON.parse(lines[i]));
475
+ }
476
+ catch {
477
+ // skip a malformed event line rather than dropping the whole session
478
+ }
479
+ }
480
+ return {
481
+ host: header.host,
482
+ sessionId: header.sessionId,
483
+ cwd: header.cwd ?? "",
484
+ startedAt: header.startedAt,
485
+ endedAt: header.endedAt ?? undefined,
486
+ model: header.model ?? undefined,
487
+ cliVersion: header.cliVersion ?? undefined,
488
+ events,
489
+ };
490
+ }
491
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/sessionArchive/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Hard cap on a single transcript's on-disk size. Files larger than this are
3
+ * skipped at ingest (a `skip` progress event with reason `"oversize"` is
4
+ * emitted) and not read into memory, bounding the worst-case heap a single
5
+ * descriptor can demand. 50 MiB is far above any real session and well below a
6
+ * memory-pressure threshold.
7
+ */
8
+ export declare const MAX_TRANSCRIPT_BYTES: number;
9
+ export type HostId = "claude-code" | "codex" | "gemini" | "claude-desktop" | string;
10
+ export interface VortexTranscriptSession {
11
+ readonly host: HostId;
12
+ readonly sessionId: string;
13
+ readonly cwd: string;
14
+ readonly startedAt: string;
15
+ readonly endedAt?: string;
16
+ readonly model?: string;
17
+ readonly cliVersion?: string;
18
+ readonly events: readonly VortexTranscriptEvent[];
19
+ }
20
+ export type VortexTranscriptEvent = UserMessageEvent | AssistantMessageEvent | ToolCallEvent | ToolResultEvent | AttachmentEvent | UsageEvent | MetaEvent;
21
+ export interface UserMessageEvent {
22
+ readonly kind: "user_message";
23
+ readonly turnId: string;
24
+ readonly at: string;
25
+ readonly text: string;
26
+ readonly hostRaw?: unknown;
27
+ }
28
+ export interface AssistantMessageEvent {
29
+ readonly kind: "assistant_message";
30
+ readonly turnId: string;
31
+ readonly at: string;
32
+ readonly text: string;
33
+ readonly thinking?: string;
34
+ readonly hostRaw?: unknown;
35
+ }
36
+ export interface ToolCallEvent {
37
+ readonly kind: "tool_call";
38
+ readonly turnId: string;
39
+ readonly at: string;
40
+ readonly name: string;
41
+ readonly input: unknown;
42
+ readonly toolUseId: string;
43
+ readonly hostRaw?: unknown;
44
+ }
45
+ export interface ToolResultEvent {
46
+ readonly kind: "tool_result";
47
+ readonly turnId: string;
48
+ readonly at: string;
49
+ readonly toolUseId: string;
50
+ readonly content: string;
51
+ readonly isError?: boolean;
52
+ readonly hostRaw?: unknown;
53
+ }
54
+ export interface AttachmentEvent {
55
+ readonly kind: "attachment";
56
+ readonly turnId: string;
57
+ readonly at: string;
58
+ readonly path?: string;
59
+ readonly mime?: string;
60
+ readonly hostRaw?: unknown;
61
+ }
62
+ export interface UsageEvent {
63
+ readonly kind: "usage";
64
+ readonly turnId: string;
65
+ readonly at: string;
66
+ readonly inputTokens?: number;
67
+ readonly outputTokens?: number;
68
+ readonly cachedTokens?: number;
69
+ readonly hostRaw?: unknown;
70
+ }
71
+ export interface MetaEvent {
72
+ readonly kind: "meta";
73
+ readonly at: string;
74
+ readonly payload: unknown;
75
+ }
76
+ export interface SessionDescriptor {
77
+ readonly host: HostId;
78
+ readonly sessionId: string;
79
+ readonly cwd: string;
80
+ readonly path: string;
81
+ readonly mtimeMs: number;
82
+ readonly bytes: number;
83
+ }
84
+ export interface AdapterEnv {
85
+ readonly home: string;
86
+ readonly platform: NodeJS.Platform;
87
+ readonly now: () => Date;
88
+ }
89
+ export interface ListQuery {
90
+ readonly cwd?: string;
91
+ readonly cwdAnywhere?: boolean;
92
+ readonly since?: string;
93
+ }
94
+ /**
95
+ * Host-specific transcript adapter. Each first-party host (Claude Code / Codex / Gemini /
96
+ * Claude Desktop) implements this once; external hosts (Cursor, Zed, etc.) can implement
97
+ * it externally and be passed into ingest() at the consumer side.
98
+ *
99
+ * Adapters are stateless: open files, read, close. The orchestrator tracks ingestion progress.
100
+ */
101
+ export interface TranscriptAdapter {
102
+ readonly host: HostId;
103
+ /** Cheap probe — does this host appear to be installed on this machine? */
104
+ detect(env: AdapterEnv): Promise<boolean>;
105
+ /** All sessions found on disk, optionally filtered by cwd / since. */
106
+ list(query: ListQuery, env: AdapterEnv): Promise<readonly SessionDescriptor[]>;
107
+ /** Read a single session and yield normalized events. */
108
+ read(descriptor: SessionDescriptor, env: AdapterEnv): Promise<VortexTranscriptSession>;
109
+ }
110
+ export interface AdapterOptions {
111
+ /** Optional redaction hook — runs after normalization, before storage. First-party adapters leave this undefined. */
112
+ readonly redact?: (event: VortexTranscriptEvent) => VortexTranscriptEvent;
113
+ }
114
+ /**
115
+ * Typed error surfaced when the Claude Desktop adapter cannot open the LevelDB
116
+ * because Claude Desktop is running and holds the lock. The orchestrator catches
117
+ * this specifically and surfaces a user-facing "quit Desktop and retry" message
118
+ * instead of a stack trace.
119
+ */
120
+ export declare class ClaudeDesktopRunningError extends Error {
121
+ readonly host: HostId;
122
+ constructor(message?: string);
123
+ }
124
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/sessionArchive/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ // Types shared across the sessionArchive namespace.
2
+ // Schema is captured in docs/transcript-adapter-design.md — keep this file aligned with that document.
3
+ /**
4
+ * Hard cap on a single transcript's on-disk size. Files larger than this are
5
+ * skipped at ingest (a `skip` progress event with reason `"oversize"` is
6
+ * emitted) and not read into memory, bounding the worst-case heap a single
7
+ * descriptor can demand. 50 MiB is far above any real session and well below a
8
+ * memory-pressure threshold.
9
+ */
10
+ export const MAX_TRANSCRIPT_BYTES = 50 * 1024 * 1024;
11
+ /**
12
+ * Typed error surfaced when the Claude Desktop adapter cannot open the LevelDB
13
+ * because Claude Desktop is running and holds the lock. The orchestrator catches
14
+ * this specifically and surfaces a user-facing "quit Desktop and retry" message
15
+ * instead of a stack trace.
16
+ */
17
+ export class ClaudeDesktopRunningError extends Error {
18
+ host = "claude-desktop";
19
+ constructor(message = "Claude Desktop is currently running and holds the LevelDB lock. Quit it (system tray → Quit) and retry.") {
20
+ super(message);
21
+ this.name = "ClaudeDesktopRunningError";
22
+ }
23
+ }
24
+ //# sourceMappingURL=types.js.map