@jphutchins/code-review 0.1.0-alpha.33 → 0.1.0-alpha.35
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/index.js +68 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -773,24 +773,35 @@ var DEFAULT_RESERVE = {
|
|
|
773
773
|
frac: 0.15,
|
|
774
774
|
growth: 0.25,
|
|
775
775
|
flatUsd: 0.02,
|
|
776
|
-
flatMs: 12e4
|
|
776
|
+
flatMs: 12e4,
|
|
777
|
+
flatMem: 2 * 1024 * 1024 * 1024
|
|
777
778
|
};
|
|
778
779
|
var SOFT_MULTIPLE = 2;
|
|
779
|
-
var
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
780
|
+
var growingReserve = (used, limit, flat, r) => {
|
|
781
|
+
const usedFrac = Math.min(1, Math.max(0, used / limit));
|
|
782
|
+
return Math.max(flat, (r.frac + r.growth * usedFrac) * limit);
|
|
783
|
+
};
|
|
784
|
+
var costAxis = (i) => i.spentUsd !== null && i.budgetUsd !== null && i.budgetUsd > 0 ? {
|
|
785
|
+
used: i.spentUsd,
|
|
786
|
+
limit: i.budgetUsd,
|
|
787
|
+
hardReserve: growingReserve(i.spentUsd, i.budgetUsd, i.reserve.flatUsd, i.reserve)
|
|
788
|
+
} : null;
|
|
789
|
+
var timeAxis = (i) => i.elapsedMs !== null && i.wallMs !== null && i.wallMs > 0 ? {
|
|
790
|
+
used: i.elapsedMs,
|
|
791
|
+
limit: i.wallMs,
|
|
792
|
+
hardReserve: growingReserve(i.elapsedMs, i.wallMs, i.reserve.flatMs, i.reserve)
|
|
793
|
+
} : null;
|
|
794
|
+
var axisSeverity = (a) => {
|
|
785
795
|
const remaining = a.limit - a.used;
|
|
786
|
-
if (remaining <= hardReserve) return 2;
|
|
787
|
-
if (remaining <= SOFT_MULTIPLE * hardReserve) return 1;
|
|
796
|
+
if (remaining <= a.hardReserve) return 2;
|
|
797
|
+
if (remaining <= SOFT_MULTIPLE * a.hardReserve) return 1;
|
|
788
798
|
return 0;
|
|
789
799
|
};
|
|
790
800
|
var decideBudget = (i) => {
|
|
791
|
-
const worst = [costAxis(i), timeAxis(i)].filter((a) => a !== null).reduce((max, a) => Math.max(max, axisSeverity(a
|
|
801
|
+
const worst = [costAxis(i), timeAxis(i)].filter((a) => a !== null).reduce((max, a) => Math.max(max, axisSeverity(a)), 0);
|
|
792
802
|
return worst === 2 ? { kind: "hard" } : worst === 1 ? { kind: "soft" } : { kind: "ok" };
|
|
793
803
|
};
|
|
804
|
+
var memoryCritical = (availMemBytes, totalMemBytes, floorBytes) => availMemBytes !== null && totalMemBytes !== null && totalMemBytes > 0 && availMemBytes <= floorBytes;
|
|
794
805
|
var pct = (n) => `${String(Math.round(n * 100))}%`;
|
|
795
806
|
var money = (n) => `$${n.toFixed(2)}`;
|
|
796
807
|
var mins = (ms) => `${(ms / 6e4).toFixed(1)}m`;
|
|
@@ -845,6 +856,7 @@ var lastValidPath = (draftPath) => {
|
|
|
845
856
|
};
|
|
846
857
|
var mainHasWrittenDraft = (draftMtimeMs, seedMarkerMtimeMs) => draftMtimeMs !== null && (seedMarkerMtimeMs === null || draftMtimeMs > seedMarkerMtimeMs);
|
|
847
858
|
var spawnFloorMessage = (draftPath) => `Write your own first-pass findings to ${draftPath} before spawning subagents \u2014 a review must never depend on subagents alone, and a pre-seeded draft does not count until you have revised it yourself this run. Write ${draftPath} from what you have read so far (preliminary findings are fine), run \`code-review validate ${draftPath} --explain\` until it passes, then fan out; your subagents run in the background, so keep refining the draft as their reports arrive.`;
|
|
859
|
+
var memoryPressureMessage = (draftPath) => `System memory is critically low right now, so another subagent can't be spawned \u2014 a fresh process is the fastest way to tip the runner into an out-of-memory kill that would lose the whole review. Don't wind down: keep reading code directly and keep folding the reports from subagents already running into ${draftPath}, then try spawning again in a moment \u2014 this clears as soon as running subagents finish and free their memory.`;
|
|
848
860
|
var forceBackgroundSpawn = (toolInput) => ({
|
|
849
861
|
hookSpecificOutput: {
|
|
850
862
|
hookEventName: "PreToolUse",
|
|
@@ -890,6 +902,8 @@ var evaluateBudgetHook = (input, params) => {
|
|
|
890
902
|
if (phase.kind === "hard" && blockedDuringConvergence(toolName, rec["tool_input"]))
|
|
891
903
|
return denyPreTool(budgetMessage(inputs, phase, params.draftPath, isSubagent));
|
|
892
904
|
if (SPAWN_TOOLS.has(toolName)) {
|
|
905
|
+
if (memoryCritical(params.availMemBytes, params.totalMemBytes, params.reserve.flatMem))
|
|
906
|
+
return denyPreTool(memoryPressureMessage(params.draftPath));
|
|
893
907
|
if (!isSubagent && !params.mainDraftWritten)
|
|
894
908
|
return denyPreTool(spawnFloorMessage(params.draftPath));
|
|
895
909
|
return forceBackgroundSpawn(rec["tool_input"]);
|
|
@@ -936,6 +950,21 @@ var parseFraction = (raw, fallback) => {
|
|
|
936
950
|
const n = Number.parseFloat(raw);
|
|
937
951
|
return Number.isFinite(n) && n >= 0 && n <= 1 ? n : fallback;
|
|
938
952
|
};
|
|
953
|
+
var BYTE_UNIT = {
|
|
954
|
+
"": 1,
|
|
955
|
+
k: 1024,
|
|
956
|
+
m: 1024 * 1024,
|
|
957
|
+
g: 1024 * 1024 * 1024,
|
|
958
|
+
t: 1024 * 1024 * 1024 * 1024
|
|
959
|
+
};
|
|
960
|
+
var parseByteSize = (raw) => {
|
|
961
|
+
const m = /^(\d+(?:\.\d+)?)\s*([kmgt])?(?:i?b)?$/i.exec(raw.trim());
|
|
962
|
+
if (m === null) return null;
|
|
963
|
+
const [, num = "", unit = ""] = m;
|
|
964
|
+
const n = Number.parseFloat(num);
|
|
965
|
+
const mult = BYTE_UNIT[unit.toLowerCase()];
|
|
966
|
+
return Number.isFinite(n) && mult !== void 0 ? n * mult : null;
|
|
967
|
+
};
|
|
939
968
|
var budgetHookCommand = (draftPath, opts) => [
|
|
940
969
|
"code-review budget-hook --draft",
|
|
941
970
|
shellQuote(draftPath),
|
|
@@ -945,7 +974,8 @@ var budgetHookCommand = (draftPath, opts) => [
|
|
|
945
974
|
...opts.reserveFrac ? ["--reserve-frac", shellQuote(opts.reserveFrac)] : [],
|
|
946
975
|
...opts.reserveGrowth ? ["--reserve-growth", shellQuote(opts.reserveGrowth)] : [],
|
|
947
976
|
...opts.reserveUsd ? ["--reserve-usd", shellQuote(opts.reserveUsd)] : [],
|
|
948
|
-
...opts.reserveWall ? ["--reserve-wall", shellQuote(opts.reserveWall)] : []
|
|
977
|
+
...opts.reserveWall ? ["--reserve-wall", shellQuote(opts.reserveWall)] : [],
|
|
978
|
+
...opts.reserveMem ? ["--reserve-mem", shellQuote(opts.reserveMem)] : []
|
|
949
979
|
].join(" ");
|
|
950
980
|
|
|
951
981
|
// src/format.ts
|
|
@@ -3002,6 +3032,18 @@ var snapshotIfValid = (draftPath) => {
|
|
|
3002
3032
|
);
|
|
3003
3033
|
}
|
|
3004
3034
|
};
|
|
3035
|
+
var readMemInfo = () => {
|
|
3036
|
+
try {
|
|
3037
|
+
const text = readFileSync("/proc/meminfo", "utf8");
|
|
3038
|
+
const kb = (key2) => {
|
|
3039
|
+
const m = new RegExp(`^${key2}:\\s+(\\d+)\\s+kB`, "m").exec(text);
|
|
3040
|
+
return m?.[1] !== void 0 ? Number(m[1]) * 1024 : null;
|
|
3041
|
+
};
|
|
3042
|
+
return { availBytes: kb("MemAvailable"), totalBytes: kb("MemTotal") };
|
|
3043
|
+
} catch {
|
|
3044
|
+
return { availBytes: null, totalBytes: null };
|
|
3045
|
+
}
|
|
3046
|
+
};
|
|
3005
3047
|
var budgetHookCmd = defineCommand({
|
|
3006
3048
|
meta: {
|
|
3007
3049
|
name: "budget-hook",
|
|
@@ -3040,12 +3082,17 @@ var budgetHookCmd = defineCommand({
|
|
|
3040
3082
|
"reserve-wall": {
|
|
3041
3083
|
type: "string",
|
|
3042
3084
|
description: "Flat wall-clock wind-down floor (e.g. 2m, 120s), whichever is larger with --reserve-frac (default: 2m)"
|
|
3085
|
+
},
|
|
3086
|
+
"reserve-mem": {
|
|
3087
|
+
type: "string",
|
|
3088
|
+
description: "Free-RAM floor (e.g. 2g, 1536m) below which new subagent spawns are denied until memory recovers; not a convergence axis (default: 2g)"
|
|
3043
3089
|
}
|
|
3044
3090
|
},
|
|
3045
3091
|
run: async ({ args }) => {
|
|
3046
3092
|
try {
|
|
3047
3093
|
const draftPath = resolve$1(args.draft);
|
|
3048
3094
|
const input = readStdinJSON();
|
|
3095
|
+
const mem = readMemInfo();
|
|
3049
3096
|
const transcriptPath = transcriptPathOf(input);
|
|
3050
3097
|
const tree = transcriptPath ? readTranscriptTree(resolve$1(transcriptPath)) : void 0;
|
|
3051
3098
|
const usage = tree ? sumTranscriptUsage(tree.entries) : void 0;
|
|
@@ -3062,11 +3109,14 @@ var budgetHookCmd = defineCommand({
|
|
|
3062
3109
|
nowMs: Date.now()
|
|
3063
3110
|
}),
|
|
3064
3111
|
wallMs,
|
|
3112
|
+
availMemBytes: mem.availBytes,
|
|
3113
|
+
totalMemBytes: mem.totalBytes,
|
|
3065
3114
|
reserve: {
|
|
3066
3115
|
frac: parseFraction(args["reserve-frac"], DEFAULT_RESERVE.frac),
|
|
3067
3116
|
growth: parseFraction(args["reserve-growth"], DEFAULT_RESERVE.growth),
|
|
3068
3117
|
flatUsd: parseBudgetUsd(args["reserve-usd"]) ?? DEFAULT_RESERVE.flatUsd,
|
|
3069
|
-
flatMs: args["reserve-wall"] ? parseWallMs(args["reserve-wall"]) ?? DEFAULT_RESERVE.flatMs : DEFAULT_RESERVE.flatMs
|
|
3118
|
+
flatMs: args["reserve-wall"] ? parseWallMs(args["reserve-wall"]) ?? DEFAULT_RESERVE.flatMs : DEFAULT_RESERVE.flatMs,
|
|
3119
|
+
flatMem: args["reserve-mem"] ? parseByteSize(args["reserve-mem"]) ?? DEFAULT_RESERVE.flatMem : DEFAULT_RESERVE.flatMem
|
|
3070
3120
|
},
|
|
3071
3121
|
draftPath,
|
|
3072
3122
|
mainDraftWritten: mainHasWrittenDraft(
|
|
@@ -3143,6 +3193,10 @@ var printSettingsCmd = defineCommand({
|
|
|
3143
3193
|
"reserve-wall": {
|
|
3144
3194
|
type: "string",
|
|
3145
3195
|
description: "Flat wall-clock wind-down floor (e.g. 2m), whichever is larger with --reserve-frac (default: 2m)"
|
|
3196
|
+
},
|
|
3197
|
+
"reserve-mem": {
|
|
3198
|
+
type: "string",
|
|
3199
|
+
description: "Free-RAM floor (e.g. 2g) below which new subagent spawns are denied until memory recovers (default: 2g)"
|
|
3146
3200
|
}
|
|
3147
3201
|
},
|
|
3148
3202
|
run: async ({ args }) => {
|
|
@@ -3164,7 +3218,8 @@ var printSettingsCmd = defineCommand({
|
|
|
3164
3218
|
reserveFrac: args["reserve-frac"],
|
|
3165
3219
|
reserveGrowth: args["reserve-growth"],
|
|
3166
3220
|
reserveUsd: args["reserve-usd"],
|
|
3167
|
-
reserveWall: args["reserve-wall"]
|
|
3221
|
+
reserveWall: args["reserve-wall"],
|
|
3222
|
+
reserveMem: args["reserve-mem"]
|
|
3168
3223
|
}
|
|
3169
3224
|
});
|
|
3170
3225
|
process.stdout.write(`${JSON.stringify(settings)}
|