opencode-immune 1.0.85 → 1.0.87
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 +27 -40
- package/package.json +1 -1
package/dist/plugin/server.js
CHANGED
|
@@ -5518,31 +5518,6 @@ async function fileHash(filePath) {
|
|
|
5518
5518
|
return "";
|
|
5519
5519
|
}
|
|
5520
5520
|
}
|
|
5521
|
-
async function fileExists(filePath) {
|
|
5522
|
-
try {
|
|
5523
|
-
await stat(filePath);
|
|
5524
|
-
return true;
|
|
5525
|
-
} catch {
|
|
5526
|
-
return false;
|
|
5527
|
-
}
|
|
5528
|
-
}
|
|
5529
|
-
async function getHarnessIntegrityIssue(directory) {
|
|
5530
|
-
try {
|
|
5531
|
-
const configPath = join(directory, "opencode.json");
|
|
5532
|
-
const raw = await readFile(configPath, "utf-8");
|
|
5533
|
-
const config = JSON.parse(raw);
|
|
5534
|
-
const plugins = Array.isArray(config.plugin) ? config.plugin : [];
|
|
5535
|
-
const usesLoader = plugins.includes(".opencode/plugin-loader.cjs") || plugins.includes(".opencode\\plugin-loader.cjs");
|
|
5536
|
-
if (!usesLoader) return null;
|
|
5537
|
-
const loaderPath = join(directory, ".opencode", "plugin-loader.cjs");
|
|
5538
|
-
if (!await fileExists(loaderPath)) {
|
|
5539
|
-
return "opencode.json references .opencode/plugin-loader.cjs but the file is missing";
|
|
5540
|
-
}
|
|
5541
|
-
} catch {
|
|
5542
|
-
return null;
|
|
5543
|
-
}
|
|
5544
|
-
return null;
|
|
5545
|
-
}
|
|
5546
5521
|
function parseImmunePluginSpec(value) {
|
|
5547
5522
|
const trimmed = value.trim();
|
|
5548
5523
|
const match = trimmed.match(/^opencode-immune(?:@(.+))?$/);
|
|
@@ -5651,19 +5626,13 @@ async function syncHarness(state) {
|
|
|
5651
5626
|
const release = await fetchLatestHarnessRelease(state.input.directory, repo, token);
|
|
5652
5627
|
if (!release) return;
|
|
5653
5628
|
const localVersion = await readLocalHarnessVersion(state.input.directory);
|
|
5654
|
-
|
|
5655
|
-
if (localVersion === release.tagName && !integrityIssue) {
|
|
5629
|
+
if (localVersion === release.tagName) {
|
|
5656
5630
|
pluginLog.info(
|
|
5657
5631
|
`[opencode-immune] Harness sync: already up to date (${release.tagName})`
|
|
5658
5632
|
);
|
|
5659
5633
|
return;
|
|
5660
5634
|
}
|
|
5661
|
-
if (localVersion
|
|
5662
|
-
pluginLog.warn(
|
|
5663
|
-
`[opencode-immune] Harness sync: integrity issue detected for ${release.tagName}: ${integrityIssue}. Reinstalling harness files from release.`
|
|
5664
|
-
);
|
|
5665
|
-
}
|
|
5666
|
-
if (localVersion && localVersion !== release.tagName) {
|
|
5635
|
+
if (localVersion) {
|
|
5667
5636
|
const versionOrder = compareHarnessVersions(localVersion, release.tagName);
|
|
5668
5637
|
if (versionOrder === null) {
|
|
5669
5638
|
pluginLog.warn(
|
|
@@ -5919,7 +5888,7 @@ Router action: retry the SAME pipeline slot once by creating a NEW Task call to
|
|
|
5919
5888
|
if (state.lastEditAttempt) {
|
|
5920
5889
|
const edit = state.lastEditAttempt;
|
|
5921
5890
|
output.system.push(
|
|
5922
|
-
`[
|
|
5891
|
+
`[File Modification Recovery] Previous ${edit.tool} operation failed for "${edit.filePath}". Read the file first to get the correct content, then retry with the available file modification tool. If using edit, use the exact oldString from the file. If using apply_patch, build the patch from the current file content.`
|
|
5923
5892
|
);
|
|
5924
5893
|
state.lastEditAttempt = null;
|
|
5925
5894
|
}
|
|
@@ -5928,19 +5897,37 @@ Router action: retry the SAME pipeline slot once by creating a NEW Task call to
|
|
|
5928
5897
|
}
|
|
5929
5898
|
};
|
|
5930
5899
|
}
|
|
5900
|
+
function isFileModificationTool(tool) {
|
|
5901
|
+
return tool === "edit" || tool === "write" || tool === "apply_patch";
|
|
5902
|
+
}
|
|
5903
|
+
function getPatchPath(patchText) {
|
|
5904
|
+
const match = patchText.match(/^\*\*\* (?:Add|Update|Delete) File: (.+)$/m);
|
|
5905
|
+
return match?.[1]?.trim() || "patch";
|
|
5906
|
+
}
|
|
5907
|
+
function getFileModificationPath(tool, args) {
|
|
5908
|
+
if (tool === "apply_patch") return getPatchPath(args?.patchText ?? "");
|
|
5909
|
+
return args?.filePath ?? "unknown";
|
|
5910
|
+
}
|
|
5911
|
+
function getFileModificationContent(tool, args) {
|
|
5912
|
+
if (tool === "edit") return args?.newString ?? "";
|
|
5913
|
+
if (tool === "write") return args?.content ?? "";
|
|
5914
|
+
if (tool === "apply_patch") return args?.patchText ?? "";
|
|
5915
|
+
return "";
|
|
5916
|
+
}
|
|
5931
5917
|
function createRalphLoopToolAfter(state) {
|
|
5932
5918
|
return async (input, output) => {
|
|
5933
|
-
if (input.tool
|
|
5919
|
+
if (!isFileModificationTool(input.tool)) return;
|
|
5934
5920
|
const outputText = typeof output.output === "string" ? output.output : "";
|
|
5935
5921
|
if (outputText.includes("oldString not found") || outputText.includes("Found multiple matches")) {
|
|
5936
5922
|
state.lastEditAttempt = {
|
|
5937
|
-
filePath: input.args
|
|
5923
|
+
filePath: getFileModificationPath(input.tool, input.args),
|
|
5938
5924
|
oldString: input.args?.oldString ?? "",
|
|
5939
|
-
newString: input.args
|
|
5925
|
+
newString: getFileModificationContent(input.tool, input.args),
|
|
5926
|
+
tool: input.tool,
|
|
5940
5927
|
timestamp: Date.now()
|
|
5941
5928
|
};
|
|
5942
5929
|
pluginLog.warn(
|
|
5943
|
-
`[opencode-immune] Ralph Loop:
|
|
5930
|
+
`[opencode-immune] Ralph Loop: ${input.tool} failed for "${state.lastEditAttempt.filePath}". Recovery hint will be injected in next system transform.`
|
|
5944
5931
|
);
|
|
5945
5932
|
} else {
|
|
5946
5933
|
state.lastEditAttempt = null;
|
|
@@ -5982,8 +5969,8 @@ var EMOJI_PATTERN = /[\u{1F600}-\u{1F64F}\u{1F300}-\u{1F5FF}\u{1F680}-\u{1F6FF}\
|
|
|
5982
5969
|
var TODO_PATTERN = /\b(TODO|FIXME|HACK|XXX)\b/i;
|
|
5983
5970
|
function createCommentCheckerToolAfter(state) {
|
|
5984
5971
|
return async (input, _output) => {
|
|
5985
|
-
if (input.tool
|
|
5986
|
-
const content = input.tool
|
|
5972
|
+
if (!isFileModificationTool(input.tool)) return;
|
|
5973
|
+
const content = getFileModificationContent(input.tool, input.args);
|
|
5987
5974
|
if (!content) return;
|
|
5988
5975
|
if (EMOJI_PATTERN.test(content)) {
|
|
5989
5976
|
pluginLog.warn(
|