opencode-immune 1.0.5 → 1.0.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/dist/plugin.js +38 -0
- package/package.json +1 -1
package/dist/plugin.js
CHANGED
|
@@ -13,6 +13,7 @@ function createState(input) {
|
|
|
13
13
|
retryTimers: new Map(),
|
|
14
14
|
retryCount: new Map(),
|
|
15
15
|
managedSessionsCachePath: (0, path_1.join)(input.directory, ".opencode", "state", "opencode-immune-managed-sessions.json"),
|
|
16
|
+
diagnosticsLogPath: (0, path_1.join)(input.directory, ".opencode", "state", "opencode-immune-debug.log"),
|
|
16
17
|
lastEditAttempt: null,
|
|
17
18
|
toolCallCount: 0,
|
|
18
19
|
todoWriteUsed: false,
|
|
@@ -66,6 +67,17 @@ async function writeManagedSessionsCache(state) {
|
|
|
66
67
|
console.log(`[opencode-immune] Pruned ${removed} expired managed ultrawork session(s) while writing cache.`);
|
|
67
68
|
}
|
|
68
69
|
}
|
|
70
|
+
async function writeDiagnosticLog(state, event, data = {}) {
|
|
71
|
+
try {
|
|
72
|
+
const cacheDir = (0, path_1.join)(state.input.directory, ".opencode", "state");
|
|
73
|
+
await (0, promises_1.mkdir)(cacheDir, { recursive: true });
|
|
74
|
+
const line = JSON.stringify({ ts: new Date().toISOString(), event, ...data });
|
|
75
|
+
await (0, promises_1.appendFile)(state.diagnosticsLogPath, `${line}\n`, "utf-8");
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// diagnostics must never affect runtime behavior
|
|
79
|
+
}
|
|
80
|
+
}
|
|
69
81
|
async function loadManagedSessionsCache(state) {
|
|
70
82
|
try {
|
|
71
83
|
const raw = await (0, promises_1.readFile)(state.managedSessionsCachePath, "utf-8");
|
|
@@ -219,6 +231,26 @@ async function forceRetryManagedSession(state, sessionID, reason) {
|
|
|
219
231
|
const retryText = retryAgent === ULTRAWORK_AGENT
|
|
220
232
|
? "[SYSTEM: Previous API call failed with a transient error. Re-read memory-bank/tasks.md, check the Phase Status block, and continue the pipeline. Use the exact neutral prompt from your Step 5 table for the next router call. Do NOT analyze or evaluate file contents.]"
|
|
221
233
|
: `[SYSTEM: Previous API call failed with a transient error. Resume the current task in your current role as ${retryAgent}. Continue from the existing session state. Do not restart from scratch unless the current session state is missing.]`;
|
|
234
|
+
await writeDiagnosticLog(state, "force-retry:start", {
|
|
235
|
+
sessionID,
|
|
236
|
+
reason,
|
|
237
|
+
retryAgent,
|
|
238
|
+
managedKind: managedSession.kind,
|
|
239
|
+
rootSessionID: managedSession.rootSessionID,
|
|
240
|
+
fallbackModel,
|
|
241
|
+
});
|
|
242
|
+
try {
|
|
243
|
+
await state.input.client.session.abort({
|
|
244
|
+
path: { id: sessionID },
|
|
245
|
+
});
|
|
246
|
+
await writeDiagnosticLog(state, "force-retry:abort-success", { sessionID });
|
|
247
|
+
}
|
|
248
|
+
catch (err) {
|
|
249
|
+
await writeDiagnosticLog(state, "force-retry:abort-failed", {
|
|
250
|
+
sessionID,
|
|
251
|
+
error: err instanceof Error ? err.message : String(err),
|
|
252
|
+
});
|
|
253
|
+
}
|
|
222
254
|
await state.input.client.session.promptAsync({
|
|
223
255
|
body: {
|
|
224
256
|
...(fallbackModel ? { model: fallbackModel } : {}),
|
|
@@ -236,6 +268,12 @@ async function forceRetryManagedSession(state, sessionID, reason) {
|
|
|
236
268
|
(fallbackModel
|
|
237
269
|
? ` using fallback model ${fallbackModel.providerID}/${fallbackModel.modelID}`
|
|
238
270
|
: ""));
|
|
271
|
+
await writeDiagnosticLog(state, "force-retry:prompt-sent", {
|
|
272
|
+
sessionID,
|
|
273
|
+
reason,
|
|
274
|
+
retryAgent,
|
|
275
|
+
fallbackModel,
|
|
276
|
+
});
|
|
239
277
|
}
|
|
240
278
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
241
279
|
// UTILITY: ERROR BOUNDARY
|