opencode-immune 1.0.38 → 1.0.40

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 +28 -1
  2. package/package.json +1 -1
package/dist/plugin.js CHANGED
@@ -11,7 +11,7 @@ const child_process_1 = require("child_process");
11
11
  // ═══════════════════════════════════════════════════════════════════════════════
12
12
  // PLUGIN VERSION CHECK
13
13
  // ═══════════════════════════════════════════════════════════════════════════════
14
- const PLUGIN_VERSION = "1.0.38";
14
+ const PLUGIN_VERSION = "1.0.40";
15
15
  const PLUGIN_PACKAGE_NAME = "opencode-immune";
16
16
  /**
17
17
  * Read plugin version from package.json at runtime.
@@ -294,6 +294,13 @@ function isRetryableApiError(error) {
294
294
  message.includes("timeout") ||
295
295
  message.includes("sse read") ||
296
296
  message.includes("stream error") ||
297
+ // Certificate/TLS provider failures must pass this primary retry gate
298
+ // before the managed-session fallback model branch can run.
299
+ message.includes("unknown certificate verification error") ||
300
+ message.includes("certificate has expired") ||
301
+ message.includes("certificate verification") ||
302
+ message.includes("tls") ||
303
+ message.includes("ssl") ||
297
304
  message.includes("connection reset") ||
298
305
  message.includes("socket hang up") ||
299
306
  message.includes("aborted")) {
@@ -343,6 +350,9 @@ function isCertificateApiError(error) {
343
350
  type.includes("tls") ||
344
351
  type.includes("ssl"));
345
352
  }
353
+ function isProviderRetryBanner(text) {
354
+ return /(?:<none>\s*)?retrying in \d+s\s*-\s*attempt #\d+/i.test(text);
355
+ }
346
356
  async function setSessionFallbackModel(state, sessionID, model) {
347
357
  const existing = state.managedUltraworkSessions.get(sessionID);
348
358
  if (!existing)
@@ -1463,6 +1473,23 @@ function createTextCompleteHandler(state) {
1463
1473
  const text = output.text ?? "";
1464
1474
  if (!text)
1465
1475
  return;
1476
+ // Some provider/SDK failures render as a retry banner instead of a
1477
+ // session.error event, leaving the UI waiting for long internal backoff.
1478
+ if (isProviderRetryBanner(text) && isManagedUltraworkSession(state, sessionID)) {
1479
+ const managedSession = getManagedSession(state, sessionID);
1480
+ const fallbackModel = managedSession?.kind === "child"
1481
+ ? CHILD_SESSION_FALLBACK_MODEL
1482
+ : RATE_LIMIT_FALLBACK_MODEL;
1483
+ await setSessionFallbackModel(state, sessionID, fallbackModel);
1484
+ scheduleManagedSessionRetry(state, sessionID, {
1485
+ delayMs: 1_000,
1486
+ reason: "provider retry banner fallback",
1487
+ countAgainstBudget: false,
1488
+ abortBeforePrompt: true,
1489
+ });
1490
+ console.log(`[opencode-immune] Provider retry banner detected for session ${sessionID}. ` +
1491
+ `Fallback model pinned to ${fallbackModel.providerID}/${fallbackModel.modelID}.`);
1492
+ }
1466
1493
  // ── ALL_CYCLES_COMPLETE: clear ultrawork marker ──
1467
1494
  if (text.includes(ALL_CYCLES_COMPLETE_MARKER)) {
1468
1495
  await clearUltraworkMarker(state);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-immune",
3
- "version": "1.0.38",
3
+ "version": "1.0.40",
4
4
  "description": "OpenCode plugin: session recovery, auto-retry, multi-cycle automation, context monitoring",
5
5
  "exports": {
6
6
  "./server": "./dist/plugin.js"