@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/cli.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
|
-
import { mkdirSync as
|
|
4
|
+
import { mkdirSync as mkdirSync10, realpathSync } from "node:fs";
|
|
5
5
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
6
6
|
|
|
7
7
|
// src/config.ts
|
|
8
|
-
import { existsSync as existsSync9, mkdirSync as mkdirSync2, readFileSync as
|
|
8
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync2, readFileSync as readFileSync8, writeFileSync as writeFileSync2 } from "node:fs";
|
|
9
9
|
import { homedir as homedir4, totalmem } from "node:os";
|
|
10
10
|
import path8 from "node:path";
|
|
11
11
|
|
|
@@ -461,6 +461,7 @@ function readMemAvailableBytes(meminfoText) {
|
|
|
461
461
|
|
|
462
462
|
// src/resource-gate.ts
|
|
463
463
|
import path7 from "node:path";
|
|
464
|
+
import { readFileSync as readFileSync7 } from "node:fs";
|
|
464
465
|
|
|
465
466
|
// src/disk-gate.ts
|
|
466
467
|
import { statfsSync as statfsSync2 } from "node:fs";
|
|
@@ -485,23 +486,23 @@ function isWslHost() {
|
|
|
485
486
|
function observeWslHostDisk(options = {}) {
|
|
486
487
|
const wsl = options.forceWsl === void 0 ? isWslHost() : options.forceWsl;
|
|
487
488
|
if (!wsl) return null;
|
|
488
|
-
const
|
|
489
|
+
const path69 = options.wslHostMount?.trim() || process.env.KYNVER_WSL_HOST_MOUNT?.trim() || DEFAULT_WSL_HOST_MOUNT;
|
|
489
490
|
const warnBelowBytes = options.wslHostFreeWarnBytes ?? DEFAULT_WSL_HOST_WARN_FREE_BYTES;
|
|
490
491
|
const criticalBelowBytes = options.wslHostFreeCriticalBytes ?? DEFAULT_WSL_HOST_CRITICAL_FREE_BYTES;
|
|
491
492
|
const statfs = options.statfs ?? statfsSync;
|
|
492
493
|
let stats;
|
|
493
494
|
try {
|
|
494
|
-
stats = statfs(
|
|
495
|
+
stats = statfs(path69);
|
|
495
496
|
} catch (error) {
|
|
496
497
|
return {
|
|
497
498
|
ok: false,
|
|
498
|
-
path:
|
|
499
|
+
path: path69,
|
|
499
500
|
freeBytes: 0,
|
|
500
501
|
totalBytes: 0,
|
|
501
502
|
usedPercent: 100,
|
|
502
503
|
warnBelowBytes,
|
|
503
504
|
criticalBelowBytes,
|
|
504
|
-
reason: `Windows host disk probe failed at ${
|
|
505
|
+
reason: `Windows host disk probe failed at ${path69}: ${error.message}`,
|
|
505
506
|
probeError: error.message
|
|
506
507
|
};
|
|
507
508
|
}
|
|
@@ -515,11 +516,11 @@ function observeWslHostDisk(options = {}) {
|
|
|
515
516
|
let reason = null;
|
|
516
517
|
if (!ok) {
|
|
517
518
|
const tag = criticalFree ? "critical" : "warning";
|
|
518
|
-
reason = `Windows host disk ${
|
|
519
|
+
reason = `Windows host disk ${path69} at ${tag}: ${freeGiB} GiB free (<${(criticalFree ? criticalBelowBytes : warnBelowBytes) / 1024 / 1024 / 1024} GiB); WSL VHDX cannot grow safely. ${summarizeWslRecoverySteps()}`;
|
|
519
520
|
}
|
|
520
521
|
return {
|
|
521
522
|
ok,
|
|
522
|
-
path:
|
|
523
|
+
path: path69,
|
|
523
524
|
freeBytes,
|
|
524
525
|
totalBytes,
|
|
525
526
|
usedPercent,
|
|
@@ -539,12 +540,12 @@ var DEFAULT_CRITICAL_FREE_BYTES = 15 * 1024 * 1024 * 1024;
|
|
|
539
540
|
var DEFAULT_MAX_USED_PERCENT = 80;
|
|
540
541
|
var DEFAULT_HARD_MAX_USED_PERCENT = 90;
|
|
541
542
|
function observeRunnerDiskGate(input = {}) {
|
|
542
|
-
const
|
|
543
|
+
const path69 = input.diskPath?.trim() || "/";
|
|
543
544
|
const warnBelowBytes = input.diskFreeWarnBytes ?? DEFAULT_WARN_FREE_BYTES;
|
|
544
545
|
const criticalBelowBytes = input.diskFreeCriticalBytes ?? DEFAULT_CRITICAL_FREE_BYTES;
|
|
545
546
|
const maxUsedPercent = input.diskMaxUsedPercent ?? DEFAULT_MAX_USED_PERCENT;
|
|
546
547
|
const hardMaxUsedPercent = input.diskHardMaxUsedPercent ?? DEFAULT_HARD_MAX_USED_PERCENT;
|
|
547
|
-
const stats = statfsSync2(
|
|
548
|
+
const stats = statfsSync2(path69);
|
|
548
549
|
const freeBytes = Number(stats.bavail) * Number(stats.bsize);
|
|
549
550
|
const totalBytes = Number(stats.blocks) * Number(stats.bsize);
|
|
550
551
|
const usedPercent = totalBytes > 0 ? (totalBytes - freeBytes) / totalBytes * 100 : 100;
|
|
@@ -567,7 +568,7 @@ function observeRunnerDiskGate(input = {}) {
|
|
|
567
568
|
}
|
|
568
569
|
return {
|
|
569
570
|
ok,
|
|
570
|
-
path:
|
|
571
|
+
path: path69,
|
|
571
572
|
freeBytes,
|
|
572
573
|
totalBytes,
|
|
573
574
|
usedPercent,
|
|
@@ -1991,11 +1992,29 @@ function computeAutoMaxWorkers(totalMemBytes, opts = {}) {
|
|
|
1991
1992
|
function readAvailableMemBytes() {
|
|
1992
1993
|
return readMemAvailableBytes();
|
|
1993
1994
|
}
|
|
1995
|
+
function pidCommandLine(pid) {
|
|
1996
|
+
if (!pid || process.platform !== "linux") return null;
|
|
1997
|
+
try {
|
|
1998
|
+
return readFileSync7(`/proc/${pid}/cmdline`, "utf8").replace(/\0/g, " ");
|
|
1999
|
+
} catch {
|
|
2000
|
+
return null;
|
|
2001
|
+
}
|
|
2002
|
+
}
|
|
2003
|
+
function workerProcessMatchesRecord(worker) {
|
|
2004
|
+
if (!worker.pid || process.platform !== "linux") return true;
|
|
2005
|
+
const cmdline = pidCommandLine(worker.pid);
|
|
2006
|
+
if (!cmdline) return false;
|
|
2007
|
+
const probes = [worker.worktreePath, worker.workerDir, worker.heartbeatPath].filter(
|
|
2008
|
+
(value) => typeof value === "string" && value.trim().length > 0
|
|
2009
|
+
);
|
|
2010
|
+
return probes.some((probe) => cmdline.includes(probe));
|
|
2011
|
+
}
|
|
1994
2012
|
function isActiveHarnessWorker(worker) {
|
|
1995
2013
|
if (typeof worker.completionBlocker === "string" && worker.completionBlocker.trim()) {
|
|
1996
2014
|
return false;
|
|
1997
2015
|
}
|
|
1998
2016
|
const status = computeWorkerStatus(worker);
|
|
2017
|
+
if (status.alive && !workerProcessMatchesRecord(worker)) return false;
|
|
1999
2018
|
return status.alive && !status.finalResult && status.attention.state !== "done";
|
|
2000
2019
|
}
|
|
2001
2020
|
function countActiveWorkersForRun(run) {
|
|
@@ -2146,7 +2165,7 @@ var CREDENTIALS_FILE = path8.join(CONFIG_DIR, "credentials");
|
|
|
2146
2165
|
function loadUserConfig() {
|
|
2147
2166
|
if (!existsSync9(CONFIG_FILE)) return {};
|
|
2148
2167
|
try {
|
|
2149
|
-
return JSON.parse(
|
|
2168
|
+
return JSON.parse(readFileSync8(CONFIG_FILE, "utf8"));
|
|
2150
2169
|
} catch {
|
|
2151
2170
|
return {};
|
|
2152
2171
|
}
|
|
@@ -2223,7 +2242,7 @@ function resolveSetupWorkerConfig(existing, args, totalMemBytes = totalmem()) {
|
|
|
2223
2242
|
function loadCredentialsFile() {
|
|
2224
2243
|
if (!existsSync9(CREDENTIALS_FILE)) return {};
|
|
2225
2244
|
try {
|
|
2226
|
-
return JSON.parse(
|
|
2245
|
+
return JSON.parse(readFileSync8(CREDENTIALS_FILE, "utf8"));
|
|
2227
2246
|
} catch {
|
|
2228
2247
|
return {};
|
|
2229
2248
|
}
|
|
@@ -2493,15 +2512,30 @@ async function withTimeout(fn) {
|
|
|
2493
2512
|
clearTimeout(timeout);
|
|
2494
2513
|
}
|
|
2495
2514
|
}
|
|
2515
|
+
function callbackFetchError(error) {
|
|
2516
|
+
return {
|
|
2517
|
+
ok: false,
|
|
2518
|
+
status: 0,
|
|
2519
|
+
response: {
|
|
2520
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2521
|
+
timeoutMs: callbackTimeoutMs()
|
|
2522
|
+
}
|
|
2523
|
+
};
|
|
2524
|
+
}
|
|
2496
2525
|
async function postJson(url, secret, body) {
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2526
|
+
let res;
|
|
2527
|
+
try {
|
|
2528
|
+
res = await withTimeout(
|
|
2529
|
+
(signal) => fetch(url, {
|
|
2530
|
+
method: "POST",
|
|
2531
|
+
headers: buildHarnessCallbackHeaders(secret),
|
|
2532
|
+
body: JSON.stringify(body),
|
|
2533
|
+
signal
|
|
2534
|
+
})
|
|
2535
|
+
);
|
|
2536
|
+
} catch (error) {
|
|
2537
|
+
return callbackFetchError(error);
|
|
2538
|
+
}
|
|
2505
2539
|
let response = null;
|
|
2506
2540
|
try {
|
|
2507
2541
|
response = await res.json();
|
|
@@ -2519,13 +2553,18 @@ async function postJsonWithCredentialRefresh(url, secret, body, opts) {
|
|
|
2519
2553
|
return { ...retry, refreshedAuth: true };
|
|
2520
2554
|
}
|
|
2521
2555
|
async function getJson(url, secret) {
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2556
|
+
let res;
|
|
2557
|
+
try {
|
|
2558
|
+
res = await withTimeout(
|
|
2559
|
+
(signal) => fetch(url, {
|
|
2560
|
+
method: "GET",
|
|
2561
|
+
headers: buildHarnessCallbackHeaders(secret),
|
|
2562
|
+
signal
|
|
2563
|
+
})
|
|
2564
|
+
);
|
|
2565
|
+
} catch (error) {
|
|
2566
|
+
return callbackFetchError(error);
|
|
2567
|
+
}
|
|
2529
2568
|
let response = null;
|
|
2530
2569
|
try {
|
|
2531
2570
|
response = await res.json();
|
|
@@ -2535,41 +2574,6 @@ async function getJson(url, secret) {
|
|
|
2535
2574
|
return { ok: res.ok, status: res.status, response };
|
|
2536
2575
|
}
|
|
2537
2576
|
|
|
2538
|
-
// src/dispatch-lane-normalization.ts
|
|
2539
|
-
function trimLower(value) {
|
|
2540
|
-
return (value ?? "").trim().toLowerCase();
|
|
2541
|
-
}
|
|
2542
|
-
function roleLaneToDispatchLane(roleLane) {
|
|
2543
|
-
switch (trimLower(roleLane)) {
|
|
2544
|
-
case "implementer":
|
|
2545
|
-
case "repair_implementer":
|
|
2546
|
-
case "plan_author":
|
|
2547
|
-
case "runtime_verifier":
|
|
2548
|
-
return "implementation";
|
|
2549
|
-
case "plan_reviewer":
|
|
2550
|
-
case "report_reviewer":
|
|
2551
|
-
case "deep_reviewer":
|
|
2552
|
-
return "review";
|
|
2553
|
-
default:
|
|
2554
|
-
return null;
|
|
2555
|
-
}
|
|
2556
|
-
}
|
|
2557
|
-
function normalizeDispatchNextLaneFilter(raw) {
|
|
2558
|
-
const key = trimLower(raw);
|
|
2559
|
-
if (!key) return void 0;
|
|
2560
|
-
if (key === "implementation" || key === "review" || key === "landing" || key === "any") {
|
|
2561
|
-
return key;
|
|
2562
|
-
}
|
|
2563
|
-
const mapped = roleLaneToDispatchLane(key);
|
|
2564
|
-
if (mapped) return mapped;
|
|
2565
|
-
if (key === "implement" || key === "repair" || key === "coding") return "implementation";
|
|
2566
|
-
if (key === "land" || key === "merge") return "landing";
|
|
2567
|
-
return void 0;
|
|
2568
|
-
}
|
|
2569
|
-
function resolveDispatchNextLaneFilter(raw) {
|
|
2570
|
-
return normalizeDispatchNextLaneFilter(raw) ?? "any";
|
|
2571
|
-
}
|
|
2572
|
-
|
|
2573
2577
|
// src/worker-persona-catalog.ts
|
|
2574
2578
|
var WORKER_PERSONA_CATALOG = [
|
|
2575
2579
|
{
|
|
@@ -2672,6 +2676,41 @@ function workerPersonaReviewSlugs() {
|
|
|
2672
2676
|
);
|
|
2673
2677
|
}
|
|
2674
2678
|
|
|
2679
|
+
// src/dispatch-lane-normalization.ts
|
|
2680
|
+
function trimLower(value) {
|
|
2681
|
+
return (value ?? "").trim().toLowerCase();
|
|
2682
|
+
}
|
|
2683
|
+
function roleLaneToDispatchLane(roleLane) {
|
|
2684
|
+
switch (trimLower(roleLane)) {
|
|
2685
|
+
case "implementer":
|
|
2686
|
+
case "repair_implementer":
|
|
2687
|
+
case "plan_author":
|
|
2688
|
+
case "runtime_verifier":
|
|
2689
|
+
return "implementation";
|
|
2690
|
+
case "plan_reviewer":
|
|
2691
|
+
case "report_reviewer":
|
|
2692
|
+
case "deep_reviewer":
|
|
2693
|
+
return "review";
|
|
2694
|
+
default:
|
|
2695
|
+
return null;
|
|
2696
|
+
}
|
|
2697
|
+
}
|
|
2698
|
+
function normalizeDispatchNextLaneFilter(raw) {
|
|
2699
|
+
const key = trimLower(raw);
|
|
2700
|
+
if (!key) return void 0;
|
|
2701
|
+
if (key === "implementation" || key === "review" || key === "landing" || key === "any") {
|
|
2702
|
+
return key;
|
|
2703
|
+
}
|
|
2704
|
+
const mapped = roleLaneToDispatchLane(key);
|
|
2705
|
+
if (mapped) return mapped;
|
|
2706
|
+
if (key === "implement" || key === "repair" || key === "coding") return "implementation";
|
|
2707
|
+
if (key === "land" || key === "merge") return "landing";
|
|
2708
|
+
return void 0;
|
|
2709
|
+
}
|
|
2710
|
+
function resolveDispatchNextLaneFilter(raw) {
|
|
2711
|
+
return normalizeDispatchNextLaneFilter(raw) ?? "any";
|
|
2712
|
+
}
|
|
2713
|
+
|
|
2675
2714
|
// src/model-routing-task-enrich.ts
|
|
2676
2715
|
function taskString(task, key) {
|
|
2677
2716
|
const v = task[key];
|
|
@@ -3129,7 +3168,7 @@ function probeCursorOAuthBinding(nowIso = (/* @__PURE__ */ new Date()).toISOStri
|
|
|
3129
3168
|
}
|
|
3130
3169
|
|
|
3131
3170
|
// src/orchestration-providers/hermes-cli-adapter.ts
|
|
3132
|
-
import { existsSync as existsSync14, readFileSync as
|
|
3171
|
+
import { existsSync as existsSync14, readFileSync as readFileSync9 } from "node:fs";
|
|
3133
3172
|
import { homedir as homedir9 } from "node:os";
|
|
3134
3173
|
import path13 from "node:path";
|
|
3135
3174
|
var PROFILE_ENV_KEYS = [
|
|
@@ -3145,7 +3184,7 @@ function hermesProfileEnvPath() {
|
|
|
3145
3184
|
}
|
|
3146
3185
|
function profileEnvKeyPresence(envPath) {
|
|
3147
3186
|
try {
|
|
3148
|
-
const text =
|
|
3187
|
+
const text = readFileSync9(envPath, "utf8");
|
|
3149
3188
|
const present = [];
|
|
3150
3189
|
for (const key of PROFILE_ENV_KEYS) {
|
|
3151
3190
|
const re = new RegExp(`^${key}=`, "m");
|
|
@@ -4106,7 +4145,7 @@ function buildPrompt(input) {
|
|
|
4106
4145
|
"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.",
|
|
4107
4146
|
"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.",
|
|
4108
4147
|
"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.",
|
|
4109
|
-
"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.",
|
|
4148
|
+
"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.",
|
|
4110
4149
|
"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.",
|
|
4111
4150
|
"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.",
|
|
4112
4151
|
"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.",
|
|
@@ -4982,8 +5021,8 @@ function dirtyPathsCoveredByDisposableRemoval(changedFiles, removed) {
|
|
|
4982
5021
|
if (removed.length === 0) return false;
|
|
4983
5022
|
const removedSet = new Set(removed.map((p) => normalizeRelativePath(p)));
|
|
4984
5023
|
return material.every((line) => {
|
|
4985
|
-
const
|
|
4986
|
-
return removedSet.has(
|
|
5024
|
+
const path69 = normalizeRelativePath(pathFromGitStatusLine(line));
|
|
5025
|
+
return removedSet.has(path69);
|
|
4987
5026
|
});
|
|
4988
5027
|
}
|
|
4989
5028
|
|
|
@@ -6277,7 +6316,7 @@ function collectRunActiveHarnessWorkers(runId) {
|
|
|
6277
6316
|
path22.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
|
|
6278
6317
|
void 0
|
|
6279
6318
|
);
|
|
6280
|
-
if (!worker?.taskId || !
|
|
6319
|
+
if (!worker?.taskId || !workerProcessMatchesRecord(worker)) continue;
|
|
6281
6320
|
out.push({
|
|
6282
6321
|
runId: run.id,
|
|
6283
6322
|
workerName: name,
|
|
@@ -6516,7 +6555,7 @@ function isTmpOnlyPath(filePath) {
|
|
|
6516
6555
|
// src/plan-persist/outbox-store.ts
|
|
6517
6556
|
import {
|
|
6518
6557
|
existsSync as existsSync21,
|
|
6519
|
-
readFileSync as
|
|
6558
|
+
readFileSync as readFileSync10,
|
|
6520
6559
|
renameSync,
|
|
6521
6560
|
readdirSync as readdirSync5,
|
|
6522
6561
|
writeFileSync as writeFileSync3,
|
|
@@ -6544,7 +6583,7 @@ function findOutboxByIdempotencyKey(key) {
|
|
|
6544
6583
|
function readOutboxItem(jsonPath) {
|
|
6545
6584
|
if (!existsSync21(jsonPath)) return null;
|
|
6546
6585
|
try {
|
|
6547
|
-
return JSON.parse(
|
|
6586
|
+
return JSON.parse(readFileSync10(jsonPath, "utf8"));
|
|
6548
6587
|
} catch {
|
|
6549
6588
|
return null;
|
|
6550
6589
|
}
|
|
@@ -6552,7 +6591,7 @@ function readOutboxItem(jsonPath) {
|
|
|
6552
6591
|
function readOutboxBody(item) {
|
|
6553
6592
|
const { outboxDir } = ensurePlanOutboxDirs();
|
|
6554
6593
|
const bodyFile = path24.join(outboxDir, item.bodyPath);
|
|
6555
|
-
return
|
|
6594
|
+
return readFileSync10(bodyFile, "utf8");
|
|
6556
6595
|
}
|
|
6557
6596
|
function writeOutboxItem(input, opts) {
|
|
6558
6597
|
const { outboxDir } = ensurePlanOutboxDirs();
|
|
@@ -7373,7 +7412,7 @@ import { existsSync as existsSync25, mkdirSync as mkdirSync6 } from "node:fs";
|
|
|
7373
7412
|
import path34 from "node:path";
|
|
7374
7413
|
|
|
7375
7414
|
// src/run-list.ts
|
|
7376
|
-
import { existsSync as existsSync24, readFileSync as
|
|
7415
|
+
import { existsSync as existsSync24, readFileSync as readFileSync11 } from "node:fs";
|
|
7377
7416
|
import path33 from "node:path";
|
|
7378
7417
|
|
|
7379
7418
|
// src/stale-reconcile.ts
|
|
@@ -8092,7 +8131,7 @@ function reconcileRunsCli() {
|
|
|
8092
8131
|
function heartbeatByteLength(heartbeatPath) {
|
|
8093
8132
|
if (!heartbeatPath || !existsSync24(heartbeatPath)) return 0;
|
|
8094
8133
|
try {
|
|
8095
|
-
return
|
|
8134
|
+
return readFileSync11(heartbeatPath, "utf8").trim().length;
|
|
8096
8135
|
} catch {
|
|
8097
8136
|
return 0;
|
|
8098
8137
|
}
|
|
@@ -8427,12 +8466,12 @@ async function fireKynverCronJob(input) {
|
|
|
8427
8466
|
}
|
|
8428
8467
|
|
|
8429
8468
|
// src/cron/cron-lock.ts
|
|
8430
|
-
import { closeSync as closeSync6, existsSync as existsSync28, openSync as openSync6, readFileSync as
|
|
8469
|
+
import { closeSync as closeSync6, existsSync as existsSync28, openSync as openSync6, readFileSync as readFileSync12, unlinkSync as unlinkSync3, writeFileSync as writeFileSync4 } from "node:fs";
|
|
8431
8470
|
var STALE_LOCK_MS = 10 * 6e4;
|
|
8432
8471
|
function readLockInfo(lockPath) {
|
|
8433
8472
|
if (!existsSync28(lockPath)) return null;
|
|
8434
8473
|
try {
|
|
8435
|
-
const parsed = JSON.parse(
|
|
8474
|
+
const parsed = JSON.parse(readFileSync12(lockPath, "utf8"));
|
|
8436
8475
|
if (typeof parsed.pid === "number" && typeof parsed.at === "string") return parsed;
|
|
8437
8476
|
} catch {
|
|
8438
8477
|
return null;
|
|
@@ -9208,11 +9247,11 @@ var LIVE_SKIP_REASONS = /* @__PURE__ */ new Set([
|
|
|
9208
9247
|
function collectPreservedLivePaths(actions, skips) {
|
|
9209
9248
|
const out = [];
|
|
9210
9249
|
const seen = /* @__PURE__ */ new Set();
|
|
9211
|
-
const push = (
|
|
9212
|
-
const key = `${
|
|
9250
|
+
const push = (path69, reason, detail) => {
|
|
9251
|
+
const key = `${path69}\0${reason}`;
|
|
9213
9252
|
if (seen.has(key) || out.length >= MAX_PRESERVED_LIVE_PATH_SAMPLES) return;
|
|
9214
9253
|
seen.add(key);
|
|
9215
|
-
out.push({ path:
|
|
9254
|
+
out.push({ path: path69, reason, ...detail ? { detail } : {} });
|
|
9216
9255
|
};
|
|
9217
9256
|
for (const skip2 of skips) {
|
|
9218
9257
|
if (!LIVE_SKIP_REASONS.has(skip2.reason)) continue;
|
|
@@ -10693,7 +10732,7 @@ import { homedir as homedir13 } from "node:os";
|
|
|
10693
10732
|
import path54 from "node:path";
|
|
10694
10733
|
|
|
10695
10734
|
// src/memory-cost-package-version-guard.ts
|
|
10696
|
-
import { existsSync as existsSync40, readFileSync as
|
|
10735
|
+
import { existsSync as existsSync40, readFileSync as readFileSync13 } from "node:fs";
|
|
10697
10736
|
import path53 from "node:path";
|
|
10698
10737
|
var MEMORY_COST_PACKAGE_MIN_VERSIONS = {
|
|
10699
10738
|
"@kynver-app/runtime": "0.1.83",
|
|
@@ -10745,7 +10784,7 @@ function maxSemver(versions) {
|
|
|
10745
10784
|
}
|
|
10746
10785
|
function readPackageJsonVersion(packageJsonPath) {
|
|
10747
10786
|
try {
|
|
10748
|
-
const parsed = JSON.parse(
|
|
10787
|
+
const parsed = JSON.parse(readFileSync13(packageJsonPath, "utf8"));
|
|
10749
10788
|
return typeof parsed.version === "string" && parsed.version.trim() ? parsed.version.trim() : null;
|
|
10750
10789
|
} catch {
|
|
10751
10790
|
return null;
|
|
@@ -11146,17 +11185,17 @@ async function runDaemon(args) {
|
|
|
11146
11185
|
idleStreak = 0;
|
|
11147
11186
|
}
|
|
11148
11187
|
const backoff = idleStreak >= MAX_IDLE_STREAK ? IDLE_INTERVAL_MS : intervalMs;
|
|
11149
|
-
sleepMs(backoff);
|
|
11188
|
+
await sleepMs(backoff);
|
|
11150
11189
|
} catch (error) {
|
|
11151
11190
|
console.error(JSON.stringify({ event: "daemon_tick_error", error: error.message }));
|
|
11152
|
-
sleepMs(intervalMs);
|
|
11191
|
+
await sleepMs(intervalMs);
|
|
11153
11192
|
}
|
|
11154
11193
|
}
|
|
11155
11194
|
console.error(JSON.stringify({ event: "daemon_stop", runId, agentOsId }));
|
|
11156
11195
|
}
|
|
11157
11196
|
|
|
11158
11197
|
// src/plan-progress.ts
|
|
11159
|
-
import
|
|
11198
|
+
import path59 from "node:path";
|
|
11160
11199
|
|
|
11161
11200
|
// src/bounded-build/constants.ts
|
|
11162
11201
|
var DEFAULT_BUILD_MEM_BUDGET_BYTES = 1536 * 1024 * 1024;
|
|
@@ -11286,14 +11325,235 @@ function waitForBuildAdmission(timeoutMs, pollMs = 2e3, opts = {}) {
|
|
|
11286
11325
|
}
|
|
11287
11326
|
|
|
11288
11327
|
// src/bounded-build/exec.ts
|
|
11328
|
+
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
11329
|
+
|
|
11330
|
+
// src/heavy-verification/slot.ts
|
|
11331
|
+
import {
|
|
11332
|
+
closeSync as closeSync7,
|
|
11333
|
+
existsSync as existsSync41,
|
|
11334
|
+
mkdirSync as mkdirSync8,
|
|
11335
|
+
openSync as openSync7,
|
|
11336
|
+
readdirSync as readdirSync15,
|
|
11337
|
+
readFileSync as readFileSync14,
|
|
11338
|
+
unlinkSync as unlinkSync4,
|
|
11339
|
+
writeFileSync as writeFileSync5
|
|
11340
|
+
} from "node:fs";
|
|
11341
|
+
import path57 from "node:path";
|
|
11342
|
+
|
|
11343
|
+
// src/heavy-verification/paths.ts
|
|
11344
|
+
import { mkdirSync as mkdirSync7 } from "node:fs";
|
|
11345
|
+
import path56 from "node:path";
|
|
11346
|
+
function resolveHeavyVerificationRoot() {
|
|
11347
|
+
return path56.join(resolveKynverStateRoot(), "heavy-verification");
|
|
11348
|
+
}
|
|
11349
|
+
function heavyVerificationSlotsDir() {
|
|
11350
|
+
return path56.join(resolveHeavyVerificationRoot(), "slots");
|
|
11351
|
+
}
|
|
11352
|
+
function ensureHeavyVerificationDirs() {
|
|
11353
|
+
const dir = heavyVerificationSlotsDir();
|
|
11354
|
+
mkdirSync7(dir, { recursive: true });
|
|
11355
|
+
return dir;
|
|
11356
|
+
}
|
|
11357
|
+
|
|
11358
|
+
// src/heavy-verification/slot.ts
|
|
11359
|
+
var DEFAULT_HEAVY_VERIFICATION_STALE_MS = 2 * 60 * 6e4;
|
|
11360
|
+
var DEFAULT_HEAVY_VERIFICATION_MAX_CONCURRENT = 1;
|
|
11361
|
+
function positiveInt5(value, fallback) {
|
|
11362
|
+
const n = Number(value);
|
|
11363
|
+
if (!Number.isFinite(n) || n <= 0) return fallback;
|
|
11364
|
+
return Math.floor(n);
|
|
11365
|
+
}
|
|
11366
|
+
function isHeavyVerificationGateSkipped() {
|
|
11367
|
+
const v = process.env.KYNVER_HEAVY_VERIFICATION_SKIP?.trim().toLowerCase();
|
|
11368
|
+
return v === "1" || v === "true" || v === "yes";
|
|
11369
|
+
}
|
|
11370
|
+
function resolveHeavyVerificationMaxConcurrent() {
|
|
11371
|
+
const env = process.env.KYNVER_HEAVY_VERIFICATION_MAX_CONCURRENT;
|
|
11372
|
+
if (env) return positiveInt5(env, DEFAULT_HEAVY_VERIFICATION_MAX_CONCURRENT);
|
|
11373
|
+
return DEFAULT_HEAVY_VERIFICATION_MAX_CONCURRENT;
|
|
11374
|
+
}
|
|
11375
|
+
function indexedSlotId(index) {
|
|
11376
|
+
return `slot-${index}`;
|
|
11377
|
+
}
|
|
11378
|
+
function slotFilePath(slotId, slotsDir = heavyVerificationSlotsDir()) {
|
|
11379
|
+
return path57.join(slotsDir, `${slotId}.json`);
|
|
11380
|
+
}
|
|
11381
|
+
function readSlotRecord(filePath) {
|
|
11382
|
+
if (!existsSync41(filePath)) return null;
|
|
11383
|
+
try {
|
|
11384
|
+
const parsed = JSON.parse(readFileSync14(filePath, "utf8"));
|
|
11385
|
+
if (typeof parsed.slotId === "string" && typeof parsed.pid === "number" && typeof parsed.acquiredAt === "string" && typeof parsed.command === "string") {
|
|
11386
|
+
return parsed;
|
|
11387
|
+
}
|
|
11388
|
+
} catch {
|
|
11389
|
+
return null;
|
|
11390
|
+
}
|
|
11391
|
+
return null;
|
|
11392
|
+
}
|
|
11393
|
+
function slotIsStale(record, staleMs = DEFAULT_HEAVY_VERIFICATION_STALE_MS) {
|
|
11394
|
+
if (!record) return true;
|
|
11395
|
+
if (!isPidAlive(record.pid)) return true;
|
|
11396
|
+
const atMs = Date.parse(record.acquiredAt);
|
|
11397
|
+
if (Number.isNaN(atMs)) return true;
|
|
11398
|
+
return Date.now() - atMs > staleMs;
|
|
11399
|
+
}
|
|
11400
|
+
function reclaimStaleSlot(filePath, staleMs) {
|
|
11401
|
+
const record = readSlotRecord(filePath);
|
|
11402
|
+
if (!slotIsStale(record, staleMs)) return;
|
|
11403
|
+
try {
|
|
11404
|
+
unlinkSync4(filePath);
|
|
11405
|
+
} catch {
|
|
11406
|
+
}
|
|
11407
|
+
}
|
|
11408
|
+
function ensureSlotsDir(slotsDir) {
|
|
11409
|
+
mkdirSync8(slotsDir, { recursive: true });
|
|
11410
|
+
return slotsDir;
|
|
11411
|
+
}
|
|
11412
|
+
function reclaimStaleHeavyVerificationSlots(opts = {}) {
|
|
11413
|
+
const slotsDir = ensureSlotsDir(opts.slotsDir ?? ensureHeavyVerificationDirs());
|
|
11414
|
+
const staleMs = opts.staleMs ?? DEFAULT_HEAVY_VERIFICATION_STALE_MS;
|
|
11415
|
+
let reclaimed = 0;
|
|
11416
|
+
for (const name of readdirSync15(slotsDir)) {
|
|
11417
|
+
if (!name.endsWith(".json")) continue;
|
|
11418
|
+
const filePath = path57.join(slotsDir, name);
|
|
11419
|
+
const before = existsSync41(filePath);
|
|
11420
|
+
reclaimStaleSlot(filePath, staleMs);
|
|
11421
|
+
if (before && !existsSync41(filePath)) reclaimed += 1;
|
|
11422
|
+
}
|
|
11423
|
+
return reclaimed;
|
|
11424
|
+
}
|
|
11425
|
+
function listActiveHeavyVerificationSlots(opts = {}) {
|
|
11426
|
+
const slotsDir = opts.slotsDir ?? ensureHeavyVerificationDirs();
|
|
11427
|
+
const staleMs = opts.staleMs ?? DEFAULT_HEAVY_VERIFICATION_STALE_MS;
|
|
11428
|
+
reclaimStaleHeavyVerificationSlots({ slotsDir, staleMs });
|
|
11429
|
+
const active = [];
|
|
11430
|
+
for (const name of readdirSync15(slotsDir)) {
|
|
11431
|
+
if (!name.endsWith(".json")) continue;
|
|
11432
|
+
const record = readSlotRecord(path57.join(slotsDir, name));
|
|
11433
|
+
if (record && !slotIsStale(record, staleMs)) active.push(record);
|
|
11434
|
+
}
|
|
11435
|
+
return active;
|
|
11436
|
+
}
|
|
11437
|
+
function countActiveHeavyVerificationSlots(opts = {}) {
|
|
11438
|
+
return listActiveHeavyVerificationSlots(opts).length;
|
|
11439
|
+
}
|
|
11440
|
+
function tryAcquireHeavyVerificationSlot(command, opts = {}) {
|
|
11441
|
+
if (isHeavyVerificationGateSkipped()) {
|
|
11442
|
+
return {
|
|
11443
|
+
admitted: true,
|
|
11444
|
+
slotId: null,
|
|
11445
|
+
activeSlots: 0,
|
|
11446
|
+
maxSlots: resolveHeavyVerificationMaxConcurrent(),
|
|
11447
|
+
reason: null
|
|
11448
|
+
};
|
|
11449
|
+
}
|
|
11450
|
+
const slotsDir = opts.slotsDir ?? ensureHeavyVerificationDirs();
|
|
11451
|
+
const staleMs = opts.staleMs ?? DEFAULT_HEAVY_VERIFICATION_STALE_MS;
|
|
11452
|
+
const maxSlots = opts.maxSlots ?? resolveHeavyVerificationMaxConcurrent();
|
|
11453
|
+
reclaimStaleHeavyVerificationSlots({ slotsDir, staleMs });
|
|
11454
|
+
for (let index = 0; index < maxSlots; index += 1) {
|
|
11455
|
+
const slotId = indexedSlotId(index);
|
|
11456
|
+
const filePath = slotFilePath(slotId, slotsDir);
|
|
11457
|
+
const existing = readSlotRecord(filePath);
|
|
11458
|
+
if (existing && slotIsStale(existing, staleMs)) {
|
|
11459
|
+
try {
|
|
11460
|
+
unlinkSync4(filePath);
|
|
11461
|
+
} catch {
|
|
11462
|
+
}
|
|
11463
|
+
} else if (existing && !slotIsStale(existing, staleMs)) {
|
|
11464
|
+
continue;
|
|
11465
|
+
}
|
|
11466
|
+
const record = {
|
|
11467
|
+
slotId,
|
|
11468
|
+
pid: process.pid,
|
|
11469
|
+
acquiredAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11470
|
+
command
|
|
11471
|
+
};
|
|
11472
|
+
try {
|
|
11473
|
+
const fd = openSync7(filePath, "wx");
|
|
11474
|
+
writeFileSync5(fd, JSON.stringify(record, null, 2), "utf8");
|
|
11475
|
+
closeSync7(fd);
|
|
11476
|
+
const activeSlots2 = countActiveHeavyVerificationSlots({ slotsDir, staleMs });
|
|
11477
|
+
return {
|
|
11478
|
+
admitted: true,
|
|
11479
|
+
slotId,
|
|
11480
|
+
activeSlots: activeSlots2,
|
|
11481
|
+
maxSlots,
|
|
11482
|
+
reason: null
|
|
11483
|
+
};
|
|
11484
|
+
} catch (err) {
|
|
11485
|
+
if (err.code === "EEXIST") {
|
|
11486
|
+
continue;
|
|
11487
|
+
}
|
|
11488
|
+
throw err;
|
|
11489
|
+
}
|
|
11490
|
+
}
|
|
11491
|
+
const activeSlots = countActiveHeavyVerificationSlots({ slotsDir, staleMs });
|
|
11492
|
+
return {
|
|
11493
|
+
admitted: false,
|
|
11494
|
+
slotId: null,
|
|
11495
|
+
activeSlots,
|
|
11496
|
+
maxSlots,
|
|
11497
|
+
reason: `heavy verification at capacity (${activeSlots}/${maxSlots} slots)`
|
|
11498
|
+
};
|
|
11499
|
+
}
|
|
11500
|
+
function releaseHeavyVerificationSlot(slotId, opts = {}) {
|
|
11501
|
+
if (!slotId) return;
|
|
11502
|
+
const filePath = slotFilePath(slotId, opts.slotsDir ?? heavyVerificationSlotsDir());
|
|
11503
|
+
try {
|
|
11504
|
+
unlinkSync4(filePath);
|
|
11505
|
+
} catch {
|
|
11506
|
+
}
|
|
11507
|
+
}
|
|
11508
|
+
function assessHeavyVerificationGate(command, opts = {}) {
|
|
11509
|
+
if (isHeavyVerificationGateSkipped()) {
|
|
11510
|
+
return {
|
|
11511
|
+
admitted: true,
|
|
11512
|
+
slotId: null,
|
|
11513
|
+
activeSlots: 0,
|
|
11514
|
+
maxSlots: resolveHeavyVerificationMaxConcurrent(),
|
|
11515
|
+
reason: null
|
|
11516
|
+
};
|
|
11517
|
+
}
|
|
11518
|
+
const slotsDir = opts.slotsDir ?? ensureHeavyVerificationDirs();
|
|
11519
|
+
const staleMs = opts.staleMs ?? DEFAULT_HEAVY_VERIFICATION_STALE_MS;
|
|
11520
|
+
const maxSlots = opts.maxSlots ?? resolveHeavyVerificationMaxConcurrent();
|
|
11521
|
+
reclaimStaleHeavyVerificationSlots({ slotsDir, staleMs });
|
|
11522
|
+
const activeSlots = countActiveHeavyVerificationSlots({ slotsDir, staleMs });
|
|
11523
|
+
const admitted = activeSlots < maxSlots;
|
|
11524
|
+
return {
|
|
11525
|
+
admitted,
|
|
11526
|
+
slotId: null,
|
|
11527
|
+
activeSlots,
|
|
11528
|
+
maxSlots,
|
|
11529
|
+
reason: admitted ? null : `heavy verification at capacity (${activeSlots}/${maxSlots} slots); waiting for ${command}`
|
|
11530
|
+
};
|
|
11531
|
+
}
|
|
11532
|
+
|
|
11533
|
+
// src/heavy-verification/gate.ts
|
|
11289
11534
|
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
11535
|
+
function sleepMs3(ms) {
|
|
11536
|
+
if (ms <= 0) return;
|
|
11537
|
+
spawnSync7(process.execPath, ["-e", `const d=Date.now()+${Math.floor(ms)};while(Date.now()<d);`], {
|
|
11538
|
+
stdio: "ignore"
|
|
11539
|
+
});
|
|
11540
|
+
}
|
|
11541
|
+
function waitForHeavyVerificationSlot(command, timeoutMs, pollMs = 2e3, opts = {}) {
|
|
11542
|
+
const deadline = Date.now() + Math.max(0, timeoutMs);
|
|
11543
|
+
let verdict = tryAcquireHeavyVerificationSlot(command, opts);
|
|
11544
|
+
while (!verdict.admitted && Date.now() < deadline) {
|
|
11545
|
+
sleepMs3(Math.min(pollMs, deadline - Date.now()));
|
|
11546
|
+
verdict = tryAcquireHeavyVerificationSlot(command, opts);
|
|
11547
|
+
}
|
|
11548
|
+
return verdict;
|
|
11549
|
+
}
|
|
11290
11550
|
|
|
11291
11551
|
// src/harness-worktree-build-guard.ts
|
|
11292
|
-
import
|
|
11552
|
+
import path58 from "node:path";
|
|
11293
11553
|
function isPathUnderHarnessWorktree(cwd) {
|
|
11294
11554
|
const worktreesDir = harnessWorktreesDir(resolveHarnessRoot());
|
|
11295
|
-
const rel =
|
|
11296
|
-
return rel.length > 0 && !rel.startsWith("..") && !
|
|
11555
|
+
const rel = path58.relative(worktreesDir, path58.resolve(cwd));
|
|
11556
|
+
return rel.length > 0 && !rel.startsWith("..") && !path58.isAbsolute(rel);
|
|
11297
11557
|
}
|
|
11298
11558
|
function assessHarnessWorktreeBuildGuard(cwd) {
|
|
11299
11559
|
if (!isPathUnderHarnessWorktree(cwd)) return { ok: true };
|
|
@@ -11317,7 +11577,7 @@ function envArgv(env) {
|
|
|
11317
11577
|
return out;
|
|
11318
11578
|
}
|
|
11319
11579
|
function runSpawn(argv, opts) {
|
|
11320
|
-
const res =
|
|
11580
|
+
const res = spawnSync8(argv[0], argv.slice(1), {
|
|
11321
11581
|
cwd: opts.cwd,
|
|
11322
11582
|
env: opts.env,
|
|
11323
11583
|
encoding: "utf8",
|
|
@@ -11333,8 +11593,25 @@ function runSpawn(argv, opts) {
|
|
|
11333
11593
|
}
|
|
11334
11594
|
function runBoundedBuildCheck(input) {
|
|
11335
11595
|
const waitMs = input.waitForAdmissionMs ?? 6e5;
|
|
11596
|
+
const verificationGate = waitMs > 0 ? waitForHeavyVerificationSlot(input.command, waitMs) : tryAcquireOrAssessVerificationGate(input.command);
|
|
11597
|
+
if (!verificationGate.admitted) {
|
|
11598
|
+
return {
|
|
11599
|
+
ok: false,
|
|
11600
|
+
exitCode: 1,
|
|
11601
|
+
stdout: "",
|
|
11602
|
+
stderr: verificationGate.reason ?? "heavy verification gate denied",
|
|
11603
|
+
admitted: false,
|
|
11604
|
+
wrappedWithSystemd: false,
|
|
11605
|
+
nodeOptionsFlag: formatNodeOptionsFlag(),
|
|
11606
|
+
admission: assessBuildAdmission(),
|
|
11607
|
+
verificationGate,
|
|
11608
|
+
command: input.command
|
|
11609
|
+
};
|
|
11610
|
+
}
|
|
11611
|
+
const slotId = verificationGate.slotId;
|
|
11336
11612
|
const admission = waitMs > 0 ? waitForBuildAdmission(waitMs) : assessBuildAdmission();
|
|
11337
11613
|
if (!admission.admitted) {
|
|
11614
|
+
releaseHeavyVerificationSlot(slotId);
|
|
11338
11615
|
return {
|
|
11339
11616
|
ok: false,
|
|
11340
11617
|
exitCode: 1,
|
|
@@ -11344,11 +11621,13 @@ function runBoundedBuildCheck(input) {
|
|
|
11344
11621
|
wrappedWithSystemd: false,
|
|
11345
11622
|
nodeOptionsFlag: formatNodeOptionsFlag(),
|
|
11346
11623
|
admission,
|
|
11624
|
+
verificationGate,
|
|
11347
11625
|
command: input.command
|
|
11348
11626
|
};
|
|
11349
11627
|
}
|
|
11350
11628
|
const worktreeGuard = assessHarnessWorktreeBuildGuard(input.cwd);
|
|
11351
11629
|
if (!worktreeGuard.ok) {
|
|
11630
|
+
releaseHeavyVerificationSlot(slotId);
|
|
11352
11631
|
return {
|
|
11353
11632
|
ok: false,
|
|
11354
11633
|
exitCode: 1,
|
|
@@ -11358,6 +11637,7 @@ function runBoundedBuildCheck(input) {
|
|
|
11358
11637
|
wrappedWithSystemd: false,
|
|
11359
11638
|
nodeOptionsFlag: formatNodeOptionsFlag(),
|
|
11360
11639
|
admission,
|
|
11640
|
+
verificationGate,
|
|
11361
11641
|
command: input.command
|
|
11362
11642
|
};
|
|
11363
11643
|
}
|
|
@@ -11390,12 +11670,19 @@ function runBoundedBuildCheck(input) {
|
|
|
11390
11670
|
wrappedWithSystemd: useSystemd,
|
|
11391
11671
|
nodeOptionsFlag,
|
|
11392
11672
|
admission,
|
|
11673
|
+
verificationGate,
|
|
11393
11674
|
command: input.command
|
|
11394
11675
|
};
|
|
11395
11676
|
} finally {
|
|
11396
11677
|
registerBuildEnd();
|
|
11678
|
+
releaseHeavyVerificationSlot(slotId);
|
|
11397
11679
|
}
|
|
11398
11680
|
}
|
|
11681
|
+
function tryAcquireOrAssessVerificationGate(command) {
|
|
11682
|
+
const acquired = waitForHeavyVerificationSlot(command, 0);
|
|
11683
|
+
if (acquired.admitted) return acquired;
|
|
11684
|
+
return { ...assessHeavyVerificationGate(command), slotId: null };
|
|
11685
|
+
}
|
|
11399
11686
|
|
|
11400
11687
|
// src/harness-verify.ts
|
|
11401
11688
|
var DEFAULT_HARNESS_VERIFY_COMMANDS = ["npm run typecheck", "npm run test"];
|
|
@@ -11478,7 +11765,7 @@ async function emitPlanProgress(args) {
|
|
|
11478
11765
|
}
|
|
11479
11766
|
function verifyPlanLocal(args) {
|
|
11480
11767
|
const worktree = required(args.worktree ? String(args.worktree) : void 0, "worktree");
|
|
11481
|
-
const cwd =
|
|
11768
|
+
const cwd = path59.resolve(worktree);
|
|
11482
11769
|
const summary = runHarnessVerifyCommands(cwd);
|
|
11483
11770
|
const emitJson = args.json === true || args.json === "true";
|
|
11484
11771
|
const payload = { passed: summary.passed, worktree: cwd, steps: summary.steps };
|
|
@@ -11527,9 +11814,9 @@ async function verifyPlan(args) {
|
|
|
11527
11814
|
}
|
|
11528
11815
|
|
|
11529
11816
|
// src/harness-verify-cli.ts
|
|
11530
|
-
import
|
|
11817
|
+
import path60 from "node:path";
|
|
11531
11818
|
function runHarnessVerifyCli(args) {
|
|
11532
|
-
const cwd =
|
|
11819
|
+
const cwd = path60.resolve(required(args.worktree ? String(args.worktree) : void 0, "worktree"));
|
|
11533
11820
|
const emitJson = args.json === true || args.json === "true" || args.emitJson === true || args.emitJson === "true";
|
|
11534
11821
|
const commands = [];
|
|
11535
11822
|
const rawCmd = args.command;
|
|
@@ -11557,6 +11844,7 @@ function runHarnessVerifyCli(args) {
|
|
|
11557
11844
|
wrappedWithSystemd: s.result.wrappedWithSystemd,
|
|
11558
11845
|
nodeOptionsFlag: s.result.nodeOptionsFlag,
|
|
11559
11846
|
admission: s.result.admission,
|
|
11847
|
+
verificationGate: s.result.verificationGate,
|
|
11560
11848
|
stderr: s.result.stderr.slice(0, 4e3)
|
|
11561
11849
|
}))
|
|
11562
11850
|
};
|
|
@@ -11573,7 +11861,7 @@ function runHarnessVerifyCli(args) {
|
|
|
11573
11861
|
}
|
|
11574
11862
|
|
|
11575
11863
|
// src/plan-persist-cli.ts
|
|
11576
|
-
import { readFileSync as
|
|
11864
|
+
import { readFileSync as readFileSync15 } from "node:fs";
|
|
11577
11865
|
var OPERATIONS = ["create", "add_version", "update_metadata"];
|
|
11578
11866
|
var FAILURE_KINDS = [
|
|
11579
11867
|
"approval_guard",
|
|
@@ -11585,7 +11873,7 @@ var FAILURE_KINDS = [
|
|
|
11585
11873
|
function readBodyArg(args) {
|
|
11586
11874
|
const bodyFile = args.bodyFile ? String(args.bodyFile) : void 0;
|
|
11587
11875
|
if (bodyFile) {
|
|
11588
|
-
return { body:
|
|
11876
|
+
return { body: readFileSync15(bodyFile, "utf8"), bodyPathHint: bodyFile };
|
|
11589
11877
|
}
|
|
11590
11878
|
const inline = args.body ? String(args.body) : void 0;
|
|
11591
11879
|
if (inline) return { body: inline };
|
|
@@ -11736,7 +12024,7 @@ function formatMonitorTickNotice(tick) {
|
|
|
11736
12024
|
}
|
|
11737
12025
|
|
|
11738
12026
|
// src/monitor/monitor.service.ts
|
|
11739
|
-
import
|
|
12027
|
+
import path62 from "node:path";
|
|
11740
12028
|
|
|
11741
12029
|
// src/monitor/monitor.classify.ts
|
|
11742
12030
|
function classifyWorkerHealth(input) {
|
|
@@ -11788,19 +12076,19 @@ function classifyWorkerHealth(input) {
|
|
|
11788
12076
|
}
|
|
11789
12077
|
|
|
11790
12078
|
// src/monitor/monitor.store.ts
|
|
11791
|
-
import { existsSync as
|
|
11792
|
-
import
|
|
12079
|
+
import { existsSync as existsSync42, mkdirSync as mkdirSync9, readdirSync as readdirSync16, unlinkSync as unlinkSync5 } from "node:fs";
|
|
12080
|
+
import path61 from "node:path";
|
|
11793
12081
|
function monitorsDir() {
|
|
11794
12082
|
const { harnessRoot } = getHarnessPaths();
|
|
11795
|
-
const dir =
|
|
11796
|
-
|
|
12083
|
+
const dir = path61.join(harnessRoot, "monitors");
|
|
12084
|
+
mkdirSync9(dir, { recursive: true });
|
|
11797
12085
|
return dir;
|
|
11798
12086
|
}
|
|
11799
12087
|
function monitorIdFor(runId, workerName) {
|
|
11800
12088
|
return workerName ? `${safeSlug(runId)}--${safeSlug(workerName)}` : safeSlug(runId);
|
|
11801
12089
|
}
|
|
11802
12090
|
function monitorPath(monitorId) {
|
|
11803
|
-
return
|
|
12091
|
+
return path61.join(monitorsDir(), `${monitorId}.json`);
|
|
11804
12092
|
}
|
|
11805
12093
|
function loadMonitorSession(monitorId) {
|
|
11806
12094
|
return readJson(monitorPath(monitorId), void 0);
|
|
@@ -11810,18 +12098,18 @@ function saveMonitorSession(session) {
|
|
|
11810
12098
|
}
|
|
11811
12099
|
function deleteMonitorSession(monitorId) {
|
|
11812
12100
|
const file = monitorPath(monitorId);
|
|
11813
|
-
if (!
|
|
11814
|
-
|
|
12101
|
+
if (!existsSync42(file)) return false;
|
|
12102
|
+
unlinkSync5(file);
|
|
11815
12103
|
return true;
|
|
11816
12104
|
}
|
|
11817
12105
|
function listMonitorSessions() {
|
|
11818
12106
|
const dir = monitorsDir();
|
|
11819
|
-
if (!
|
|
12107
|
+
if (!existsSync42(dir)) return [];
|
|
11820
12108
|
const entries = [];
|
|
11821
|
-
for (const name of
|
|
12109
|
+
for (const name of readdirSync16(dir)) {
|
|
11822
12110
|
if (!name.endsWith(".json")) continue;
|
|
11823
12111
|
const session = readJson(
|
|
11824
|
-
|
|
12112
|
+
path61.join(dir, name),
|
|
11825
12113
|
void 0
|
|
11826
12114
|
);
|
|
11827
12115
|
if (!session?.monitorId) continue;
|
|
@@ -11912,7 +12200,7 @@ async function fetchTaskLeasesForWorkers(input) {
|
|
|
11912
12200
|
// src/monitor/monitor.service.ts
|
|
11913
12201
|
function workerRecord2(runId, name) {
|
|
11914
12202
|
return readJson(
|
|
11915
|
-
|
|
12203
|
+
path62.join(runDirectory(runId), "workers", safeSlug(name), "worker.json"),
|
|
11916
12204
|
void 0
|
|
11917
12205
|
);
|
|
11918
12206
|
}
|
|
@@ -12118,21 +12406,21 @@ async function runMonitorLoop(args) {
|
|
|
12118
12406
|
|
|
12119
12407
|
// src/monitor/monitor-spawn.ts
|
|
12120
12408
|
import { spawn as spawn6 } from "node:child_process";
|
|
12121
|
-
import { closeSync as
|
|
12122
|
-
import
|
|
12409
|
+
import { closeSync as closeSync8, existsSync as existsSync43, openSync as openSync8 } from "node:fs";
|
|
12410
|
+
import path63 from "node:path";
|
|
12123
12411
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
12124
12412
|
function resolveDefaultCliPath2() {
|
|
12125
|
-
return
|
|
12413
|
+
return path63.join(fileURLToPath3(new URL(".", import.meta.url)), "cli.js");
|
|
12126
12414
|
}
|
|
12127
12415
|
function spawnMonitorSidecar(opts) {
|
|
12128
12416
|
const cliPath = opts.cliPath ?? resolveDefaultCliPath2();
|
|
12129
|
-
if (!
|
|
12417
|
+
if (!existsSync43(cliPath)) return void 0;
|
|
12130
12418
|
const monitorId = monitorIdFor(opts.runId, opts.workerName);
|
|
12131
12419
|
const { harnessRoot } = getHarnessPaths();
|
|
12132
|
-
const logPath =
|
|
12420
|
+
const logPath = path63.join(harnessRoot, "monitors", `${monitorId}.log`);
|
|
12133
12421
|
let logFd;
|
|
12134
12422
|
try {
|
|
12135
|
-
logFd =
|
|
12423
|
+
logFd = openSync8(logPath, "a");
|
|
12136
12424
|
} catch {
|
|
12137
12425
|
logFd = void 0;
|
|
12138
12426
|
}
|
|
@@ -12172,7 +12460,7 @@ function spawnMonitorSidecar(opts) {
|
|
|
12172
12460
|
env: process.env
|
|
12173
12461
|
})
|
|
12174
12462
|
);
|
|
12175
|
-
if (logFd !== void 0)
|
|
12463
|
+
if (logFd !== void 0) closeSync8(logFd);
|
|
12176
12464
|
child.unref();
|
|
12177
12465
|
const session = {
|
|
12178
12466
|
monitorId,
|
|
@@ -12189,7 +12477,7 @@ function spawnMonitorSidecar(opts) {
|
|
|
12189
12477
|
} catch {
|
|
12190
12478
|
if (logFd !== void 0) {
|
|
12191
12479
|
try {
|
|
12192
|
-
|
|
12480
|
+
closeSync8(logFd);
|
|
12193
12481
|
} catch {
|
|
12194
12482
|
}
|
|
12195
12483
|
}
|
|
@@ -12249,13 +12537,13 @@ async function monitorTickCli(args) {
|
|
|
12249
12537
|
}
|
|
12250
12538
|
|
|
12251
12539
|
// src/package-version.ts
|
|
12252
|
-
import { existsSync as
|
|
12540
|
+
import { existsSync as existsSync44, readFileSync as readFileSync16 } from "node:fs";
|
|
12253
12541
|
import { dirname, join } from "node:path";
|
|
12254
12542
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
12255
12543
|
function resolvePackageRoot(moduleUrl) {
|
|
12256
12544
|
let dir = dirname(fileURLToPath4(moduleUrl));
|
|
12257
12545
|
for (let depth = 0; depth < 6; depth += 1) {
|
|
12258
|
-
if (
|
|
12546
|
+
if (existsSync44(join(dir, "package.json"))) return dir;
|
|
12259
12547
|
const parent = dirname(dir);
|
|
12260
12548
|
if (parent === dir) break;
|
|
12261
12549
|
dir = parent;
|
|
@@ -12264,7 +12552,7 @@ function resolvePackageRoot(moduleUrl) {
|
|
|
12264
12552
|
}
|
|
12265
12553
|
function readOwnPackageVersion(moduleUrl = import.meta.url) {
|
|
12266
12554
|
const pkgPath = join(resolvePackageRoot(moduleUrl), "package.json");
|
|
12267
|
-
const pkg = JSON.parse(
|
|
12555
|
+
const pkg = JSON.parse(readFileSync16(pkgPath, "utf8"));
|
|
12268
12556
|
if (typeof pkg.version !== "string" || !pkg.version.trim()) {
|
|
12269
12557
|
throw new Error(`Missing package.json version at ${pkgPath}`);
|
|
12270
12558
|
}
|
|
@@ -12331,7 +12619,7 @@ function shouldEnforceMemoryCostPackageGuardCli(scope, action) {
|
|
|
12331
12619
|
}
|
|
12332
12620
|
|
|
12333
12621
|
// src/post-restart-unblock.ts
|
|
12334
|
-
import
|
|
12622
|
+
import path64 from "node:path";
|
|
12335
12623
|
function skip(runId, worker, taskId, agentOsId, leaseOwner, reason) {
|
|
12336
12624
|
return { runId, worker, taskId, agentOsId, leaseOwner, action: "skipped", reason };
|
|
12337
12625
|
}
|
|
@@ -12344,7 +12632,7 @@ async function postRestartUnblock(args) {
|
|
|
12344
12632
|
const errors = [];
|
|
12345
12633
|
for (const run of listRunRecords()) {
|
|
12346
12634
|
for (const name of Object.keys(run.workers ?? {})) {
|
|
12347
|
-
const workerPath =
|
|
12635
|
+
const workerPath = path64.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json");
|
|
12348
12636
|
const worker = readJson(workerPath, void 0);
|
|
12349
12637
|
if (!worker) {
|
|
12350
12638
|
skipped.push(skip(run.id, name, "", "", "", "worker.json missing"));
|
|
@@ -12456,9 +12744,9 @@ async function postRestartUnblockCli(args) {
|
|
|
12456
12744
|
}
|
|
12457
12745
|
|
|
12458
12746
|
// src/default-repo-cli.ts
|
|
12459
|
-
import
|
|
12747
|
+
import path65 from "node:path";
|
|
12460
12748
|
import { homedir as homedir14 } from "node:os";
|
|
12461
|
-
var CONFIG_FILE2 =
|
|
12749
|
+
var CONFIG_FILE2 = path65.join(homedir14(), ".kynver", "config.json");
|
|
12462
12750
|
function ensureDefaultRepo(opts) {
|
|
12463
12751
|
const existing = loadUserConfig();
|
|
12464
12752
|
const resolved = resolveDefaultRepo({ ...opts, config: existing });
|
|
@@ -12539,16 +12827,16 @@ function summarizeResolvedDefaultRepo(resolved) {
|
|
|
12539
12827
|
}
|
|
12540
12828
|
|
|
12541
12829
|
// src/doctor/runtime-takeover.ts
|
|
12542
|
-
import
|
|
12830
|
+
import path67 from "node:path";
|
|
12543
12831
|
|
|
12544
12832
|
// src/doctor/runtime-takeover.probes.ts
|
|
12545
|
-
import { accessSync, constants, existsSync as
|
|
12833
|
+
import { accessSync, constants, existsSync as existsSync45, readFileSync as readFileSync17 } from "node:fs";
|
|
12546
12834
|
import { homedir as homedir15 } from "node:os";
|
|
12547
|
-
import
|
|
12548
|
-
import { spawnSync as
|
|
12835
|
+
import path66 from "node:path";
|
|
12836
|
+
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
12549
12837
|
function captureCommand(bin, args) {
|
|
12550
12838
|
try {
|
|
12551
|
-
const res =
|
|
12839
|
+
const res = spawnSync9(bin, args, { encoding: "utf8" });
|
|
12552
12840
|
const stdout = (res.stdout || "").trim();
|
|
12553
12841
|
const stderr = (res.stderr || "").trim();
|
|
12554
12842
|
const ok = res.status === 0;
|
|
@@ -12573,7 +12861,7 @@ function tokenPrefix(token) {
|
|
|
12573
12861
|
return trimmed.length <= 12 ? `${trimmed}\u2026` : `${trimmed.slice(0, 12)}\u2026`;
|
|
12574
12862
|
}
|
|
12575
12863
|
function isWritable(target) {
|
|
12576
|
-
if (!
|
|
12864
|
+
if (!existsSync45(target)) return false;
|
|
12577
12865
|
try {
|
|
12578
12866
|
accessSync(target, constants.W_OK);
|
|
12579
12867
|
return true;
|
|
@@ -12586,15 +12874,15 @@ var defaultRuntimeTakeoverProbes = {
|
|
|
12586
12874
|
commandOnPath: (bin) => captureCommand(process.platform === "win32" ? "where" : "which", [bin]),
|
|
12587
12875
|
kynverVersion: (bin) => captureCommand(bin, ["--version"]),
|
|
12588
12876
|
loadConfig: () => loadUserConfig(),
|
|
12589
|
-
configFilePath: () =>
|
|
12590
|
-
credentialsFilePath: () =>
|
|
12877
|
+
configFilePath: () => path66.join(homedir15(), ".kynver", "config.json"),
|
|
12878
|
+
credentialsFilePath: () => path66.join(homedir15(), ".kynver", "credentials"),
|
|
12591
12879
|
readCredentials: () => {
|
|
12592
|
-
const credPath =
|
|
12593
|
-
if (!
|
|
12880
|
+
const credPath = path66.join(homedir15(), ".kynver", "credentials");
|
|
12881
|
+
if (!existsSync45(credPath)) {
|
|
12594
12882
|
return { hasApiKey: false };
|
|
12595
12883
|
}
|
|
12596
12884
|
try {
|
|
12597
|
-
const parsed = JSON.parse(
|
|
12885
|
+
const parsed = JSON.parse(readFileSync17(credPath, "utf8"));
|
|
12598
12886
|
return {
|
|
12599
12887
|
hasApiKey: Boolean(parsed.apiKey?.trim()),
|
|
12600
12888
|
runnerTokenPrefix: tokenPrefix(parsed.runnerToken),
|
|
@@ -12624,8 +12912,8 @@ var defaultRuntimeTakeoverProbes = {
|
|
|
12624
12912
|
})()
|
|
12625
12913
|
}),
|
|
12626
12914
|
harnessRoot: () => resolveHarnessRoot(),
|
|
12627
|
-
legacyOpenclawHarnessRoot: () =>
|
|
12628
|
-
pathExists: (target) =>
|
|
12915
|
+
legacyOpenclawHarnessRoot: () => path66.join(homedir15(), ".openclaw", "harness"),
|
|
12916
|
+
pathExists: (target) => existsSync45(target),
|
|
12629
12917
|
pathWritable: (target) => isWritable(target)
|
|
12630
12918
|
};
|
|
12631
12919
|
|
|
@@ -13031,8 +13319,8 @@ function assessVercelDeployEvidence(probes) {
|
|
|
13031
13319
|
}
|
|
13032
13320
|
function assessHarnessDirs(probes) {
|
|
13033
13321
|
const harnessRoot = probes.harnessRoot();
|
|
13034
|
-
const runsDir =
|
|
13035
|
-
const worktreesDir =
|
|
13322
|
+
const runsDir = path67.join(harnessRoot, "runs");
|
|
13323
|
+
const worktreesDir = path67.join(harnessRoot, "worktrees");
|
|
13036
13324
|
const displayHarnessRoot = redactHomePath(harnessRoot);
|
|
13037
13325
|
const displayRunsDir = redactHomePath(runsDir);
|
|
13038
13326
|
const displayWorktreesDir = redactHomePath(worktreesDir);
|
|
@@ -13296,9 +13584,9 @@ function applySchedulerCutoverAttestation(config) {
|
|
|
13296
13584
|
}
|
|
13297
13585
|
|
|
13298
13586
|
// src/scheduler-cutover-cli.ts
|
|
13299
|
-
import
|
|
13587
|
+
import path68 from "node:path";
|
|
13300
13588
|
import { homedir as homedir16 } from "node:os";
|
|
13301
|
-
var CONFIG_FILE3 =
|
|
13589
|
+
var CONFIG_FILE3 = path68.join(homedir16(), ".kynver", "config.json");
|
|
13302
13590
|
function runSchedulerCutoverCheckCli(json = false) {
|
|
13303
13591
|
const config = loadUserConfig();
|
|
13304
13592
|
const report = assessSchedulerCutover(config);
|
|
@@ -13510,8 +13798,8 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
13510
13798
|
if (action && isHelpFlag(action) || rest.some(isHelpFlag)) return usage(0);
|
|
13511
13799
|
const args = parseArgs(rest);
|
|
13512
13800
|
const { runsDir, worktreesDir } = getPaths();
|
|
13513
|
-
|
|
13514
|
-
|
|
13801
|
+
mkdirSync10(runsDir, { recursive: true });
|
|
13802
|
+
mkdirSync10(worktreesDir, { recursive: true });
|
|
13515
13803
|
if (shouldEnforceMemoryCostPackageGuardCli(scope, action)) {
|
|
13516
13804
|
let repoRoot;
|
|
13517
13805
|
const runId = args.run ? String(args.run).trim() : "";
|