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 +1 -0
- package/dist/index.js +6 -6
- package/dist/nativeExtraction.d.ts +2 -0
- package/dist/nativeExtraction.js +38 -0
- package/package.json +1 -1
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
|
|
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
|
|
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")),
|
|
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
|
-
|
|
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
|
-
|
|
463
|
+
logNativeExtractionFailure(client, directory, sessionID, e);
|
|
464
464
|
});
|
|
465
465
|
}, NATIVE_EXTRACT_DEBOUNCE_MS));
|
|
466
466
|
},
|
|
@@ -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.
|
|
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",
|