@jphutchins/code-review 0.1.0-alpha.35 → 0.1.0-alpha.36
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 +63 -51
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -773,8 +773,7 @@ var DEFAULT_RESERVE = {
|
|
|
773
773
|
frac: 0.15,
|
|
774
774
|
growth: 0.25,
|
|
775
775
|
flatUsd: 0.02,
|
|
776
|
-
flatMs: 12e4
|
|
777
|
-
flatMem: 2 * 1024 * 1024 * 1024
|
|
776
|
+
flatMs: 12e4
|
|
778
777
|
};
|
|
779
778
|
var SOFT_MULTIPLE = 2;
|
|
780
779
|
var growingReserve = (used, limit, flat, r) => {
|
|
@@ -801,7 +800,6 @@ var decideBudget = (i) => {
|
|
|
801
800
|
const worst = [costAxis(i), timeAxis(i)].filter((a) => a !== null).reduce((max, a) => Math.max(max, axisSeverity(a)), 0);
|
|
802
801
|
return worst === 2 ? { kind: "hard" } : worst === 1 ? { kind: "soft" } : { kind: "ok" };
|
|
803
802
|
};
|
|
804
|
-
var memoryCritical = (availMemBytes, totalMemBytes, floorBytes) => availMemBytes !== null && totalMemBytes !== null && totalMemBytes > 0 && availMemBytes <= floorBytes;
|
|
805
803
|
var pct = (n) => `${String(Math.round(n * 100))}%`;
|
|
806
804
|
var money = (n) => `$${n.toFixed(2)}`;
|
|
807
805
|
var mins = (ms) => `${(ms / 6e4).toFixed(1)}m`;
|
|
@@ -856,7 +854,6 @@ var lastValidPath = (draftPath) => {
|
|
|
856
854
|
};
|
|
857
855
|
var mainHasWrittenDraft = (draftMtimeMs, seedMarkerMtimeMs) => draftMtimeMs !== null && (seedMarkerMtimeMs === null || draftMtimeMs > seedMarkerMtimeMs);
|
|
858
856
|
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.`;
|
|
860
857
|
var forceBackgroundSpawn = (toolInput) => ({
|
|
861
858
|
hookSpecificOutput: {
|
|
862
859
|
hookEventName: "PreToolUse",
|
|
@@ -902,8 +899,6 @@ var evaluateBudgetHook = (input, params) => {
|
|
|
902
899
|
if (phase.kind === "hard" && blockedDuringConvergence(toolName, rec["tool_input"]))
|
|
903
900
|
return denyPreTool(budgetMessage(inputs, phase, params.draftPath, isSubagent));
|
|
904
901
|
if (SPAWN_TOOLS.has(toolName)) {
|
|
905
|
-
if (memoryCritical(params.availMemBytes, params.totalMemBytes, params.reserve.flatMem))
|
|
906
|
-
return denyPreTool(memoryPressureMessage(params.draftPath));
|
|
907
902
|
if (!isSubagent && !params.mainDraftWritten)
|
|
908
903
|
return denyPreTool(spawnFloorMessage(params.draftPath));
|
|
909
904
|
return forceBackgroundSpawn(rec["tool_input"]);
|
|
@@ -950,21 +945,6 @@ var parseFraction = (raw, fallback) => {
|
|
|
950
945
|
const n = Number.parseFloat(raw);
|
|
951
946
|
return Number.isFinite(n) && n >= 0 && n <= 1 ? n : fallback;
|
|
952
947
|
};
|
|
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
|
-
};
|
|
968
948
|
var budgetHookCommand = (draftPath, opts) => [
|
|
969
949
|
"code-review budget-hook --draft",
|
|
970
950
|
shellQuote(draftPath),
|
|
@@ -974,8 +954,7 @@ var budgetHookCommand = (draftPath, opts) => [
|
|
|
974
954
|
...opts.reserveFrac ? ["--reserve-frac", shellQuote(opts.reserveFrac)] : [],
|
|
975
955
|
...opts.reserveGrowth ? ["--reserve-growth", shellQuote(opts.reserveGrowth)] : [],
|
|
976
956
|
...opts.reserveUsd ? ["--reserve-usd", shellQuote(opts.reserveUsd)] : [],
|
|
977
|
-
...opts.reserveWall ? ["--reserve-wall", shellQuote(opts.reserveWall)] : []
|
|
978
|
-
...opts.reserveMem ? ["--reserve-mem", shellQuote(opts.reserveMem)] : []
|
|
957
|
+
...opts.reserveWall ? ["--reserve-wall", shellQuote(opts.reserveWall)] : []
|
|
979
958
|
].join(" ");
|
|
980
959
|
|
|
981
960
|
// src/format.ts
|
|
@@ -2736,6 +2715,32 @@ var composeReviewSettings = (opts) => {
|
|
|
2736
2715
|
};
|
|
2737
2716
|
};
|
|
2738
2717
|
|
|
2718
|
+
// src/sandbox.ts
|
|
2719
|
+
var GITHUB_HOSTS = ["api.github.com", "github.com"];
|
|
2720
|
+
var deriveModelHost = (apiBaseUrl) => {
|
|
2721
|
+
const host = URL.canParse(apiBaseUrl) ? new URL(apiBaseUrl).hostname : "";
|
|
2722
|
+
if (host === "") {
|
|
2723
|
+
throw new Error(
|
|
2724
|
+
`could not derive the model host from api_base_url ${JSON.stringify(apiBaseUrl)} \u2014 expected a URL like https://api.deepseek.com/anthropic`
|
|
2725
|
+
);
|
|
2726
|
+
}
|
|
2727
|
+
return host;
|
|
2728
|
+
};
|
|
2729
|
+
var parseExtraEndpoints = (extra) => extra.split(/\s+/).map((token) => token.replace(/:\d+$/, "")).filter((token) => token.length > 0);
|
|
2730
|
+
var buildSandboxConfig = (opts) => ({
|
|
2731
|
+
network: {
|
|
2732
|
+
allowedDomains: [
|
|
2733
|
+
.../* @__PURE__ */ new Set([
|
|
2734
|
+
deriveModelHost(opts.apiBaseUrl),
|
|
2735
|
+
...GITHUB_HOSTS,
|
|
2736
|
+
...parseExtraEndpoints(opts.extra ?? "")
|
|
2737
|
+
])
|
|
2738
|
+
],
|
|
2739
|
+
deniedDomains: []
|
|
2740
|
+
},
|
|
2741
|
+
filesystem: { allowRead: [], denyRead: [], allowWrite: ["/"], denyWrite: [] }
|
|
2742
|
+
});
|
|
2743
|
+
|
|
2739
2744
|
// src/index.ts
|
|
2740
2745
|
var readJSON = (path) => {
|
|
2741
2746
|
try {
|
|
@@ -3032,18 +3037,6 @@ var snapshotIfValid = (draftPath) => {
|
|
|
3032
3037
|
);
|
|
3033
3038
|
}
|
|
3034
3039
|
};
|
|
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
|
-
};
|
|
3047
3040
|
var budgetHookCmd = defineCommand({
|
|
3048
3041
|
meta: {
|
|
3049
3042
|
name: "budget-hook",
|
|
@@ -3082,17 +3075,12 @@ var budgetHookCmd = defineCommand({
|
|
|
3082
3075
|
"reserve-wall": {
|
|
3083
3076
|
type: "string",
|
|
3084
3077
|
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)"
|
|
3089
3078
|
}
|
|
3090
3079
|
},
|
|
3091
3080
|
run: async ({ args }) => {
|
|
3092
3081
|
try {
|
|
3093
3082
|
const draftPath = resolve$1(args.draft);
|
|
3094
3083
|
const input = readStdinJSON();
|
|
3095
|
-
const mem = readMemInfo();
|
|
3096
3084
|
const transcriptPath = transcriptPathOf(input);
|
|
3097
3085
|
const tree = transcriptPath ? readTranscriptTree(resolve$1(transcriptPath)) : void 0;
|
|
3098
3086
|
const usage = tree ? sumTranscriptUsage(tree.entries) : void 0;
|
|
@@ -3109,14 +3097,11 @@ var budgetHookCmd = defineCommand({
|
|
|
3109
3097
|
nowMs: Date.now()
|
|
3110
3098
|
}),
|
|
3111
3099
|
wallMs,
|
|
3112
|
-
availMemBytes: mem.availBytes,
|
|
3113
|
-
totalMemBytes: mem.totalBytes,
|
|
3114
3100
|
reserve: {
|
|
3115
3101
|
frac: parseFraction(args["reserve-frac"], DEFAULT_RESERVE.frac),
|
|
3116
3102
|
growth: parseFraction(args["reserve-growth"], DEFAULT_RESERVE.growth),
|
|
3117
3103
|
flatUsd: parseBudgetUsd(args["reserve-usd"]) ?? DEFAULT_RESERVE.flatUsd,
|
|
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
|
|
3104
|
+
flatMs: args["reserve-wall"] ? parseWallMs(args["reserve-wall"]) ?? DEFAULT_RESERVE.flatMs : DEFAULT_RESERVE.flatMs
|
|
3120
3105
|
},
|
|
3121
3106
|
draftPath,
|
|
3122
3107
|
mainDraftWritten: mainHasWrittenDraft(
|
|
@@ -3193,10 +3178,6 @@ var printSettingsCmd = defineCommand({
|
|
|
3193
3178
|
"reserve-wall": {
|
|
3194
3179
|
type: "string",
|
|
3195
3180
|
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)"
|
|
3200
3181
|
}
|
|
3201
3182
|
},
|
|
3202
3183
|
run: async ({ args }) => {
|
|
@@ -3218,8 +3199,7 @@ var printSettingsCmd = defineCommand({
|
|
|
3218
3199
|
reserveFrac: args["reserve-frac"],
|
|
3219
3200
|
reserveGrowth: args["reserve-growth"],
|
|
3220
3201
|
reserveUsd: args["reserve-usd"],
|
|
3221
|
-
reserveWall: args["reserve-wall"]
|
|
3222
|
-
reserveMem: args["reserve-mem"]
|
|
3202
|
+
reserveWall: args["reserve-wall"]
|
|
3223
3203
|
}
|
|
3224
3204
|
});
|
|
3225
3205
|
process.stdout.write(`${JSON.stringify(settings)}
|
|
@@ -4189,6 +4169,37 @@ var awaitCiCmd = defineCommand({
|
|
|
4189
4169
|
process.stdout.write(renderCiOutputs(outcome));
|
|
4190
4170
|
}
|
|
4191
4171
|
});
|
|
4172
|
+
var sandboxConfigCmd = defineCommand({
|
|
4173
|
+
meta: {
|
|
4174
|
+
name: "sandbox-config",
|
|
4175
|
+
description: "Emit the sandbox-runtime (srt) settings that jail the untrusted review agent's egress: allow the model host (derived from api_base_url), the GitHub API/host, and the consumer's extra_endpoints; deny all else; filesystem isolation off"
|
|
4176
|
+
},
|
|
4177
|
+
args: {
|
|
4178
|
+
"api-base-url": {
|
|
4179
|
+
type: "string",
|
|
4180
|
+
description: "The model endpoint the CLI dials (ANTHROPIC_BASE_URL) \u2014 its host is allowlisted",
|
|
4181
|
+
required: true
|
|
4182
|
+
},
|
|
4183
|
+
extra: {
|
|
4184
|
+
type: "string",
|
|
4185
|
+
description: "Whitespace-separated host[:port] list of extra domains to allow (the extra_endpoints input)"
|
|
4186
|
+
},
|
|
4187
|
+
out: {
|
|
4188
|
+
type: "string",
|
|
4189
|
+
description: "Write the settings JSON here instead of stdout"
|
|
4190
|
+
}
|
|
4191
|
+
},
|
|
4192
|
+
run: ({ args }) => {
|
|
4193
|
+
const config = buildSandboxConfig({ apiBaseUrl: args["api-base-url"], extra: args.extra });
|
|
4194
|
+
const json = `${JSON.stringify(config, null, 2)}
|
|
4195
|
+
`;
|
|
4196
|
+
if (args.out) {
|
|
4197
|
+
writeFileSync(resolve$1(args.out), json);
|
|
4198
|
+
} else {
|
|
4199
|
+
process.stdout.write(json);
|
|
4200
|
+
}
|
|
4201
|
+
}
|
|
4202
|
+
});
|
|
4192
4203
|
var main = defineCommand({
|
|
4193
4204
|
meta: {
|
|
4194
4205
|
name: "code-review",
|
|
@@ -4218,7 +4229,8 @@ var main = defineCommand({
|
|
|
4218
4229
|
"stop-gate": stopGateCmd,
|
|
4219
4230
|
"budget-hook": budgetHookCmd,
|
|
4220
4231
|
"print-settings": printSettingsCmd,
|
|
4221
|
-
deadline: deadlineCmd
|
|
4232
|
+
deadline: deadlineCmd,
|
|
4233
|
+
"sandbox-config": sandboxConfigCmd
|
|
4222
4234
|
}
|
|
4223
4235
|
});
|
|
4224
4236
|
if (!process.env["VITEST"]) {
|