code-session-memory 0.6.0 → 0.7.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.
package/README.md CHANGED
@@ -235,6 +235,7 @@ code-session-memory/
235
235
  │ ├── transcript-to-messages.ts # Claude Code JSONL transcript parser
236
236
  │ ├── cursor-to-messages.ts # Cursor state.vscdb reader (metadata + title)
237
237
  │ ├── cursor-transcript-to-messages.ts # Cursor JSONL transcript parser → FullMessage[]
238
+ │ ├── opencode-db-to-messages.ts # OpenCode internal DB reader (fallback for -s mode)
238
239
  │ ├── indexer.ts # Orchestrator: incremental indexing
239
240
  │ ├── indexer-cli.ts # Node.js subprocess (called by OpenCode plugin)
240
241
  │ ├── indexer-cli-claude.ts # Node.js subprocess (called by Claude Code hook)
@@ -259,6 +260,7 @@ code-session-memory/
259
260
  ├── session-to-md.test.ts
260
261
  ├── cursor-to-messages.test.ts # Unit tests: Cursor SQLite reader
261
262
  ├── cursor-transcript-to-messages.test.ts # Unit tests: Cursor JSONL parser
263
+ ├── opencode-db-to-messages.test.ts # Unit tests: OpenCode internal DB reader
262
264
  ├── e2e-claude.test.ts # End-to-end: Claude Code pipeline
263
265
  ├── e2e-opencode.test.ts # End-to-end: OpenCode pipeline
264
266
  ├── e2e-cursor.test.ts # End-to-end: Cursor pipeline
@@ -303,10 +305,11 @@ Tests use [Vitest](https://vitest.dev) and run without any external dependencies
303
305
  ✓ tests/indexer.test.ts (9 tests)
304
306
  ✓ tests/cursor-to-messages.test.ts (15 tests)
305
307
  ✓ tests/cursor-transcript-to-messages.test.ts (7 tests)
308
+ ✓ tests/opencode-db-to-messages.test.ts (8 tests)
306
309
  ✓ tests/e2e-claude.test.ts (18 tests)
307
310
  ✓ tests/e2e-cursor.test.ts (8 tests)
308
311
  ✓ tests/e2e-opencode.test.ts (14 tests)
309
- Tests 157 passed
312
+ Tests 165 passed
310
313
  ```
311
314
 
312
315
  To refresh the e2e fixtures (e.g. after changing the indexer or parsers), run:
@@ -14,8 +14,12 @@
14
14
  * Uses plain fetch() to call the REST API — no ESM/CJS SDK dependency.
15
15
  */
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ const openai_1 = require("openai");
17
18
  const database_1 = require("./database");
18
19
  const indexer_1 = require("./indexer");
20
+ const opencode_db_to_messages_1 = require("./opencode-db-to-messages");
21
+ const FETCH_RETRIES = 3;
22
+ const FETCH_RETRY_DELAY_MS = 500;
19
23
  async function fetchJson(url) {
20
24
  const res = await fetch(url);
21
25
  if (!res.ok) {
@@ -23,6 +27,41 @@ async function fetchJson(url) {
23
27
  }
24
28
  return res.json();
25
29
  }
30
+ /**
31
+ * Fetches JSON from the OpenCode REST API with retries.
32
+ * If the server is unreachable (network error), retries up to FETCH_RETRIES
33
+ * times with a short delay. This handles the case where session.idle fires
34
+ * just as OpenCode is shutting down or restarting.
35
+ *
36
+ * Returns null if the server remains unreachable after all retries — the
37
+ * caller should treat this as a graceful no-op (session is gone, nothing to index).
38
+ *
39
+ * Only retries on network-level errors (fetch failed). HTTP errors (4xx/5xx)
40
+ * are propagated immediately.
41
+ */
42
+ async function fetchJsonWithRetry(url) {
43
+ for (let attempt = 0; attempt <= FETCH_RETRIES; attempt++) {
44
+ try {
45
+ return await fetchJson(url);
46
+ }
47
+ catch (err) {
48
+ // TypeError with message "fetch failed" covers all network-level failures:
49
+ // ECONNREFUSED, EADDRNOTAVAIL, ENOTFOUND, bad port, IPv6 unreachable, etc.
50
+ const isNetworkError = err instanceof TypeError && err.message === "fetch failed";
51
+ if (isNetworkError) {
52
+ if (attempt < FETCH_RETRIES) {
53
+ await new Promise((r) => setTimeout(r, FETCH_RETRY_DELAY_MS));
54
+ continue;
55
+ }
56
+ // All retries exhausted — server is gone, signal graceful no-op.
57
+ return null;
58
+ }
59
+ // Non-network error (e.g. HTTP 4xx/5xx) — propagate immediately.
60
+ throw err;
61
+ }
62
+ }
63
+ return null;
64
+ }
26
65
  async function main() {
27
66
  const sessionId = process.argv[2];
28
67
  const serverUrl = process.argv[3];
@@ -30,12 +69,43 @@ async function main() {
30
69
  process.stderr.write("Usage: indexer-cli <sessionId> <serverUrl>\n");
31
70
  process.exit(1);
32
71
  }
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`),
72
+ // Normalize the server URL:
73
+ // - Strip trailing slash
74
+ // - Rewrite IPv6 loopback [::1] and "localhost" to 127.0.0.1 (IPv4).
75
+ // OpenCode binds to 127.0.0.1 by default, but when started with -s it may
76
+ // construct serverUrl using "localhost", which on many systems resolves to
77
+ // ::1 (IPv6) first. Node's fetch then fails with ECONNREFUSED because the
78
+ // server isn't listening on IPv6.
79
+ const base = serverUrl
80
+ .replace(/\/$/, "")
81
+ .replace(/^http:\/\/\[::1\]/i, "http://127.0.0.1")
82
+ .replace(/^http:\/\/localhost/i, "http://127.0.0.1");
83
+ // Fetch session + messages in parallel via REST API, with retry on network errors.
84
+ // Returns null on any network-level failure (server not running / no --port).
85
+ const [fetchedSession, fetchedMessages] = await Promise.all([
86
+ fetchJsonWithRetry(`${base}/session/${sessionId}`),
87
+ fetchJsonWithRetry(`${base}/session/${sessionId}/message`),
38
88
  ]);
89
+ let session;
90
+ let messages;
91
+ if (fetchedSession && fetchedMessages) {
92
+ // Happy path: REST API responded.
93
+ session = fetchedSession;
94
+ messages = fetchedMessages;
95
+ }
96
+ else {
97
+ // REST API unavailable (e.g. OpenCode started with -s and no --port, so no
98
+ // HTTP server is running). Fall back to reading directly from OpenCode's
99
+ // internal SQLite DB.
100
+ const dbSession = (0, opencode_db_to_messages_1.getSessionFromOpenCodeDb)(sessionId);
101
+ const dbMessages = (0, opencode_db_to_messages_1.getMessagesFromOpenCodeDb)(sessionId);
102
+ if (!dbSession || !dbMessages) {
103
+ // Neither source available — nothing to index, exit cleanly.
104
+ process.exit(0);
105
+ }
106
+ session = dbSession;
107
+ messages = dbMessages;
108
+ }
39
109
  const dbPath = (0, database_1.resolveDbPath)();
40
110
  const db = (0, database_1.openDatabase)({ dbPath });
41
111
  try {
@@ -47,7 +117,14 @@ async function main() {
47
117
  // No output — the plugin runs this silently via Bun's $.quiet()
48
118
  }
49
119
  main().catch((err) => {
50
- process.stderr.write(`[code-session-memory] indexer-cli error: ${err instanceof Error ? err.message : String(err)}\n`);
120
+ // Transient OpenAI errors (network blip, rate limit) exit cleanly so the
121
+ // plugin doesn't log a noisy red error. The messages remain un-indexed and
122
+ // will be picked up on the next session.idle event.
123
+ if (err instanceof openai_1.APIConnectionError || err instanceof openai_1.RateLimitError) {
124
+ process.exit(0);
125
+ }
126
+ const url = process.argv[3] ?? "(no url)";
127
+ process.stderr.write(`[code-session-memory] indexer-cli error: ${err instanceof Error ? err.message : String(err)} (serverUrl: ${url})\n`);
51
128
  process.exit(1);
52
129
  });
53
130
  //# 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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"}
@@ -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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "code-session-memory",
3
- "version": "0.6.0",
3
+ "version": "0.7.1",
4
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",
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}`);