opencode-immune 1.0.35 → 1.0.36

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.
Files changed (2) hide show
  1. package/dist/plugin.js +34 -1
  2. package/package.json +3 -3
package/dist/plugin.js CHANGED
@@ -263,6 +263,15 @@ function isRetryableApiError(error) {
263
263
  const message = `${maybeError.message ?? ""} ${maybeError.data?.message ?? ""}`.toLowerCase();
264
264
  if (message.includes("не разрешен") ||
265
265
  message.includes("not allowed") ||
266
+ message.includes("expected") ||
267
+ message.includes("to be a string") ||
268
+ message.includes("invalid_type") ||
269
+ message.includes("validation") ||
270
+ message.includes("schema") ||
271
+ message.includes("zod") ||
272
+ message.includes("parse error") ||
273
+ message.includes("invalid id") ||
274
+ message.includes("expected id") ||
266
275
  message.includes("model not available") ||
267
276
  message.includes("model_not_found") ||
268
277
  message.includes("access denied") ||
@@ -1207,9 +1216,33 @@ function createEventHandler(state) {
1207
1216
  const eventType = event.type ?? "unknown";
1208
1217
  const info = event.properties?.info;
1209
1218
  const sessionID = event.properties?.sessionID ?? info?.id;
1219
+ const error = event.properties?.error;
1220
+ // Fallback: some SDK/schema errors can arrive without a valid sessionID
1221
+ // (for example: "Expected 'id' to be a string."). If there is exactly one
1222
+ // active managed root session, retry it as a best-effort recovery path.
1223
+ if (eventType === "session.error" && !sessionID && isRetryableApiError(error)) {
1224
+ const rootCandidates = Array.from(state.managedUltraworkSessions.entries())
1225
+ .filter(([, record]) => record.kind === "root")
1226
+ .map(([id]) => id);
1227
+ if (rootCandidates.length === 1) {
1228
+ const fallbackSessionID = rootCandidates[0];
1229
+ const count = state.sessionErrorRetryCount.get(fallbackSessionID) ?? 0;
1230
+ if (count < MAX_RETRIES && !state.sessionRetryTimers.has(fallbackSessionID)) {
1231
+ const delay = Math.min(BASE_DELAY_MS * Math.pow(2, count), MAX_DELAY_MS);
1232
+ state.sessionErrorRetryCount.set(fallbackSessionID, count + 1);
1233
+ console.warn(`[opencode-immune] session.error without sessionID matched retryable error. ` +
1234
+ `Retrying sole managed root session ${fallbackSessionID}.`);
1235
+ scheduleManagedSessionRetry(state, fallbackSessionID, {
1236
+ delayMs: delay,
1237
+ reason: "session.error without sessionID",
1238
+ attemptLabel: `fallback attempt ${count + 1}/${MAX_RETRIES}`,
1239
+ countAgainstBudget: true,
1240
+ });
1241
+ }
1242
+ }
1243
+ }
1210
1244
  // ── Auto-retry on retryable API error for managed ultrawork sessions ──
1211
1245
  if (eventType === "session.error" && sessionID) {
1212
- const error = event.properties?.error;
1213
1246
  const managedSession = getManagedSession(state, sessionID);
1214
1247
  const isRoot = managedSession?.kind === "root";
1215
1248
  const isChild = managedSession?.kind === "child";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-immune",
3
- "version": "1.0.35",
3
+ "version": "1.0.36",
4
4
  "description": "OpenCode plugin: session recovery, auto-retry, multi-cycle automation, context monitoring",
5
5
  "exports": {
6
6
  "./server": "./dist/plugin.js"
@@ -14,7 +14,7 @@
14
14
  "prepublishOnly": "npm run build"
15
15
  },
16
16
  "dependencies": {
17
- "@opencode-ai/plugin": "1.4.3"
17
+ "@opencode-ai/plugin": "1.4.7"
18
18
  },
19
19
  "devDependencies": {
20
20
  "@types/node": "^25.5.2",
@@ -29,4 +29,4 @@
29
29
  "retry"
30
30
  ],
31
31
  "license": "MIT"
32
- }
32
+ }