opencode-immune 1.0.65 → 1.0.66

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.
@@ -3777,7 +3777,7 @@ import { fileURLToPath } from "url";
3777
3777
  import { createHash } from "crypto";
3778
3778
  import { tmpdir } from "os";
3779
3779
  import { execFile } from "child_process";
3780
- var PLUGIN_VERSION = "1.0.65";
3780
+ var PLUGIN_VERSION = "1.0.66";
3781
3781
  var PLUGIN_PACKAGE_NAME = "opencode-immune";
3782
3782
  var PLUGIN_DIRNAME = dirname(fileURLToPath(import.meta.url));
3783
3783
  function getServerAuthHeaders() {
@@ -3873,6 +3873,8 @@ function createState(input) {
3873
3873
  sessionActive: false,
3874
3874
  autoResumeAttempted: false,
3875
3875
  autoResumeInFlight: false,
3876
+ autoCycleInFlight: false,
3877
+ autoCycleSourceSessions: /* @__PURE__ */ new Set(),
3876
3878
  cycleCount: 0,
3877
3879
  commitPending: false,
3878
3880
  pluginUpdateMessage: null
@@ -3966,6 +3968,7 @@ async function applyUltraworkSessionPermissions(state, sessionID) {
3966
3968
  }
3967
3969
  }
3968
3970
  async function promptManagedSession(state, sessionID, text, options = {}) {
3971
+ await applyUltraworkSessionPermissions(state, sessionID);
3969
3972
  const result = await state.client.session.promptAsync({
3970
3973
  directory: state.input.directory,
3971
3974
  sessionID,
@@ -4726,6 +4729,15 @@ async function parseTasksFile(directory) {
4726
4729
  return null;
4727
4730
  }
4728
4731
  }
4732
+ async function hasPendingBacklogTasks(directory) {
4733
+ try {
4734
+ const backlogPath = join(directory, "memory-bank", "backlog.md");
4735
+ const backlogContent = await readFile(backlogPath, "utf-8");
4736
+ return /- \[ \]/.test(backlogContent);
4737
+ } catch {
4738
+ return false;
4739
+ }
4740
+ }
4729
4741
  var HARNESS_VERSION_FILE = ".harness-version";
4730
4742
  var HARNESS_TOKEN_ENV = "OPENCODE_IMMUNE_TOKEN";
4731
4743
  var DEFAULT_HARNESS_REPO = "gendoor/opencode-immune-harness";
@@ -5512,8 +5524,9 @@ function createTextCompleteHandler(state) {
5512
5524
  const sessionID = input.sessionID;
5513
5525
  const text = output.text ?? "";
5514
5526
  if (!text) return;
5527
+ const isManagedRootSession = isManagedRootUltraworkSession(state, sessionID);
5515
5528
  cancelProviderRetryWatchdog(state, sessionID, "assistant text completed");
5516
- if (isProviderRetryBanner(text) && isManagedRootUltraworkSession(state, sessionID)) {
5529
+ if (isProviderRetryBanner(text) && isManagedRootSession) {
5517
5530
  const fallbackModel = getSessionFallbackModel(state, sessionID);
5518
5531
  await setSessionFallbackModel(state, sessionID, fallbackModel);
5519
5532
  scheduleManagedSessionRetry(state, sessionID, {
@@ -5595,6 +5608,40 @@ function createTextCompleteHandler(state) {
5595
5608
  } catch (err) {
5596
5609
  pluginLog.error("[opencode-immune] Multi-Cycle: Failed to create session or send prompt:", err);
5597
5610
  }
5611
+ return;
5612
+ }
5613
+ if (!isManagedRootSession || state.autoCycleInFlight) return;
5614
+ const recovery = await parseTasksFile(state.input.directory);
5615
+ if (recovery) return;
5616
+ const hasPendingTasks = await hasPendingBacklogTasks(state.input.directory);
5617
+ if (!hasPendingTasks) return;
5618
+ if (state.autoCycleSourceSessions.has(sessionID)) return;
5619
+ state.autoCycleSourceSessions.add(sessionID);
5620
+ state.autoCycleInFlight = true;
5621
+ pluginLog.warn(
5622
+ `[opencode-immune] Multi-Cycle fallback: no CYCLE_COMPLETE marker detected for ${sessionID}, but tasks.md has no active task and backlog has pending items. Starting AUTO-CYCLE.`
5623
+ );
5624
+ try {
5625
+ const newSessionID = await createManagedUltraworkSession(
5626
+ state,
5627
+ `AUTO-CYCLE: next backlog task`
5628
+ );
5629
+ if (!newSessionID) {
5630
+ pluginLog.error("[opencode-immune] Multi-Cycle fallback: Failed to create new session \u2014 no ID returned.");
5631
+ return;
5632
+ }
5633
+ pluginLog.info(`[opencode-immune] Multi-Cycle fallback: New session created: ${newSessionID}`);
5634
+ await promptManagedSession(
5635
+ state,
5636
+ newSessionID,
5637
+ `[AUTO-CYCLE] Continue processing task backlog. Read memory-bank/tasks.md and memory-bank/backlog.md, pick the next pending task, and run the full pipeline.`
5638
+ );
5639
+ pluginLog.info(`[opencode-immune] Multi-Cycle fallback: Bootstrap prompt sent to ${newSessionID}`);
5640
+ } catch (err) {
5641
+ state.autoCycleSourceSessions.delete(sessionID);
5642
+ pluginLog.error("[opencode-immune] Multi-Cycle fallback: Failed to create session or send prompt:", err);
5643
+ } finally {
5644
+ state.autoCycleInFlight = false;
5598
5645
  }
5599
5646
  };
5600
5647
  }
@@ -5708,9 +5755,7 @@ async function server(input) {
5708
5755
  }, 5e3);
5709
5756
  } else {
5710
5757
  try {
5711
- const backlogPath = join(state.input.directory, "memory-bank", "backlog.md");
5712
- const backlogContent = await readFile(backlogPath, "utf-8");
5713
- const hasPendingTasks = /- \[ \]/.test(backlogContent);
5758
+ const hasPendingTasks = await hasPendingBacklogTasks(state.input.directory);
5714
5759
  if (hasPendingTasks) {
5715
5760
  pluginLog.info(
5716
5761
  `[opencode-immune] Plugin init: no active task but backlog has pending items. Will create new session to start next cycle.`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-immune",
3
- "version": "1.0.65",
3
+ "version": "1.0.66",
4
4
  "type": "module",
5
5
  "description": "OpenCode plugin: session recovery, auto-retry, multi-cycle automation, context monitoring",
6
6
  "exports": {