@codemem/opencode-plugin 0.40.0 → 0.40.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/.opencode/plugins/codemem.js +78 -5
- package/package.json +1 -1
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
|
|
16
16
|
const TRUTHY_VALUES = ["1", "true", "yes"];
|
|
17
17
|
const DISABLED_VALUES = ["0", "false", "off"];
|
|
18
|
-
const PINNED_BACKEND_VERSION = "0.40.
|
|
18
|
+
const PINNED_BACKEND_VERSION = "0.40.1";
|
|
19
19
|
const COMPAT_CHECK_DELAY_MS = 1500;
|
|
20
20
|
const COMPAT_CHECK_CACHE_TTL_MS = 5 * 60 * 1000;
|
|
21
21
|
const CODEMEM_CONTEXT_PART_ID_PREFIX = "codemem-context-";
|
|
@@ -91,6 +91,45 @@ const rejectsInternalLedgerFlag = (result) => {
|
|
|
91
91
|
&& /(?:unknown|unsupported|unrecognized|invalid)\s+(?:option|argument)/i.test(diagnostics);
|
|
92
92
|
};
|
|
93
93
|
|
|
94
|
+
const parseFallbackStructuredError = (stdout) => {
|
|
95
|
+
const lines = String(stdout || "").trim().split(/\r?\n/).reverse();
|
|
96
|
+
for (const line of lines) {
|
|
97
|
+
try {
|
|
98
|
+
const parsed = JSON.parse(line);
|
|
99
|
+
if (parsed && typeof parsed === "object") {
|
|
100
|
+
return {
|
|
101
|
+
code: typeof parsed.error === "string" ? parsed.error : "",
|
|
102
|
+
message: typeof parsed.message === "string" ? parsed.message : "",
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
} catch {
|
|
106
|
+
// Continue past non-JSON CLI output.
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return { code: "", message: "" };
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const classifyFallbackCommandResult = (result) => {
|
|
113
|
+
const structured = parseFallbackStructuredError(result?.stdout);
|
|
114
|
+
const diagnostic = [structured.code, structured.message, result?.stderr, result?.stdout]
|
|
115
|
+
.filter(Boolean)
|
|
116
|
+
.join("\n");
|
|
117
|
+
if (/SQLITE_(?:BUSY|LOCKED)|database(?: table)? (?:is )?(?:busy|locked)/i.test(diagnostic)) {
|
|
118
|
+
return { retryable: true, cause: "SQLite database is locked" };
|
|
119
|
+
}
|
|
120
|
+
if (result?.exitCode == null && /(?:timeout|timed out|ETIMEDOUT)/i.test(diagnostic)) {
|
|
121
|
+
return { retryable: true, cause: "enqueue-raw-event command timeout" };
|
|
122
|
+
}
|
|
123
|
+
if (structured.code === "validation_error" || /invalid raw event|session id required/i.test(diagnostic)) {
|
|
124
|
+
return { retryable: false, cause: "enqueue-raw-event validation failed" };
|
|
125
|
+
}
|
|
126
|
+
if (/unknown command ['\"]?enqueue-raw-event|command not found|\bENOENT\b/i.test(diagnostic)) {
|
|
127
|
+
return { retryable: false, cause: "enqueue-raw-event command unavailable" };
|
|
128
|
+
}
|
|
129
|
+
const exitCode = result?.exitCode ?? "unknown";
|
|
130
|
+
return { retryable: false, cause: `enqueue-raw-event failed (${exitCode})` };
|
|
131
|
+
};
|
|
132
|
+
|
|
94
133
|
const DEFAULT_LOG_PATH = (homeDir, cwd) => `${homeDir || cwd}/.codemem/plugin.log`;
|
|
95
134
|
|
|
96
135
|
const resolveLogPath = (logPathEnvRaw, cwd, homeDir) => {
|
|
@@ -1369,13 +1408,24 @@ export const OpencodeMemPlugin = async ({
|
|
|
1369
1408
|
};
|
|
1370
1409
|
|
|
1371
1410
|
const queueRawEventViaCli = async (body) => {
|
|
1372
|
-
const
|
|
1411
|
+
const runFallback = () => runCli(["enqueue-raw-event"], {
|
|
1373
1412
|
stdinText: JSON.stringify(body),
|
|
1374
1413
|
});
|
|
1414
|
+
let result = await runFallback();
|
|
1415
|
+
let classification = classifyFallbackCommandResult(result);
|
|
1416
|
+
let attemptedRetry = false;
|
|
1417
|
+
if (result?.exitCode !== 0 && classification.retryable) {
|
|
1418
|
+
attemptedRetry = true;
|
|
1419
|
+
result = await runFallback();
|
|
1420
|
+
classification = classifyFallbackCommandResult(result);
|
|
1421
|
+
}
|
|
1375
1422
|
if (result?.exitCode !== 0) {
|
|
1376
|
-
|
|
1377
|
-
|
|
1423
|
+
const retryExhausted = attemptedRetry && classification.retryable;
|
|
1424
|
+
const error = new Error(
|
|
1425
|
+
retryExhausted ? `${classification.cause} after retry` : classification.cause
|
|
1378
1426
|
);
|
|
1427
|
+
error.retryable = classification.retryable && !attemptedRetry;
|
|
1428
|
+
throw error;
|
|
1379
1429
|
}
|
|
1380
1430
|
return true;
|
|
1381
1431
|
};
|
|
@@ -1434,6 +1484,9 @@ export const OpencodeMemPlugin = async ({
|
|
|
1434
1484
|
}
|
|
1435
1485
|
return true;
|
|
1436
1486
|
} catch (fallbackErr) {
|
|
1487
|
+
if (payload && typeof payload === "object") {
|
|
1488
|
+
payload._raw_fallback_terminal = fallbackErr?.retryable !== true;
|
|
1489
|
+
}
|
|
1437
1490
|
await logLine(
|
|
1438
1491
|
`raw_events.fallback.error sessionID=${sessionID} type=${type} err=${String(
|
|
1439
1492
|
fallbackErr
|
|
@@ -1525,6 +1578,9 @@ export const OpencodeMemPlugin = async ({
|
|
|
1525
1578
|
await queueRawEventViaCli(body);
|
|
1526
1579
|
fallbackOk = true;
|
|
1527
1580
|
} catch (fallbackErr) {
|
|
1581
|
+
if (payload && typeof payload === "object") {
|
|
1582
|
+
payload._raw_fallback_terminal = fallbackErr?.retryable !== true;
|
|
1583
|
+
}
|
|
1528
1584
|
await logLine(
|
|
1529
1585
|
`raw_events.fallback.error sessionID=${sessionID} type=${type} err=${String(
|
|
1530
1586
|
fallbackErr
|
|
@@ -1570,6 +1626,7 @@ export const OpencodeMemPlugin = async ({
|
|
|
1570
1626
|
|
|
1571
1627
|
if (!streamErrorNoted) {
|
|
1572
1628
|
streamErrorNoted = true;
|
|
1629
|
+
fallbackFailureNoted = true;
|
|
1573
1630
|
try {
|
|
1574
1631
|
await client.app.log({
|
|
1575
1632
|
service: "codemem",
|
|
@@ -2726,10 +2783,18 @@ export const OpencodeMemPlugin = async ({
|
|
|
2726
2783
|
}
|
|
2727
2784
|
|
|
2728
2785
|
const failed = [];
|
|
2786
|
+
let droppedCount = 0;
|
|
2729
2787
|
for (const queuedEvent of batch) {
|
|
2730
2788
|
if (queuedEvent && typeof queuedEvent === "object" && queuedEvent._raw_enqueued) {
|
|
2731
2789
|
continue;
|
|
2732
2790
|
}
|
|
2791
|
+
if (queuedEvent && typeof queuedEvent === "object" && queuedEvent._raw_fallback_terminal) {
|
|
2792
|
+
droppedCount += 1;
|
|
2793
|
+
await logLine(
|
|
2794
|
+
`flush.drop terminal_fallback event_id=${queuedEvent?._raw_event_id || "unknown"}`
|
|
2795
|
+
);
|
|
2796
|
+
continue;
|
|
2797
|
+
}
|
|
2733
2798
|
const queuedSessionID =
|
|
2734
2799
|
queuedEvent?._raw_session_id ||
|
|
2735
2800
|
queuedEvent?.properties?.sessionID ||
|
|
@@ -2740,6 +2805,13 @@ export const OpencodeMemPlugin = async ({
|
|
|
2740
2805
|
payload: queuedEvent,
|
|
2741
2806
|
});
|
|
2742
2807
|
if (!ok) {
|
|
2808
|
+
if (queuedEvent?._raw_fallback_terminal) {
|
|
2809
|
+
droppedCount += 1;
|
|
2810
|
+
await logLine(
|
|
2811
|
+
`flush.drop terminal_fallback event_id=${queuedEvent?._raw_event_id || "unknown"}`
|
|
2812
|
+
);
|
|
2813
|
+
continue;
|
|
2814
|
+
}
|
|
2743
2815
|
const currentRetry =
|
|
2744
2816
|
typeof queuedEvent?._raw_retry_count === "number" && Number.isFinite(queuedEvent._raw_retry_count)
|
|
2745
2817
|
? queuedEvent._raw_retry_count
|
|
@@ -2764,7 +2836,7 @@ export const OpencodeMemPlugin = async ({
|
|
|
2764
2836
|
await logLine(
|
|
2765
2837
|
`flush.stream_only finalize count=${batch.length} tools=${sessionContext.toolCount} prompts=${sessionContext.promptCount} duration=${Math.round(durationMs / 1000)}s`
|
|
2766
2838
|
);
|
|
2767
|
-
await logLine(`flush.ok count=${batch.length}`);
|
|
2839
|
+
await logLine(`flush.ok count=${batch.length - droppedCount} dropped=${droppedCount}`);
|
|
2768
2840
|
sessionStartedAt = null;
|
|
2769
2841
|
resetSessionContext();
|
|
2770
2842
|
};
|
|
@@ -3203,6 +3275,7 @@ export const __testUtils = {
|
|
|
3203
3275
|
hashPromptPackQuery,
|
|
3204
3276
|
redactPackCommand,
|
|
3205
3277
|
rejectsInternalLedgerFlag,
|
|
3278
|
+
classifyFallbackCommandResult,
|
|
3206
3279
|
parsePackText,
|
|
3207
3280
|
parsePackMetrics,
|
|
3208
3281
|
resolveInjectSurface,
|