opencode-immune 1.0.68 → 1.0.70
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.
|
|
3780
|
+
var PLUGIN_VERSION = "1.0.70";
|
|
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:
|
|
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
|
-
|
|
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 ${
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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 ${
|
|
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
|
|
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.
|
|
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,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-immune",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.70",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "OpenCode plugin: session recovery, auto-retry, multi-cycle automation, context monitoring",
|
|
6
6
|
"exports": {
|
|
7
|
-
".": "./dist/plugin/server
|
|
8
|
-
"./server": "./dist/plugin/server
|
|
7
|
+
".": "./dist/plugin/server.js",
|
|
8
|
+
"./server": "./dist/plugin/server.js"
|
|
9
9
|
},
|
|
10
|
-
"main": "./dist/plugin/server
|
|
10
|
+
"main": "./dist/plugin/server.js",
|
|
11
11
|
"files": [
|
|
12
|
-
"dist/plugin/server
|
|
12
|
+
"dist/plugin/server.js"
|
|
13
13
|
],
|
|
14
14
|
"scripts": {
|
|
15
|
-
"build": "esbuild plugin.ts --bundle --platform=node --format=esm --target=node22 --outfile=dist/plugin/server
|
|
15
|
+
"build": "esbuild plugin.ts --bundle --platform=node --format=esm --target=node22 --outfile=dist/plugin/server.js",
|
|
16
16
|
"dev": "node ./node_modules/typescript/bin/tsc --project tsconfig.json --watch",
|
|
17
17
|
"prepublishOnly": "npm run build"
|
|
18
18
|
},
|