@kynver-app/runtime 0.1.95 → 0.1.99
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/bounded-build/admission.d.ts +2 -2
- package/dist/bounded-build/exec.d.ts +6 -2
- package/dist/cli.js +427 -139
- package/dist/cli.js.map +4 -4
- package/dist/harness-verify.d.ts +3 -2
- package/dist/heavy-verification/gate.d.ts +10 -0
- package/dist/heavy-verification/index.d.ts +3 -0
- package/dist/heavy-verification/paths.d.ts +3 -0
- package/dist/heavy-verification/slot.d.ts +49 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +432 -134
- package/dist/index.js.map +4 -4
- package/dist/resource-gate.d.ts +7 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -725,7 +725,7 @@ function shouldEnforceMemoryCostPackageGuardCli(scope, action) {
|
|
|
725
725
|
}
|
|
726
726
|
|
|
727
727
|
// src/config.ts
|
|
728
|
-
import { existsSync as existsSync11, mkdirSync as mkdirSync2, readFileSync as
|
|
728
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync2, readFileSync as readFileSync10, writeFileSync as writeFileSync2 } from "node:fs";
|
|
729
729
|
import { homedir as homedir5, totalmem } from "node:os";
|
|
730
730
|
import path10 from "node:path";
|
|
731
731
|
|
|
@@ -803,6 +803,7 @@ function readMemAvailableBytes(meminfoText) {
|
|
|
803
803
|
|
|
804
804
|
// src/resource-gate.ts
|
|
805
805
|
import path9 from "node:path";
|
|
806
|
+
import { readFileSync as readFileSync9 } from "node:fs";
|
|
806
807
|
|
|
807
808
|
// src/disk-gate.ts
|
|
808
809
|
import { statfsSync as statfsSync2 } from "node:fs";
|
|
@@ -827,23 +828,23 @@ function isWslHost() {
|
|
|
827
828
|
function observeWslHostDisk(options = {}) {
|
|
828
829
|
const wsl = options.forceWsl === void 0 ? isWslHost() : options.forceWsl;
|
|
829
830
|
if (!wsl) return null;
|
|
830
|
-
const
|
|
831
|
+
const path71 = options.wslHostMount?.trim() || process.env.KYNVER_WSL_HOST_MOUNT?.trim() || DEFAULT_WSL_HOST_MOUNT;
|
|
831
832
|
const warnBelowBytes = options.wslHostFreeWarnBytes ?? DEFAULT_WSL_HOST_WARN_FREE_BYTES;
|
|
832
833
|
const criticalBelowBytes = options.wslHostFreeCriticalBytes ?? DEFAULT_WSL_HOST_CRITICAL_FREE_BYTES;
|
|
833
834
|
const statfs = options.statfs ?? statfsSync;
|
|
834
835
|
let stats;
|
|
835
836
|
try {
|
|
836
|
-
stats = statfs(
|
|
837
|
+
stats = statfs(path71);
|
|
837
838
|
} catch (error) {
|
|
838
839
|
return {
|
|
839
840
|
ok: false,
|
|
840
|
-
path:
|
|
841
|
+
path: path71,
|
|
841
842
|
freeBytes: 0,
|
|
842
843
|
totalBytes: 0,
|
|
843
844
|
usedPercent: 100,
|
|
844
845
|
warnBelowBytes,
|
|
845
846
|
criticalBelowBytes,
|
|
846
|
-
reason: `Windows host disk probe failed at ${
|
|
847
|
+
reason: `Windows host disk probe failed at ${path71}: ${error.message}`,
|
|
847
848
|
probeError: error.message
|
|
848
849
|
};
|
|
849
850
|
}
|
|
@@ -857,11 +858,11 @@ function observeWslHostDisk(options = {}) {
|
|
|
857
858
|
let reason = null;
|
|
858
859
|
if (!ok) {
|
|
859
860
|
const tag = criticalFree ? "critical" : "warning";
|
|
860
|
-
reason = `Windows host disk ${
|
|
861
|
+
reason = `Windows host disk ${path71} at ${tag}: ${freeGiB} GiB free (<${(criticalFree ? criticalBelowBytes : warnBelowBytes) / 1024 / 1024 / 1024} GiB); WSL VHDX cannot grow safely. ${summarizeWslRecoverySteps()}`;
|
|
861
862
|
}
|
|
862
863
|
return {
|
|
863
864
|
ok,
|
|
864
|
-
path:
|
|
865
|
+
path: path71,
|
|
865
866
|
freeBytes,
|
|
866
867
|
totalBytes,
|
|
867
868
|
usedPercent,
|
|
@@ -881,12 +882,12 @@ var DEFAULT_CRITICAL_FREE_BYTES = 15 * 1024 * 1024 * 1024;
|
|
|
881
882
|
var DEFAULT_MAX_USED_PERCENT = 80;
|
|
882
883
|
var DEFAULT_HARD_MAX_USED_PERCENT = 90;
|
|
883
884
|
function observeRunnerDiskGate(input = {}) {
|
|
884
|
-
const
|
|
885
|
+
const path71 = input.diskPath?.trim() || "/";
|
|
885
886
|
const warnBelowBytes = input.diskFreeWarnBytes ?? DEFAULT_WARN_FREE_BYTES;
|
|
886
887
|
const criticalBelowBytes = input.diskFreeCriticalBytes ?? DEFAULT_CRITICAL_FREE_BYTES;
|
|
887
888
|
const maxUsedPercent = input.diskMaxUsedPercent ?? DEFAULT_MAX_USED_PERCENT;
|
|
888
889
|
const hardMaxUsedPercent = input.diskHardMaxUsedPercent ?? DEFAULT_HARD_MAX_USED_PERCENT;
|
|
889
|
-
const stats = statfsSync2(
|
|
890
|
+
const stats = statfsSync2(path71);
|
|
890
891
|
const freeBytes = Number(stats.bavail) * Number(stats.bsize);
|
|
891
892
|
const totalBytes = Number(stats.blocks) * Number(stats.bsize);
|
|
892
893
|
const usedPercent = totalBytes > 0 ? (totalBytes - freeBytes) / totalBytes * 100 : 100;
|
|
@@ -909,7 +910,7 @@ function observeRunnerDiskGate(input = {}) {
|
|
|
909
910
|
}
|
|
910
911
|
return {
|
|
911
912
|
ok,
|
|
912
|
-
path:
|
|
913
|
+
path: path71,
|
|
913
914
|
freeBytes,
|
|
914
915
|
totalBytes,
|
|
915
916
|
usedPercent,
|
|
@@ -2336,11 +2337,29 @@ function computeAutoMaxWorkers(totalMemBytes, opts = {}) {
|
|
|
2336
2337
|
function readAvailableMemBytes() {
|
|
2337
2338
|
return readMemAvailableBytes();
|
|
2338
2339
|
}
|
|
2340
|
+
function pidCommandLine(pid) {
|
|
2341
|
+
if (!pid || process.platform !== "linux") return null;
|
|
2342
|
+
try {
|
|
2343
|
+
return readFileSync9(`/proc/${pid}/cmdline`, "utf8").replace(/\0/g, " ");
|
|
2344
|
+
} catch {
|
|
2345
|
+
return null;
|
|
2346
|
+
}
|
|
2347
|
+
}
|
|
2348
|
+
function workerProcessMatchesRecord(worker) {
|
|
2349
|
+
if (!worker.pid || process.platform !== "linux") return true;
|
|
2350
|
+
const cmdline = pidCommandLine(worker.pid);
|
|
2351
|
+
if (!cmdline) return false;
|
|
2352
|
+
const probes = [worker.worktreePath, worker.workerDir, worker.heartbeatPath].filter(
|
|
2353
|
+
(value) => typeof value === "string" && value.trim().length > 0
|
|
2354
|
+
);
|
|
2355
|
+
return probes.some((probe) => cmdline.includes(probe));
|
|
2356
|
+
}
|
|
2339
2357
|
function isActiveHarnessWorker(worker) {
|
|
2340
2358
|
if (typeof worker.completionBlocker === "string" && worker.completionBlocker.trim()) {
|
|
2341
2359
|
return false;
|
|
2342
2360
|
}
|
|
2343
2361
|
const status = computeWorkerStatus(worker);
|
|
2362
|
+
if (status.alive && !workerProcessMatchesRecord(worker)) return false;
|
|
2344
2363
|
return status.alive && !status.finalResult && status.attention.state !== "done";
|
|
2345
2364
|
}
|
|
2346
2365
|
function countActiveWorkersForRun(run) {
|
|
@@ -2491,7 +2510,7 @@ var CREDENTIALS_FILE = path10.join(CONFIG_DIR, "credentials");
|
|
|
2491
2510
|
function loadUserConfig() {
|
|
2492
2511
|
if (!existsSync11(CONFIG_FILE)) return {};
|
|
2493
2512
|
try {
|
|
2494
|
-
return JSON.parse(
|
|
2513
|
+
return JSON.parse(readFileSync10(CONFIG_FILE, "utf8"));
|
|
2495
2514
|
} catch {
|
|
2496
2515
|
return {};
|
|
2497
2516
|
}
|
|
@@ -2568,7 +2587,7 @@ function resolveSetupWorkerConfig(existing, args, totalMemBytes = totalmem()) {
|
|
|
2568
2587
|
function loadCredentialsFile() {
|
|
2569
2588
|
if (!existsSync11(CREDENTIALS_FILE)) return {};
|
|
2570
2589
|
try {
|
|
2571
|
-
return JSON.parse(
|
|
2590
|
+
return JSON.parse(readFileSync10(CREDENTIALS_FILE, "utf8"));
|
|
2572
2591
|
} catch {
|
|
2573
2592
|
return {};
|
|
2574
2593
|
}
|
|
@@ -2845,15 +2864,30 @@ async function withTimeout(fn) {
|
|
|
2845
2864
|
clearTimeout(timeout);
|
|
2846
2865
|
}
|
|
2847
2866
|
}
|
|
2867
|
+
function callbackFetchError(error) {
|
|
2868
|
+
return {
|
|
2869
|
+
ok: false,
|
|
2870
|
+
status: 0,
|
|
2871
|
+
response: {
|
|
2872
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2873
|
+
timeoutMs: callbackTimeoutMs()
|
|
2874
|
+
}
|
|
2875
|
+
};
|
|
2876
|
+
}
|
|
2848
2877
|
async function postJson(url, secret, body) {
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2878
|
+
let res;
|
|
2879
|
+
try {
|
|
2880
|
+
res = await withTimeout(
|
|
2881
|
+
(signal) => fetch(url, {
|
|
2882
|
+
method: "POST",
|
|
2883
|
+
headers: buildHarnessCallbackHeaders(secret),
|
|
2884
|
+
body: JSON.stringify(body),
|
|
2885
|
+
signal
|
|
2886
|
+
})
|
|
2887
|
+
);
|
|
2888
|
+
} catch (error) {
|
|
2889
|
+
return callbackFetchError(error);
|
|
2890
|
+
}
|
|
2857
2891
|
let response = null;
|
|
2858
2892
|
try {
|
|
2859
2893
|
response = await res.json();
|
|
@@ -2871,13 +2905,18 @@ async function postJsonWithCredentialRefresh(url, secret, body, opts) {
|
|
|
2871
2905
|
return { ...retry, refreshedAuth: true };
|
|
2872
2906
|
}
|
|
2873
2907
|
async function getJson(url, secret) {
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2908
|
+
let res;
|
|
2909
|
+
try {
|
|
2910
|
+
res = await withTimeout(
|
|
2911
|
+
(signal) => fetch(url, {
|
|
2912
|
+
method: "GET",
|
|
2913
|
+
headers: buildHarnessCallbackHeaders(secret),
|
|
2914
|
+
signal
|
|
2915
|
+
})
|
|
2916
|
+
);
|
|
2917
|
+
} catch (error) {
|
|
2918
|
+
return callbackFetchError(error);
|
|
2919
|
+
}
|
|
2881
2920
|
let response = null;
|
|
2882
2921
|
try {
|
|
2883
2922
|
response = await res.json();
|
|
@@ -2887,41 +2926,6 @@ async function getJson(url, secret) {
|
|
|
2887
2926
|
return { ok: res.ok, status: res.status, response };
|
|
2888
2927
|
}
|
|
2889
2928
|
|
|
2890
|
-
// src/dispatch-lane-normalization.ts
|
|
2891
|
-
function trimLower(value) {
|
|
2892
|
-
return (value ?? "").trim().toLowerCase();
|
|
2893
|
-
}
|
|
2894
|
-
function roleLaneToDispatchLane(roleLane) {
|
|
2895
|
-
switch (trimLower(roleLane)) {
|
|
2896
|
-
case "implementer":
|
|
2897
|
-
case "repair_implementer":
|
|
2898
|
-
case "plan_author":
|
|
2899
|
-
case "runtime_verifier":
|
|
2900
|
-
return "implementation";
|
|
2901
|
-
case "plan_reviewer":
|
|
2902
|
-
case "report_reviewer":
|
|
2903
|
-
case "deep_reviewer":
|
|
2904
|
-
return "review";
|
|
2905
|
-
default:
|
|
2906
|
-
return null;
|
|
2907
|
-
}
|
|
2908
|
-
}
|
|
2909
|
-
function normalizeDispatchNextLaneFilter(raw) {
|
|
2910
|
-
const key = trimLower(raw);
|
|
2911
|
-
if (!key) return void 0;
|
|
2912
|
-
if (key === "implementation" || key === "review" || key === "landing" || key === "any") {
|
|
2913
|
-
return key;
|
|
2914
|
-
}
|
|
2915
|
-
const mapped = roleLaneToDispatchLane(key);
|
|
2916
|
-
if (mapped) return mapped;
|
|
2917
|
-
if (key === "implement" || key === "repair" || key === "coding") return "implementation";
|
|
2918
|
-
if (key === "land" || key === "merge") return "landing";
|
|
2919
|
-
return void 0;
|
|
2920
|
-
}
|
|
2921
|
-
function resolveDispatchNextLaneFilter(raw) {
|
|
2922
|
-
return normalizeDispatchNextLaneFilter(raw) ?? "any";
|
|
2923
|
-
}
|
|
2924
|
-
|
|
2925
2929
|
// src/worker-persona-catalog.ts
|
|
2926
2930
|
var WORKER_PERSONA_CATALOG = [
|
|
2927
2931
|
{
|
|
@@ -3036,6 +3040,41 @@ function workerPersonaLandingSlugs() {
|
|
|
3036
3040
|
);
|
|
3037
3041
|
}
|
|
3038
3042
|
|
|
3043
|
+
// src/dispatch-lane-normalization.ts
|
|
3044
|
+
function trimLower(value) {
|
|
3045
|
+
return (value ?? "").trim().toLowerCase();
|
|
3046
|
+
}
|
|
3047
|
+
function roleLaneToDispatchLane(roleLane) {
|
|
3048
|
+
switch (trimLower(roleLane)) {
|
|
3049
|
+
case "implementer":
|
|
3050
|
+
case "repair_implementer":
|
|
3051
|
+
case "plan_author":
|
|
3052
|
+
case "runtime_verifier":
|
|
3053
|
+
return "implementation";
|
|
3054
|
+
case "plan_reviewer":
|
|
3055
|
+
case "report_reviewer":
|
|
3056
|
+
case "deep_reviewer":
|
|
3057
|
+
return "review";
|
|
3058
|
+
default:
|
|
3059
|
+
return null;
|
|
3060
|
+
}
|
|
3061
|
+
}
|
|
3062
|
+
function normalizeDispatchNextLaneFilter(raw) {
|
|
3063
|
+
const key = trimLower(raw);
|
|
3064
|
+
if (!key) return void 0;
|
|
3065
|
+
if (key === "implementation" || key === "review" || key === "landing" || key === "any") {
|
|
3066
|
+
return key;
|
|
3067
|
+
}
|
|
3068
|
+
const mapped = roleLaneToDispatchLane(key);
|
|
3069
|
+
if (mapped) return mapped;
|
|
3070
|
+
if (key === "implement" || key === "repair" || key === "coding") return "implementation";
|
|
3071
|
+
if (key === "land" || key === "merge") return "landing";
|
|
3072
|
+
return void 0;
|
|
3073
|
+
}
|
|
3074
|
+
function resolveDispatchNextLaneFilter(raw) {
|
|
3075
|
+
return normalizeDispatchNextLaneFilter(raw) ?? "any";
|
|
3076
|
+
}
|
|
3077
|
+
|
|
3039
3078
|
// src/model-routing-task-enrich.ts
|
|
3040
3079
|
function taskString(task, key) {
|
|
3041
3080
|
const v = task[key];
|
|
@@ -3503,7 +3542,7 @@ function probeCursorOAuthBinding(nowIso = (/* @__PURE__ */ new Date()).toISOStri
|
|
|
3503
3542
|
}
|
|
3504
3543
|
|
|
3505
3544
|
// src/orchestration-providers/hermes-cli-adapter.ts
|
|
3506
|
-
import { existsSync as existsSync16, readFileSync as
|
|
3545
|
+
import { existsSync as existsSync16, readFileSync as readFileSync11 } from "node:fs";
|
|
3507
3546
|
import { homedir as homedir10 } from "node:os";
|
|
3508
3547
|
import path15 from "node:path";
|
|
3509
3548
|
var PROFILE_ENV_KEYS = [
|
|
@@ -3519,7 +3558,7 @@ function hermesProfileEnvPath() {
|
|
|
3519
3558
|
}
|
|
3520
3559
|
function profileEnvKeyPresence(envPath) {
|
|
3521
3560
|
try {
|
|
3522
|
-
const text =
|
|
3561
|
+
const text = readFileSync11(envPath, "utf8");
|
|
3523
3562
|
const present = [];
|
|
3524
3563
|
for (const key of PROFILE_ENV_KEYS) {
|
|
3525
3564
|
const re = new RegExp(`^${key}=`, "m");
|
|
@@ -4493,7 +4532,7 @@ function buildPrompt(input) {
|
|
|
4493
4532
|
"Completion handoff (required): before you stop, ensure the harness records a final result \u2014 summarize outcome in your last message and append a heartbeat line with phase `complete`. If you leave uncommitted changes or committed work without a PR, the orchestrator blocks completion until a GitHub PR exists (or you discard/commit cleanly). One-off helper scripts must be removed (`kynver worker discard-disposable --path <file>`) or committed before completion \u2014 maintenance/board-drain workers are not exempt. Exiting with only dirty files and no PR routes to salvage review, not production review.",
|
|
4494
4533
|
"PR-ready handoff: for substantial implementation work, commit, push, and open a GitHub PR (draft OK) on your branch before finishing \u2014 or rely on the harness to run `gh pr create` at completion when `gh` is authenticated.",
|
|
4495
4534
|
"Expert review / production-review workers (Dalton/Lorentz, plan-review-task, scheduledJob reviewer children): do NOT open new implementation PRs \u2014 review the parent task's existing PR and record reviewVerdict in finalResult; landing-contract targetPrReconciliation does not apply.",
|
|
4496
|
-
"Worker resource guard: do not run full monorepo verification (`npm run typecheck`, `npm run build`, or equivalent) from this worker lane unless an operator explicitly requests it. Use targeted checks for touched paths and rely on CI/operator lanes for heavy gates.",
|
|
4535
|
+
"Worker resource guard: do not run full monorepo verification (`npm run typecheck`, `npm run build`, or equivalent) from this worker lane unless an operator explicitly requests it. Use targeted checks for touched paths and rely on CI/operator lanes for heavy gates. When heavy verification is required, route through `node scripts/verify-pr-local.mjs` or `kynver harness verify` \u2014 they acquire the global heavy-verification lease so parallel workers do not launch simultaneous typechecks.",
|
|
4497
4536
|
"npm publish boundary: do not run `npm publish`, do not republish `@kynver-app/*` packages, and do not block on an operator to publish. When you need newer runtime code than npm, use this repo checkout (`npm run kynver:build`, `npm run kynver`) and record evidence: packages/kynver-runtime/package.json version + git ref in your completion report.",
|
|
4498
4537
|
"If verification fails (including OOM), append a heartbeat line immediately with the last command, failure reason, dirty-file status, commit/PR handoff state, and next action so recovery does not require log spelunking.",
|
|
4499
4538
|
"Landing-wrapper cleanup on a git ref: use `node scripts/agent-os-land-pr-cleanup-verify.mjs --ref origin/main` (JSON, exit 0). Do not use `git show <ref>:scripts/agent-os-land-pr.mjs | rg \u2026` \u2014 ripgrep exit 1 when markers are absent is reported as a failed command in Telegram/status tooling.",
|
|
@@ -5369,8 +5408,8 @@ function dirtyPathsCoveredByDisposableRemoval(changedFiles, removed) {
|
|
|
5369
5408
|
if (removed.length === 0) return false;
|
|
5370
5409
|
const removedSet = new Set(removed.map((p) => normalizeRelativePath(p)));
|
|
5371
5410
|
return material.every((line) => {
|
|
5372
|
-
const
|
|
5373
|
-
return removedSet.has(
|
|
5411
|
+
const path71 = normalizeRelativePath(pathFromGitStatusLine(line));
|
|
5412
|
+
return removedSet.has(path71);
|
|
5374
5413
|
});
|
|
5375
5414
|
}
|
|
5376
5415
|
|
|
@@ -6678,7 +6717,7 @@ function collectRunActiveHarnessWorkers(runId) {
|
|
|
6678
6717
|
path24.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
|
|
6679
6718
|
void 0
|
|
6680
6719
|
);
|
|
6681
|
-
if (!worker?.taskId || !
|
|
6720
|
+
if (!worker?.taskId || !workerProcessMatchesRecord(worker)) continue;
|
|
6682
6721
|
out.push({
|
|
6683
6722
|
runId: run.id,
|
|
6684
6723
|
workerName: name,
|
|
@@ -6917,7 +6956,7 @@ function isTmpOnlyPath(filePath) {
|
|
|
6917
6956
|
// src/plan-persist/outbox-store.ts
|
|
6918
6957
|
import {
|
|
6919
6958
|
existsSync as existsSync23,
|
|
6920
|
-
readFileSync as
|
|
6959
|
+
readFileSync as readFileSync12,
|
|
6921
6960
|
renameSync,
|
|
6922
6961
|
readdirSync as readdirSync5,
|
|
6923
6962
|
writeFileSync as writeFileSync3,
|
|
@@ -6945,7 +6984,7 @@ function findOutboxByIdempotencyKey(key) {
|
|
|
6945
6984
|
function readOutboxItem(jsonPath) {
|
|
6946
6985
|
if (!existsSync23(jsonPath)) return null;
|
|
6947
6986
|
try {
|
|
6948
|
-
return JSON.parse(
|
|
6987
|
+
return JSON.parse(readFileSync12(jsonPath, "utf8"));
|
|
6949
6988
|
} catch {
|
|
6950
6989
|
return null;
|
|
6951
6990
|
}
|
|
@@ -6953,7 +6992,7 @@ function readOutboxItem(jsonPath) {
|
|
|
6953
6992
|
function readOutboxBody(item) {
|
|
6954
6993
|
const { outboxDir } = ensurePlanOutboxDirs();
|
|
6955
6994
|
const bodyFile = path26.join(outboxDir, item.bodyPath);
|
|
6956
|
-
return
|
|
6995
|
+
return readFileSync12(bodyFile, "utf8");
|
|
6957
6996
|
}
|
|
6958
6997
|
function writeOutboxItem(input, opts) {
|
|
6959
6998
|
const { outboxDir } = ensurePlanOutboxDirs();
|
|
@@ -8263,7 +8302,7 @@ import { existsSync as existsSync29, mkdirSync as mkdirSync6 } from "node:fs";
|
|
|
8263
8302
|
import path37 from "node:path";
|
|
8264
8303
|
|
|
8265
8304
|
// src/run-list.ts
|
|
8266
|
-
import { existsSync as existsSync28, readFileSync as
|
|
8305
|
+
import { existsSync as existsSync28, readFileSync as readFileSync15 } from "node:fs";
|
|
8267
8306
|
import path36 from "node:path";
|
|
8268
8307
|
|
|
8269
8308
|
// src/stale-reconcile.ts
|
|
@@ -9034,7 +9073,7 @@ function reconcileRunsCli() {
|
|
|
9034
9073
|
function heartbeatByteLength(heartbeatPath) {
|
|
9035
9074
|
if (!heartbeatPath || !existsSync28(heartbeatPath)) return 0;
|
|
9036
9075
|
try {
|
|
9037
|
-
return
|
|
9076
|
+
return readFileSync15(heartbeatPath, "utf8").trim().length;
|
|
9038
9077
|
} catch {
|
|
9039
9078
|
return 0;
|
|
9040
9079
|
}
|
|
@@ -9544,11 +9583,11 @@ var LIVE_SKIP_REASONS = /* @__PURE__ */ new Set([
|
|
|
9544
9583
|
function collectPreservedLivePaths(actions, skips) {
|
|
9545
9584
|
const out = [];
|
|
9546
9585
|
const seen = /* @__PURE__ */ new Set();
|
|
9547
|
-
const push = (
|
|
9548
|
-
const key = `${
|
|
9586
|
+
const push = (path71, reason, detail) => {
|
|
9587
|
+
const key = `${path71}\0${reason}`;
|
|
9549
9588
|
if (seen.has(key) || out.length >= MAX_PRESERVED_LIVE_PATH_SAMPLES) return;
|
|
9550
9589
|
seen.add(key);
|
|
9551
|
-
out.push({ path:
|
|
9590
|
+
out.push({ path: path71, reason, ...detail ? { detail } : {} });
|
|
9552
9591
|
};
|
|
9553
9592
|
for (const skip2 of skips) {
|
|
9554
9593
|
if (!LIVE_SKIP_REASONS.has(skip2.reason)) continue;
|
|
@@ -10899,7 +10938,7 @@ function isPipelineCleanupEnabled() {
|
|
|
10899
10938
|
}
|
|
10900
10939
|
|
|
10901
10940
|
// src/cli.ts
|
|
10902
|
-
import { mkdirSync as
|
|
10941
|
+
import { mkdirSync as mkdirSync10, realpathSync } from "node:fs";
|
|
10903
10942
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
10904
10943
|
|
|
10905
10944
|
// src/discard-disposable.ts
|
|
@@ -11087,12 +11126,12 @@ async function fireKynverCronJob(input) {
|
|
|
11087
11126
|
}
|
|
11088
11127
|
|
|
11089
11128
|
// src/cron/cron-lock.ts
|
|
11090
|
-
import { closeSync as closeSync6, existsSync as existsSync43, openSync as openSync6, readFileSync as
|
|
11129
|
+
import { closeSync as closeSync6, existsSync as existsSync43, openSync as openSync6, readFileSync as readFileSync16, unlinkSync as unlinkSync3, writeFileSync as writeFileSync4 } from "node:fs";
|
|
11091
11130
|
var STALE_LOCK_MS = 10 * 6e4;
|
|
11092
11131
|
function readLockInfo(lockPath) {
|
|
11093
11132
|
if (!existsSync43(lockPath)) return null;
|
|
11094
11133
|
try {
|
|
11095
|
-
const parsed = JSON.parse(
|
|
11134
|
+
const parsed = JSON.parse(readFileSync16(lockPath, "utf8"));
|
|
11096
11135
|
if (typeof parsed.pid === "number" && typeof parsed.at === "string") return parsed;
|
|
11097
11136
|
} catch {
|
|
11098
11137
|
return null;
|
|
@@ -11881,17 +11920,17 @@ async function runDaemon(args) {
|
|
|
11881
11920
|
idleStreak = 0;
|
|
11882
11921
|
}
|
|
11883
11922
|
const backoff = idleStreak >= MAX_IDLE_STREAK ? IDLE_INTERVAL_MS : intervalMs;
|
|
11884
|
-
sleepMs(backoff);
|
|
11923
|
+
await sleepMs(backoff);
|
|
11885
11924
|
} catch (error) {
|
|
11886
11925
|
console.error(JSON.stringify({ event: "daemon_tick_error", error: error.message }));
|
|
11887
|
-
sleepMs(intervalMs);
|
|
11926
|
+
await sleepMs(intervalMs);
|
|
11888
11927
|
}
|
|
11889
11928
|
}
|
|
11890
11929
|
console.error(JSON.stringify({ event: "daemon_stop", runId, agentOsId }));
|
|
11891
11930
|
}
|
|
11892
11931
|
|
|
11893
11932
|
// src/plan-progress.ts
|
|
11894
|
-
import
|
|
11933
|
+
import path61 from "node:path";
|
|
11895
11934
|
|
|
11896
11935
|
// src/bounded-build/constants.ts
|
|
11897
11936
|
var DEFAULT_BUILD_MEM_BUDGET_BYTES = 1536 * 1024 * 1024;
|
|
@@ -12021,14 +12060,235 @@ function waitForBuildAdmission(timeoutMs, pollMs = 2e3, opts = {}) {
|
|
|
12021
12060
|
}
|
|
12022
12061
|
|
|
12023
12062
|
// src/bounded-build/exec.ts
|
|
12063
|
+
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
12064
|
+
|
|
12065
|
+
// src/heavy-verification/slot.ts
|
|
12066
|
+
import {
|
|
12067
|
+
closeSync as closeSync7,
|
|
12068
|
+
existsSync as existsSync44,
|
|
12069
|
+
mkdirSync as mkdirSync8,
|
|
12070
|
+
openSync as openSync7,
|
|
12071
|
+
readdirSync as readdirSync15,
|
|
12072
|
+
readFileSync as readFileSync17,
|
|
12073
|
+
unlinkSync as unlinkSync4,
|
|
12074
|
+
writeFileSync as writeFileSync5
|
|
12075
|
+
} from "node:fs";
|
|
12076
|
+
import path59 from "node:path";
|
|
12077
|
+
|
|
12078
|
+
// src/heavy-verification/paths.ts
|
|
12079
|
+
import { mkdirSync as mkdirSync7 } from "node:fs";
|
|
12080
|
+
import path58 from "node:path";
|
|
12081
|
+
function resolveHeavyVerificationRoot() {
|
|
12082
|
+
return path58.join(resolveKynverStateRoot(), "heavy-verification");
|
|
12083
|
+
}
|
|
12084
|
+
function heavyVerificationSlotsDir() {
|
|
12085
|
+
return path58.join(resolveHeavyVerificationRoot(), "slots");
|
|
12086
|
+
}
|
|
12087
|
+
function ensureHeavyVerificationDirs() {
|
|
12088
|
+
const dir = heavyVerificationSlotsDir();
|
|
12089
|
+
mkdirSync7(dir, { recursive: true });
|
|
12090
|
+
return dir;
|
|
12091
|
+
}
|
|
12092
|
+
|
|
12093
|
+
// src/heavy-verification/slot.ts
|
|
12094
|
+
var DEFAULT_HEAVY_VERIFICATION_STALE_MS = 2 * 60 * 6e4;
|
|
12095
|
+
var DEFAULT_HEAVY_VERIFICATION_MAX_CONCURRENT = 1;
|
|
12096
|
+
function positiveInt5(value, fallback) {
|
|
12097
|
+
const n = Number(value);
|
|
12098
|
+
if (!Number.isFinite(n) || n <= 0) return fallback;
|
|
12099
|
+
return Math.floor(n);
|
|
12100
|
+
}
|
|
12101
|
+
function isHeavyVerificationGateSkipped() {
|
|
12102
|
+
const v = process.env.KYNVER_HEAVY_VERIFICATION_SKIP?.trim().toLowerCase();
|
|
12103
|
+
return v === "1" || v === "true" || v === "yes";
|
|
12104
|
+
}
|
|
12105
|
+
function resolveHeavyVerificationMaxConcurrent() {
|
|
12106
|
+
const env = process.env.KYNVER_HEAVY_VERIFICATION_MAX_CONCURRENT;
|
|
12107
|
+
if (env) return positiveInt5(env, DEFAULT_HEAVY_VERIFICATION_MAX_CONCURRENT);
|
|
12108
|
+
return DEFAULT_HEAVY_VERIFICATION_MAX_CONCURRENT;
|
|
12109
|
+
}
|
|
12110
|
+
function indexedSlotId(index) {
|
|
12111
|
+
return `slot-${index}`;
|
|
12112
|
+
}
|
|
12113
|
+
function slotFilePath(slotId, slotsDir = heavyVerificationSlotsDir()) {
|
|
12114
|
+
return path59.join(slotsDir, `${slotId}.json`);
|
|
12115
|
+
}
|
|
12116
|
+
function readSlotRecord(filePath) {
|
|
12117
|
+
if (!existsSync44(filePath)) return null;
|
|
12118
|
+
try {
|
|
12119
|
+
const parsed = JSON.parse(readFileSync17(filePath, "utf8"));
|
|
12120
|
+
if (typeof parsed.slotId === "string" && typeof parsed.pid === "number" && typeof parsed.acquiredAt === "string" && typeof parsed.command === "string") {
|
|
12121
|
+
return parsed;
|
|
12122
|
+
}
|
|
12123
|
+
} catch {
|
|
12124
|
+
return null;
|
|
12125
|
+
}
|
|
12126
|
+
return null;
|
|
12127
|
+
}
|
|
12128
|
+
function slotIsStale(record3, staleMs = DEFAULT_HEAVY_VERIFICATION_STALE_MS) {
|
|
12129
|
+
if (!record3) return true;
|
|
12130
|
+
if (!isPidAlive(record3.pid)) return true;
|
|
12131
|
+
const atMs = Date.parse(record3.acquiredAt);
|
|
12132
|
+
if (Number.isNaN(atMs)) return true;
|
|
12133
|
+
return Date.now() - atMs > staleMs;
|
|
12134
|
+
}
|
|
12135
|
+
function reclaimStaleSlot(filePath, staleMs) {
|
|
12136
|
+
const record3 = readSlotRecord(filePath);
|
|
12137
|
+
if (!slotIsStale(record3, staleMs)) return;
|
|
12138
|
+
try {
|
|
12139
|
+
unlinkSync4(filePath);
|
|
12140
|
+
} catch {
|
|
12141
|
+
}
|
|
12142
|
+
}
|
|
12143
|
+
function ensureSlotsDir(slotsDir) {
|
|
12144
|
+
mkdirSync8(slotsDir, { recursive: true });
|
|
12145
|
+
return slotsDir;
|
|
12146
|
+
}
|
|
12147
|
+
function reclaimStaleHeavyVerificationSlots(opts = {}) {
|
|
12148
|
+
const slotsDir = ensureSlotsDir(opts.slotsDir ?? ensureHeavyVerificationDirs());
|
|
12149
|
+
const staleMs = opts.staleMs ?? DEFAULT_HEAVY_VERIFICATION_STALE_MS;
|
|
12150
|
+
let reclaimed = 0;
|
|
12151
|
+
for (const name of readdirSync15(slotsDir)) {
|
|
12152
|
+
if (!name.endsWith(".json")) continue;
|
|
12153
|
+
const filePath = path59.join(slotsDir, name);
|
|
12154
|
+
const before = existsSync44(filePath);
|
|
12155
|
+
reclaimStaleSlot(filePath, staleMs);
|
|
12156
|
+
if (before && !existsSync44(filePath)) reclaimed += 1;
|
|
12157
|
+
}
|
|
12158
|
+
return reclaimed;
|
|
12159
|
+
}
|
|
12160
|
+
function listActiveHeavyVerificationSlots(opts = {}) {
|
|
12161
|
+
const slotsDir = opts.slotsDir ?? ensureHeavyVerificationDirs();
|
|
12162
|
+
const staleMs = opts.staleMs ?? DEFAULT_HEAVY_VERIFICATION_STALE_MS;
|
|
12163
|
+
reclaimStaleHeavyVerificationSlots({ slotsDir, staleMs });
|
|
12164
|
+
const active = [];
|
|
12165
|
+
for (const name of readdirSync15(slotsDir)) {
|
|
12166
|
+
if (!name.endsWith(".json")) continue;
|
|
12167
|
+
const record3 = readSlotRecord(path59.join(slotsDir, name));
|
|
12168
|
+
if (record3 && !slotIsStale(record3, staleMs)) active.push(record3);
|
|
12169
|
+
}
|
|
12170
|
+
return active;
|
|
12171
|
+
}
|
|
12172
|
+
function countActiveHeavyVerificationSlots(opts = {}) {
|
|
12173
|
+
return listActiveHeavyVerificationSlots(opts).length;
|
|
12174
|
+
}
|
|
12175
|
+
function tryAcquireHeavyVerificationSlot(command, opts = {}) {
|
|
12176
|
+
if (isHeavyVerificationGateSkipped()) {
|
|
12177
|
+
return {
|
|
12178
|
+
admitted: true,
|
|
12179
|
+
slotId: null,
|
|
12180
|
+
activeSlots: 0,
|
|
12181
|
+
maxSlots: resolveHeavyVerificationMaxConcurrent(),
|
|
12182
|
+
reason: null
|
|
12183
|
+
};
|
|
12184
|
+
}
|
|
12185
|
+
const slotsDir = opts.slotsDir ?? ensureHeavyVerificationDirs();
|
|
12186
|
+
const staleMs = opts.staleMs ?? DEFAULT_HEAVY_VERIFICATION_STALE_MS;
|
|
12187
|
+
const maxSlots = opts.maxSlots ?? resolveHeavyVerificationMaxConcurrent();
|
|
12188
|
+
reclaimStaleHeavyVerificationSlots({ slotsDir, staleMs });
|
|
12189
|
+
for (let index = 0; index < maxSlots; index += 1) {
|
|
12190
|
+
const slotId = indexedSlotId(index);
|
|
12191
|
+
const filePath = slotFilePath(slotId, slotsDir);
|
|
12192
|
+
const existing = readSlotRecord(filePath);
|
|
12193
|
+
if (existing && slotIsStale(existing, staleMs)) {
|
|
12194
|
+
try {
|
|
12195
|
+
unlinkSync4(filePath);
|
|
12196
|
+
} catch {
|
|
12197
|
+
}
|
|
12198
|
+
} else if (existing && !slotIsStale(existing, staleMs)) {
|
|
12199
|
+
continue;
|
|
12200
|
+
}
|
|
12201
|
+
const record3 = {
|
|
12202
|
+
slotId,
|
|
12203
|
+
pid: process.pid,
|
|
12204
|
+
acquiredAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12205
|
+
command
|
|
12206
|
+
};
|
|
12207
|
+
try {
|
|
12208
|
+
const fd = openSync7(filePath, "wx");
|
|
12209
|
+
writeFileSync5(fd, JSON.stringify(record3, null, 2), "utf8");
|
|
12210
|
+
closeSync7(fd);
|
|
12211
|
+
const activeSlots2 = countActiveHeavyVerificationSlots({ slotsDir, staleMs });
|
|
12212
|
+
return {
|
|
12213
|
+
admitted: true,
|
|
12214
|
+
slotId,
|
|
12215
|
+
activeSlots: activeSlots2,
|
|
12216
|
+
maxSlots,
|
|
12217
|
+
reason: null
|
|
12218
|
+
};
|
|
12219
|
+
} catch (err) {
|
|
12220
|
+
if (err.code === "EEXIST") {
|
|
12221
|
+
continue;
|
|
12222
|
+
}
|
|
12223
|
+
throw err;
|
|
12224
|
+
}
|
|
12225
|
+
}
|
|
12226
|
+
const activeSlots = countActiveHeavyVerificationSlots({ slotsDir, staleMs });
|
|
12227
|
+
return {
|
|
12228
|
+
admitted: false,
|
|
12229
|
+
slotId: null,
|
|
12230
|
+
activeSlots,
|
|
12231
|
+
maxSlots,
|
|
12232
|
+
reason: `heavy verification at capacity (${activeSlots}/${maxSlots} slots)`
|
|
12233
|
+
};
|
|
12234
|
+
}
|
|
12235
|
+
function releaseHeavyVerificationSlot(slotId, opts = {}) {
|
|
12236
|
+
if (!slotId) return;
|
|
12237
|
+
const filePath = slotFilePath(slotId, opts.slotsDir ?? heavyVerificationSlotsDir());
|
|
12238
|
+
try {
|
|
12239
|
+
unlinkSync4(filePath);
|
|
12240
|
+
} catch {
|
|
12241
|
+
}
|
|
12242
|
+
}
|
|
12243
|
+
function assessHeavyVerificationGate(command, opts = {}) {
|
|
12244
|
+
if (isHeavyVerificationGateSkipped()) {
|
|
12245
|
+
return {
|
|
12246
|
+
admitted: true,
|
|
12247
|
+
slotId: null,
|
|
12248
|
+
activeSlots: 0,
|
|
12249
|
+
maxSlots: resolveHeavyVerificationMaxConcurrent(),
|
|
12250
|
+
reason: null
|
|
12251
|
+
};
|
|
12252
|
+
}
|
|
12253
|
+
const slotsDir = opts.slotsDir ?? ensureHeavyVerificationDirs();
|
|
12254
|
+
const staleMs = opts.staleMs ?? DEFAULT_HEAVY_VERIFICATION_STALE_MS;
|
|
12255
|
+
const maxSlots = opts.maxSlots ?? resolveHeavyVerificationMaxConcurrent();
|
|
12256
|
+
reclaimStaleHeavyVerificationSlots({ slotsDir, staleMs });
|
|
12257
|
+
const activeSlots = countActiveHeavyVerificationSlots({ slotsDir, staleMs });
|
|
12258
|
+
const admitted = activeSlots < maxSlots;
|
|
12259
|
+
return {
|
|
12260
|
+
admitted,
|
|
12261
|
+
slotId: null,
|
|
12262
|
+
activeSlots,
|
|
12263
|
+
maxSlots,
|
|
12264
|
+
reason: admitted ? null : `heavy verification at capacity (${activeSlots}/${maxSlots} slots); waiting for ${command}`
|
|
12265
|
+
};
|
|
12266
|
+
}
|
|
12267
|
+
|
|
12268
|
+
// src/heavy-verification/gate.ts
|
|
12024
12269
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
12270
|
+
function sleepMs3(ms) {
|
|
12271
|
+
if (ms <= 0) return;
|
|
12272
|
+
spawnSync8(process.execPath, ["-e", `const d=Date.now()+${Math.floor(ms)};while(Date.now()<d);`], {
|
|
12273
|
+
stdio: "ignore"
|
|
12274
|
+
});
|
|
12275
|
+
}
|
|
12276
|
+
function waitForHeavyVerificationSlot(command, timeoutMs, pollMs = 2e3, opts = {}) {
|
|
12277
|
+
const deadline = Date.now() + Math.max(0, timeoutMs);
|
|
12278
|
+
let verdict = tryAcquireHeavyVerificationSlot(command, opts);
|
|
12279
|
+
while (!verdict.admitted && Date.now() < deadline) {
|
|
12280
|
+
sleepMs3(Math.min(pollMs, deadline - Date.now()));
|
|
12281
|
+
verdict = tryAcquireHeavyVerificationSlot(command, opts);
|
|
12282
|
+
}
|
|
12283
|
+
return verdict;
|
|
12284
|
+
}
|
|
12025
12285
|
|
|
12026
12286
|
// src/harness-worktree-build-guard.ts
|
|
12027
|
-
import
|
|
12287
|
+
import path60 from "node:path";
|
|
12028
12288
|
function isPathUnderHarnessWorktree(cwd) {
|
|
12029
12289
|
const worktreesDir = harnessWorktreesDir(resolveHarnessRoot());
|
|
12030
|
-
const rel =
|
|
12031
|
-
return rel.length > 0 && !rel.startsWith("..") && !
|
|
12290
|
+
const rel = path60.relative(worktreesDir, path60.resolve(cwd));
|
|
12291
|
+
return rel.length > 0 && !rel.startsWith("..") && !path60.isAbsolute(rel);
|
|
12032
12292
|
}
|
|
12033
12293
|
function assessHarnessWorktreeBuildGuard(cwd) {
|
|
12034
12294
|
if (!isPathUnderHarnessWorktree(cwd)) return { ok: true };
|
|
@@ -12052,7 +12312,7 @@ function envArgv(env) {
|
|
|
12052
12312
|
return out;
|
|
12053
12313
|
}
|
|
12054
12314
|
function runSpawn(argv, opts) {
|
|
12055
|
-
const res =
|
|
12315
|
+
const res = spawnSync9(argv[0], argv.slice(1), {
|
|
12056
12316
|
cwd: opts.cwd,
|
|
12057
12317
|
env: opts.env,
|
|
12058
12318
|
encoding: "utf8",
|
|
@@ -12068,8 +12328,25 @@ function runSpawn(argv, opts) {
|
|
|
12068
12328
|
}
|
|
12069
12329
|
function runBoundedBuildCheck(input) {
|
|
12070
12330
|
const waitMs = input.waitForAdmissionMs ?? 6e5;
|
|
12331
|
+
const verificationGate = waitMs > 0 ? waitForHeavyVerificationSlot(input.command, waitMs) : tryAcquireOrAssessVerificationGate(input.command);
|
|
12332
|
+
if (!verificationGate.admitted) {
|
|
12333
|
+
return {
|
|
12334
|
+
ok: false,
|
|
12335
|
+
exitCode: 1,
|
|
12336
|
+
stdout: "",
|
|
12337
|
+
stderr: verificationGate.reason ?? "heavy verification gate denied",
|
|
12338
|
+
admitted: false,
|
|
12339
|
+
wrappedWithSystemd: false,
|
|
12340
|
+
nodeOptionsFlag: formatNodeOptionsFlag(),
|
|
12341
|
+
admission: assessBuildAdmission(),
|
|
12342
|
+
verificationGate,
|
|
12343
|
+
command: input.command
|
|
12344
|
+
};
|
|
12345
|
+
}
|
|
12346
|
+
const slotId = verificationGate.slotId;
|
|
12071
12347
|
const admission = waitMs > 0 ? waitForBuildAdmission(waitMs) : assessBuildAdmission();
|
|
12072
12348
|
if (!admission.admitted) {
|
|
12349
|
+
releaseHeavyVerificationSlot(slotId);
|
|
12073
12350
|
return {
|
|
12074
12351
|
ok: false,
|
|
12075
12352
|
exitCode: 1,
|
|
@@ -12079,11 +12356,13 @@ function runBoundedBuildCheck(input) {
|
|
|
12079
12356
|
wrappedWithSystemd: false,
|
|
12080
12357
|
nodeOptionsFlag: formatNodeOptionsFlag(),
|
|
12081
12358
|
admission,
|
|
12359
|
+
verificationGate,
|
|
12082
12360
|
command: input.command
|
|
12083
12361
|
};
|
|
12084
12362
|
}
|
|
12085
12363
|
const worktreeGuard = assessHarnessWorktreeBuildGuard(input.cwd);
|
|
12086
12364
|
if (!worktreeGuard.ok) {
|
|
12365
|
+
releaseHeavyVerificationSlot(slotId);
|
|
12087
12366
|
return {
|
|
12088
12367
|
ok: false,
|
|
12089
12368
|
exitCode: 1,
|
|
@@ -12093,6 +12372,7 @@ function runBoundedBuildCheck(input) {
|
|
|
12093
12372
|
wrappedWithSystemd: false,
|
|
12094
12373
|
nodeOptionsFlag: formatNodeOptionsFlag(),
|
|
12095
12374
|
admission,
|
|
12375
|
+
verificationGate,
|
|
12096
12376
|
command: input.command
|
|
12097
12377
|
};
|
|
12098
12378
|
}
|
|
@@ -12125,12 +12405,19 @@ function runBoundedBuildCheck(input) {
|
|
|
12125
12405
|
wrappedWithSystemd: useSystemd,
|
|
12126
12406
|
nodeOptionsFlag,
|
|
12127
12407
|
admission,
|
|
12408
|
+
verificationGate,
|
|
12128
12409
|
command: input.command
|
|
12129
12410
|
};
|
|
12130
12411
|
} finally {
|
|
12131
12412
|
registerBuildEnd();
|
|
12413
|
+
releaseHeavyVerificationSlot(slotId);
|
|
12132
12414
|
}
|
|
12133
12415
|
}
|
|
12416
|
+
function tryAcquireOrAssessVerificationGate(command) {
|
|
12417
|
+
const acquired = waitForHeavyVerificationSlot(command, 0);
|
|
12418
|
+
if (acquired.admitted) return acquired;
|
|
12419
|
+
return { ...assessHeavyVerificationGate(command), slotId: null };
|
|
12420
|
+
}
|
|
12134
12421
|
|
|
12135
12422
|
// src/harness-verify.ts
|
|
12136
12423
|
var DEFAULT_HARNESS_VERIFY_COMMANDS = ["npm run typecheck", "npm run test"];
|
|
@@ -12213,7 +12500,7 @@ async function emitPlanProgress(args) {
|
|
|
12213
12500
|
}
|
|
12214
12501
|
function verifyPlanLocal(args) {
|
|
12215
12502
|
const worktree = required(args.worktree ? String(args.worktree) : void 0, "worktree");
|
|
12216
|
-
const cwd =
|
|
12503
|
+
const cwd = path61.resolve(worktree);
|
|
12217
12504
|
const summary = runHarnessVerifyCommands(cwd);
|
|
12218
12505
|
const emitJson = args.json === true || args.json === "true";
|
|
12219
12506
|
const payload = { passed: summary.passed, worktree: cwd, steps: summary.steps };
|
|
@@ -12262,9 +12549,9 @@ async function verifyPlan(args) {
|
|
|
12262
12549
|
}
|
|
12263
12550
|
|
|
12264
12551
|
// src/harness-verify-cli.ts
|
|
12265
|
-
import
|
|
12552
|
+
import path62 from "node:path";
|
|
12266
12553
|
function runHarnessVerifyCli(args) {
|
|
12267
|
-
const cwd =
|
|
12554
|
+
const cwd = path62.resolve(required(args.worktree ? String(args.worktree) : void 0, "worktree"));
|
|
12268
12555
|
const emitJson = args.json === true || args.json === "true" || args.emitJson === true || args.emitJson === "true";
|
|
12269
12556
|
const commands = [];
|
|
12270
12557
|
const rawCmd = args.command;
|
|
@@ -12292,6 +12579,7 @@ function runHarnessVerifyCli(args) {
|
|
|
12292
12579
|
wrappedWithSystemd: s.result.wrappedWithSystemd,
|
|
12293
12580
|
nodeOptionsFlag: s.result.nodeOptionsFlag,
|
|
12294
12581
|
admission: s.result.admission,
|
|
12582
|
+
verificationGate: s.result.verificationGate,
|
|
12295
12583
|
stderr: s.result.stderr.slice(0, 4e3)
|
|
12296
12584
|
}))
|
|
12297
12585
|
};
|
|
@@ -12308,7 +12596,7 @@ function runHarnessVerifyCli(args) {
|
|
|
12308
12596
|
}
|
|
12309
12597
|
|
|
12310
12598
|
// src/plan-persist-cli.ts
|
|
12311
|
-
import { readFileSync as
|
|
12599
|
+
import { readFileSync as readFileSync18 } from "node:fs";
|
|
12312
12600
|
var OPERATIONS = ["create", "add_version", "update_metadata"];
|
|
12313
12601
|
var FAILURE_KINDS = [
|
|
12314
12602
|
"approval_guard",
|
|
@@ -12320,7 +12608,7 @@ var FAILURE_KINDS = [
|
|
|
12320
12608
|
function readBodyArg(args) {
|
|
12321
12609
|
const bodyFile = args.bodyFile ? String(args.bodyFile) : void 0;
|
|
12322
12610
|
if (bodyFile) {
|
|
12323
|
-
return { body:
|
|
12611
|
+
return { body: readFileSync18(bodyFile, "utf8"), bodyPathHint: bodyFile };
|
|
12324
12612
|
}
|
|
12325
12613
|
const inline = args.body ? String(args.body) : void 0;
|
|
12326
12614
|
if (inline) return { body: inline };
|
|
@@ -12700,7 +12988,7 @@ ${text.slice(0, 800)}`,
|
|
|
12700
12988
|
}
|
|
12701
12989
|
|
|
12702
12990
|
// src/monitor/monitor.service.ts
|
|
12703
|
-
import
|
|
12991
|
+
import path64 from "node:path";
|
|
12704
12992
|
|
|
12705
12993
|
// src/monitor/monitor.classify.ts
|
|
12706
12994
|
function classifyWorkerHealth(input) {
|
|
@@ -12752,19 +13040,19 @@ function classifyWorkerHealth(input) {
|
|
|
12752
13040
|
}
|
|
12753
13041
|
|
|
12754
13042
|
// src/monitor/monitor.store.ts
|
|
12755
|
-
import { existsSync as
|
|
12756
|
-
import
|
|
13043
|
+
import { existsSync as existsSync45, mkdirSync as mkdirSync9, readdirSync as readdirSync16, unlinkSync as unlinkSync5 } from "node:fs";
|
|
13044
|
+
import path63 from "node:path";
|
|
12757
13045
|
function monitorsDir() {
|
|
12758
13046
|
const { harnessRoot } = getHarnessPaths();
|
|
12759
|
-
const dir =
|
|
12760
|
-
|
|
13047
|
+
const dir = path63.join(harnessRoot, "monitors");
|
|
13048
|
+
mkdirSync9(dir, { recursive: true });
|
|
12761
13049
|
return dir;
|
|
12762
13050
|
}
|
|
12763
13051
|
function monitorIdFor(runId, workerName) {
|
|
12764
13052
|
return workerName ? `${safeSlug(runId)}--${safeSlug(workerName)}` : safeSlug(runId);
|
|
12765
13053
|
}
|
|
12766
13054
|
function monitorPath(monitorId) {
|
|
12767
|
-
return
|
|
13055
|
+
return path63.join(monitorsDir(), `${monitorId}.json`);
|
|
12768
13056
|
}
|
|
12769
13057
|
function loadMonitorSession(monitorId) {
|
|
12770
13058
|
return readJson(monitorPath(monitorId), void 0);
|
|
@@ -12774,18 +13062,18 @@ function saveMonitorSession(session) {
|
|
|
12774
13062
|
}
|
|
12775
13063
|
function deleteMonitorSession(monitorId) {
|
|
12776
13064
|
const file = monitorPath(monitorId);
|
|
12777
|
-
if (!
|
|
12778
|
-
|
|
13065
|
+
if (!existsSync45(file)) return false;
|
|
13066
|
+
unlinkSync5(file);
|
|
12779
13067
|
return true;
|
|
12780
13068
|
}
|
|
12781
13069
|
function listMonitorSessions() {
|
|
12782
13070
|
const dir = monitorsDir();
|
|
12783
|
-
if (!
|
|
13071
|
+
if (!existsSync45(dir)) return [];
|
|
12784
13072
|
const entries = [];
|
|
12785
|
-
for (const name of
|
|
13073
|
+
for (const name of readdirSync16(dir)) {
|
|
12786
13074
|
if (!name.endsWith(".json")) continue;
|
|
12787
13075
|
const session = readJson(
|
|
12788
|
-
|
|
13076
|
+
path63.join(dir, name),
|
|
12789
13077
|
void 0
|
|
12790
13078
|
);
|
|
12791
13079
|
if (!session?.monitorId) continue;
|
|
@@ -12876,7 +13164,7 @@ async function fetchTaskLeasesForWorkers(input) {
|
|
|
12876
13164
|
// src/monitor/monitor.service.ts
|
|
12877
13165
|
function workerRecord2(runId, name) {
|
|
12878
13166
|
return readJson(
|
|
12879
|
-
|
|
13167
|
+
path64.join(runDirectory(runId), "workers", safeSlug(name), "worker.json"),
|
|
12880
13168
|
void 0
|
|
12881
13169
|
);
|
|
12882
13170
|
}
|
|
@@ -13082,21 +13370,21 @@ async function runMonitorLoop(args) {
|
|
|
13082
13370
|
|
|
13083
13371
|
// src/monitor/monitor-spawn.ts
|
|
13084
13372
|
import { spawn as spawn6 } from "node:child_process";
|
|
13085
|
-
import { closeSync as
|
|
13086
|
-
import
|
|
13373
|
+
import { closeSync as closeSync8, existsSync as existsSync46, openSync as openSync8 } from "node:fs";
|
|
13374
|
+
import path65 from "node:path";
|
|
13087
13375
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
13088
13376
|
function resolveDefaultCliPath2() {
|
|
13089
|
-
return
|
|
13377
|
+
return path65.join(fileURLToPath4(new URL(".", import.meta.url)), "cli.js");
|
|
13090
13378
|
}
|
|
13091
13379
|
function spawnMonitorSidecar(opts) {
|
|
13092
13380
|
const cliPath = opts.cliPath ?? resolveDefaultCliPath2();
|
|
13093
|
-
if (!
|
|
13381
|
+
if (!existsSync46(cliPath)) return void 0;
|
|
13094
13382
|
const monitorId = monitorIdFor(opts.runId, opts.workerName);
|
|
13095
13383
|
const { harnessRoot } = getHarnessPaths();
|
|
13096
|
-
const logPath =
|
|
13384
|
+
const logPath = path65.join(harnessRoot, "monitors", `${monitorId}.log`);
|
|
13097
13385
|
let logFd;
|
|
13098
13386
|
try {
|
|
13099
|
-
logFd =
|
|
13387
|
+
logFd = openSync8(logPath, "a");
|
|
13100
13388
|
} catch {
|
|
13101
13389
|
logFd = void 0;
|
|
13102
13390
|
}
|
|
@@ -13136,7 +13424,7 @@ function spawnMonitorSidecar(opts) {
|
|
|
13136
13424
|
env: process.env
|
|
13137
13425
|
})
|
|
13138
13426
|
);
|
|
13139
|
-
if (logFd !== void 0)
|
|
13427
|
+
if (logFd !== void 0) closeSync8(logFd);
|
|
13140
13428
|
child.unref();
|
|
13141
13429
|
const session = {
|
|
13142
13430
|
monitorId,
|
|
@@ -13153,7 +13441,7 @@ function spawnMonitorSidecar(opts) {
|
|
|
13153
13441
|
} catch {
|
|
13154
13442
|
if (logFd !== void 0) {
|
|
13155
13443
|
try {
|
|
13156
|
-
|
|
13444
|
+
closeSync8(logFd);
|
|
13157
13445
|
} catch {
|
|
13158
13446
|
}
|
|
13159
13447
|
}
|
|
@@ -13213,7 +13501,7 @@ async function monitorTickCli(args) {
|
|
|
13213
13501
|
}
|
|
13214
13502
|
|
|
13215
13503
|
// src/post-restart-unblock.ts
|
|
13216
|
-
import
|
|
13504
|
+
import path66 from "node:path";
|
|
13217
13505
|
function skip(runId, worker, taskId, agentOsId, leaseOwner, reason) {
|
|
13218
13506
|
return { runId, worker, taskId, agentOsId, leaseOwner, action: "skipped", reason };
|
|
13219
13507
|
}
|
|
@@ -13226,7 +13514,7 @@ async function postRestartUnblock(args) {
|
|
|
13226
13514
|
const errors = [];
|
|
13227
13515
|
for (const run of listRunRecords()) {
|
|
13228
13516
|
for (const name of Object.keys(run.workers ?? {})) {
|
|
13229
|
-
const workerPath =
|
|
13517
|
+
const workerPath = path66.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json");
|
|
13230
13518
|
const worker = readJson(workerPath, void 0);
|
|
13231
13519
|
if (!worker) {
|
|
13232
13520
|
skipped.push(skip(run.id, name, "", "", "", "worker.json missing"));
|
|
@@ -13338,9 +13626,9 @@ async function postRestartUnblockCli(args) {
|
|
|
13338
13626
|
}
|
|
13339
13627
|
|
|
13340
13628
|
// src/default-repo-cli.ts
|
|
13341
|
-
import
|
|
13629
|
+
import path67 from "node:path";
|
|
13342
13630
|
import { homedir as homedir15 } from "node:os";
|
|
13343
|
-
var CONFIG_FILE2 =
|
|
13631
|
+
var CONFIG_FILE2 = path67.join(homedir15(), ".kynver", "config.json");
|
|
13344
13632
|
function ensureDefaultRepo(opts) {
|
|
13345
13633
|
const existing = loadUserConfig();
|
|
13346
13634
|
const resolved = resolveDefaultRepo({ ...opts, config: existing });
|
|
@@ -13421,16 +13709,16 @@ function summarizeResolvedDefaultRepo(resolved) {
|
|
|
13421
13709
|
}
|
|
13422
13710
|
|
|
13423
13711
|
// src/doctor/runtime-takeover.ts
|
|
13424
|
-
import
|
|
13712
|
+
import path69 from "node:path";
|
|
13425
13713
|
|
|
13426
13714
|
// src/doctor/runtime-takeover.probes.ts
|
|
13427
|
-
import { accessSync, constants, existsSync as
|
|
13715
|
+
import { accessSync, constants, existsSync as existsSync47, readFileSync as readFileSync19 } from "node:fs";
|
|
13428
13716
|
import { homedir as homedir16 } from "node:os";
|
|
13429
|
-
import
|
|
13430
|
-
import { spawnSync as
|
|
13717
|
+
import path68 from "node:path";
|
|
13718
|
+
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
13431
13719
|
function captureCommand(bin, args) {
|
|
13432
13720
|
try {
|
|
13433
|
-
const res =
|
|
13721
|
+
const res = spawnSync10(bin, args, { encoding: "utf8" });
|
|
13434
13722
|
const stdout = (res.stdout || "").trim();
|
|
13435
13723
|
const stderr = (res.stderr || "").trim();
|
|
13436
13724
|
const ok = res.status === 0;
|
|
@@ -13455,7 +13743,7 @@ function tokenPrefix(token) {
|
|
|
13455
13743
|
return trimmed.length <= 12 ? `${trimmed}\u2026` : `${trimmed.slice(0, 12)}\u2026`;
|
|
13456
13744
|
}
|
|
13457
13745
|
function isWritable(target) {
|
|
13458
|
-
if (!
|
|
13746
|
+
if (!existsSync47(target)) return false;
|
|
13459
13747
|
try {
|
|
13460
13748
|
accessSync(target, constants.W_OK);
|
|
13461
13749
|
return true;
|
|
@@ -13468,15 +13756,15 @@ var defaultRuntimeTakeoverProbes = {
|
|
|
13468
13756
|
commandOnPath: (bin) => captureCommand(process.platform === "win32" ? "where" : "which", [bin]),
|
|
13469
13757
|
kynverVersion: (bin) => captureCommand(bin, ["--version"]),
|
|
13470
13758
|
loadConfig: () => loadUserConfig(),
|
|
13471
|
-
configFilePath: () =>
|
|
13472
|
-
credentialsFilePath: () =>
|
|
13759
|
+
configFilePath: () => path68.join(homedir16(), ".kynver", "config.json"),
|
|
13760
|
+
credentialsFilePath: () => path68.join(homedir16(), ".kynver", "credentials"),
|
|
13473
13761
|
readCredentials: () => {
|
|
13474
|
-
const credPath =
|
|
13475
|
-
if (!
|
|
13762
|
+
const credPath = path68.join(homedir16(), ".kynver", "credentials");
|
|
13763
|
+
if (!existsSync47(credPath)) {
|
|
13476
13764
|
return { hasApiKey: false };
|
|
13477
13765
|
}
|
|
13478
13766
|
try {
|
|
13479
|
-
const parsed = JSON.parse(
|
|
13767
|
+
const parsed = JSON.parse(readFileSync19(credPath, "utf8"));
|
|
13480
13768
|
return {
|
|
13481
13769
|
hasApiKey: Boolean(parsed.apiKey?.trim()),
|
|
13482
13770
|
runnerTokenPrefix: tokenPrefix(parsed.runnerToken),
|
|
@@ -13506,8 +13794,8 @@ var defaultRuntimeTakeoverProbes = {
|
|
|
13506
13794
|
})()
|
|
13507
13795
|
}),
|
|
13508
13796
|
harnessRoot: () => resolveHarnessRoot(),
|
|
13509
|
-
legacyOpenclawHarnessRoot: () =>
|
|
13510
|
-
pathExists: (target) =>
|
|
13797
|
+
legacyOpenclawHarnessRoot: () => path68.join(homedir16(), ".openclaw", "harness"),
|
|
13798
|
+
pathExists: (target) => existsSync47(target),
|
|
13511
13799
|
pathWritable: (target) => isWritable(target)
|
|
13512
13800
|
};
|
|
13513
13801
|
|
|
@@ -13913,8 +14201,8 @@ function assessVercelDeployEvidence(probes) {
|
|
|
13913
14201
|
}
|
|
13914
14202
|
function assessHarnessDirs(probes) {
|
|
13915
14203
|
const harnessRoot = probes.harnessRoot();
|
|
13916
|
-
const runsDir =
|
|
13917
|
-
const worktreesDir =
|
|
14204
|
+
const runsDir = path69.join(harnessRoot, "runs");
|
|
14205
|
+
const worktreesDir = path69.join(harnessRoot, "worktrees");
|
|
13918
14206
|
const displayHarnessRoot = redactHomePath(harnessRoot);
|
|
13919
14207
|
const displayRunsDir = redactHomePath(runsDir);
|
|
13920
14208
|
const displayWorktreesDir = redactHomePath(worktreesDir);
|
|
@@ -14178,9 +14466,9 @@ function applySchedulerCutoverAttestation(config) {
|
|
|
14178
14466
|
}
|
|
14179
14467
|
|
|
14180
14468
|
// src/scheduler-cutover-cli.ts
|
|
14181
|
-
import
|
|
14469
|
+
import path70 from "node:path";
|
|
14182
14470
|
import { homedir as homedir17 } from "node:os";
|
|
14183
|
-
var CONFIG_FILE3 =
|
|
14471
|
+
var CONFIG_FILE3 = path70.join(homedir17(), ".kynver", "config.json");
|
|
14184
14472
|
function runSchedulerCutoverCheckCli(json = false) {
|
|
14185
14473
|
const config = loadUserConfig();
|
|
14186
14474
|
const report = assessSchedulerCutover(config);
|
|
@@ -14392,8 +14680,8 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
14392
14680
|
if (action && isHelpFlag(action) || rest.some(isHelpFlag)) return usage(0);
|
|
14393
14681
|
const args = parseArgs(rest);
|
|
14394
14682
|
const { runsDir, worktreesDir } = getPaths();
|
|
14395
|
-
|
|
14396
|
-
|
|
14683
|
+
mkdirSync10(runsDir, { recursive: true });
|
|
14684
|
+
mkdirSync10(worktreesDir, { recursive: true });
|
|
14397
14685
|
if (shouldEnforceMemoryCostPackageGuardCli(scope, action)) {
|
|
14398
14686
|
let repoRoot;
|
|
14399
14687
|
const runId = args.run ? String(args.run).trim() : "";
|
|
@@ -14828,6 +15116,7 @@ export {
|
|
|
14828
15116
|
CODEX_DEFAULT_MODEL,
|
|
14829
15117
|
DEFAULT_DISPATCH_LEASE_MS,
|
|
14830
15118
|
DEFAULT_HARNESS_VERIFY_COMMANDS,
|
|
15119
|
+
DEFAULT_HEAVY_VERIFICATION_MAX_CONCURRENT,
|
|
14831
15120
|
DEFAULT_MAX_ACTIONS_PER_SWEEP,
|
|
14832
15121
|
DEFAULT_NODE_MODULES_AGE_MS,
|
|
14833
15122
|
DEFAULT_RUN_DIRECTORIES_AGE_MS,
|
|
@@ -14856,6 +15145,7 @@ export {
|
|
|
14856
15145
|
assessAutoCompleteEligibility,
|
|
14857
15146
|
assessBuildAdmission,
|
|
14858
15147
|
assessExitedWorkerSalvage,
|
|
15148
|
+
assessHeavyVerificationGate,
|
|
14859
15149
|
assessOrphanWorktreeSafety,
|
|
14860
15150
|
assessPrHandoffRequirement,
|
|
14861
15151
|
assessWorkerLanding,
|
|
@@ -14889,6 +15179,7 @@ export {
|
|
|
14889
15179
|
completeWorker,
|
|
14890
15180
|
computeAttention,
|
|
14891
15181
|
computeWorkerStatus,
|
|
15182
|
+
countActiveHeavyVerificationSlots,
|
|
14892
15183
|
createRun,
|
|
14893
15184
|
defaultBoxId,
|
|
14894
15185
|
deriveRunStatus,
|
|
@@ -14942,6 +15233,7 @@ export {
|
|
|
14942
15233
|
isForbiddenWorkerEnvKey,
|
|
14943
15234
|
isGeneratedHarnessPath,
|
|
14944
15235
|
isHarnessRunMetadataPath,
|
|
15236
|
+
isHeavyVerificationGateSkipped,
|
|
14945
15237
|
isInspectableVercelTarget,
|
|
14946
15238
|
isKnownWorkerPersonaSlug,
|
|
14947
15239
|
isKynverMonorepoRoot,
|
|
@@ -14956,6 +15248,7 @@ export {
|
|
|
14956
15248
|
isWslHost,
|
|
14957
15249
|
joinHarnessNotice,
|
|
14958
15250
|
landingContractAttentionReason,
|
|
15251
|
+
listActiveHeavyVerificationSlots,
|
|
14959
15252
|
listForbiddenWorkerEnvKeys,
|
|
14960
15253
|
listMonitors,
|
|
14961
15254
|
listOrchestrationProviderCapabilities,
|
|
@@ -14995,12 +15288,14 @@ export {
|
|
|
14995
15288
|
providerCapableForRisk,
|
|
14996
15289
|
readMemAvailableBytes,
|
|
14997
15290
|
readProductionDbKeysFromEnvFile,
|
|
15291
|
+
reclaimStaleHeavyVerificationSlots,
|
|
14998
15292
|
reconcileRunsCli,
|
|
14999
15293
|
reconcileStaleWorkers,
|
|
15000
15294
|
reconcileWorkerMetadata,
|
|
15001
15295
|
reconcileWorkerMetadataCli,
|
|
15002
15296
|
redactHarness,
|
|
15003
15297
|
redactProviderErrorText,
|
|
15298
|
+
releaseHeavyVerificationSlot,
|
|
15004
15299
|
remediateDefaultRepo,
|
|
15005
15300
|
repairMissingRunMetadata,
|
|
15006
15301
|
repairNestedRunsPath,
|
|
@@ -15012,6 +15307,7 @@ export {
|
|
|
15012
15307
|
resolveConfiguredWorkerProvider,
|
|
15013
15308
|
resolveDefaultRepo,
|
|
15014
15309
|
resolveHarnessRoot,
|
|
15310
|
+
resolveHeavyVerificationMaxConcurrent,
|
|
15015
15311
|
resolveOpenAiCodexRetryBudget,
|
|
15016
15312
|
resolveOrchestrationPolicyMode,
|
|
15017
15313
|
resolveOrchestrationRouting,
|
|
@@ -15049,12 +15345,14 @@ export {
|
|
|
15049
15345
|
tailWorker,
|
|
15050
15346
|
taskAllowsClaudeWorker,
|
|
15051
15347
|
terminalFinalResultFromHeartbeat,
|
|
15348
|
+
tryAcquireHeavyVerificationSlot,
|
|
15052
15349
|
usage,
|
|
15053
15350
|
validateOwnedPaths,
|
|
15054
15351
|
validateRepo,
|
|
15055
15352
|
validateRunId,
|
|
15056
15353
|
validateTailLines,
|
|
15057
15354
|
validateWorkerName,
|
|
15355
|
+
waitForHeavyVerificationSlot,
|
|
15058
15356
|
workerDirHasActiveRetentionSignals,
|
|
15059
15357
|
workerPersonaLandingSlugs,
|
|
15060
15358
|
workerPersonaReviewSlugs,
|