opencode-claude-memory 1.7.5 → 1.7.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -217,6 +217,7 @@ Yes. Set `OPENCODE_MEMORY_AUTODREAM=0`. You can also tune gates with:
217
217
  - `OPENCODE_MEMORY_TERMINAL_LOG` (default `foreground-only`): set `1` to force terminal logs on, `0` to force them off
218
218
  - `OPENCODE_MEMORY_MODEL`: override model used for extraction
219
219
  - `OPENCODE_MEMORY_AGENT`: override agent used for extraction
220
+ - `OPENCODE_MEMORY_EXTRACT_TIMEOUT_MS` (default `120000`): positive integer timeout for a native extraction request in milliseconds
220
221
  - `OPENCODE_MEMORY_RECALL_MODEL`: override model used for LLM memory recall selection
221
222
  - `OPENCODE_MEMORY_RECALL_AGENT` (default `opencode-memory-recall`): override agent used for LLM memory recall selection
222
223
  - `OPENCODE_MEMORY_AUTODREAM` (default `1`): set `0` to disable auto-dream consolidation
package/dist/index.js CHANGED
@@ -6,6 +6,7 @@ import { isSupportedRecallSelectorClient, selectRelevantMemoryFilenames } from "
6
6
  import { scanMemoryFiles } from "./memoryScan.js";
7
7
  import { saveMemory, deleteMemory, listMemories, searchMemories, readMemory, MEMORY_TYPES, } from "./memory.js";
8
8
  import { getMemoryDir } from "./paths.js";
9
+ import { getNativeExtractTimeoutMs, logNativeExtractionFailure } from "./nativeExtraction.js";
9
10
  const turnContextBySession = new Map();
10
11
  const selectorSessionIDs = new Set();
11
12
  function shouldIgnoreMemoryContext(query) {
@@ -282,7 +283,6 @@ For each memory worth saving, call \`memory_save\` with:
282
283
  5. Be selective: 0-3 memories per session is typical. Quality over quantity.
283
284
  6. Do NOT save a memory about the extraction process itself.`;
284
285
  const NATIVE_EXTRACT_DEBOUNCE_MS = 10000;
285
- const NATIVE_EXTRACT_TIMEOUT_MS = 120000; // hard cap on a single extraction fork (prevents permanent leak on hang)
286
286
  const NATIVE_EXTRACT_MAX_CONV_CHARS = 60000;
287
287
  const NATIVE_EXTRACT_GRACE_MS = 60000; // keep forkID in the guard after delete — covers the idle-race window
288
288
  const nativeIdleTimer = new Map();
@@ -335,7 +335,7 @@ function buildConversationForExtraction(messages) {
335
335
  }
336
336
  // Security: the extraction fork runs on raw, potentially-untrusted transcript content (fetched web
337
337
  // pages, tool output). It MUST be sandboxed to the memory tools only (no bash/edit/write) and capped
338
- // by a timeout so a hang can't leak the sub-session forever.
338
+ // by a timeout so a hung prompt stops blocking best-effort sub-session cleanup.
339
339
  async function runNativeExtraction(client, sessionID, directory) {
340
340
  const c = client;
341
341
  if (!c?.session?.messages || !c.session.create || !c.session.prompt)
@@ -368,10 +368,10 @@ async function runNativeExtraction(client, sessionID, directory) {
368
368
  const extractModel = getNativeExtractModel();
369
369
  if (extractModel)
370
370
  body.model = extractModel;
371
- // Race the prompt against a hard timeout so a hung/permission-gated fork can't leak.
371
+ // Race the prompt against a timeout so a hung/permission-gated fork stops blocking cleanup.
372
372
  let timer;
373
373
  const timeout = new Promise((_, reject) => {
374
- timer = setTimeout(() => reject(new Error("native extraction timed out")), NATIVE_EXTRACT_TIMEOUT_MS);
374
+ timer = setTimeout(() => reject(new Error("native extraction timed out")), getNativeExtractTimeoutMs());
375
375
  });
376
376
  try {
377
377
  await Promise.race([
@@ -385,7 +385,7 @@ async function runNativeExtraction(client, sessionID, directory) {
385
385
  }
386
386
  }
387
387
  catch (e) {
388
- console.error("[opencode-claude-memory] native extraction failed:", e?.message ?? e);
388
+ logNativeExtractionFailure(client, directory, sessionID, e);
389
389
  }
390
390
  finally {
391
391
  if (forkID) {
@@ -460,7 +460,7 @@ export const MemoryPlugin = async ({ worktree, directory, client }) => {
460
460
  nativeIdleTimer.set(sessionID, setTimeout(() => {
461
461
  nativeIdleTimer.delete(sessionID);
462
462
  void runNativeExtraction(client, sessionID, directory).catch((e) => {
463
- console.error("[opencode-claude-memory] native extraction failed:", e?.message ?? e);
463
+ logNativeExtractionFailure(client, directory, sessionID, e);
464
464
  });
465
465
  }, NATIVE_EXTRACT_DEBOUNCE_MS));
466
466
  },
@@ -0,0 +1,2 @@
1
+ export declare function getNativeExtractTimeoutMs(raw?: string | undefined): number;
2
+ export declare function logNativeExtractionFailure(client: unknown, directory: string, sessionID: string, error: unknown): void;
@@ -0,0 +1,38 @@
1
+ const DEFAULT_NATIVE_EXTRACT_TIMEOUT_MS = 120_000;
2
+ const MAX_TIMER_DELAY_MS = 2_147_483_647;
3
+ function getErrorMessage(error) {
4
+ if (error instanceof Error)
5
+ return error.message;
6
+ if (error && typeof error === "object") {
7
+ const message = error.message;
8
+ if (typeof message === "string")
9
+ return message;
10
+ }
11
+ return String(error);
12
+ }
13
+ export function getNativeExtractTimeoutMs(raw = process.env.OPENCODE_MEMORY_EXTRACT_TIMEOUT_MS) {
14
+ const timeout = Number(raw);
15
+ return Number.isSafeInteger(timeout) && timeout > 0 && timeout <= MAX_TIMER_DELAY_MS
16
+ ? timeout
17
+ : DEFAULT_NATIVE_EXTRACT_TIMEOUT_MS;
18
+ }
19
+ export function logNativeExtractionFailure(client, directory, sessionID, error) {
20
+ const c = client;
21
+ if (!c?.app?.log)
22
+ return;
23
+ try {
24
+ const message = getErrorMessage(error);
25
+ void c.app.log({
26
+ body: {
27
+ service: "opencode-claude-memory",
28
+ level: "error",
29
+ message: "Native extraction failed",
30
+ extra: { error: message, sessionID },
31
+ },
32
+ query: { directory },
33
+ }).catch(() => { });
34
+ }
35
+ catch {
36
+ // Logging must stay best-effort: stderr is rendered into the OpenCode chat UI.
37
+ }
38
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-claude-memory",
3
- "version": "1.7.5",
3
+ "version": "1.7.6",
4
4
  "type": "module",
5
5
  "description": "OpenCode plugin for Claude Code memory: persistent, local-first shared memory with Claude Code-compatible Markdown files, auto extraction, and auto-dream",
6
6
  "main": "dist/index.js",