mergejudge-runner 0.4.4 → 0.4.5
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/README.md +1 -0
- package/dist/cli.js +38 -17
- 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.5** (2026-10-17): policy files share the total budget fairly (MergeJudge #100): a large first file (e.g. AGENTS.md) no longer silently drops later ones (e.g. APPROVAL_POLICY.md); truncation is reported. Local-code mode keeps one extra char per file so the cut is visible. No config or protocol changes; works with older Workers.
|
|
127
128
|
- **0.4.4** (2026-10-17): learning v2 (MergeJudge #94/#96/#97): the runner prompt now includes the repo's team preferences (known false alarms, recent writer lessons, outcome hints) sent by the Worker, re-sanitised and capped; context only, never lowers a lane. Additive job field; works with older Workers. No config changes.
|
|
128
129
|
- **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.
|
|
129
130
|
- **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.
|
package/dist/cli.js
CHANGED
|
@@ -30535,28 +30535,48 @@ async function retrieveDeepContext(snap, files, opts = {}, log = () => {
|
|
|
30535
30535
|
// ../../src/policy.ts
|
|
30536
30536
|
var POLICY_MAX_EACH = 8 * 1024;
|
|
30537
30537
|
var POLICY_MAX_TOTAL = 8 * 1024;
|
|
30538
|
+
function fairShares(sizes, total) {
|
|
30539
|
+
const out = sizes.map(() => 0);
|
|
30540
|
+
let left = Math.max(0, total);
|
|
30541
|
+
let pending = sizes.map((_, i) => i).sort((x, y) => sizes[x] - sizes[y]);
|
|
30542
|
+
while (pending.length) {
|
|
30543
|
+
const share = Math.floor(left / pending.length);
|
|
30544
|
+
const i = pending[0];
|
|
30545
|
+
if (sizes[i] <= share) {
|
|
30546
|
+
out[i] = sizes[i];
|
|
30547
|
+
left -= sizes[i];
|
|
30548
|
+
pending = pending.slice(1);
|
|
30549
|
+
continue;
|
|
30550
|
+
}
|
|
30551
|
+
for (const j of pending) out[j] = share;
|
|
30552
|
+
break;
|
|
30553
|
+
}
|
|
30554
|
+
return out;
|
|
30555
|
+
}
|
|
30538
30556
|
async function loadPolicies(paths, fetchFile, caps = { each: POLICY_MAX_EACH, total: POLICY_MAX_TOTAL }) {
|
|
30539
|
-
const
|
|
30540
|
-
const
|
|
30541
|
-
let total = 0;
|
|
30557
|
+
const found = [];
|
|
30558
|
+
const skipped = [];
|
|
30542
30559
|
for (const path2 of paths) {
|
|
30543
|
-
if (total >= caps.total) break;
|
|
30544
30560
|
let t;
|
|
30545
30561
|
try {
|
|
30546
30562
|
t = await fetchFile(path2);
|
|
30547
30563
|
} catch {
|
|
30548
30564
|
t = null;
|
|
30549
30565
|
}
|
|
30550
|
-
if (!t || !t.trim())
|
|
30551
|
-
|
|
30566
|
+
if (!t || !t.trim()) skipped.push(path2);
|
|
30567
|
+
else found.push({ path: path2, t });
|
|
30568
|
+
}
|
|
30569
|
+
const shares = fairShares(found.map((f) => Math.min(f.t.length, caps.each)), caps.total);
|
|
30570
|
+
const parts = [];
|
|
30571
|
+
const used = [];
|
|
30572
|
+
found.forEach(({ path: path2, t }, i) => {
|
|
30573
|
+
const budget = shares[i];
|
|
30552
30574
|
const truncated = t.length > budget;
|
|
30553
|
-
const body = truncated ? t.slice(0, budget) + "\n[... truncated by MergeJudge ...]" : t;
|
|
30554
|
-
total += Math.min(t.length, budget);
|
|
30555
30575
|
parts.push(`--- ${path2} ---
|
|
30556
|
-
${
|
|
30576
|
+
${truncated ? t.slice(0, budget) + "\n[... truncated by MergeJudge ...]" : t}`);
|
|
30557
30577
|
used.push({ path: path2, truncated });
|
|
30558
|
-
}
|
|
30559
|
-
return { text: parts.join("\n\n"), used };
|
|
30578
|
+
});
|
|
30579
|
+
return { text: parts.join("\n\n"), used, skipped };
|
|
30560
30580
|
}
|
|
30561
30581
|
function filterPolicyPaths(paths, exclude) {
|
|
30562
30582
|
if (!exclude.length) return paths;
|
|
@@ -31445,7 +31465,7 @@ async function prepareLocalJob(o, j, log, signal) {
|
|
|
31445
31465
|
const policySource = cfgSha === j.baseSha ? base : new GitSource(dir, cfgSha, o.env, o.limits, signal);
|
|
31446
31466
|
for (const p of filterPolicyPaths(j.cfg.policy_files, j.cfg.policy_exclude)) {
|
|
31447
31467
|
const t = await policySource.readFile(p).catch(() => null);
|
|
31448
|
-
if (t) policyFiles[p] = t.slice(0, j.cfg.policy.max_each_bytes);
|
|
31468
|
+
if (t) policyFiles[p] = t.slice(0, j.cfg.policy.max_each_bytes + 1);
|
|
31449
31469
|
}
|
|
31450
31470
|
if (policySource !== base) policySource.close();
|
|
31451
31471
|
notes.push("Deep mode on a runner with a local clone: repo context was retrieved from an index on this machine and reviewed in one pass (no tool calls).");
|
|
@@ -32423,7 +32443,7 @@ async function produceReviewResult(o) {
|
|
|
32423
32443
|
const labels = (pr.labels ?? []).map((l) => l.name);
|
|
32424
32444
|
if (o.providerNote && cfg.provider.type !== "none") notes.push(`LLM disabled (${!provider && o.keyNote || o.providerNote}); rules-only.`);
|
|
32425
32445
|
let llm = null;
|
|
32426
|
-
let policies = { text: "", used: [] };
|
|
32446
|
+
let policies = { text: "", used: [], skipped: [] };
|
|
32427
32447
|
let tokens2 = 0;
|
|
32428
32448
|
let usedMode = cfg.review.mode;
|
|
32429
32449
|
let breakdown = null;
|
|
@@ -32432,15 +32452,16 @@ async function produceReviewResult(o) {
|
|
|
32432
32452
|
llm = cached2.llm;
|
|
32433
32453
|
tokens2 = cached2.tokens;
|
|
32434
32454
|
breakdown = cached2.breakdown;
|
|
32435
|
-
policies = { text: "", used: cached2.policiesUsed };
|
|
32455
|
+
policies = { text: "", used: cached2.policiesUsed, skipped: [] };
|
|
32436
32456
|
log.info(`Re-using LLM result for head ${pr.head.sha.slice(0, 7)} (no LLM call).`);
|
|
32437
32457
|
} else if (provider) {
|
|
32438
32458
|
const paths = filterPolicyPaths(cfg.policy_files, cfg.policy_exclude);
|
|
32439
32459
|
policies = paths.length ? await loadPolicies(paths, (p) => o.readRepoFile(p, cfgRef), {
|
|
32440
32460
|
each: cfg.policy.max_each_bytes,
|
|
32441
32461
|
total: cfg.policy.max_total_bytes
|
|
32442
|
-
}) : { text: "", used: [] };
|
|
32443
|
-
if (policies.used.length) log.info(`Policy files: ${policies.used.map((u) => u.path).join(", ")}`);
|
|
32462
|
+
}) : { text: "", used: [], skipped: [] };
|
|
32463
|
+
if (policies.used.length) log.info(`Policy files: ${policies.used.map((u) => u.path).join(", ")}${policies.used.some((u) => u.truncated) ? " (truncated)" : ""}`);
|
|
32464
|
+
if (policies.skipped.length) log.info(`Policy files not found or empty: ${policies.skipped.join(", ")}`);
|
|
32444
32465
|
else if (!cfg.policy_files.length) log.info("Policy files disabled (policy_files: []).");
|
|
32445
32466
|
const criteria = cfg.rubrics.enabled ? selectCriteria(cfg.rubrics.packs, cfg.rubrics.custom, cfg.rubrics.notes) : [];
|
|
32446
32467
|
const { kept, skipped } = excludeFromLlm(files, cfg.diff_exclude);
|
|
@@ -32790,7 +32811,7 @@ function installAutostart(d, bundle) {
|
|
|
32790
32811
|
}
|
|
32791
32812
|
|
|
32792
32813
|
// src/version.ts
|
|
32793
|
-
var VERSION = "0.4.
|
|
32814
|
+
var VERSION = "0.4.5";
|
|
32794
32815
|
var MODES = ["diff", "context", "deep"];
|
|
32795
32816
|
var FEATURES = ["local-code"];
|
|
32796
32817
|
|
package/package.json
CHANGED