opencode-immune 1.0.77 → 1.0.79
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.
- package/dist/plugin/server.js +45 -82
- package/package.json +1 -1
package/dist/plugin/server.js
CHANGED
|
@@ -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.79";
|
|
3781
3781
|
var PLUGIN_PACKAGE_NAME = "opencode-immune";
|
|
3782
3782
|
var PLUGIN_DIRNAME = dirname(fileURLToPath(import.meta.url));
|
|
3783
3783
|
function getServerAuthHeaders() {
|
|
@@ -3895,8 +3895,6 @@ var PROVIDER_RETRY_WATCHDOG_MS = 3e4;
|
|
|
3895
3895
|
var RETRY_PROMPT_DELIVERY_ATTEMPTS = 3;
|
|
3896
3896
|
var CHILD_FALLBACK_REQUEST_TTL_MS = 10 * 60 * 1e3;
|
|
3897
3897
|
var AUTO_CYCLE_LOCK_TTL_MS = 30 * 60 * 1e3;
|
|
3898
|
-
var PROJECT_TMP_RELATIVE_PATH = ".opencode/tmp";
|
|
3899
|
-
var PROJECT_LOG_RELATIVE_PATH = ".opencode/state/logs";
|
|
3900
3898
|
var MODEL_NAME_CAPABILITY_SCORE = {
|
|
3901
3899
|
"claude-opus-4-7": 100,
|
|
3902
3900
|
"gpt-5.5": 100,
|
|
@@ -3916,12 +3914,6 @@ function isManagedRootUltraworkSession(state, sessionID) {
|
|
|
3916
3914
|
const record = getManagedSession(state, sessionID);
|
|
3917
3915
|
return !!record && record.kind === "root";
|
|
3918
3916
|
}
|
|
3919
|
-
function getProjectTmpDir(state) {
|
|
3920
|
-
return join(state.input.directory, PROJECT_TMP_RELATIVE_PATH);
|
|
3921
|
-
}
|
|
3922
|
-
function getProjectLogDir(state) {
|
|
3923
|
-
return join(state.input.directory, PROJECT_LOG_RELATIVE_PATH);
|
|
3924
|
-
}
|
|
3925
3917
|
async function createManagedUltraworkSession(state, title) {
|
|
3926
3918
|
const result = await state.client.session.create({
|
|
3927
3919
|
directory: state.input.directory,
|
|
@@ -5798,6 +5790,18 @@ var PRE_COMMIT_MARKER = "0-ULTRAWORK: PRE_COMMIT";
|
|
|
5798
5790
|
var CYCLE_COMPLETE_MARKER = "0-ULTRAWORK: CYCLE_COMPLETE";
|
|
5799
5791
|
var NEXT_TASK_PATTERN = /Next task:\s*(.+)/;
|
|
5800
5792
|
var ALL_CYCLES_COMPLETE_MARKER = "0-ULTRAWORK: ALL_CYCLES_COMPLETE";
|
|
5793
|
+
async function commitCycleChanges(state, reason) {
|
|
5794
|
+
if (state.commitPending) return;
|
|
5795
|
+
state.commitPending = true;
|
|
5796
|
+
pluginLog.info(`[opencode-immune] Multi-Cycle: ${reason}, running git commit...`);
|
|
5797
|
+
try {
|
|
5798
|
+
await runGitCommit(state.input.directory);
|
|
5799
|
+
} catch (err) {
|
|
5800
|
+
pluginLog.error(`[opencode-immune] Multi-Cycle: git commit failed (${reason}):`, err);
|
|
5801
|
+
} finally {
|
|
5802
|
+
state.commitPending = false;
|
|
5803
|
+
}
|
|
5804
|
+
}
|
|
5801
5805
|
async function archiveProgress(directory) {
|
|
5802
5806
|
const progressPath = join(directory, "memory-bank", "progress.md");
|
|
5803
5807
|
try {
|
|
@@ -5905,62 +5909,55 @@ function createTextCompleteHandler(state) {
|
|
|
5905
5909
|
return;
|
|
5906
5910
|
}
|
|
5907
5911
|
if (text.includes(PRE_COMMIT_MARKER) && !text.includes(CYCLE_COMPLETE_MARKER)) {
|
|
5908
|
-
|
|
5909
|
-
state.commitPending = true;
|
|
5910
|
-
pluginLog.info("[opencode-immune] Multi-Cycle: PRE_COMMIT detected (standalone), running git commit...");
|
|
5911
|
-
try {
|
|
5912
|
-
await runGitCommit(state.input.directory);
|
|
5913
|
-
} catch (err) {
|
|
5914
|
-
pluginLog.error("[opencode-immune] Multi-Cycle: git commit failed (standalone):", err);
|
|
5915
|
-
} finally {
|
|
5916
|
-
state.commitPending = false;
|
|
5917
|
-
}
|
|
5918
|
-
}
|
|
5912
|
+
await commitCycleChanges(state, "PRE_COMMIT detected (standalone)");
|
|
5919
5913
|
return;
|
|
5920
5914
|
}
|
|
5921
5915
|
if (text.includes(CYCLE_COMPLETE_MARKER)) {
|
|
5916
|
+
if (state.autoCycleInFlight || state.autoCycleSourceSessions.has(sessionID)) return;
|
|
5917
|
+
const lockAcquired2 = await acquireAutoCycleLock(
|
|
5918
|
+
state,
|
|
5919
|
+
"cycle-complete",
|
|
5920
|
+
sessionID
|
|
5921
|
+
);
|
|
5922
|
+
if (!lockAcquired2) return;
|
|
5923
|
+
state.autoCycleSourceSessions.add(sessionID);
|
|
5924
|
+
state.autoCycleInFlight = true;
|
|
5922
5925
|
try {
|
|
5923
|
-
await archiveProgress(state.input.directory);
|
|
5924
|
-
} catch (err) {
|
|
5925
|
-
pluginLog.warn("[opencode-immune] Multi-Cycle: archive progress failed:", err);
|
|
5926
|
-
}
|
|
5927
|
-
if (!state.commitPending) {
|
|
5928
|
-
state.commitPending = true;
|
|
5929
|
-
pluginLog.info("[opencode-immune] Multi-Cycle: CYCLE_COMPLETE detected, running git commit first...");
|
|
5930
5926
|
try {
|
|
5931
|
-
await
|
|
5932
|
-
pluginLog.info("[opencode-immune] Multi-Cycle: git commit completed before new cycle.");
|
|
5927
|
+
await archiveProgress(state.input.directory);
|
|
5933
5928
|
} catch (err) {
|
|
5934
|
-
pluginLog.
|
|
5935
|
-
} finally {
|
|
5936
|
-
state.commitPending = false;
|
|
5929
|
+
pluginLog.warn("[opencode-immune] Multi-Cycle: archive progress failed:", err);
|
|
5937
5930
|
}
|
|
5938
|
-
|
|
5939
|
-
|
|
5940
|
-
|
|
5931
|
+
await commitCycleChanges(state, "CYCLE_COMPLETE detected");
|
|
5932
|
+
state.cycleCount++;
|
|
5933
|
+
if (state.cycleCount >= MAX_CYCLES) {
|
|
5934
|
+
pluginLog.info(
|
|
5935
|
+
`[opencode-immune] Multi-Cycle: MAX_CYCLES (${MAX_CYCLES}) reached. Not creating new session.`
|
|
5936
|
+
);
|
|
5937
|
+
await clearUltraworkMarker(state);
|
|
5938
|
+
await clearAutoCycleLock(state, "max cycles reached");
|
|
5939
|
+
return;
|
|
5940
|
+
}
|
|
5941
|
+
const taskMatch = text.match(NEXT_TASK_PATTERN);
|
|
5942
|
+
const nextTask = taskMatch?.[1]?.trim() ?? "Continue processing task backlog";
|
|
5941
5943
|
pluginLog.info(
|
|
5942
|
-
`[opencode-immune] Multi-Cycle:
|
|
5944
|
+
`[opencode-immune] Multi-Cycle: Starting next cycle in a new session (cycle ${state.cycleCount}/${MAX_CYCLES}) for: "${nextTask}"`
|
|
5943
5945
|
);
|
|
5944
|
-
await clearUltraworkMarker(state);
|
|
5945
|
-
return;
|
|
5946
|
-
}
|
|
5947
|
-
const taskMatch = text.match(NEXT_TASK_PATTERN);
|
|
5948
|
-
const nextTask = taskMatch?.[1]?.trim() ?? "Continue processing task backlog";
|
|
5949
|
-
pluginLog.info(
|
|
5950
|
-
`[opencode-immune] Multi-Cycle: Starting next cycle in a new session (cycle ${state.cycleCount}/${MAX_CYCLES}) for: "${nextTask}"`
|
|
5951
|
-
);
|
|
5952
|
-
try {
|
|
5953
5946
|
await startAutoCycleInNewSession(
|
|
5954
5947
|
state,
|
|
5955
5948
|
{
|
|
5956
5949
|
sourceSessionID: sessionID,
|
|
5957
5950
|
nextTask,
|
|
5958
5951
|
logContext: "Multi-Cycle",
|
|
5952
|
+
clearLockOnFailureReason: "cycle complete bootstrap failed",
|
|
5959
5953
|
retireSourceSession: true
|
|
5960
5954
|
}
|
|
5961
5955
|
);
|
|
5962
5956
|
} catch (err) {
|
|
5957
|
+
state.autoCycleSourceSessions.delete(sessionID);
|
|
5963
5958
|
pluginLog.error("[opencode-immune] Multi-Cycle: Failed to send prompt:", err);
|
|
5959
|
+
} finally {
|
|
5960
|
+
state.autoCycleInFlight = false;
|
|
5964
5961
|
}
|
|
5965
5962
|
return;
|
|
5966
5963
|
}
|
|
@@ -5982,6 +5979,7 @@ function createTextCompleteHandler(state) {
|
|
|
5982
5979
|
`[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.`
|
|
5983
5980
|
);
|
|
5984
5981
|
try {
|
|
5982
|
+
await commitCycleChanges(state, "fallback AUTO-CYCLE before new session");
|
|
5985
5983
|
await refreshAutoCycleLock(state, sessionID);
|
|
5986
5984
|
await startAutoCycleInNewSession(
|
|
5987
5985
|
state,
|
|
@@ -6049,25 +6047,11 @@ function createPermissionAskHandler(state) {
|
|
|
6049
6047
|
`[opencode-immune] Permission request recovered AUTO-RESUME session ${sessionID}; tracking as managed ultrawork session.`
|
|
6050
6048
|
);
|
|
6051
6049
|
}
|
|
6052
|
-
const permissionType = getPermissionType(input);
|
|
6053
|
-
const patterns = getPermissionPatterns(input);
|
|
6054
|
-
if (isManagedUltraworkSession(state, sessionID) && permissionType === "external_directory" && patterns.some(isExternalTmpPattern)) {
|
|
6055
|
-
output.status = "deny";
|
|
6056
|
-
await writeDiagnosticLog(state, "permission:auto-deny-external-tmp", {
|
|
6057
|
-
sessionID,
|
|
6058
|
-
status: output.status,
|
|
6059
|
-
permission: permissionType,
|
|
6060
|
-
patterns,
|
|
6061
|
-
projectTmpDir: getProjectTmpDir(state),
|
|
6062
|
-
projectLogDir: getProjectLogDir(state)
|
|
6063
|
-
});
|
|
6064
|
-
return;
|
|
6065
|
-
}
|
|
6066
6050
|
await writeDiagnosticLog(state, "permission:ask", {
|
|
6067
6051
|
sessionID,
|
|
6068
6052
|
status: output.status,
|
|
6069
|
-
permission:
|
|
6070
|
-
patterns
|
|
6053
|
+
permission: getPermissionType(input),
|
|
6054
|
+
patterns: getPermissionPatterns(input)
|
|
6071
6055
|
});
|
|
6072
6056
|
};
|
|
6073
6057
|
}
|
|
@@ -6083,22 +6067,6 @@ function getPermissionPatterns(input) {
|
|
|
6083
6067
|
if (Array.isArray(source)) return source.filter((item) => typeof item === "string");
|
|
6084
6068
|
return typeof source === "string" ? [source] : [];
|
|
6085
6069
|
}
|
|
6086
|
-
function isExternalTmpPattern(pattern) {
|
|
6087
|
-
return pattern === "/tmp" || pattern.startsWith("/tmp/") || pattern === "/tmp/*";
|
|
6088
|
-
}
|
|
6089
|
-
function createShellEnvHandler(state) {
|
|
6090
|
-
return async (_input, output) => {
|
|
6091
|
-
const projectTmpDir = getProjectTmpDir(state);
|
|
6092
|
-
const projectLogDir = getProjectLogDir(state);
|
|
6093
|
-
await mkdir(projectTmpDir, { recursive: true });
|
|
6094
|
-
await mkdir(projectLogDir, { recursive: true });
|
|
6095
|
-
output.env.TMPDIR = projectTmpDir;
|
|
6096
|
-
output.env.TMP = projectTmpDir;
|
|
6097
|
-
output.env.TEMP = projectTmpDir;
|
|
6098
|
-
output.env.OPENCODE_TMP_DIR = projectTmpDir;
|
|
6099
|
-
output.env.OPENCODE_LOG_DIR = projectLogDir;
|
|
6100
|
-
};
|
|
6101
|
-
}
|
|
6102
6070
|
async function server(input) {
|
|
6103
6071
|
const state = createState(input);
|
|
6104
6072
|
checkPluginUpdate(state).catch(() => {
|
|
@@ -6238,11 +6206,6 @@ async function server(input) {
|
|
|
6238
6206
|
state,
|
|
6239
6207
|
"permission.ask",
|
|
6240
6208
|
createPermissionAskHandler(state)
|
|
6241
|
-
),
|
|
6242
|
-
"shell.env": withErrorBoundary(
|
|
6243
|
-
state,
|
|
6244
|
-
"shell.env",
|
|
6245
|
-
createShellEnvHandler(state)
|
|
6246
6209
|
)
|
|
6247
6210
|
};
|
|
6248
6211
|
}
|