mergejudge-runner 0.4.2 → 0.4.3

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.
Files changed (3) hide show
  1. package/README.md +1 -0
  2. package/dist/cli.js +67 -9
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -124,6 +124,7 @@ Logs go to stderr.
124
124
 
125
125
  ## Changelog
126
126
 
127
+ - **0.4.3** (2026-10-17): bundles the MergeJudge #92 rules fix: a safety guard (e.g. `persist-credentials: false`) removed together with its whole YAML step or job no longer forces block. No config or protocol changes.
127
128
  - **0.4.2** (2026-10-17): a heartbeat answered with `done` after the result was accepted is treated as benign, not as a lost lease (MergeJudge #86). In deep-local mode the runner secret-scans the full local diff, including files GitHub strips from the API diff (large or generated files) (MergeJudge #87). No config changes.
128
129
  - **0.4.1** (2026-10-16): local-code deep reviews use the new retrieval from MergeJudge #82: two-hop importers/imports and a repo search for changed string literals, keys and env names, within fixed budgets. No config or protocol changes.
129
130
  - **0.4.0**: local code source (`runner.code_source: local`).
package/dist/cli.js CHANGED
@@ -29173,15 +29173,73 @@ var SAFETY_GUARDS = [
29173
29173
  { name: "set -e", why: "shell fail-fast guard", re: /^\s*(?:run\s*:\s*)?set\s+-[a-z]*e[a-z]*(?:\s|$)/ },
29174
29174
  { name: "--frozen-lockfile", why: "dependency-integrity guard", re: /--frozen-lockfile\b|\bnpm\s+ci\b/ }
29175
29175
  ];
29176
- function findRemovedGuards(patch) {
29177
- if (!patch) return [];
29178
- const removed = [];
29179
- const added = [];
29176
+ function parsePatchLines(patch) {
29177
+ const out = [];
29178
+ let hunk = 0;
29180
29179
  for (const line of patch.split("\n")) {
29181
- if (line.startsWith("-")) removed.push(line.slice(1));
29182
- else if (line.startsWith("+")) added.push(line.slice(1));
29180
+ if (line.startsWith("@@")) hunk++;
29181
+ else if (line.startsWith("-")) out.push({ op: "del", text: line.slice(1), hunk });
29182
+ else if (line.startsWith("+")) out.push({ op: "add", text: line.slice(1), hunk });
29183
+ else if (line.startsWith(" ")) out.push({ op: "ctx", text: line.slice(1), hunk });
29184
+ }
29185
+ return out;
29186
+ }
29187
+ function yamlIndent(text) {
29188
+ const m = /^( *)\S/.exec(text);
29189
+ return m ? m[1].length : void 0;
29190
+ }
29191
+ var isListItemStart = (text) => /^ *-(?: |$)/.test(text);
29192
+ function isBlockKey(text) {
29193
+ if (isListItemStart(text)) return false;
29194
+ const i = text.indexOf(":");
29195
+ if (i < 1 || /[#{}\[\],&*!|>'"@`]/.test(text.slice(0, i))) return false;
29196
+ return /^:(\s*(?:[|>][+-]?\d*)?)(\s+#.*)?$/.test(text.slice(i));
29197
+ }
29198
+ function opensStepContainer(lines, j) {
29199
+ const h = yamlIndent(lines[j].text);
29200
+ for (let k = j + 1; k < lines.length && lines[k].hunk === lines[j].hunk; k++) {
29201
+ const ind = yamlIndent(lines[k].text);
29202
+ if (ind === void 0) continue;
29203
+ if (ind <= h) return false;
29204
+ if (isListItemStart(lines[k].text)) return true;
29205
+ }
29206
+ return false;
29207
+ }
29208
+ function blockRemovedWhole(lines, j, g) {
29209
+ const h = yamlIndent(lines[j].text);
29210
+ let sawGuard = j === g;
29211
+ for (let k = j + 1; k < lines.length && lines[k].hunk === lines[j].hunk; k++) {
29212
+ const e = lines[k];
29213
+ if (e.op === "add") return false;
29214
+ const ind = yamlIndent(e.text);
29215
+ if (ind === void 0) continue;
29216
+ if (ind <= h) return sawGuard;
29217
+ if (e.op === "ctx") return false;
29218
+ if (k === g) sawGuard = true;
29219
+ }
29220
+ return false;
29221
+ }
29222
+ function guardRemovedWithItsBlock(lines, i) {
29223
+ const guard = yamlIndent(lines[i].text);
29224
+ if (guard === void 0) return false;
29225
+ for (let j = i; j >= 0 && lines[j].op === "del" && lines[j].hunk === lines[i].hunk; j--) {
29226
+ const text = lines[j].text;
29227
+ const h = yamlIndent(text);
29228
+ if (h === void 0 || j < i && h >= guard) continue;
29229
+ const isStep = isListItemStart(text);
29230
+ if (!isStep && !(isBlockKey(text) && opensStepContainer(lines, j))) continue;
29231
+ if (blockRemovedWhole(lines, j, i)) return true;
29183
29232
  }
29184
- return SAFETY_GUARDS.filter((g) => removed.some((l) => g.re.test(l)) && !added.some((l) => g.re.test(l))).map((g) => g.name);
29233
+ return false;
29234
+ }
29235
+ function findRemovedGuards(patch, path2 = "") {
29236
+ if (!patch) return [];
29237
+ const lines = parsePatchLines(patch);
29238
+ const added = lines.filter((l) => l.op === "add").map((l) => l.text);
29239
+ const yaml = /\.ya?ml$/i.test(path2);
29240
+ return SAFETY_GUARDS.filter(
29241
+ (g) => !added.some((l) => g.re.test(l)) && lines.some((l, i) => l.op === "del" && g.re.test(l.text) && (!yaml || !guardRemovedWithItsBlock(lines, i)))
29242
+ ).map((g) => g.name);
29185
29243
  }
29186
29244
  var CODE_AUTO_NEVER_GLOBS = [".github/**", "**/.env*", "_headers", "**/_headers"];
29187
29245
  var ALWAYS_REVIEW_GLOBS = ["_headers", "**/_headers"];
@@ -29213,7 +29271,7 @@ function classifyFileInner(file2, cfg) {
29213
29271
  const isProtected = paths.some((p) => matchesAny(p, cfg.lanes.protected));
29214
29272
  if (isProtected) {
29215
29273
  raise("review", "protected path");
29216
- const gone = findRemovedGuards(file2.patch);
29274
+ const gone = findRemovedGuards(file2.patch, file2.path);
29217
29275
  for (const g of SAFETY_GUARDS.filter((g2) => gone.includes(g2.name)))
29218
29276
  raise("block", `removes ${g.why} \`${g.name}\` from a protected path`);
29219
29277
  }
@@ -32663,7 +32721,7 @@ function installAutostart(d, bundle) {
32663
32721
  }
32664
32722
 
32665
32723
  // src/version.ts
32666
- var VERSION = "0.4.2";
32724
+ var VERSION = "0.4.3";
32667
32725
  var MODES = ["diff", "context", "deep"];
32668
32726
  var FEATURES = ["local-code"];
32669
32727
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mergejudge-runner",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "description": "Run MergeJudge reviews on your own machine with your own Claude Code login (runner protocol /runner/v1)",