code-session-memory 0.4.4 → 0.7.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 (43) hide show
  1. package/README.md +78 -58
  2. package/dist/mcp/index.js +23 -2
  3. package/dist/mcp/index.js.map +1 -1
  4. package/dist/mcp/server.d.ts +4 -2
  5. package/dist/mcp/server.d.ts.map +1 -1
  6. package/dist/mcp/server.js +11 -3
  7. package/dist/mcp/server.js.map +1 -1
  8. package/dist/src/cli-sessions.d.ts +6 -7
  9. package/dist/src/cli-sessions.d.ts.map +1 -1
  10. package/dist/src/cli-sessions.js +238 -178
  11. package/dist/src/cli-sessions.js.map +1 -1
  12. package/dist/src/cli.js +272 -12
  13. package/dist/src/cli.js.map +1 -1
  14. package/dist/src/cursor-to-messages.d.ts +64 -0
  15. package/dist/src/cursor-to-messages.d.ts.map +1 -0
  16. package/dist/src/cursor-to-messages.js +243 -0
  17. package/dist/src/cursor-to-messages.js.map +1 -0
  18. package/dist/src/cursor-transcript-to-messages.d.ts +22 -0
  19. package/dist/src/cursor-transcript-to-messages.d.ts.map +1 -0
  20. package/dist/src/cursor-transcript-to-messages.js +79 -0
  21. package/dist/src/cursor-transcript-to-messages.js.map +1 -0
  22. package/dist/src/database.d.ts +13 -2
  23. package/dist/src/database.d.ts.map +1 -1
  24. package/dist/src/database.js +42 -8
  25. package/dist/src/database.js.map +1 -1
  26. package/dist/src/indexer-cli-cursor.d.ts +25 -0
  27. package/dist/src/indexer-cli-cursor.d.ts.map +1 -0
  28. package/dist/src/indexer-cli-cursor.js +118 -0
  29. package/dist/src/indexer-cli-cursor.js.map +1 -0
  30. package/dist/src/indexer-cli.js +76 -6
  31. package/dist/src/indexer-cli.js.map +1 -1
  32. package/dist/src/indexer.d.ts.map +1 -1
  33. package/dist/src/indexer.js +46 -9
  34. package/dist/src/indexer.js.map +1 -1
  35. package/dist/src/opencode-db-to-messages.d.ts +30 -0
  36. package/dist/src/opencode-db-to-messages.d.ts.map +1 -0
  37. package/dist/src/opencode-db-to-messages.js +88 -0
  38. package/dist/src/opencode-db-to-messages.js.map +1 -0
  39. package/dist/src/types.d.ts +6 -1
  40. package/dist/src/types.d.ts.map +1 -1
  41. package/package.json +3 -2
  42. package/plugin/memory.ts +9 -1
  43. package/skill/memory.md +7 -2
@@ -0,0 +1,118 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * Entry point for Cursor session indexing.
5
+ *
6
+ * Called by the Cursor stop hook. Receives JSON on stdin:
7
+ * {
8
+ * conversation_id: string, // the composerId
9
+ * workspace_roots: string[], // project directories
10
+ * transcript_path: string, // path to the JSONL transcript (always complete)
11
+ * model: string,
12
+ * status: "completed" | "aborted" | "error",
13
+ * ...
14
+ * }
15
+ *
16
+ * Strategy:
17
+ * - Read messages from transcript_path (JSONL written by Cursor before the
18
+ * hook fires — always complete and race-condition-free).
19
+ * - Read session title from state.vscdb (best-effort, falls back to first
20
+ * user message).
21
+ * - Index new messages into the shared sqlite-vec DB incrementally.
22
+ *
23
+ * No retries needed: the transcript file is the authoritative source.
24
+ */
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ const database_1 = require("./database");
27
+ const indexer_1 = require("./indexer");
28
+ const cursor_to_messages_1 = require("./cursor-to-messages");
29
+ const cursor_transcript_to_messages_1 = require("./cursor-transcript-to-messages");
30
+ async function main() {
31
+ // Read JSON payload from stdin
32
+ const chunks = [];
33
+ for await (const chunk of process.stdin) {
34
+ chunks.push(chunk);
35
+ }
36
+ let payload;
37
+ try {
38
+ payload = JSON.parse(Buffer.concat(chunks).toString("utf8"));
39
+ }
40
+ catch (err) {
41
+ process.stderr.write(`[code-session-memory] Failed to parse stdin: ${err}\n`);
42
+ process.exit(1);
43
+ }
44
+ const { conversation_id: composerId, workspace_roots: workspaceRoots, transcript_path: transcriptPath, } = payload;
45
+ if (!composerId) {
46
+ process.stderr.write("[code-session-memory] Missing conversation_id in hook payload\n");
47
+ process.exit(1);
48
+ }
49
+ if (!transcriptPath) {
50
+ process.stderr.write("[code-session-memory] Missing transcript_path in hook payload — cannot index\n");
51
+ return;
52
+ }
53
+ // Determine the project directory from workspace_roots
54
+ const projectDir = (workspaceRoots ?? [])
55
+ .map((r) => r.replace(/^file:\/\//, ""))
56
+ .filter(Boolean)[0] ?? "";
57
+ // Read messages from the transcript JSONL.
58
+ // Cursor writes this file synchronously before firing the hook, so it is
59
+ // always complete — no retry needed.
60
+ const messages = (0, cursor_transcript_to_messages_1.cursorTranscriptToMessages)(transcriptPath, composerId);
61
+ if (messages.length === 0) {
62
+ process.stderr.write(`[code-session-memory] No messages in transcript: ${transcriptPath}\n`);
63
+ return;
64
+ }
65
+ const dbPath = (0, database_1.resolveDbPath)();
66
+ const db = (0, database_1.openDatabase)({ dbPath });
67
+ try {
68
+ // Derive session title from SQLite (best-effort — don't fail if unavailable)
69
+ const existingMeta = (0, database_1.getSessionMeta)(db, composerId);
70
+ let title = existingMeta?.session_title ?? "";
71
+ if (!title) {
72
+ try {
73
+ const cursorDb = (0, cursor_to_messages_1.openCursorDb)((0, cursor_to_messages_1.resolveCursorDbPath)());
74
+ try {
75
+ const composer = (0, cursor_to_messages_1.getComposerData)(cursorDb, composerId);
76
+ if (composer) {
77
+ title = (0, cursor_to_messages_1.deriveCursorSessionTitle)(composer, messages);
78
+ }
79
+ }
80
+ finally {
81
+ cursorDb.close();
82
+ }
83
+ }
84
+ catch {
85
+ // SQLite unavailable — fall back to first user message text
86
+ }
87
+ if (!title) {
88
+ for (const msg of messages) {
89
+ if (msg.info.role === "user") {
90
+ const part = msg.parts.find((p) => p.type === "text");
91
+ if (part && part.type === "text") {
92
+ title = (part.text ?? "").replace(/\s+/g, " ").trim().slice(0, 80);
93
+ break;
94
+ }
95
+ }
96
+ }
97
+ }
98
+ }
99
+ const session = {
100
+ id: composerId,
101
+ title: title || composerId,
102
+ directory: projectDir,
103
+ };
104
+ await (0, indexer_1.indexNewMessages)(db, session, messages, "cursor");
105
+ }
106
+ catch (err) {
107
+ const msg = err instanceof Error ? err.message : String(err);
108
+ process.stderr.write(`[code-session-memory] Indexing error: ${msg}\n`);
109
+ }
110
+ finally {
111
+ db.close();
112
+ }
113
+ }
114
+ main().catch((err) => {
115
+ process.stderr.write(`[code-session-memory] Fatal: ${err}\n`);
116
+ process.exit(1);
117
+ });
118
+ //# sourceMappingURL=indexer-cli-cursor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indexer-cli-cursor.js","sourceRoot":"","sources":["../../src/indexer-cli-cursor.ts"],"names":[],"mappings":"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"}
@@ -16,6 +16,9 @@
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  const database_1 = require("./database");
18
18
  const indexer_1 = require("./indexer");
19
+ const opencode_db_to_messages_1 = require("./opencode-db-to-messages");
20
+ const FETCH_RETRIES = 3;
21
+ const FETCH_RETRY_DELAY_MS = 500;
19
22
  async function fetchJson(url) {
20
23
  const res = await fetch(url);
21
24
  if (!res.ok) {
@@ -23,6 +26,41 @@ async function fetchJson(url) {
23
26
  }
24
27
  return res.json();
25
28
  }
29
+ /**
30
+ * Fetches JSON from the OpenCode REST API with retries.
31
+ * If the server is unreachable (network error), retries up to FETCH_RETRIES
32
+ * times with a short delay. This handles the case where session.idle fires
33
+ * just as OpenCode is shutting down or restarting.
34
+ *
35
+ * Returns null if the server remains unreachable after all retries — the
36
+ * caller should treat this as a graceful no-op (session is gone, nothing to index).
37
+ *
38
+ * Only retries on network-level errors (fetch failed). HTTP errors (4xx/5xx)
39
+ * are propagated immediately.
40
+ */
41
+ async function fetchJsonWithRetry(url) {
42
+ for (let attempt = 0; attempt <= FETCH_RETRIES; attempt++) {
43
+ try {
44
+ return await fetchJson(url);
45
+ }
46
+ catch (err) {
47
+ // TypeError with message "fetch failed" covers all network-level failures:
48
+ // ECONNREFUSED, EADDRNOTAVAIL, ENOTFOUND, bad port, IPv6 unreachable, etc.
49
+ const isNetworkError = err instanceof TypeError && err.message === "fetch failed";
50
+ if (isNetworkError) {
51
+ if (attempt < FETCH_RETRIES) {
52
+ await new Promise((r) => setTimeout(r, FETCH_RETRY_DELAY_MS));
53
+ continue;
54
+ }
55
+ // All retries exhausted — server is gone, signal graceful no-op.
56
+ return null;
57
+ }
58
+ // Non-network error (e.g. HTTP 4xx/5xx) — propagate immediately.
59
+ throw err;
60
+ }
61
+ }
62
+ return null;
63
+ }
26
64
  async function main() {
27
65
  const sessionId = process.argv[2];
28
66
  const serverUrl = process.argv[3];
@@ -30,12 +68,43 @@ async function main() {
30
68
  process.stderr.write("Usage: indexer-cli <sessionId> <serverUrl>\n");
31
69
  process.exit(1);
32
70
  }
33
- // Normalize: strip trailing slash
34
- const base = serverUrl.replace(/\/$/, "");
35
- const [session, messages] = await Promise.all([
36
- fetchJson(`${base}/session/${sessionId}`),
37
- fetchJson(`${base}/session/${sessionId}/message`),
71
+ // Normalize the server URL:
72
+ // - Strip trailing slash
73
+ // - Rewrite IPv6 loopback [::1] and "localhost" to 127.0.0.1 (IPv4).
74
+ // OpenCode binds to 127.0.0.1 by default, but when started with -s it may
75
+ // construct serverUrl using "localhost", which on many systems resolves to
76
+ // ::1 (IPv6) first. Node's fetch then fails with ECONNREFUSED because the
77
+ // server isn't listening on IPv6.
78
+ const base = serverUrl
79
+ .replace(/\/$/, "")
80
+ .replace(/^http:\/\/\[::1\]/i, "http://127.0.0.1")
81
+ .replace(/^http:\/\/localhost/i, "http://127.0.0.1");
82
+ // Fetch session + messages in parallel via REST API, with retry on network errors.
83
+ // Returns null on any network-level failure (server not running / no --port).
84
+ const [fetchedSession, fetchedMessages] = await Promise.all([
85
+ fetchJsonWithRetry(`${base}/session/${sessionId}`),
86
+ fetchJsonWithRetry(`${base}/session/${sessionId}/message`),
38
87
  ]);
88
+ let session;
89
+ let messages;
90
+ if (fetchedSession && fetchedMessages) {
91
+ // Happy path: REST API responded.
92
+ session = fetchedSession;
93
+ messages = fetchedMessages;
94
+ }
95
+ else {
96
+ // REST API unavailable (e.g. OpenCode started with -s and no --port, so no
97
+ // HTTP server is running). Fall back to reading directly from OpenCode's
98
+ // internal SQLite DB.
99
+ const dbSession = (0, opencode_db_to_messages_1.getSessionFromOpenCodeDb)(sessionId);
100
+ const dbMessages = (0, opencode_db_to_messages_1.getMessagesFromOpenCodeDb)(sessionId);
101
+ if (!dbSession || !dbMessages) {
102
+ // Neither source available — nothing to index, exit cleanly.
103
+ process.exit(0);
104
+ }
105
+ session = dbSession;
106
+ messages = dbMessages;
107
+ }
39
108
  const dbPath = (0, database_1.resolveDbPath)();
40
109
  const db = (0, database_1.openDatabase)({ dbPath });
41
110
  try {
@@ -47,7 +116,8 @@ async function main() {
47
116
  // No output — the plugin runs this silently via Bun's $.quiet()
48
117
  }
49
118
  main().catch((err) => {
50
- process.stderr.write(`[code-session-memory] indexer-cli error: ${err instanceof Error ? err.message : String(err)}\n`);
119
+ const url = process.argv[3] ?? "(no url)";
120
+ process.stderr.write(`[code-session-memory] indexer-cli error: ${err instanceof Error ? err.message : String(err)} (serverUrl: ${url})\n`);
51
121
  process.exit(1);
52
122
  });
53
123
  //# sourceMappingURL=indexer-cli.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"indexer-cli.js","sourceRoot":"","sources":["../../src/indexer-cli.ts"],"names":[],"mappings":";;AACA;;;;;;;;;;;;GAYG;;AAEH,yCAAyD;AACzD,uCAA6C;AAG7C,KAAK,UAAU,SAAS,CAAI,GAAW;IACrC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,QAAQ,GAAG,CAAC,MAAM,aAAa,GAAG,KAAK,MAAM,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAC7E,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,EAAgB,CAAC;AAClC,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClC,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAElC,IAAI,CAAC,SAAS,IAAI,CAAC,SAAS,EAAE,CAAC;QAC7B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC;QACrE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,kCAAkC;IAClC,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAE1C,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC5C,SAAS,CACP,GAAG,IAAI,YAAY,SAAS,EAAE,CAC/B;QACD,SAAS,CAAgB,GAAG,IAAI,YAAY,SAAS,UAAU,CAAC;KACjE,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,IAAA,wBAAa,GAAE,CAAC;IAC/B,MAAM,EAAE,GAAG,IAAA,uBAAY,EAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IACpC,IAAI,CAAC;QACH,MAAM,IAAA,0BAAgB,EACpB,EAAE,EACF,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,EACtE,QAAQ,EACR,UAAU,CACX,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;IAED,gEAAgE;AAClE,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,4CAA4C,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CACjG,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"indexer-cli.js","sourceRoot":"","sources":["../../src/indexer-cli.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"indexer.d.ts","sourceRoot":"","sources":["../../src/indexer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACvE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAU3C,MAAM,WAAW,cAAc;IAC7B,gFAAgF;IAChF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,0EAA0E;IAC1E,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,QAAQ,EACZ,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,WAAW,EAAE,EACvB,MAAM,GAAE,aAA0B,EAClC,OAAO,GAAE,IAAI,CAAC,cAAc,EAAE,cAAc,GAAG,gBAAgB,CAAM,GACpE,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAoE/C;AAMD;;;GAGG;AACH,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,WAAW,EAAE,EACvB,MAAM,GAAE,aAA0B,EAClC,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAU/C;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,WAAW,EAAE,EACvB,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAmB9B"}
1
+ {"version":3,"file":"indexer.d.ts","sourceRoot":"","sources":["../../src/indexer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACvE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAU3C,MAAM,WAAW,cAAc;IAC7B,gFAAgF;IAChF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,0EAA0E;IAC1E,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,QAAQ,EACZ,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,WAAW,EAAE,EACvB,MAAM,GAAE,aAA0B,EAClC,OAAO,GAAE,IAAI,CAAC,cAAc,EAAE,cAAc,GAAG,gBAAgB,CAAM,GACpE,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CA+G/C;AAMD;;;GAGG;AACH,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,WAAW,EAAE,EACvB,MAAM,GAAE,aAA0B,EAClC,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAU/C;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,WAAW,EAAE,EACvB,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAmB9B"}
@@ -34,14 +34,25 @@ async function indexNewMessages(db, session, messages, source = "opencode", opti
34
34
  // Load or initialise the session meta record
35
35
  const meta = (0, database_1.getSessionMeta)(db, sessionId);
36
36
  const lastIndexedId = meta?.last_indexed_message_id ?? null;
37
- // Filter to only messages after the last indexed one
37
+ // Filter to only messages after the last indexed one.
38
+ // If lastIndexedId is set but not found in the message list, this means the
39
+ // ID format changed (e.g. migrating from SQLite bubble IDs to transcript line
40
+ // IDs). In that case, purge the existing session chunks and re-index from
41
+ // scratch to avoid duplicates.
38
42
  let newMessages;
39
43
  if (lastIndexedId === null) {
40
44
  newMessages = messages;
41
45
  }
42
46
  else {
43
47
  const lastIdx = messages.findIndex((m) => m.info.id === lastIndexedId);
44
- newMessages = lastIdx === -1 ? messages : messages.slice(lastIdx + 1);
48
+ if (lastIdx === -1) {
49
+ // ID not found — purge stale chunks and re-index everything
50
+ (0, database_1.deleteSession)(db, sessionId);
51
+ newMessages = messages;
52
+ }
53
+ else {
54
+ newMessages = messages.slice(lastIdx + 1);
55
+ }
45
56
  }
46
57
  if (newMessages.length === 0) {
47
58
  return { indexed: 0, skipped: messages.length };
@@ -50,11 +61,22 @@ async function indexNewMessages(db, session, messages, source = "opencode", opti
50
61
  apiKey: options.openAiApiKey,
51
62
  model: options.embeddingModel,
52
63
  });
53
- let totalChunksIndexed = 0;
54
- for (const msg of newMessages) {
64
+ // Single timestamp for all chunks in this indexing run — represents when
65
+ // the session turn was indexed (within seconds of when it was written).
66
+ const indexedAt = Date.now();
67
+ // The first new message's position within the full session (0-based).
68
+ // Used to assign stable message_order values so chunks sort chronologically
69
+ // regardless of message ID format (works for OpenCode, Claude Code, Cursor).
70
+ const firstNewMessageOrder = messages.length - newMessages.length;
71
+ const perMessage = [];
72
+ const allTexts = [];
73
+ for (let i = 0; i < newMessages.length; i++) {
74
+ const msg = newMessages[i];
55
75
  const md = (0, session_to_md_1.messageToMarkdown)(msg);
56
- if (!md.trim())
76
+ if (!md.trim()) {
77
+ perMessage.push({ chunks: [] });
57
78
  continue;
79
+ }
58
80
  const msgUrl = `session://${sessionId}#${msg.info.id}`;
59
81
  const chunks = (0, chunker_1.chunkMarkdown)(md, {
60
82
  sessionId,
@@ -62,14 +84,26 @@ async function indexNewMessages(db, session, messages, source = "opencode", opti
62
84
  project,
63
85
  baseUrl: msgUrl,
64
86
  });
87
+ // Stamp every chunk with the indexing time and message position
88
+ const messageOrder = firstNewMessageOrder + i;
89
+ for (const chunk of chunks) {
90
+ chunk.metadata.created_at = indexedAt;
91
+ chunk.metadata.message_order = messageOrder;
92
+ }
93
+ perMessage.push({ chunks });
94
+ allTexts.push(...chunks.map((c) => c.content));
95
+ }
96
+ // --- Phase 2: embed all chunks in one batch ---
97
+ const allEmbeddings = allTexts.length > 0 ? await embedder.embedBatch(allTexts) : [];
98
+ // --- Phase 3: slice embeddings back per message and insert ---
99
+ let embeddingOffset = 0;
100
+ for (const { chunks } of perMessage) {
65
101
  if (chunks.length === 0)
66
102
  continue;
67
- const texts = chunks.map((c) => c.content);
68
- const embeddings = await embedder.embedBatch(texts);
103
+ const embeddings = allEmbeddings.slice(embeddingOffset, embeddingOffset + chunks.length);
69
104
  (0, database_1.insertChunks)(db, chunks, embeddings);
70
- totalChunksIndexed += chunks.length;
105
+ embeddingOffset += chunks.length;
71
106
  }
72
- void totalChunksIndexed;
73
107
  // Update session meta with the last message we processed
74
108
  const lastMsg = newMessages[newMessages.length - 1];
75
109
  (0, database_1.upsertSessionMeta)(db, {
@@ -80,6 +114,9 @@ async function indexNewMessages(db, session, messages, source = "opencode", opti
80
114
  last_indexed_message_id: lastMsg.info.id,
81
115
  updated_at: Date.now(),
82
116
  });
117
+ // Flush WAL to the main DB file so that a subsequent status check on a
118
+ // separate connection sees the newly indexed data immediately.
119
+ db.pragma("wal_checkpoint(PASSIVE)");
83
120
  return { indexed: newMessages.length, skipped: messages.length - newMessages.length };
84
121
  }
85
122
  // ---------------------------------------------------------------------------
@@ -1 +1 @@
1
- {"version":3,"file":"indexer.js","sourceRoot":"","sources":["../../src/indexer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"indexer.js","sourceRoot":"","sources":["../../src/indexer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * opencode-db-to-messages
3
+ *
4
+ * Reads session info and messages directly from OpenCode's internal SQLite
5
+ * database (~/.local/share/opencode/opencode.db), bypassing the REST API.
6
+ *
7
+ * This is the fallback path used by indexer-cli when OpenCode was started
8
+ * without --port (e.g. `opencode -s <sessionId>`), in which case no HTTP
9
+ * server is started and the REST API is unavailable.
10
+ *
11
+ * The DB is opened read-only — no WAL conflicts, no write contention.
12
+ */
13
+ import type { FullMessage } from "./types";
14
+ export interface OpenCodeSession {
15
+ id: string;
16
+ title: string;
17
+ directory: string;
18
+ }
19
+ /**
20
+ * Returns session metadata from the OpenCode DB, or null if not found.
21
+ */
22
+ export declare function getSessionFromOpenCodeDb(sessionId: string, dbPath?: string): OpenCodeSession | null;
23
+ /**
24
+ * Returns all messages for a session from the OpenCode DB, in chronological
25
+ * order, shaped as FullMessage[] (same format as the REST API response).
26
+ *
27
+ * Returns null if the DB is not accessible.
28
+ */
29
+ export declare function getMessagesFromOpenCodeDb(sessionId: string, dbPath?: string): FullMessage[] | null;
30
+ //# sourceMappingURL=opencode-db-to-messages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode-db-to-messages.d.ts","sourceRoot":"","sources":["../../src/opencode-db-to-messages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,OAAO,KAAK,EAAE,WAAW,EAA4B,MAAM,SAAS,CAAC;AAkCrE,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,MAAM,EACjB,MAAM,SAA0B,GAC/B,eAAe,GAAG,IAAI,CAcxB;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,EACjB,MAAM,SAA0B,GAC/B,WAAW,EAAE,GAAG,IAAI,CA8CtB"}
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ /**
3
+ * opencode-db-to-messages
4
+ *
5
+ * Reads session info and messages directly from OpenCode's internal SQLite
6
+ * database (~/.local/share/opencode/opencode.db), bypassing the REST API.
7
+ *
8
+ * This is the fallback path used by indexer-cli when OpenCode was started
9
+ * without --port (e.g. `opencode -s <sessionId>`), in which case no HTTP
10
+ * server is started and the REST API is unavailable.
11
+ *
12
+ * The DB is opened read-only — no WAL conflicts, no write contention.
13
+ */
14
+ var __importDefault = (this && this.__importDefault) || function (mod) {
15
+ return (mod && mod.__esModule) ? mod : { "default": mod };
16
+ };
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.getSessionFromOpenCodeDb = getSessionFromOpenCodeDb;
19
+ exports.getMessagesFromOpenCodeDb = getMessagesFromOpenCodeDb;
20
+ const path_1 = __importDefault(require("path"));
21
+ const os_1 = __importDefault(require("os"));
22
+ const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
23
+ // ---------------------------------------------------------------------------
24
+ // Default DB path
25
+ // ---------------------------------------------------------------------------
26
+ function resolveOpenCodeDbPath() {
27
+ return path_1.default.join(os_1.default.homedir(), ".local", "share", "opencode", "opencode.db");
28
+ }
29
+ /**
30
+ * Returns session metadata from the OpenCode DB, or null if not found.
31
+ */
32
+ function getSessionFromOpenCodeDb(sessionId, dbPath = resolveOpenCodeDbPath()) {
33
+ let db;
34
+ try {
35
+ db = new better_sqlite3_1.default(dbPath, { readonly: true, fileMustExist: true });
36
+ const row = db
37
+ .prepare("SELECT id, title, directory FROM session WHERE id = ?")
38
+ .get(sessionId);
39
+ if (!row)
40
+ return null;
41
+ return { id: row.id, title: row.title, directory: row.directory };
42
+ }
43
+ catch {
44
+ return null;
45
+ }
46
+ finally {
47
+ db?.close();
48
+ }
49
+ }
50
+ /**
51
+ * Returns all messages for a session from the OpenCode DB, in chronological
52
+ * order, shaped as FullMessage[] (same format as the REST API response).
53
+ *
54
+ * Returns null if the DB is not accessible.
55
+ */
56
+ function getMessagesFromOpenCodeDb(sessionId, dbPath = resolveOpenCodeDbPath()) {
57
+ let db;
58
+ try {
59
+ db = new better_sqlite3_1.default(dbPath, { readonly: true, fileMustExist: true });
60
+ const messageRows = db
61
+ .prepare("SELECT id, data FROM message WHERE session_id = ? ORDER BY time_created ASC")
62
+ .all(sessionId);
63
+ if (messageRows.length === 0)
64
+ return [];
65
+ return messageRows.map((row) => {
66
+ const msgData = JSON.parse(row.data);
67
+ const info = {
68
+ id: row.id,
69
+ role: msgData.role,
70
+ time: msgData.time,
71
+ agent: msgData.agent,
72
+ modelID: msgData.modelID,
73
+ };
74
+ const partRows = db
75
+ .prepare("SELECT id, data FROM part WHERE message_id = ? ORDER BY time_created ASC")
76
+ .all(row.id);
77
+ const parts = partRows.map((p) => JSON.parse(p.data));
78
+ return { info, parts };
79
+ });
80
+ }
81
+ catch {
82
+ return null;
83
+ }
84
+ finally {
85
+ db?.close();
86
+ }
87
+ }
88
+ //# sourceMappingURL=opencode-db-to-messages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode-db-to-messages.js","sourceRoot":"","sources":["../../src/opencode-db-to-messages.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;;;AAgDH,4DAiBC;AAQD,8DAiDC;AAxHD,gDAAwB;AACxB,4CAAoB;AACpB,oEAAsC;AAGtC,8EAA8E;AAC9E,kBAAkB;AAClB,8EAA8E;AAE9E,SAAS,qBAAqB;IAC5B,OAAO,cAAI,CAAC,IAAI,CAAC,YAAE,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,aAAa,CAAC,CAAC;AAC/E,CAAC;AAgCD;;GAEG;AACH,SAAgB,wBAAwB,CACtC,SAAiB,EACjB,MAAM,GAAG,qBAAqB,EAAE;IAEhC,IAAI,EAAiC,CAAC;IACtC,IAAI,CAAC;QACH,EAAE,GAAG,IAAI,wBAAQ,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QACnE,MAAM,GAAG,GAAG,EAAE;aACX,OAAO,CAAC,uDAAuD,CAAC;aAChE,GAAG,CAAC,SAAS,CAA2B,CAAC;QAC5C,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC;QACtB,OAAO,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,CAAC;IACpE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;YAAS,CAAC;QACT,EAAE,EAAE,KAAK,EAAE,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAgB,yBAAyB,CACvC,SAAiB,EACjB,MAAM,GAAG,qBAAqB,EAAE;IAEhC,IAAI,EAAiC,CAAC;IACtC,IAAI,CAAC;QACH,EAAE,GAAG,IAAI,wBAAQ,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAEnE,MAAM,WAAW,GAAG,EAAE;aACnB,OAAO,CACN,6EAA6E,CAC9E;aACA,GAAG,CAAC,SAAS,CAAiB,CAAC;QAElC,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAExC,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;YAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAKlC,CAAC;YAEF,MAAM,IAAI,GAAgB;gBACxB,EAAE,EAAE,GAAG,CAAC,EAAE;gBACV,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,KAAK,EAAE,OAAO,CAAC,KAAK;gBACpB,OAAO,EAAE,OAAO,CAAC,OAAO;aACzB,CAAC;YAEF,MAAM,QAAQ,GAAG,EAAG;iBACjB,OAAO,CACN,0EAA0E,CAC3E;iBACA,GAAG,CAAC,GAAG,CAAC,EAAE,CAAc,CAAC;YAE5B,MAAM,KAAK,GAAkB,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAC9C,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAgB,CAClC,CAAC;YAEF,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;QACzB,CAAC,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;YAAS,CAAC;QACT,EAAE,EAAE,KAAK,EAAE,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -14,12 +14,16 @@ export interface DocumentChunk {
14
14
  hash: string;
15
15
  chunk_index: number;
16
16
  total_chunks: number;
17
+ /** 0-based position of this message within the session (set at index time). Used for correct print ordering. */
18
+ message_order?: number;
19
+ /** Unix ms timestamp set at insert time (Date.now()). Used for date filtering. */
20
+ created_at?: number;
17
21
  };
18
22
  }
19
23
  /**
20
24
  * Which tool produced a session.
21
25
  */
22
- export type SessionSource = "opencode" | "claude-code";
26
+ export type SessionSource = "opencode" | "claude-code" | "cursor";
23
27
  /**
24
28
  * A row in the sessions_meta table — tracks per-session indexing progress.
25
29
  */
@@ -92,6 +96,7 @@ export interface QueryResult {
92
96
  chunk_index?: number;
93
97
  total_chunks?: number;
94
98
  source?: SessionSource;
99
+ created_at?: number;
95
100
  }
96
101
  /**
97
102
  * Config for the database layer.
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "code-session-memory",
3
- "version": "0.4.4",
4
- "description": "Automatically index OpenCode and Claude Code sessions into a shared sqlite-vec vector database for semantic search across your AI coding history",
3
+ "version": "0.7.0",
4
+ "description": "Automatically index OpenCode, Claude Code, and Cursor sessions into a shared sqlite-vec vector database for semantic search across your AI coding history",
5
5
  "type": "commonjs",
6
6
  "main": "dist/src/indexer.js",
7
7
  "types": "dist/src/indexer.d.ts",
@@ -26,6 +26,7 @@
26
26
  "keywords": [
27
27
  "opencode",
28
28
  "claude-code",
29
+ "cursor",
29
30
  "mcp",
30
31
  "sqlite-vec",
31
32
  "vector",
package/plugin/memory.ts CHANGED
@@ -29,7 +29,15 @@ const MemoryPlugin: Plugin = async ({ $, serverUrl }) => {
29
29
  if (!sessionId) return;
30
30
 
31
31
  try {
32
- await $`node ${INDEXER_CLI} ${sessionId} ${serverUrl.toString()}`.quiet();
32
+ const result = await $`node ${INDEXER_CLI} ${sessionId} ${serverUrl.toString()}`
33
+ .quiet()
34
+ .nothrow();
35
+ if (result.exitCode !== 0) {
36
+ const stderr = result.stderr.toString().trim();
37
+ console.error(
38
+ `[opencode-memory] Failed to index session ${sessionId}: exit code ${result.exitCode}${stderr ? `: ${stderr}` : ""}`,
39
+ );
40
+ }
33
41
  } catch (err: unknown) {
34
42
  const msg = err instanceof Error ? err.message : String(err);
35
43
  console.error(`[opencode-memory] Failed to index session ${sessionId}: ${msg}`);
package/skill/memory.md CHANGED
@@ -15,8 +15,10 @@ Semantically search across all indexed sessions to find past conversations, deci
15
15
  **Parameters:**
16
16
  - `queryText` *(required)*: A natural language description of what you are looking for.
17
17
  - `project` *(optional)*: Filter results to a specific project directory path (e.g. `"/Users/me/myproject"`).
18
- - `source` *(optional)*: Filter by tool — `"opencode"` or `"claude-code"`. Omit to search across both.
18
+ - `source` *(optional)*: Filter by tool — `"opencode"`, `"claude-code"`, or `"cursor"`. Omit to search across all.
19
19
  - `limit` *(optional, default 5)*: Number of results to return (1–20).
20
+ - `fromDate` *(optional)*: Return only chunks indexed on or after this date. ISO 8601, e.g. `"2026-02-01"` or `"2026-02-20T15:00:00Z"`.
21
+ - `toDate` *(optional)*: Return only chunks indexed on or before this date. ISO 8601, e.g. `"2026-02-20"`. Date-only values are treated as end-of-day UTC.
20
22
 
21
23
  ### `get_session_chunks`
22
24
 
@@ -49,13 +51,16 @@ query_sessions("dark mode toggle", project="/Users/me/myapp", source="opencode")
49
51
  # Search only Claude Code sessions
50
52
  query_sessions("sqlite migration", source="claude-code")
51
53
 
54
+ # Search sessions from a specific date range
55
+ query_sessions("authentication middleware", fromDate="2026-02-01", toDate="2026-02-20")
56
+
52
57
  # Get more context from a specific result
53
58
  get_session_chunks("session://ses_abc123#msg_def456")
54
59
  ```
55
60
 
56
61
  ## Notes
57
62
 
58
- - Sessions from both OpenCode and Claude Code are indexed into the **same** database.
63
+ - Sessions from OpenCode, Claude Code, and Cursor are indexed into the **same** database.
59
64
  - Indexing is automatic — no manual action needed.
60
65
  - The database lives at `~/.local/share/code-session-memory/sessions.db`.
61
66
  - Embeddings use OpenAI `text-embedding-3-large` (3072 dimensions).