opencode-immune 1.0.68 → 1.0.69

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.68";
3780
+ var PLUGIN_VERSION = "1.0.69";
3781
3781
  var PLUGIN_PACKAGE_NAME = "opencode-immune";
3782
3782
  var PLUGIN_DIRNAME = dirname(fileURLToPath(import.meta.url));
3783
3783
  function getServerAuthHeaders() {
@@ -4748,6 +4748,7 @@ async function hasPendingBacklogTasks(directory) {
4748
4748
  async function acquireAutoCycleLock(state, source, sourceSessionID) {
4749
4749
  try {
4750
4750
  const now = Date.now();
4751
+ let shouldReplaceStaleLock = false;
4751
4752
  try {
4752
4753
  const raw = await readFile(state.autoCycleLockPath, "utf-8");
4753
4754
  const existing = JSON.parse(raw);
@@ -4758,8 +4759,16 @@ async function acquireAutoCycleLock(state, source, sourceSessionID) {
4758
4759
  );
4759
4760
  return false;
4760
4761
  }
4762
+ shouldReplaceStaleLock = true;
4761
4763
  } catch {
4762
4764
  }
4765
+ if (shouldReplaceStaleLock) {
4766
+ try {
4767
+ await unlink(state.autoCycleLockPath);
4768
+ pluginLog.info(`[opencode-immune] Auto-cycle stale lock replaced for ${source}.`);
4769
+ } catch {
4770
+ }
4771
+ }
4763
4772
  await mkdir(dirname(state.autoCycleLockPath), { recursive: true });
4764
4773
  const payload = JSON.stringify(
4765
4774
  {
@@ -5155,6 +5164,40 @@ function createSessionRecoveryEvent(state) {
5155
5164
  } else {
5156
5165
  state.recoveryContext = null;
5157
5166
  pluginLog.info("[opencode-immune] No active task found.");
5167
+ const hasPendingTasks = await hasPendingBacklogTasks(state.input.directory);
5168
+ if (!hasPendingTasks || state.autoResumeAttempted || state.autoResumeInFlight) {
5169
+ return;
5170
+ }
5171
+ const lockAcquired = await acquireAutoCycleLock(
5172
+ state,
5173
+ "root-session-auto-cycle",
5174
+ sessionID
5175
+ );
5176
+ if (!lockAcquired) return;
5177
+ await addManagedUltraworkSession(state, sessionID);
5178
+ await refreshAutoCycleLock(state, sessionID);
5179
+ state.autoResumeInFlight = true;
5180
+ setTimeout(async () => {
5181
+ try {
5182
+ await promptManagedSession(
5183
+ state,
5184
+ sessionID,
5185
+ `[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.`
5186
+ );
5187
+ state.autoResumeAttempted = true;
5188
+ pluginLog.info(
5189
+ `[opencode-immune] Auto-cycle prompt sent to root ultrawork session ${sessionID}`
5190
+ );
5191
+ } catch (err) {
5192
+ await clearAutoCycleLock(state, "root session auto-cycle failed");
5193
+ pluginLog.error(
5194
+ `[opencode-immune] Auto-cycle prompt failed for root session ${sessionID}:`,
5195
+ err
5196
+ );
5197
+ } finally {
5198
+ state.autoResumeInFlight = false;
5199
+ }
5200
+ }, 3e3);
5158
5201
  }
5159
5202
  }
5160
5203
  };
@@ -5655,26 +5698,17 @@ function createTextCompleteHandler(state) {
5655
5698
  const taskMatch = text.match(NEXT_TASK_PATTERN);
5656
5699
  const nextTask = taskMatch?.[1]?.trim() ?? "Continue processing task backlog";
5657
5700
  pluginLog.info(
5658
- `[opencode-immune] Multi-Cycle: Creating new session (cycle ${state.cycleCount}/${MAX_CYCLES}) for: "${nextTask}"`
5701
+ `[opencode-immune] Multi-Cycle: Starting next cycle in current session (cycle ${state.cycleCount}/${MAX_CYCLES}) for: "${nextTask}"`
5659
5702
  );
5660
5703
  try {
5661
- const newSessionID = await createManagedUltraworkSession(
5662
- state,
5663
- `Ultrawork Cycle ${state.cycleCount + 1}`
5664
- );
5665
- if (!newSessionID) {
5666
- pluginLog.error("[opencode-immune] Multi-Cycle: Failed to create new session \u2014 no ID returned.");
5667
- return;
5668
- }
5669
- pluginLog.info(`[opencode-immune] Multi-Cycle: New session created: ${newSessionID}`);
5670
5704
  await promptManagedSession(
5671
5705
  state,
5672
- newSessionID,
5706
+ sessionID,
5673
5707
  `[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.`
5674
5708
  );
5675
- pluginLog.info(`[opencode-immune] Multi-Cycle: Bootstrap prompt sent to ${newSessionID}`);
5709
+ pluginLog.info(`[opencode-immune] Multi-Cycle: Bootstrap prompt sent to ${sessionID}`);
5676
5710
  } catch (err) {
5677
- pluginLog.error("[opencode-immune] Multi-Cycle: Failed to create session or send prompt:", err);
5711
+ pluginLog.error("[opencode-immune] Multi-Cycle: Failed to send prompt:", err);
5678
5712
  }
5679
5713
  return;
5680
5714
  }
@@ -5696,27 +5730,17 @@ function createTextCompleteHandler(state) {
5696
5730
  `[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.`
5697
5731
  );
5698
5732
  try {
5699
- const newSessionID = await createManagedUltraworkSession(
5700
- state,
5701
- `AUTO-CYCLE: next backlog task`
5702
- );
5703
- if (!newSessionID) {
5704
- await clearAutoCycleLock(state, "fallback create returned no session ID");
5705
- pluginLog.error("[opencode-immune] Multi-Cycle fallback: Failed to create new session \u2014 no ID returned.");
5706
- return;
5707
- }
5708
- await refreshAutoCycleLock(state, newSessionID);
5709
- pluginLog.info(`[opencode-immune] Multi-Cycle fallback: New session created: ${newSessionID}`);
5733
+ await refreshAutoCycleLock(state, sessionID);
5710
5734
  await promptManagedSession(
5711
5735
  state,
5712
- newSessionID,
5736
+ sessionID,
5713
5737
  `[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.`
5714
5738
  );
5715
- pluginLog.info(`[opencode-immune] Multi-Cycle fallback: Bootstrap prompt sent to ${newSessionID}`);
5739
+ pluginLog.info(`[opencode-immune] Multi-Cycle fallback: Bootstrap prompt sent to ${sessionID}`);
5716
5740
  } catch (err) {
5717
5741
  state.autoCycleSourceSessions.delete(sessionID);
5718
5742
  await clearAutoCycleLock(state, "fallback bootstrap failed");
5719
- pluginLog.error("[opencode-immune] Multi-Cycle fallback: Failed to create session or send prompt:", err);
5743
+ pluginLog.error("[opencode-immune] Multi-Cycle fallback: Failed to send prompt:", err);
5720
5744
  } finally {
5721
5745
  state.autoCycleInFlight = false;
5722
5746
  }
@@ -5834,51 +5858,9 @@ async function server(input) {
5834
5858
  try {
5835
5859
  const hasPendingTasks = await hasPendingBacklogTasks(state.input.directory);
5836
5860
  if (hasPendingTasks) {
5837
- const lockAcquired = await acquireAutoCycleLock(
5838
- state,
5839
- "plugin-init-auto-cycle"
5840
- );
5841
- if (!lockAcquired) return;
5842
5861
  pluginLog.info(
5843
- `[opencode-immune] Plugin init: no active task but backlog has pending items. Will create new session to start next cycle.`
5862
+ `[opencode-immune] Plugin init: no active task but backlog has pending items. Waiting for root session before starting AUTO-CYCLE.`
5844
5863
  );
5845
- state.autoResumeInFlight = true;
5846
- setTimeout(async () => {
5847
- try {
5848
- const newSessionID = await createManagedUltraworkSession(
5849
- state,
5850
- `AUTO-CYCLE: next backlog task`
5851
- );
5852
- if (!newSessionID) {
5853
- await clearAutoCycleLock(state, "init auto-cycle create returned no session ID");
5854
- pluginLog.error(
5855
- "[opencode-immune] Auto-cycle: Failed to create session \u2014 no session ID returned."
5856
- );
5857
- return;
5858
- }
5859
- await refreshAutoCycleLock(state, newSessionID);
5860
- pluginLog.info(
5861
- `[opencode-immune] Auto-cycle: New session created: ${newSessionID}`
5862
- );
5863
- await promptManagedSession(
5864
- state,
5865
- newSessionID,
5866
- `[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.`
5867
- );
5868
- state.autoResumeAttempted = true;
5869
- pluginLog.info(
5870
- `[opencode-immune] Auto-cycle prompt sent to new session ${newSessionID}`
5871
- );
5872
- } catch (err) {
5873
- await clearAutoCycleLock(state, "init auto-cycle bootstrap failed");
5874
- pluginLog.error(
5875
- "[opencode-immune] Auto-cycle: Failed to create session or send prompt:",
5876
- err
5877
- );
5878
- } finally {
5879
- state.autoResumeInFlight = false;
5880
- }
5881
- }, 5e3);
5882
5864
  } else {
5883
5865
  await clearUltraworkMarker(state);
5884
5866
  await clearAutoCycleLock(state, "no pending backlog tasks");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-immune",
3
- "version": "1.0.68",
3
+ "version": "1.0.69",
4
4
  "type": "module",
5
5
  "description": "OpenCode plugin: session recovery, auto-retry, multi-cycle automation, context monitoring",
6
6
  "exports": {