@kynver-app/runtime 0.1.93 → 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 +752 -420
- package/dist/cli.js.map +4 -4
- package/dist/doctor/runtime-takeover.probes.d.ts +0 -2
- 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 +1005 -629
- package/dist/index.js.map +4 -4
- package/dist/installed-package-versions.d.ts +2 -0
- package/dist/resource-gate.d.ts +7 -0
- package/dist/vercel/index.d.ts +2 -1
- package/dist/vercel/vercel-api.d.ts +17 -0
- package/dist/vercel/vercel-evidence.d.ts +15 -15
- package/dist/vercel/vercel-url.d.ts +3 -3
- 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
|
|
|
@@ -315,7 +315,13 @@ function displayUserPath(value) {
|
|
|
315
315
|
}
|
|
316
316
|
|
|
317
317
|
// src/default-repo-discovery.ts
|
|
318
|
-
var WELL_KNOWN_REPO_DIRS = [
|
|
318
|
+
var WELL_KNOWN_REPO_DIRS = [
|
|
319
|
+
"Kynver",
|
|
320
|
+
"repos/Kynver",
|
|
321
|
+
"repos/kynver-source-main",
|
|
322
|
+
"code/Kynver",
|
|
323
|
+
"projects/Kynver"
|
|
324
|
+
];
|
|
319
325
|
function readPackageName(repoRoot) {
|
|
320
326
|
const pkgPath = path3.join(repoRoot, "package.json");
|
|
321
327
|
if (!existsSync2(pkgPath)) return null;
|
|
@@ -455,6 +461,7 @@ function readMemAvailableBytes(meminfoText) {
|
|
|
455
461
|
|
|
456
462
|
// src/resource-gate.ts
|
|
457
463
|
import path7 from "node:path";
|
|
464
|
+
import { readFileSync as readFileSync7 } from "node:fs";
|
|
458
465
|
|
|
459
466
|
// src/disk-gate.ts
|
|
460
467
|
import { statfsSync as statfsSync2 } from "node:fs";
|
|
@@ -479,23 +486,23 @@ function isWslHost() {
|
|
|
479
486
|
function observeWslHostDisk(options = {}) {
|
|
480
487
|
const wsl = options.forceWsl === void 0 ? isWslHost() : options.forceWsl;
|
|
481
488
|
if (!wsl) return null;
|
|
482
|
-
const
|
|
489
|
+
const path69 = options.wslHostMount?.trim() || process.env.KYNVER_WSL_HOST_MOUNT?.trim() || DEFAULT_WSL_HOST_MOUNT;
|
|
483
490
|
const warnBelowBytes = options.wslHostFreeWarnBytes ?? DEFAULT_WSL_HOST_WARN_FREE_BYTES;
|
|
484
491
|
const criticalBelowBytes = options.wslHostFreeCriticalBytes ?? DEFAULT_WSL_HOST_CRITICAL_FREE_BYTES;
|
|
485
492
|
const statfs = options.statfs ?? statfsSync;
|
|
486
493
|
let stats;
|
|
487
494
|
try {
|
|
488
|
-
stats = statfs(
|
|
495
|
+
stats = statfs(path69);
|
|
489
496
|
} catch (error) {
|
|
490
497
|
return {
|
|
491
498
|
ok: false,
|
|
492
|
-
path:
|
|
499
|
+
path: path69,
|
|
493
500
|
freeBytes: 0,
|
|
494
501
|
totalBytes: 0,
|
|
495
502
|
usedPercent: 100,
|
|
496
503
|
warnBelowBytes,
|
|
497
504
|
criticalBelowBytes,
|
|
498
|
-
reason: `Windows host disk probe failed at ${
|
|
505
|
+
reason: `Windows host disk probe failed at ${path69}: ${error.message}`,
|
|
499
506
|
probeError: error.message
|
|
500
507
|
};
|
|
501
508
|
}
|
|
@@ -509,11 +516,11 @@ function observeWslHostDisk(options = {}) {
|
|
|
509
516
|
let reason = null;
|
|
510
517
|
if (!ok) {
|
|
511
518
|
const tag = criticalFree ? "critical" : "warning";
|
|
512
|
-
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()}`;
|
|
513
520
|
}
|
|
514
521
|
return {
|
|
515
522
|
ok,
|
|
516
|
-
path:
|
|
523
|
+
path: path69,
|
|
517
524
|
freeBytes,
|
|
518
525
|
totalBytes,
|
|
519
526
|
usedPercent,
|
|
@@ -533,12 +540,12 @@ var DEFAULT_CRITICAL_FREE_BYTES = 15 * 1024 * 1024 * 1024;
|
|
|
533
540
|
var DEFAULT_MAX_USED_PERCENT = 80;
|
|
534
541
|
var DEFAULT_HARD_MAX_USED_PERCENT = 90;
|
|
535
542
|
function observeRunnerDiskGate(input = {}) {
|
|
536
|
-
const
|
|
543
|
+
const path69 = input.diskPath?.trim() || "/";
|
|
537
544
|
const warnBelowBytes = input.diskFreeWarnBytes ?? DEFAULT_WARN_FREE_BYTES;
|
|
538
545
|
const criticalBelowBytes = input.diskFreeCriticalBytes ?? DEFAULT_CRITICAL_FREE_BYTES;
|
|
539
546
|
const maxUsedPercent = input.diskMaxUsedPercent ?? DEFAULT_MAX_USED_PERCENT;
|
|
540
547
|
const hardMaxUsedPercent = input.diskHardMaxUsedPercent ?? DEFAULT_HARD_MAX_USED_PERCENT;
|
|
541
|
-
const stats = statfsSync2(
|
|
548
|
+
const stats = statfsSync2(path69);
|
|
542
549
|
const freeBytes = Number(stats.bavail) * Number(stats.bsize);
|
|
543
550
|
const totalBytes = Number(stats.blocks) * Number(stats.bsize);
|
|
544
551
|
const usedPercent = totalBytes > 0 ? (totalBytes - freeBytes) / totalBytes * 100 : 100;
|
|
@@ -561,7 +568,7 @@ function observeRunnerDiskGate(input = {}) {
|
|
|
561
568
|
}
|
|
562
569
|
return {
|
|
563
570
|
ok,
|
|
564
|
-
path:
|
|
571
|
+
path: path69,
|
|
565
572
|
freeBytes,
|
|
566
573
|
totalBytes,
|
|
567
574
|
usedPercent,
|
|
@@ -1985,11 +1992,29 @@ function computeAutoMaxWorkers(totalMemBytes, opts = {}) {
|
|
|
1985
1992
|
function readAvailableMemBytes() {
|
|
1986
1993
|
return readMemAvailableBytes();
|
|
1987
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
|
+
}
|
|
1988
2012
|
function isActiveHarnessWorker(worker) {
|
|
1989
2013
|
if (typeof worker.completionBlocker === "string" && worker.completionBlocker.trim()) {
|
|
1990
2014
|
return false;
|
|
1991
2015
|
}
|
|
1992
2016
|
const status = computeWorkerStatus(worker);
|
|
2017
|
+
if (status.alive && !workerProcessMatchesRecord(worker)) return false;
|
|
1993
2018
|
return status.alive && !status.finalResult && status.attention.state !== "done";
|
|
1994
2019
|
}
|
|
1995
2020
|
function countActiveWorkersForRun(run) {
|
|
@@ -2140,7 +2165,7 @@ var CREDENTIALS_FILE = path8.join(CONFIG_DIR, "credentials");
|
|
|
2140
2165
|
function loadUserConfig() {
|
|
2141
2166
|
if (!existsSync9(CONFIG_FILE)) return {};
|
|
2142
2167
|
try {
|
|
2143
|
-
return JSON.parse(
|
|
2168
|
+
return JSON.parse(readFileSync8(CONFIG_FILE, "utf8"));
|
|
2144
2169
|
} catch {
|
|
2145
2170
|
return {};
|
|
2146
2171
|
}
|
|
@@ -2217,7 +2242,7 @@ function resolveSetupWorkerConfig(existing, args, totalMemBytes = totalmem()) {
|
|
|
2217
2242
|
function loadCredentialsFile() {
|
|
2218
2243
|
if (!existsSync9(CREDENTIALS_FILE)) return {};
|
|
2219
2244
|
try {
|
|
2220
|
-
return JSON.parse(
|
|
2245
|
+
return JSON.parse(readFileSync8(CREDENTIALS_FILE, "utf8"));
|
|
2221
2246
|
} catch {
|
|
2222
2247
|
return {};
|
|
2223
2248
|
}
|
|
@@ -2487,15 +2512,30 @@ async function withTimeout(fn) {
|
|
|
2487
2512
|
clearTimeout(timeout);
|
|
2488
2513
|
}
|
|
2489
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
|
+
}
|
|
2490
2525
|
async function postJson(url, secret, body) {
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
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
|
+
}
|
|
2499
2539
|
let response = null;
|
|
2500
2540
|
try {
|
|
2501
2541
|
response = await res.json();
|
|
@@ -2513,13 +2553,18 @@ async function postJsonWithCredentialRefresh(url, secret, body, opts) {
|
|
|
2513
2553
|
return { ...retry, refreshedAuth: true };
|
|
2514
2554
|
}
|
|
2515
2555
|
async function getJson(url, secret) {
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
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
|
+
}
|
|
2523
2568
|
let response = null;
|
|
2524
2569
|
try {
|
|
2525
2570
|
response = await res.json();
|
|
@@ -2529,41 +2574,6 @@ async function getJson(url, secret) {
|
|
|
2529
2574
|
return { ok: res.ok, status: res.status, response };
|
|
2530
2575
|
}
|
|
2531
2576
|
|
|
2532
|
-
// src/dispatch-lane-normalization.ts
|
|
2533
|
-
function trimLower(value) {
|
|
2534
|
-
return (value ?? "").trim().toLowerCase();
|
|
2535
|
-
}
|
|
2536
|
-
function roleLaneToDispatchLane(roleLane) {
|
|
2537
|
-
switch (trimLower(roleLane)) {
|
|
2538
|
-
case "implementer":
|
|
2539
|
-
case "repair_implementer":
|
|
2540
|
-
case "plan_author":
|
|
2541
|
-
case "runtime_verifier":
|
|
2542
|
-
return "implementation";
|
|
2543
|
-
case "plan_reviewer":
|
|
2544
|
-
case "report_reviewer":
|
|
2545
|
-
case "deep_reviewer":
|
|
2546
|
-
return "review";
|
|
2547
|
-
default:
|
|
2548
|
-
return null;
|
|
2549
|
-
}
|
|
2550
|
-
}
|
|
2551
|
-
function normalizeDispatchNextLaneFilter(raw) {
|
|
2552
|
-
const key = trimLower(raw);
|
|
2553
|
-
if (!key) return void 0;
|
|
2554
|
-
if (key === "implementation" || key === "review" || key === "landing" || key === "any") {
|
|
2555
|
-
return key;
|
|
2556
|
-
}
|
|
2557
|
-
const mapped = roleLaneToDispatchLane(key);
|
|
2558
|
-
if (mapped) return mapped;
|
|
2559
|
-
if (key === "implement" || key === "repair" || key === "coding") return "implementation";
|
|
2560
|
-
if (key === "land" || key === "merge") return "landing";
|
|
2561
|
-
return void 0;
|
|
2562
|
-
}
|
|
2563
|
-
function resolveDispatchNextLaneFilter(raw) {
|
|
2564
|
-
return normalizeDispatchNextLaneFilter(raw) ?? "any";
|
|
2565
|
-
}
|
|
2566
|
-
|
|
2567
2577
|
// src/worker-persona-catalog.ts
|
|
2568
2578
|
var WORKER_PERSONA_CATALOG = [
|
|
2569
2579
|
{
|
|
@@ -2666,6 +2676,41 @@ function workerPersonaReviewSlugs() {
|
|
|
2666
2676
|
);
|
|
2667
2677
|
}
|
|
2668
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
|
+
|
|
2669
2714
|
// src/model-routing-task-enrich.ts
|
|
2670
2715
|
function taskString(task, key) {
|
|
2671
2716
|
const v = task[key];
|
|
@@ -3123,7 +3168,7 @@ function probeCursorOAuthBinding(nowIso = (/* @__PURE__ */ new Date()).toISOStri
|
|
|
3123
3168
|
}
|
|
3124
3169
|
|
|
3125
3170
|
// src/orchestration-providers/hermes-cli-adapter.ts
|
|
3126
|
-
import { existsSync as existsSync14, readFileSync as
|
|
3171
|
+
import { existsSync as existsSync14, readFileSync as readFileSync9 } from "node:fs";
|
|
3127
3172
|
import { homedir as homedir9 } from "node:os";
|
|
3128
3173
|
import path13 from "node:path";
|
|
3129
3174
|
var PROFILE_ENV_KEYS = [
|
|
@@ -3139,7 +3184,7 @@ function hermesProfileEnvPath() {
|
|
|
3139
3184
|
}
|
|
3140
3185
|
function profileEnvKeyPresence(envPath) {
|
|
3141
3186
|
try {
|
|
3142
|
-
const text =
|
|
3187
|
+
const text = readFileSync9(envPath, "utf8");
|
|
3143
3188
|
const present = [];
|
|
3144
3189
|
for (const key of PROFILE_ENV_KEYS) {
|
|
3145
3190
|
const re = new RegExp(`^${key}=`, "m");
|
|
@@ -4069,14 +4114,15 @@ function buildPrompt(input) {
|
|
|
4069
4114
|
input.planId ? `Active planId: ${input.planId}${input.taskId ? ` \xB7 taskId: ${input.taskId}` : ""}` : "No planId on this worker \u2014 still emit progress when you touch plan-scoped work."
|
|
4070
4115
|
];
|
|
4071
4116
|
const mergeGateLines = compact ? [
|
|
4072
|
-
"Merge-gate cost control: do not use Vercel previews/builds for PR verification. Run `node scripts/agent-os-pr-merge-gate.mjs --pr <url> --agent-os-id <id>` (or `verify-pr-local.mjs --from-pr` + POST pr-merge-gate/refresh) before any GitHub Actions run; request merge-gate only via refresh then POST pr-merge-gate/request-run (one Actions run per PR head unless human approves extra)."
|
|
4117
|
+
"Merge-gate cost control: do not use Vercel previews/builds for PR verification. Run `node scripts/agent-os-pr-merge-gate.mjs --pr <url> --agent-os-id <id>` (or `verify-pr-local.mjs --from-pr` + POST pr-merge-gate/refresh) before any GitHub Actions run; request merge-gate only via refresh then POST pr-merge-gate/request-run (one Actions run per PR head unless human approves extra). Per-PR Vercel preview builds are off by default \u2014 production deploy runs via release batch after merge."
|
|
4073
4118
|
] : [
|
|
4074
4119
|
"GitHub Actions merge-gate cost control (Kynver/Hermes PRs):",
|
|
4075
4120
|
"- Prefer local cached package verification (`node scripts/verify-pr-local.mjs --emit-json`) before GitHub Actions. Do not use Vercel previews/builds as PR evidence.",
|
|
4076
4121
|
"- Do not push empty commits to re-trigger CI. One budgeted merge-gate Actions run per PR candidate (head SHA) unless a human approves extra.",
|
|
4077
4122
|
"- Record evidence: POST `/api/agent-os/by-id/<agentOsId>/pr-merge-gate/refresh` with prUrl + local payloads.",
|
|
4078
4123
|
"- Request the final Actions run only when local verification is green: POST `.../pr-merge-gate/request-run` (applies `merge-gate` label).",
|
|
4079
|
-
"- Empty failed Actions jobs (no runner/steps/logs) are infra/quota \u2014 do not enter repair loops; escalate to operator."
|
|
4124
|
+
"- Empty failed Actions jobs (no runner/steps/logs) are infra/quota \u2014 do not enter repair loops; escalate to operator.",
|
|
4125
|
+
"- After merge, landed PRs accumulate into a release batch; run batch verification then manual Vercel production deploy from Command Center (release train). PR landing completes with: verification complete, awaiting release batch/deploy."
|
|
4080
4126
|
];
|
|
4081
4127
|
const planArtifactLines = compact ? [
|
|
4082
4128
|
"Plan artifacts: when authoring/revising docs/superpowers/plans/, open a GitHub PR early and iterate from that PR branch; do not leave the canonical plan only in the harness worktree."
|
|
@@ -4099,7 +4145,7 @@ function buildPrompt(input) {
|
|
|
4099
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.",
|
|
4100
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.",
|
|
4101
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.",
|
|
4102
|
-
"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.",
|
|
4103
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.",
|
|
4104
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.",
|
|
4105
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.",
|
|
@@ -4975,8 +5021,8 @@ function dirtyPathsCoveredByDisposableRemoval(changedFiles, removed) {
|
|
|
4975
5021
|
if (removed.length === 0) return false;
|
|
4976
5022
|
const removedSet = new Set(removed.map((p) => normalizeRelativePath(p)));
|
|
4977
5023
|
return material.every((line) => {
|
|
4978
|
-
const
|
|
4979
|
-
return removedSet.has(
|
|
5024
|
+
const path69 = normalizeRelativePath(pathFromGitStatusLine(line));
|
|
5025
|
+
return removedSet.has(path69);
|
|
4980
5026
|
});
|
|
4981
5027
|
}
|
|
4982
5028
|
|
|
@@ -6270,7 +6316,7 @@ function collectRunActiveHarnessWorkers(runId) {
|
|
|
6270
6316
|
path22.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
|
|
6271
6317
|
void 0
|
|
6272
6318
|
);
|
|
6273
|
-
if (!worker?.taskId || !
|
|
6319
|
+
if (!worker?.taskId || !workerProcessMatchesRecord(worker)) continue;
|
|
6274
6320
|
out.push({
|
|
6275
6321
|
runId: run.id,
|
|
6276
6322
|
workerName: name,
|
|
@@ -6509,7 +6555,7 @@ function isTmpOnlyPath(filePath) {
|
|
|
6509
6555
|
// src/plan-persist/outbox-store.ts
|
|
6510
6556
|
import {
|
|
6511
6557
|
existsSync as existsSync21,
|
|
6512
|
-
readFileSync as
|
|
6558
|
+
readFileSync as readFileSync10,
|
|
6513
6559
|
renameSync,
|
|
6514
6560
|
readdirSync as readdirSync5,
|
|
6515
6561
|
writeFileSync as writeFileSync3,
|
|
@@ -6537,7 +6583,7 @@ function findOutboxByIdempotencyKey(key) {
|
|
|
6537
6583
|
function readOutboxItem(jsonPath) {
|
|
6538
6584
|
if (!existsSync21(jsonPath)) return null;
|
|
6539
6585
|
try {
|
|
6540
|
-
return JSON.parse(
|
|
6586
|
+
return JSON.parse(readFileSync10(jsonPath, "utf8"));
|
|
6541
6587
|
} catch {
|
|
6542
6588
|
return null;
|
|
6543
6589
|
}
|
|
@@ -6545,7 +6591,7 @@ function readOutboxItem(jsonPath) {
|
|
|
6545
6591
|
function readOutboxBody(item) {
|
|
6546
6592
|
const { outboxDir } = ensurePlanOutboxDirs();
|
|
6547
6593
|
const bodyFile = path24.join(outboxDir, item.bodyPath);
|
|
6548
|
-
return
|
|
6594
|
+
return readFileSync10(bodyFile, "utf8");
|
|
6549
6595
|
}
|
|
6550
6596
|
function writeOutboxItem(input, opts) {
|
|
6551
6597
|
const { outboxDir } = ensurePlanOutboxDirs();
|
|
@@ -7027,7 +7073,7 @@ async function dispatchRun(args) {
|
|
|
7027
7073
|
runnerPresence,
|
|
7028
7074
|
harnessBoardSnapshot: buildRunBoard(run.id),
|
|
7029
7075
|
...args.lane ? { lane: resolveDispatchNextLaneFilter(String(args.lane)) } : {},
|
|
7030
|
-
|
|
7076
|
+
...args.executor ? { executor: String(args.executor) } : {},
|
|
7031
7077
|
...args.diskPath ? { diskPath: String(args.diskPath) } : {},
|
|
7032
7078
|
...args.targetTaskId ? { targetTaskId: String(args.targetTaskId) } : {},
|
|
7033
7079
|
...!args.targetTaskId && args.targetTaskIds ? {
|
|
@@ -7366,7 +7412,7 @@ import { existsSync as existsSync25, mkdirSync as mkdirSync6 } from "node:fs";
|
|
|
7366
7412
|
import path34 from "node:path";
|
|
7367
7413
|
|
|
7368
7414
|
// src/run-list.ts
|
|
7369
|
-
import { existsSync as existsSync24, readFileSync as
|
|
7415
|
+
import { existsSync as existsSync24, readFileSync as readFileSync11 } from "node:fs";
|
|
7370
7416
|
import path33 from "node:path";
|
|
7371
7417
|
|
|
7372
7418
|
// src/stale-reconcile.ts
|
|
@@ -8085,7 +8131,7 @@ function reconcileRunsCli() {
|
|
|
8085
8131
|
function heartbeatByteLength(heartbeatPath) {
|
|
8086
8132
|
if (!heartbeatPath || !existsSync24(heartbeatPath)) return 0;
|
|
8087
8133
|
try {
|
|
8088
|
-
return
|
|
8134
|
+
return readFileSync11(heartbeatPath, "utf8").trim().length;
|
|
8089
8135
|
} catch {
|
|
8090
8136
|
return 0;
|
|
8091
8137
|
}
|
|
@@ -8420,12 +8466,12 @@ async function fireKynverCronJob(input) {
|
|
|
8420
8466
|
}
|
|
8421
8467
|
|
|
8422
8468
|
// src/cron/cron-lock.ts
|
|
8423
|
-
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";
|
|
8424
8470
|
var STALE_LOCK_MS = 10 * 6e4;
|
|
8425
8471
|
function readLockInfo(lockPath) {
|
|
8426
8472
|
if (!existsSync28(lockPath)) return null;
|
|
8427
8473
|
try {
|
|
8428
|
-
const parsed = JSON.parse(
|
|
8474
|
+
const parsed = JSON.parse(readFileSync12(lockPath, "utf8"));
|
|
8429
8475
|
if (typeof parsed.pid === "number" && typeof parsed.at === "string") return parsed;
|
|
8430
8476
|
} catch {
|
|
8431
8477
|
return null;
|
|
@@ -8793,7 +8839,7 @@ async function runKynverCronTick(opts = {}) {
|
|
|
8793
8839
|
}
|
|
8794
8840
|
|
|
8795
8841
|
// src/pipeline-tick.ts
|
|
8796
|
-
import
|
|
8842
|
+
import path55 from "node:path";
|
|
8797
8843
|
|
|
8798
8844
|
// src/pipeline-dispatch.ts
|
|
8799
8845
|
var RESERVED_REVIEW_STARTS = 1;
|
|
@@ -9201,11 +9247,11 @@ var LIVE_SKIP_REASONS = /* @__PURE__ */ new Set([
|
|
|
9201
9247
|
function collectPreservedLivePaths(actions, skips) {
|
|
9202
9248
|
const out = [];
|
|
9203
9249
|
const seen = /* @__PURE__ */ new Set();
|
|
9204
|
-
const push = (
|
|
9205
|
-
const key = `${
|
|
9250
|
+
const push = (path69, reason, detail) => {
|
|
9251
|
+
const key = `${path69}\0${reason}`;
|
|
9206
9252
|
if (seen.has(key) || out.length >= MAX_PRESERVED_LIVE_PATH_SAMPLES) return;
|
|
9207
9253
|
seen.add(key);
|
|
9208
|
-
out.push({ path:
|
|
9254
|
+
out.push({ path: path69, reason, ...detail ? { detail } : {} });
|
|
9209
9255
|
};
|
|
9210
9256
|
for (const skip2 of skips) {
|
|
9211
9257
|
if (!LIVE_SKIP_REASONS.has(skip2.reason)) continue;
|
|
@@ -10683,93 +10729,293 @@ function isPipelineCleanupEnabled() {
|
|
|
10683
10729
|
// src/installed-package-versions.ts
|
|
10684
10730
|
import { readFile } from "node:fs/promises";
|
|
10685
10731
|
import { homedir as homedir13 } from "node:os";
|
|
10732
|
+
import path54 from "node:path";
|
|
10733
|
+
|
|
10734
|
+
// src/memory-cost-package-version-guard.ts
|
|
10735
|
+
import { existsSync as existsSync40, readFileSync as readFileSync13 } from "node:fs";
|
|
10686
10736
|
import path53 from "node:path";
|
|
10687
|
-
var
|
|
10688
|
-
"@kynver-app/runtime",
|
|
10689
|
-
"@kynver-app/openclaw-agent-os",
|
|
10690
|
-
"@kynver-app/mcp-agent-os"
|
|
10691
|
-
|
|
10692
|
-
|
|
10693
|
-
|
|
10694
|
-
|
|
10737
|
+
var MEMORY_COST_PACKAGE_MIN_VERSIONS = {
|
|
10738
|
+
"@kynver-app/runtime": "0.1.83",
|
|
10739
|
+
"@kynver-app/openclaw-agent-os": "0.1.43",
|
|
10740
|
+
"@kynver-app/mcp-agent-os": "0.3.34"
|
|
10741
|
+
};
|
|
10742
|
+
var MEMORY_COST_MANAGED_PACKAGES = Object.keys(
|
|
10743
|
+
MEMORY_COST_PACKAGE_MIN_VERSIONS
|
|
10744
|
+
);
|
|
10745
|
+
var DISPLAY_NAMES = {
|
|
10746
|
+
"@kynver-app/runtime": "Kynver runtime",
|
|
10747
|
+
"@kynver-app/openclaw-agent-os": "OpenClaw AgentOS plugin",
|
|
10748
|
+
"@kynver-app/mcp-agent-os": "AgentOS MCP server"
|
|
10749
|
+
};
|
|
10750
|
+
var REPO_PACKAGE_JSON_RELATIVE = {
|
|
10751
|
+
"@kynver-app/runtime": "packages/kynver-runtime/package.json",
|
|
10752
|
+
"@kynver-app/openclaw-agent-os": "packages/kynver-openclaw-agent-os/package.json",
|
|
10753
|
+
"@kynver-app/mcp-agent-os": "packages/kynver-mcp-agent-os/package.json"
|
|
10754
|
+
};
|
|
10755
|
+
function parseSemverParts(version) {
|
|
10756
|
+
const core = version.trim().split("-")[0]?.split("+")[0];
|
|
10757
|
+
if (!core) return null;
|
|
10758
|
+
const parts = core.split(".");
|
|
10759
|
+
if (parts.length < 1 || parts.length > 3) return null;
|
|
10760
|
+
const nums = parts.map((p) => Number.parseInt(p, 10));
|
|
10761
|
+
if (nums.some((n) => !Number.isFinite(n) || n < 0)) return null;
|
|
10762
|
+
while (nums.length < 3) nums.push(0);
|
|
10763
|
+
return [nums[0], nums[1], nums[2]];
|
|
10695
10764
|
}
|
|
10696
|
-
function
|
|
10697
|
-
|
|
10765
|
+
function compareSemver(a, b) {
|
|
10766
|
+
const pa = parseSemverParts(a);
|
|
10767
|
+
const pb = parseSemverParts(b);
|
|
10768
|
+
if (!pa || !pb) return 0;
|
|
10769
|
+
for (let i = 0; i < 3; i += 1) {
|
|
10770
|
+
if (pa[i] > pb[i]) return 1;
|
|
10771
|
+
if (pa[i] < pb[i]) return -1;
|
|
10772
|
+
}
|
|
10773
|
+
return 0;
|
|
10698
10774
|
}
|
|
10699
|
-
function
|
|
10700
|
-
|
|
10701
|
-
const openClawPrefix = trim(process.env.KYNVER_OPENCLAW_NPM_ROOT) ?? trim(process.env.OPENCLAW_NPM_ROOT) ?? path53.join(home, ".openclaw", "npm");
|
|
10702
|
-
const npmGlobalRoot = trim(process.env.KYNVER_NPM_GLOBAL_ROOT) ?? trim(process.env.KYNVER_NPM_GLOBAL_MODULES_ROOT) ?? (trim(process.env.NPM_CONFIG_PREFIX) ? path53.join(trim(process.env.NPM_CONFIG_PREFIX), "lib", "node_modules") : path53.join(home, ".npm-global", "lib", "node_modules"));
|
|
10703
|
-
return unique([
|
|
10704
|
-
path53.join(openClawPrefix, "lib", "node_modules"),
|
|
10705
|
-
path53.join(openClawPrefix, "node_modules"),
|
|
10706
|
-
npmGlobalRoot.endsWith("node_modules") ? npmGlobalRoot : path53.join(npmGlobalRoot, "lib", "node_modules")
|
|
10707
|
-
]);
|
|
10775
|
+
function semverAtLeast(version, minimum) {
|
|
10776
|
+
return compareSemver(version, minimum) >= 0;
|
|
10708
10777
|
}
|
|
10709
|
-
|
|
10778
|
+
function maxSemver(versions) {
|
|
10779
|
+
let best = null;
|
|
10780
|
+
for (const version of versions) {
|
|
10781
|
+
if (!best || compareSemver(version, best) > 0) best = version;
|
|
10782
|
+
}
|
|
10783
|
+
return best;
|
|
10784
|
+
}
|
|
10785
|
+
function readPackageJsonVersion(packageJsonPath) {
|
|
10710
10786
|
try {
|
|
10711
|
-
const parsed = JSON.parse(
|
|
10787
|
+
const parsed = JSON.parse(readFileSync13(packageJsonPath, "utf8"));
|
|
10712
10788
|
return typeof parsed.version === "string" && parsed.version.trim() ? parsed.version.trim() : null;
|
|
10713
10789
|
} catch {
|
|
10714
10790
|
return null;
|
|
10715
10791
|
}
|
|
10716
10792
|
}
|
|
10717
|
-
|
|
10718
|
-
const
|
|
10719
|
-
|
|
10720
|
-
|
|
10721
|
-
|
|
10722
|
-
|
|
10723
|
-
|
|
10724
|
-
|
|
10725
|
-
out[packageName] = { version, observedAt, path: packageJsonPath };
|
|
10726
|
-
break;
|
|
10793
|
+
function resolveRepoRoot(cwd, explicitRepoRoot) {
|
|
10794
|
+
const candidates = [explicitRepoRoot, process.env.KYNVER_REPO, cwd].filter(
|
|
10795
|
+
(value) => Boolean(value?.trim())
|
|
10796
|
+
);
|
|
10797
|
+
for (const candidate of candidates) {
|
|
10798
|
+
const resolved = path53.resolve(candidate);
|
|
10799
|
+
if (existsSync40(path53.join(resolved, "packages/kynver-runtime/package.json")) && existsSync40(path53.join(resolved, "package.json"))) {
|
|
10800
|
+
return resolved;
|
|
10727
10801
|
}
|
|
10728
10802
|
}
|
|
10803
|
+
const discovered = discoverDefaultRepo({ cwd });
|
|
10804
|
+
return discovered?.repo ?? null;
|
|
10805
|
+
}
|
|
10806
|
+
function probeRepoPackageVersions(input = {}) {
|
|
10807
|
+
const cwd = input.cwd ?? process.cwd();
|
|
10808
|
+
const repoRoot = resolveRepoRoot(cwd, input.repoRoot);
|
|
10809
|
+
if (!repoRoot) return {};
|
|
10810
|
+
const out = {};
|
|
10811
|
+
for (const packageName of MEMORY_COST_MANAGED_PACKAGES) {
|
|
10812
|
+
const packageJsonPath = path53.join(repoRoot, REPO_PACKAGE_JSON_RELATIVE[packageName]);
|
|
10813
|
+
const version = readPackageJsonVersion(packageJsonPath);
|
|
10814
|
+
if (!version) continue;
|
|
10815
|
+
out[packageName] = { version, source: "repo", path: packageJsonPath };
|
|
10816
|
+
}
|
|
10729
10817
|
return out;
|
|
10730
10818
|
}
|
|
10731
|
-
|
|
10732
|
-
|
|
10733
|
-
|
|
10734
|
-
|
|
10735
|
-
|
|
10736
|
-
|
|
10737
|
-
|
|
10738
|
-
|
|
10739
|
-
|
|
10819
|
+
function repoSourceCommands(packageName) {
|
|
10820
|
+
if (packageName === "@kynver-app/runtime") {
|
|
10821
|
+
return ["npm run kynver:build", "npm run kynver"];
|
|
10822
|
+
}
|
|
10823
|
+
return [`npm run build -w ${packageName}`];
|
|
10824
|
+
}
|
|
10825
|
+
function buildRemediation(input) {
|
|
10826
|
+
const { packageName, minimumVersion, effectiveVersion, effectiveSource, repoVersion } = input;
|
|
10827
|
+
const lines = [];
|
|
10828
|
+
if (repoVersion && semverAtLeast(repoVersion, minimumVersion)) {
|
|
10829
|
+
lines.push(
|
|
10830
|
+
`Use the monorepo checkout (${repoVersion}) instead of a stale npm install: ${repoSourceCommands(packageName).join("; ")}.`
|
|
10740
10831
|
);
|
|
10741
|
-
|
|
10742
|
-
|
|
10743
|
-
outcomes.push({ worker: name, ok: true, taskId: worker.taskId ?? null, skipped: true });
|
|
10744
|
-
continue;
|
|
10745
|
-
}
|
|
10746
|
-
const status = computeWorkerStatus(worker);
|
|
10747
|
-
if (!isFinishedWorkerStatus(status)) continue;
|
|
10748
|
-
const exitedSalvage = assessExitedWorkerSalvage({
|
|
10749
|
-
alive: status.alive,
|
|
10750
|
-
finalResult: status.finalResult,
|
|
10751
|
-
changedFiles: status.changedFiles,
|
|
10752
|
-
gitAncestry: status.gitAncestry
|
|
10753
|
-
});
|
|
10754
|
-
if (!worker.dispatched && !status.finalResult && !exitedSalvage?.salvageable) continue;
|
|
10755
|
-
const result = await tryCompleteWorker({
|
|
10756
|
-
run: runId,
|
|
10757
|
-
name,
|
|
10758
|
-
agentOsId: String(args.agentOsId || worker.agentOsId || ""),
|
|
10759
|
-
...args
|
|
10760
|
-
});
|
|
10761
|
-
outcomes.push({ worker: name, ok: result.ok, taskId: worker.taskId ?? null });
|
|
10832
|
+
lines.push("Do not publish npm packages or wait on an operator release.");
|
|
10833
|
+
return lines;
|
|
10762
10834
|
}
|
|
10763
|
-
|
|
10835
|
+
if (effectiveVersion) {
|
|
10836
|
+
lines.push(
|
|
10837
|
+
`Upgrade ${packageName} from ${effectiveVersion} to >= ${minimumVersion} (npm install -g ${packageName}@latest or align OpenClaw npm prefix).`
|
|
10838
|
+
);
|
|
10839
|
+
} else {
|
|
10840
|
+
lines.push(`Install ${packageName} >= ${minimumVersion} before running memory-heavy AgentOS paths.`);
|
|
10841
|
+
}
|
|
10842
|
+
if (packageName === "@kynver-app/runtime") {
|
|
10843
|
+
lines.push("Repo-source alternative: npm run kynver:build && npm run kynver");
|
|
10844
|
+
}
|
|
10845
|
+
if (effectiveSource === "installed" && repoVersion) {
|
|
10846
|
+
lines.push(`Repo checkout reports ${repoVersion}; rebuild/link repo source if you develop from the monorepo.`);
|
|
10847
|
+
}
|
|
10848
|
+
return lines;
|
|
10764
10849
|
}
|
|
10765
|
-
|
|
10766
|
-
|
|
10767
|
-
const
|
|
10768
|
-
|
|
10769
|
-
const
|
|
10770
|
-
|
|
10771
|
-
|
|
10772
|
-
|
|
10850
|
+
function pickEffectiveCandidate(candidates) {
|
|
10851
|
+
if (candidates.length === 0) return { version: null, source: "unknown" };
|
|
10852
|
+
const best = maxSemver(candidates.map((candidate) => candidate.version));
|
|
10853
|
+
if (!best) return { version: null, source: "unknown" };
|
|
10854
|
+
const winner = candidates.find((candidate) => candidate.version === best) ?? candidates[0];
|
|
10855
|
+
return { version: winner.version, source: winner.source };
|
|
10856
|
+
}
|
|
10857
|
+
function evaluateMemoryCostPackageVersionGuard(input = {}) {
|
|
10858
|
+
const normalize2 = (value, fallbackSource) => {
|
|
10859
|
+
if (!value) return null;
|
|
10860
|
+
if (typeof value === "string") return { version: value, source: fallbackSource };
|
|
10861
|
+
return value;
|
|
10862
|
+
};
|
|
10863
|
+
const packages = MEMORY_COST_MANAGED_PACKAGES.map((packageName) => {
|
|
10864
|
+
const minimumVersion = MEMORY_COST_PACKAGE_MIN_VERSIONS[packageName];
|
|
10865
|
+
const candidates = [];
|
|
10866
|
+
const installed = normalize2(input.installed?.[packageName], "installed");
|
|
10867
|
+
const repo = normalize2(input.repo?.[packageName], "repo");
|
|
10868
|
+
const self = normalize2(input.self?.[packageName], "self");
|
|
10869
|
+
if (installed) candidates.push(installed);
|
|
10870
|
+
if (repo) candidates.push(repo);
|
|
10871
|
+
if (self) candidates.push(self);
|
|
10872
|
+
const { version: effectiveVersion, source: effectiveSource } = pickEffectiveCandidate(candidates);
|
|
10873
|
+
const repoVersion = repo?.version ?? null;
|
|
10874
|
+
const ok2 = effectiveVersion ? semverAtLeast(effectiveVersion, minimumVersion) : false;
|
|
10875
|
+
const remediation = ok2 ? [] : buildRemediation({
|
|
10876
|
+
packageName,
|
|
10877
|
+
minimumVersion,
|
|
10878
|
+
effectiveVersion,
|
|
10879
|
+
effectiveSource,
|
|
10880
|
+
repoVersion
|
|
10881
|
+
});
|
|
10882
|
+
const summary2 = ok2 ? `${DISPLAY_NAMES[packageName]} ${effectiveVersion} meets memory-cost minimum ${minimumVersion} (${effectiveSource}).` : `${DISPLAY_NAMES[packageName]} is below memory-cost minimum ${minimumVersion}` + (effectiveVersion ? ` (effective ${effectiveVersion} via ${effectiveSource})` : " (no version detected)") + ".";
|
|
10883
|
+
return {
|
|
10884
|
+
packageName,
|
|
10885
|
+
displayName: DISPLAY_NAMES[packageName],
|
|
10886
|
+
minimumVersion,
|
|
10887
|
+
effectiveVersion,
|
|
10888
|
+
effectiveSource,
|
|
10889
|
+
ok: ok2,
|
|
10890
|
+
summary: summary2,
|
|
10891
|
+
remediation
|
|
10892
|
+
};
|
|
10893
|
+
});
|
|
10894
|
+
const violations = packages.filter((row) => !row.ok);
|
|
10895
|
+
const ok = violations.length === 0;
|
|
10896
|
+
const summary = ok ? "All managed AgentOS packages meet memory-cost minimum versions." : `Memory-cost package guard blocked ${violations.length} stale package(s): ${violations.map((row) => `${row.packageName} < ${row.minimumVersion}`).join("; ")}.`;
|
|
10897
|
+
return { ok, summary, packages };
|
|
10898
|
+
}
|
|
10899
|
+
var MemoryCostPackageVersionGuardError = class extends Error {
|
|
10900
|
+
result;
|
|
10901
|
+
constructor(result) {
|
|
10902
|
+
const lines = [
|
|
10903
|
+
result.summary,
|
|
10904
|
+
...result.packages.filter((row) => !row.ok).flatMap((row) => [`- ${row.summary}`, ...row.remediation.map((line) => ` \u2192 ${line}`)])
|
|
10905
|
+
];
|
|
10906
|
+
super(lines.join("\n"));
|
|
10907
|
+
this.name = "MemoryCostPackageVersionGuardError";
|
|
10908
|
+
this.result = result;
|
|
10909
|
+
}
|
|
10910
|
+
};
|
|
10911
|
+
function assertMemoryCostPackageVersionGuard(input = {}) {
|
|
10912
|
+
const result = evaluateMemoryCostPackageVersionGuard(input);
|
|
10913
|
+
if (!result.ok) throw new MemoryCostPackageVersionGuardError(result);
|
|
10914
|
+
return result;
|
|
10915
|
+
}
|
|
10916
|
+
|
|
10917
|
+
// src/installed-package-versions.ts
|
|
10918
|
+
var MANAGED_PACKAGES = [
|
|
10919
|
+
"@kynver-app/runtime",
|
|
10920
|
+
"@kynver-app/openclaw-agent-os",
|
|
10921
|
+
"@kynver-app/mcp-agent-os"
|
|
10922
|
+
];
|
|
10923
|
+
function trim(value) {
|
|
10924
|
+
const out = value?.trim();
|
|
10925
|
+
return out ? out : null;
|
|
10926
|
+
}
|
|
10927
|
+
function unique(values) {
|
|
10928
|
+
return [...new Set(values.filter((value) => Boolean(value)))];
|
|
10929
|
+
}
|
|
10930
|
+
function moduleRoots() {
|
|
10931
|
+
const home = homedir13();
|
|
10932
|
+
const openClawPrefix = trim(process.env.KYNVER_OPENCLAW_NPM_ROOT) ?? trim(process.env.OPENCLAW_NPM_ROOT) ?? path54.join(home, ".openclaw", "npm");
|
|
10933
|
+
const npmGlobalRoot = trim(process.env.KYNVER_NPM_GLOBAL_ROOT) ?? trim(process.env.KYNVER_NPM_GLOBAL_MODULES_ROOT) ?? (trim(process.env.NPM_CONFIG_PREFIX) ? path54.join(trim(process.env.NPM_CONFIG_PREFIX), "lib", "node_modules") : path54.join(home, ".npm-global", "lib", "node_modules"));
|
|
10934
|
+
return unique([
|
|
10935
|
+
path54.join(openClawPrefix, "lib", "node_modules"),
|
|
10936
|
+
path54.join(openClawPrefix, "node_modules"),
|
|
10937
|
+
npmGlobalRoot.endsWith("node_modules") ? npmGlobalRoot : path54.join(npmGlobalRoot, "lib", "node_modules")
|
|
10938
|
+
]);
|
|
10939
|
+
}
|
|
10940
|
+
async function readVersion(packageJsonPath) {
|
|
10941
|
+
try {
|
|
10942
|
+
const parsed = JSON.parse(await readFile(packageJsonPath, "utf8"));
|
|
10943
|
+
return typeof parsed.version === "string" && parsed.version.trim() ? parsed.version.trim() : null;
|
|
10944
|
+
} catch {
|
|
10945
|
+
return null;
|
|
10946
|
+
}
|
|
10947
|
+
}
|
|
10948
|
+
function installedPackageJsonCandidates(packageName) {
|
|
10949
|
+
const roots = moduleRoots();
|
|
10950
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10951
|
+
const out = [];
|
|
10952
|
+
for (const root of roots) {
|
|
10953
|
+
const candidate = path54.join(root, packageName, "package.json");
|
|
10954
|
+
if (seen.has(candidate)) continue;
|
|
10955
|
+
seen.add(candidate);
|
|
10956
|
+
out.push(candidate);
|
|
10957
|
+
}
|
|
10958
|
+
return out;
|
|
10959
|
+
}
|
|
10960
|
+
async function collectInstalledPackageVersions(observedAt = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
10961
|
+
const out = {};
|
|
10962
|
+
for (const packageName of MANAGED_PACKAGES) {
|
|
10963
|
+
let best = null;
|
|
10964
|
+
for (const packageJsonPath of installedPackageJsonCandidates(packageName)) {
|
|
10965
|
+
const version = await readVersion(packageJsonPath);
|
|
10966
|
+
if (!version) continue;
|
|
10967
|
+
if (!best || compareSemver(version, best.version) > 0) {
|
|
10968
|
+
best = { version, path: packageJsonPath };
|
|
10969
|
+
}
|
|
10970
|
+
}
|
|
10971
|
+
if (best) {
|
|
10972
|
+
out[packageName] = { version: best.version, observedAt, path: best.path };
|
|
10973
|
+
}
|
|
10974
|
+
}
|
|
10975
|
+
return out;
|
|
10976
|
+
}
|
|
10977
|
+
|
|
10978
|
+
// src/pipeline-tick.ts
|
|
10979
|
+
async function completeFinishedWorkers(runId, args) {
|
|
10980
|
+
const run = loadRun(runId);
|
|
10981
|
+
const outcomes = [];
|
|
10982
|
+
for (const name of Object.keys(run.workers || {})) {
|
|
10983
|
+
const worker = readJson(
|
|
10984
|
+
path55.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
|
|
10985
|
+
void 0
|
|
10986
|
+
);
|
|
10987
|
+
if (!worker?.taskId || worker.localOnly) continue;
|
|
10988
|
+
if (hasTerminalCompletionAck(worker)) {
|
|
10989
|
+
outcomes.push({ worker: name, ok: true, taskId: worker.taskId ?? null, skipped: true });
|
|
10990
|
+
continue;
|
|
10991
|
+
}
|
|
10992
|
+
const status = computeWorkerStatus(worker);
|
|
10993
|
+
if (!isFinishedWorkerStatus(status)) continue;
|
|
10994
|
+
const exitedSalvage = assessExitedWorkerSalvage({
|
|
10995
|
+
alive: status.alive,
|
|
10996
|
+
finalResult: status.finalResult,
|
|
10997
|
+
changedFiles: status.changedFiles,
|
|
10998
|
+
gitAncestry: status.gitAncestry
|
|
10999
|
+
});
|
|
11000
|
+
if (!worker.dispatched && !status.finalResult && !exitedSalvage?.salvageable) continue;
|
|
11001
|
+
const result = await tryCompleteWorker({
|
|
11002
|
+
run: runId,
|
|
11003
|
+
name,
|
|
11004
|
+
agentOsId: String(args.agentOsId || worker.agentOsId || ""),
|
|
11005
|
+
...args
|
|
11006
|
+
});
|
|
11007
|
+
outcomes.push({ worker: name, ok: result.ok, taskId: worker.taskId ?? null });
|
|
11008
|
+
}
|
|
11009
|
+
return outcomes;
|
|
11010
|
+
}
|
|
11011
|
+
async function postOperatorTick(agentOsId, runId, resourceGate, args, harnessCleanup) {
|
|
11012
|
+
const base = resolveBaseUrl(args.baseUrl ? String(args.baseUrl) : void 0);
|
|
11013
|
+
const secret = await resolveCallbackSecretWithMint(args.secret ? String(args.secret) : void 0, agentOsId, { baseUrl: base });
|
|
11014
|
+
const url = `${base}/api/agent-os/by-id/${encodeURIComponent(agentOsId)}/operator/tick`;
|
|
11015
|
+
const packageVersions = await collectInstalledPackageVersions();
|
|
11016
|
+
const activeHarnessWorkers = collectRunActiveHarnessWorkers(runId);
|
|
11017
|
+
const res = await postJson(url, secret, {
|
|
11018
|
+
agentOsId,
|
|
10773
11019
|
runId,
|
|
10774
11020
|
ingestHarness: true,
|
|
10775
11021
|
harnessBoardSnapshot: buildRunBoard(runId),
|
|
@@ -10939,17 +11185,17 @@ async function runDaemon(args) {
|
|
|
10939
11185
|
idleStreak = 0;
|
|
10940
11186
|
}
|
|
10941
11187
|
const backoff = idleStreak >= MAX_IDLE_STREAK ? IDLE_INTERVAL_MS : intervalMs;
|
|
10942
|
-
sleepMs(backoff);
|
|
11188
|
+
await sleepMs(backoff);
|
|
10943
11189
|
} catch (error) {
|
|
10944
11190
|
console.error(JSON.stringify({ event: "daemon_tick_error", error: error.message }));
|
|
10945
|
-
sleepMs(intervalMs);
|
|
11191
|
+
await sleepMs(intervalMs);
|
|
10946
11192
|
}
|
|
10947
11193
|
}
|
|
10948
11194
|
console.error(JSON.stringify({ event: "daemon_stop", runId, agentOsId }));
|
|
10949
11195
|
}
|
|
10950
11196
|
|
|
10951
11197
|
// src/plan-progress.ts
|
|
10952
|
-
import
|
|
11198
|
+
import path59 from "node:path";
|
|
10953
11199
|
|
|
10954
11200
|
// src/bounded-build/constants.ts
|
|
10955
11201
|
var DEFAULT_BUILD_MEM_BUDGET_BYTES = 1536 * 1024 * 1024;
|
|
@@ -11079,14 +11325,235 @@ function waitForBuildAdmission(timeoutMs, pollMs = 2e3, opts = {}) {
|
|
|
11079
11325
|
}
|
|
11080
11326
|
|
|
11081
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
|
|
11082
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
|
+
}
|
|
11083
11550
|
|
|
11084
11551
|
// src/harness-worktree-build-guard.ts
|
|
11085
|
-
import
|
|
11552
|
+
import path58 from "node:path";
|
|
11086
11553
|
function isPathUnderHarnessWorktree(cwd) {
|
|
11087
11554
|
const worktreesDir = harnessWorktreesDir(resolveHarnessRoot());
|
|
11088
|
-
const rel =
|
|
11089
|
-
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);
|
|
11090
11557
|
}
|
|
11091
11558
|
function assessHarnessWorktreeBuildGuard(cwd) {
|
|
11092
11559
|
if (!isPathUnderHarnessWorktree(cwd)) return { ok: true };
|
|
@@ -11110,7 +11577,7 @@ function envArgv(env) {
|
|
|
11110
11577
|
return out;
|
|
11111
11578
|
}
|
|
11112
11579
|
function runSpawn(argv, opts) {
|
|
11113
|
-
const res =
|
|
11580
|
+
const res = spawnSync8(argv[0], argv.slice(1), {
|
|
11114
11581
|
cwd: opts.cwd,
|
|
11115
11582
|
env: opts.env,
|
|
11116
11583
|
encoding: "utf8",
|
|
@@ -11126,8 +11593,25 @@ function runSpawn(argv, opts) {
|
|
|
11126
11593
|
}
|
|
11127
11594
|
function runBoundedBuildCheck(input) {
|
|
11128
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;
|
|
11129
11612
|
const admission = waitMs > 0 ? waitForBuildAdmission(waitMs) : assessBuildAdmission();
|
|
11130
11613
|
if (!admission.admitted) {
|
|
11614
|
+
releaseHeavyVerificationSlot(slotId);
|
|
11131
11615
|
return {
|
|
11132
11616
|
ok: false,
|
|
11133
11617
|
exitCode: 1,
|
|
@@ -11137,11 +11621,13 @@ function runBoundedBuildCheck(input) {
|
|
|
11137
11621
|
wrappedWithSystemd: false,
|
|
11138
11622
|
nodeOptionsFlag: formatNodeOptionsFlag(),
|
|
11139
11623
|
admission,
|
|
11624
|
+
verificationGate,
|
|
11140
11625
|
command: input.command
|
|
11141
11626
|
};
|
|
11142
11627
|
}
|
|
11143
11628
|
const worktreeGuard = assessHarnessWorktreeBuildGuard(input.cwd);
|
|
11144
11629
|
if (!worktreeGuard.ok) {
|
|
11630
|
+
releaseHeavyVerificationSlot(slotId);
|
|
11145
11631
|
return {
|
|
11146
11632
|
ok: false,
|
|
11147
11633
|
exitCode: 1,
|
|
@@ -11151,6 +11637,7 @@ function runBoundedBuildCheck(input) {
|
|
|
11151
11637
|
wrappedWithSystemd: false,
|
|
11152
11638
|
nodeOptionsFlag: formatNodeOptionsFlag(),
|
|
11153
11639
|
admission,
|
|
11640
|
+
verificationGate,
|
|
11154
11641
|
command: input.command
|
|
11155
11642
|
};
|
|
11156
11643
|
}
|
|
@@ -11183,12 +11670,19 @@ function runBoundedBuildCheck(input) {
|
|
|
11183
11670
|
wrappedWithSystemd: useSystemd,
|
|
11184
11671
|
nodeOptionsFlag,
|
|
11185
11672
|
admission,
|
|
11673
|
+
verificationGate,
|
|
11186
11674
|
command: input.command
|
|
11187
11675
|
};
|
|
11188
11676
|
} finally {
|
|
11189
11677
|
registerBuildEnd();
|
|
11678
|
+
releaseHeavyVerificationSlot(slotId);
|
|
11190
11679
|
}
|
|
11191
11680
|
}
|
|
11681
|
+
function tryAcquireOrAssessVerificationGate(command) {
|
|
11682
|
+
const acquired = waitForHeavyVerificationSlot(command, 0);
|
|
11683
|
+
if (acquired.admitted) return acquired;
|
|
11684
|
+
return { ...assessHeavyVerificationGate(command), slotId: null };
|
|
11685
|
+
}
|
|
11192
11686
|
|
|
11193
11687
|
// src/harness-verify.ts
|
|
11194
11688
|
var DEFAULT_HARNESS_VERIFY_COMMANDS = ["npm run typecheck", "npm run test"];
|
|
@@ -11271,7 +11765,7 @@ async function emitPlanProgress(args) {
|
|
|
11271
11765
|
}
|
|
11272
11766
|
function verifyPlanLocal(args) {
|
|
11273
11767
|
const worktree = required(args.worktree ? String(args.worktree) : void 0, "worktree");
|
|
11274
|
-
const cwd =
|
|
11768
|
+
const cwd = path59.resolve(worktree);
|
|
11275
11769
|
const summary = runHarnessVerifyCommands(cwd);
|
|
11276
11770
|
const emitJson = args.json === true || args.json === "true";
|
|
11277
11771
|
const payload = { passed: summary.passed, worktree: cwd, steps: summary.steps };
|
|
@@ -11320,9 +11814,9 @@ async function verifyPlan(args) {
|
|
|
11320
11814
|
}
|
|
11321
11815
|
|
|
11322
11816
|
// src/harness-verify-cli.ts
|
|
11323
|
-
import
|
|
11817
|
+
import path60 from "node:path";
|
|
11324
11818
|
function runHarnessVerifyCli(args) {
|
|
11325
|
-
const cwd =
|
|
11819
|
+
const cwd = path60.resolve(required(args.worktree ? String(args.worktree) : void 0, "worktree"));
|
|
11326
11820
|
const emitJson = args.json === true || args.json === "true" || args.emitJson === true || args.emitJson === "true";
|
|
11327
11821
|
const commands = [];
|
|
11328
11822
|
const rawCmd = args.command;
|
|
@@ -11350,6 +11844,7 @@ function runHarnessVerifyCli(args) {
|
|
|
11350
11844
|
wrappedWithSystemd: s.result.wrappedWithSystemd,
|
|
11351
11845
|
nodeOptionsFlag: s.result.nodeOptionsFlag,
|
|
11352
11846
|
admission: s.result.admission,
|
|
11847
|
+
verificationGate: s.result.verificationGate,
|
|
11353
11848
|
stderr: s.result.stderr.slice(0, 4e3)
|
|
11354
11849
|
}))
|
|
11355
11850
|
};
|
|
@@ -11366,7 +11861,7 @@ function runHarnessVerifyCli(args) {
|
|
|
11366
11861
|
}
|
|
11367
11862
|
|
|
11368
11863
|
// src/plan-persist-cli.ts
|
|
11369
|
-
import { readFileSync as
|
|
11864
|
+
import { readFileSync as readFileSync15 } from "node:fs";
|
|
11370
11865
|
var OPERATIONS = ["create", "add_version", "update_metadata"];
|
|
11371
11866
|
var FAILURE_KINDS = [
|
|
11372
11867
|
"approval_guard",
|
|
@@ -11378,7 +11873,7 @@ var FAILURE_KINDS = [
|
|
|
11378
11873
|
function readBodyArg(args) {
|
|
11379
11874
|
const bodyFile = args.bodyFile ? String(args.bodyFile) : void 0;
|
|
11380
11875
|
if (bodyFile) {
|
|
11381
|
-
return { body:
|
|
11876
|
+
return { body: readFileSync15(bodyFile, "utf8"), bodyPathHint: bodyFile };
|
|
11382
11877
|
}
|
|
11383
11878
|
const inline = args.body ? String(args.body) : void 0;
|
|
11384
11879
|
if (inline) return { body: inline };
|
|
@@ -11529,7 +12024,7 @@ function formatMonitorTickNotice(tick) {
|
|
|
11529
12024
|
}
|
|
11530
12025
|
|
|
11531
12026
|
// src/monitor/monitor.service.ts
|
|
11532
|
-
import
|
|
12027
|
+
import path62 from "node:path";
|
|
11533
12028
|
|
|
11534
12029
|
// src/monitor/monitor.classify.ts
|
|
11535
12030
|
function classifyWorkerHealth(input) {
|
|
@@ -11581,19 +12076,19 @@ function classifyWorkerHealth(input) {
|
|
|
11581
12076
|
}
|
|
11582
12077
|
|
|
11583
12078
|
// src/monitor/monitor.store.ts
|
|
11584
|
-
import { existsSync as
|
|
11585
|
-
import
|
|
12079
|
+
import { existsSync as existsSync42, mkdirSync as mkdirSync9, readdirSync as readdirSync16, unlinkSync as unlinkSync5 } from "node:fs";
|
|
12080
|
+
import path61 from "node:path";
|
|
11586
12081
|
function monitorsDir() {
|
|
11587
12082
|
const { harnessRoot } = getHarnessPaths();
|
|
11588
|
-
const dir =
|
|
11589
|
-
|
|
12083
|
+
const dir = path61.join(harnessRoot, "monitors");
|
|
12084
|
+
mkdirSync9(dir, { recursive: true });
|
|
11590
12085
|
return dir;
|
|
11591
12086
|
}
|
|
11592
12087
|
function monitorIdFor(runId, workerName) {
|
|
11593
12088
|
return workerName ? `${safeSlug(runId)}--${safeSlug(workerName)}` : safeSlug(runId);
|
|
11594
12089
|
}
|
|
11595
12090
|
function monitorPath(monitorId) {
|
|
11596
|
-
return
|
|
12091
|
+
return path61.join(monitorsDir(), `${monitorId}.json`);
|
|
11597
12092
|
}
|
|
11598
12093
|
function loadMonitorSession(monitorId) {
|
|
11599
12094
|
return readJson(monitorPath(monitorId), void 0);
|
|
@@ -11603,18 +12098,18 @@ function saveMonitorSession(session) {
|
|
|
11603
12098
|
}
|
|
11604
12099
|
function deleteMonitorSession(monitorId) {
|
|
11605
12100
|
const file = monitorPath(monitorId);
|
|
11606
|
-
if (!
|
|
11607
|
-
|
|
12101
|
+
if (!existsSync42(file)) return false;
|
|
12102
|
+
unlinkSync5(file);
|
|
11608
12103
|
return true;
|
|
11609
12104
|
}
|
|
11610
12105
|
function listMonitorSessions() {
|
|
11611
12106
|
const dir = monitorsDir();
|
|
11612
|
-
if (!
|
|
12107
|
+
if (!existsSync42(dir)) return [];
|
|
11613
12108
|
const entries = [];
|
|
11614
|
-
for (const name of
|
|
12109
|
+
for (const name of readdirSync16(dir)) {
|
|
11615
12110
|
if (!name.endsWith(".json")) continue;
|
|
11616
12111
|
const session = readJson(
|
|
11617
|
-
|
|
12112
|
+
path61.join(dir, name),
|
|
11618
12113
|
void 0
|
|
11619
12114
|
);
|
|
11620
12115
|
if (!session?.monitorId) continue;
|
|
@@ -11705,7 +12200,7 @@ async function fetchTaskLeasesForWorkers(input) {
|
|
|
11705
12200
|
// src/monitor/monitor.service.ts
|
|
11706
12201
|
function workerRecord2(runId, name) {
|
|
11707
12202
|
return readJson(
|
|
11708
|
-
|
|
12203
|
+
path62.join(runDirectory(runId), "workers", safeSlug(name), "worker.json"),
|
|
11709
12204
|
void 0
|
|
11710
12205
|
);
|
|
11711
12206
|
}
|
|
@@ -11911,21 +12406,21 @@ async function runMonitorLoop(args) {
|
|
|
11911
12406
|
|
|
11912
12407
|
// src/monitor/monitor-spawn.ts
|
|
11913
12408
|
import { spawn as spawn6 } from "node:child_process";
|
|
11914
|
-
import { closeSync as
|
|
11915
|
-
import
|
|
12409
|
+
import { closeSync as closeSync8, existsSync as existsSync43, openSync as openSync8 } from "node:fs";
|
|
12410
|
+
import path63 from "node:path";
|
|
11916
12411
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
11917
12412
|
function resolveDefaultCliPath2() {
|
|
11918
|
-
return
|
|
12413
|
+
return path63.join(fileURLToPath3(new URL(".", import.meta.url)), "cli.js");
|
|
11919
12414
|
}
|
|
11920
12415
|
function spawnMonitorSidecar(opts) {
|
|
11921
12416
|
const cliPath = opts.cliPath ?? resolveDefaultCliPath2();
|
|
11922
|
-
if (!
|
|
12417
|
+
if (!existsSync43(cliPath)) return void 0;
|
|
11923
12418
|
const monitorId = monitorIdFor(opts.runId, opts.workerName);
|
|
11924
12419
|
const { harnessRoot } = getHarnessPaths();
|
|
11925
|
-
const logPath =
|
|
12420
|
+
const logPath = path63.join(harnessRoot, "monitors", `${monitorId}.log`);
|
|
11926
12421
|
let logFd;
|
|
11927
12422
|
try {
|
|
11928
|
-
logFd =
|
|
12423
|
+
logFd = openSync8(logPath, "a");
|
|
11929
12424
|
} catch {
|
|
11930
12425
|
logFd = void 0;
|
|
11931
12426
|
}
|
|
@@ -11965,7 +12460,7 @@ function spawnMonitorSidecar(opts) {
|
|
|
11965
12460
|
env: process.env
|
|
11966
12461
|
})
|
|
11967
12462
|
);
|
|
11968
|
-
if (logFd !== void 0)
|
|
12463
|
+
if (logFd !== void 0) closeSync8(logFd);
|
|
11969
12464
|
child.unref();
|
|
11970
12465
|
const session = {
|
|
11971
12466
|
monitorId,
|
|
@@ -11982,7 +12477,7 @@ function spawnMonitorSidecar(opts) {
|
|
|
11982
12477
|
} catch {
|
|
11983
12478
|
if (logFd !== void 0) {
|
|
11984
12479
|
try {
|
|
11985
|
-
|
|
12480
|
+
closeSync8(logFd);
|
|
11986
12481
|
} catch {
|
|
11987
12482
|
}
|
|
11988
12483
|
}
|
|
@@ -12042,13 +12537,13 @@ async function monitorTickCli(args) {
|
|
|
12042
12537
|
}
|
|
12043
12538
|
|
|
12044
12539
|
// src/package-version.ts
|
|
12045
|
-
import { existsSync as
|
|
12540
|
+
import { existsSync as existsSync44, readFileSync as readFileSync16 } from "node:fs";
|
|
12046
12541
|
import { dirname, join } from "node:path";
|
|
12047
12542
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
12048
12543
|
function resolvePackageRoot(moduleUrl) {
|
|
12049
12544
|
let dir = dirname(fileURLToPath4(moduleUrl));
|
|
12050
12545
|
for (let depth = 0; depth < 6; depth += 1) {
|
|
12051
|
-
if (
|
|
12546
|
+
if (existsSync44(join(dir, "package.json"))) return dir;
|
|
12052
12547
|
const parent = dirname(dir);
|
|
12053
12548
|
if (parent === dir) break;
|
|
12054
12549
|
dir = parent;
|
|
@@ -12057,7 +12552,7 @@ function resolvePackageRoot(moduleUrl) {
|
|
|
12057
12552
|
}
|
|
12058
12553
|
function readOwnPackageVersion(moduleUrl = import.meta.url) {
|
|
12059
12554
|
const pkgPath = join(resolvePackageRoot(moduleUrl), "package.json");
|
|
12060
|
-
const pkg = JSON.parse(
|
|
12555
|
+
const pkg = JSON.parse(readFileSync16(pkgPath, "utf8"));
|
|
12061
12556
|
if (typeof pkg.version !== "string" || !pkg.version.trim()) {
|
|
12062
12557
|
throw new Error(`Missing package.json version at ${pkgPath}`);
|
|
12063
12558
|
}
|
|
@@ -12077,188 +12572,6 @@ function handleCliVersionFlag(argv, moduleUrl = import.meta.url, binName) {
|
|
|
12077
12572
|
return true;
|
|
12078
12573
|
}
|
|
12079
12574
|
|
|
12080
|
-
// src/memory-cost-package-version-guard.ts
|
|
12081
|
-
import { existsSync as existsSync43, readFileSync as readFileSync14 } from "node:fs";
|
|
12082
|
-
import path61 from "node:path";
|
|
12083
|
-
var MEMORY_COST_PACKAGE_MIN_VERSIONS = {
|
|
12084
|
-
"@kynver-app/runtime": "0.1.83",
|
|
12085
|
-
"@kynver-app/openclaw-agent-os": "0.1.43",
|
|
12086
|
-
"@kynver-app/mcp-agent-os": "0.3.34"
|
|
12087
|
-
};
|
|
12088
|
-
var MEMORY_COST_MANAGED_PACKAGES = Object.keys(
|
|
12089
|
-
MEMORY_COST_PACKAGE_MIN_VERSIONS
|
|
12090
|
-
);
|
|
12091
|
-
var DISPLAY_NAMES = {
|
|
12092
|
-
"@kynver-app/runtime": "Kynver runtime",
|
|
12093
|
-
"@kynver-app/openclaw-agent-os": "OpenClaw AgentOS plugin",
|
|
12094
|
-
"@kynver-app/mcp-agent-os": "AgentOS MCP server"
|
|
12095
|
-
};
|
|
12096
|
-
var REPO_PACKAGE_JSON_RELATIVE = {
|
|
12097
|
-
"@kynver-app/runtime": "packages/kynver-runtime/package.json",
|
|
12098
|
-
"@kynver-app/openclaw-agent-os": "packages/kynver-openclaw-agent-os/package.json",
|
|
12099
|
-
"@kynver-app/mcp-agent-os": "packages/kynver-mcp-agent-os/package.json"
|
|
12100
|
-
};
|
|
12101
|
-
function parseSemverParts(version) {
|
|
12102
|
-
const core = version.trim().split("-")[0]?.split("+")[0];
|
|
12103
|
-
if (!core) return null;
|
|
12104
|
-
const parts = core.split(".");
|
|
12105
|
-
if (parts.length < 1 || parts.length > 3) return null;
|
|
12106
|
-
const nums = parts.map((p) => Number.parseInt(p, 10));
|
|
12107
|
-
if (nums.some((n) => !Number.isFinite(n) || n < 0)) return null;
|
|
12108
|
-
while (nums.length < 3) nums.push(0);
|
|
12109
|
-
return [nums[0], nums[1], nums[2]];
|
|
12110
|
-
}
|
|
12111
|
-
function compareSemver(a, b) {
|
|
12112
|
-
const pa = parseSemverParts(a);
|
|
12113
|
-
const pb = parseSemverParts(b);
|
|
12114
|
-
if (!pa || !pb) return 0;
|
|
12115
|
-
for (let i = 0; i < 3; i += 1) {
|
|
12116
|
-
if (pa[i] > pb[i]) return 1;
|
|
12117
|
-
if (pa[i] < pb[i]) return -1;
|
|
12118
|
-
}
|
|
12119
|
-
return 0;
|
|
12120
|
-
}
|
|
12121
|
-
function semverAtLeast(version, minimum) {
|
|
12122
|
-
return compareSemver(version, minimum) >= 0;
|
|
12123
|
-
}
|
|
12124
|
-
function maxSemver(versions) {
|
|
12125
|
-
let best = null;
|
|
12126
|
-
for (const version of versions) {
|
|
12127
|
-
if (!best || compareSemver(version, best) > 0) best = version;
|
|
12128
|
-
}
|
|
12129
|
-
return best;
|
|
12130
|
-
}
|
|
12131
|
-
function readPackageJsonVersion(packageJsonPath) {
|
|
12132
|
-
try {
|
|
12133
|
-
const parsed = JSON.parse(readFileSync14(packageJsonPath, "utf8"));
|
|
12134
|
-
return typeof parsed.version === "string" && parsed.version.trim() ? parsed.version.trim() : null;
|
|
12135
|
-
} catch {
|
|
12136
|
-
return null;
|
|
12137
|
-
}
|
|
12138
|
-
}
|
|
12139
|
-
function resolveRepoRoot(cwd, explicitRepoRoot) {
|
|
12140
|
-
const candidates = [explicitRepoRoot, process.env.KYNVER_REPO, cwd].filter(
|
|
12141
|
-
(value) => Boolean(value?.trim())
|
|
12142
|
-
);
|
|
12143
|
-
for (const candidate of candidates) {
|
|
12144
|
-
const resolved = path61.resolve(candidate);
|
|
12145
|
-
if (existsSync43(path61.join(resolved, "packages/kynver-runtime/package.json")) && existsSync43(path61.join(resolved, "package.json"))) {
|
|
12146
|
-
return resolved;
|
|
12147
|
-
}
|
|
12148
|
-
}
|
|
12149
|
-
return null;
|
|
12150
|
-
}
|
|
12151
|
-
function probeRepoPackageVersions(input = {}) {
|
|
12152
|
-
const cwd = input.cwd ?? process.cwd();
|
|
12153
|
-
const repoRoot = resolveRepoRoot(cwd, input.repoRoot);
|
|
12154
|
-
if (!repoRoot) return {};
|
|
12155
|
-
const out = {};
|
|
12156
|
-
for (const packageName of MEMORY_COST_MANAGED_PACKAGES) {
|
|
12157
|
-
const packageJsonPath = path61.join(repoRoot, REPO_PACKAGE_JSON_RELATIVE[packageName]);
|
|
12158
|
-
const version = readPackageJsonVersion(packageJsonPath);
|
|
12159
|
-
if (!version) continue;
|
|
12160
|
-
out[packageName] = { version, source: "repo", path: packageJsonPath };
|
|
12161
|
-
}
|
|
12162
|
-
return out;
|
|
12163
|
-
}
|
|
12164
|
-
function repoSourceCommands(packageName) {
|
|
12165
|
-
if (packageName === "@kynver-app/runtime") {
|
|
12166
|
-
return ["npm run kynver:build", "npm run kynver"];
|
|
12167
|
-
}
|
|
12168
|
-
return [`npm run build -w ${packageName}`];
|
|
12169
|
-
}
|
|
12170
|
-
function buildRemediation(input) {
|
|
12171
|
-
const { packageName, minimumVersion, effectiveVersion, effectiveSource, repoVersion } = input;
|
|
12172
|
-
const lines = [];
|
|
12173
|
-
if (repoVersion && semverAtLeast(repoVersion, minimumVersion)) {
|
|
12174
|
-
lines.push(
|
|
12175
|
-
`Use the monorepo checkout (${repoVersion}) instead of a stale npm install: ${repoSourceCommands(packageName).join("; ")}.`
|
|
12176
|
-
);
|
|
12177
|
-
lines.push("Do not publish npm packages or wait on an operator release.");
|
|
12178
|
-
return lines;
|
|
12179
|
-
}
|
|
12180
|
-
if (effectiveVersion) {
|
|
12181
|
-
lines.push(
|
|
12182
|
-
`Upgrade ${packageName} from ${effectiveVersion} to >= ${minimumVersion} (npm install -g ${packageName}@latest or align OpenClaw npm prefix).`
|
|
12183
|
-
);
|
|
12184
|
-
} else {
|
|
12185
|
-
lines.push(`Install ${packageName} >= ${minimumVersion} before running memory-heavy AgentOS paths.`);
|
|
12186
|
-
}
|
|
12187
|
-
if (packageName === "@kynver-app/runtime") {
|
|
12188
|
-
lines.push("Repo-source alternative: npm run kynver:build && npm run kynver");
|
|
12189
|
-
}
|
|
12190
|
-
if (effectiveSource === "installed" && repoVersion) {
|
|
12191
|
-
lines.push(`Repo checkout reports ${repoVersion}; rebuild/link repo source if you develop from the monorepo.`);
|
|
12192
|
-
}
|
|
12193
|
-
return lines;
|
|
12194
|
-
}
|
|
12195
|
-
function pickEffectiveCandidate(candidates) {
|
|
12196
|
-
if (candidates.length === 0) return { version: null, source: "unknown" };
|
|
12197
|
-
const best = maxSemver(candidates.map((candidate) => candidate.version));
|
|
12198
|
-
if (!best) return { version: null, source: "unknown" };
|
|
12199
|
-
const winner = candidates.find((candidate) => candidate.version === best) ?? candidates[0];
|
|
12200
|
-
return { version: winner.version, source: winner.source };
|
|
12201
|
-
}
|
|
12202
|
-
function evaluateMemoryCostPackageVersionGuard(input = {}) {
|
|
12203
|
-
const normalize2 = (value, fallbackSource) => {
|
|
12204
|
-
if (!value) return null;
|
|
12205
|
-
if (typeof value === "string") return { version: value, source: fallbackSource };
|
|
12206
|
-
return value;
|
|
12207
|
-
};
|
|
12208
|
-
const packages = MEMORY_COST_MANAGED_PACKAGES.map((packageName) => {
|
|
12209
|
-
const minimumVersion = MEMORY_COST_PACKAGE_MIN_VERSIONS[packageName];
|
|
12210
|
-
const candidates = [];
|
|
12211
|
-
const installed = normalize2(input.installed?.[packageName], "installed");
|
|
12212
|
-
const repo = normalize2(input.repo?.[packageName], "repo");
|
|
12213
|
-
const self = normalize2(input.self?.[packageName], "self");
|
|
12214
|
-
if (installed) candidates.push(installed);
|
|
12215
|
-
if (repo) candidates.push(repo);
|
|
12216
|
-
if (self) candidates.push(self);
|
|
12217
|
-
const { version: effectiveVersion, source: effectiveSource } = pickEffectiveCandidate(candidates);
|
|
12218
|
-
const repoVersion = repo?.version ?? null;
|
|
12219
|
-
const ok2 = effectiveVersion ? semverAtLeast(effectiveVersion, minimumVersion) : false;
|
|
12220
|
-
const remediation = ok2 ? [] : buildRemediation({
|
|
12221
|
-
packageName,
|
|
12222
|
-
minimumVersion,
|
|
12223
|
-
effectiveVersion,
|
|
12224
|
-
effectiveSource,
|
|
12225
|
-
repoVersion
|
|
12226
|
-
});
|
|
12227
|
-
const summary2 = ok2 ? `${DISPLAY_NAMES[packageName]} ${effectiveVersion} meets memory-cost minimum ${minimumVersion} (${effectiveSource}).` : `${DISPLAY_NAMES[packageName]} is below memory-cost minimum ${minimumVersion}` + (effectiveVersion ? ` (effective ${effectiveVersion} via ${effectiveSource})` : " (no version detected)") + ".";
|
|
12228
|
-
return {
|
|
12229
|
-
packageName,
|
|
12230
|
-
displayName: DISPLAY_NAMES[packageName],
|
|
12231
|
-
minimumVersion,
|
|
12232
|
-
effectiveVersion,
|
|
12233
|
-
effectiveSource,
|
|
12234
|
-
ok: ok2,
|
|
12235
|
-
summary: summary2,
|
|
12236
|
-
remediation
|
|
12237
|
-
};
|
|
12238
|
-
});
|
|
12239
|
-
const violations = packages.filter((row) => !row.ok);
|
|
12240
|
-
const ok = violations.length === 0;
|
|
12241
|
-
const summary = ok ? "All managed AgentOS packages meet memory-cost minimum versions." : `Memory-cost package guard blocked ${violations.length} stale package(s): ${violations.map((row) => `${row.packageName} < ${row.minimumVersion}`).join("; ")}.`;
|
|
12242
|
-
return { ok, summary, packages };
|
|
12243
|
-
}
|
|
12244
|
-
var MemoryCostPackageVersionGuardError = class extends Error {
|
|
12245
|
-
result;
|
|
12246
|
-
constructor(result) {
|
|
12247
|
-
const lines = [
|
|
12248
|
-
result.summary,
|
|
12249
|
-
...result.packages.filter((row) => !row.ok).flatMap((row) => [`- ${row.summary}`, ...row.remediation.map((line) => ` \u2192 ${line}`)])
|
|
12250
|
-
];
|
|
12251
|
-
super(lines.join("\n"));
|
|
12252
|
-
this.name = "MemoryCostPackageVersionGuardError";
|
|
12253
|
-
this.result = result;
|
|
12254
|
-
}
|
|
12255
|
-
};
|
|
12256
|
-
function assertMemoryCostPackageVersionGuard(input = {}) {
|
|
12257
|
-
const result = evaluateMemoryCostPackageVersionGuard(input);
|
|
12258
|
-
if (!result.ok) throw new MemoryCostPackageVersionGuardError(result);
|
|
12259
|
-
return result;
|
|
12260
|
-
}
|
|
12261
|
-
|
|
12262
12575
|
// src/memory-cost-package-version-guard-enforce.ts
|
|
12263
12576
|
function installedVersionMap(observed) {
|
|
12264
12577
|
const out = {};
|
|
@@ -12278,10 +12591,10 @@ async function buildMemoryCostPackageGuardInput(input = {}) {
|
|
|
12278
12591
|
Promise.resolve(probeRepoPackageVersions({ cwd: input.cwd, repoRoot: input.repoRoot }))
|
|
12279
12592
|
]);
|
|
12280
12593
|
const self = {};
|
|
12281
|
-
|
|
12594
|
+
const runtimeSelfVersion = input.selfPackageName === "@kynver-app/runtime" && input.selfVersion ? input.selfVersion : PACKAGE_VERSION;
|
|
12595
|
+
self["@kynver-app/runtime"] = { version: runtimeSelfVersion, source: "self" };
|
|
12596
|
+
if (input.selfPackageName && input.selfVersion && input.selfPackageName !== "@kynver-app/runtime") {
|
|
12282
12597
|
self[input.selfPackageName] = { version: input.selfVersion, source: "self" };
|
|
12283
|
-
} else {
|
|
12284
|
-
self["@kynver-app/runtime"] = { version: PACKAGE_VERSION, source: "self" };
|
|
12285
12598
|
}
|
|
12286
12599
|
return {
|
|
12287
12600
|
installed: installedVersionMap(installed),
|
|
@@ -12306,7 +12619,7 @@ function shouldEnforceMemoryCostPackageGuardCli(scope, action) {
|
|
|
12306
12619
|
}
|
|
12307
12620
|
|
|
12308
12621
|
// src/post-restart-unblock.ts
|
|
12309
|
-
import
|
|
12622
|
+
import path64 from "node:path";
|
|
12310
12623
|
function skip(runId, worker, taskId, agentOsId, leaseOwner, reason) {
|
|
12311
12624
|
return { runId, worker, taskId, agentOsId, leaseOwner, action: "skipped", reason };
|
|
12312
12625
|
}
|
|
@@ -12319,7 +12632,7 @@ async function postRestartUnblock(args) {
|
|
|
12319
12632
|
const errors = [];
|
|
12320
12633
|
for (const run of listRunRecords()) {
|
|
12321
12634
|
for (const name of Object.keys(run.workers ?? {})) {
|
|
12322
|
-
const workerPath =
|
|
12635
|
+
const workerPath = path64.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json");
|
|
12323
12636
|
const worker = readJson(workerPath, void 0);
|
|
12324
12637
|
if (!worker) {
|
|
12325
12638
|
skipped.push(skip(run.id, name, "", "", "", "worker.json missing"));
|
|
@@ -12431,9 +12744,9 @@ async function postRestartUnblockCli(args) {
|
|
|
12431
12744
|
}
|
|
12432
12745
|
|
|
12433
12746
|
// src/default-repo-cli.ts
|
|
12434
|
-
import
|
|
12747
|
+
import path65 from "node:path";
|
|
12435
12748
|
import { homedir as homedir14 } from "node:os";
|
|
12436
|
-
var CONFIG_FILE2 =
|
|
12749
|
+
var CONFIG_FILE2 = path65.join(homedir14(), ".kynver", "config.json");
|
|
12437
12750
|
function ensureDefaultRepo(opts) {
|
|
12438
12751
|
const existing = loadUserConfig();
|
|
12439
12752
|
const resolved = resolveDefaultRepo({ ...opts, config: existing });
|
|
@@ -12514,16 +12827,16 @@ function summarizeResolvedDefaultRepo(resolved) {
|
|
|
12514
12827
|
}
|
|
12515
12828
|
|
|
12516
12829
|
// src/doctor/runtime-takeover.ts
|
|
12517
|
-
import
|
|
12830
|
+
import path67 from "node:path";
|
|
12518
12831
|
|
|
12519
12832
|
// src/doctor/runtime-takeover.probes.ts
|
|
12520
|
-
import { accessSync, constants, existsSync as
|
|
12833
|
+
import { accessSync, constants, existsSync as existsSync45, readFileSync as readFileSync17 } from "node:fs";
|
|
12521
12834
|
import { homedir as homedir15 } from "node:os";
|
|
12522
|
-
import
|
|
12523
|
-
import { spawnSync as
|
|
12835
|
+
import path66 from "node:path";
|
|
12836
|
+
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
12524
12837
|
function captureCommand(bin, args) {
|
|
12525
12838
|
try {
|
|
12526
|
-
const res =
|
|
12839
|
+
const res = spawnSync9(bin, args, { encoding: "utf8" });
|
|
12527
12840
|
const stdout = (res.stdout || "").trim();
|
|
12528
12841
|
const stderr = (res.stderr || "").trim();
|
|
12529
12842
|
const ok = res.status === 0;
|
|
@@ -12548,7 +12861,7 @@ function tokenPrefix(token) {
|
|
|
12548
12861
|
return trimmed.length <= 12 ? `${trimmed}\u2026` : `${trimmed.slice(0, 12)}\u2026`;
|
|
12549
12862
|
}
|
|
12550
12863
|
function isWritable(target) {
|
|
12551
|
-
if (!
|
|
12864
|
+
if (!existsSync45(target)) return false;
|
|
12552
12865
|
try {
|
|
12553
12866
|
accessSync(target, constants.W_OK);
|
|
12554
12867
|
return true;
|
|
@@ -12561,15 +12874,15 @@ var defaultRuntimeTakeoverProbes = {
|
|
|
12561
12874
|
commandOnPath: (bin) => captureCommand(process.platform === "win32" ? "where" : "which", [bin]),
|
|
12562
12875
|
kynverVersion: (bin) => captureCommand(bin, ["--version"]),
|
|
12563
12876
|
loadConfig: () => loadUserConfig(),
|
|
12564
|
-
configFilePath: () =>
|
|
12565
|
-
credentialsFilePath: () =>
|
|
12877
|
+
configFilePath: () => path66.join(homedir15(), ".kynver", "config.json"),
|
|
12878
|
+
credentialsFilePath: () => path66.join(homedir15(), ".kynver", "credentials"),
|
|
12566
12879
|
readCredentials: () => {
|
|
12567
|
-
const credPath =
|
|
12568
|
-
if (!
|
|
12880
|
+
const credPath = path66.join(homedir15(), ".kynver", "credentials");
|
|
12881
|
+
if (!existsSync45(credPath)) {
|
|
12569
12882
|
return { hasApiKey: false };
|
|
12570
12883
|
}
|
|
12571
12884
|
try {
|
|
12572
|
-
const parsed = JSON.parse(
|
|
12885
|
+
const parsed = JSON.parse(readFileSync17(credPath, "utf8"));
|
|
12573
12886
|
return {
|
|
12574
12887
|
hasApiKey: Boolean(parsed.apiKey?.trim()),
|
|
12575
12888
|
runnerTokenPrefix: tokenPrefix(parsed.runnerToken),
|
|
@@ -12599,11 +12912,9 @@ var defaultRuntimeTakeoverProbes = {
|
|
|
12599
12912
|
})()
|
|
12600
12913
|
}),
|
|
12601
12914
|
harnessRoot: () => resolveHarnessRoot(),
|
|
12602
|
-
legacyOpenclawHarnessRoot: () =>
|
|
12603
|
-
pathExists: (target) =>
|
|
12604
|
-
pathWritable: (target) => isWritable(target)
|
|
12605
|
-
vercelVersion: () => captureCommand("vercel", ["--version"]),
|
|
12606
|
-
vercelWhoami: () => captureCommand("vercel", ["whoami"])
|
|
12915
|
+
legacyOpenclawHarnessRoot: () => path66.join(homedir15(), ".openclaw", "harness"),
|
|
12916
|
+
pathExists: (target) => existsSync45(target),
|
|
12917
|
+
pathWritable: (target) => isWritable(target)
|
|
12607
12918
|
};
|
|
12608
12919
|
|
|
12609
12920
|
// src/doctor/runtime-takeover-scheduler.ts
|
|
@@ -12970,37 +13281,46 @@ function assessRunnerToken(probes) {
|
|
|
12970
13281
|
];
|
|
12971
13282
|
return { id: "runner_token", label: "Runner token readiness", checks };
|
|
12972
13283
|
}
|
|
12973
|
-
function
|
|
12974
|
-
const
|
|
12975
|
-
const
|
|
12976
|
-
const
|
|
13284
|
+
function assessVercelDeployEvidence(probes) {
|
|
13285
|
+
const globalCli = probes.commandOnPath("vercel");
|
|
13286
|
+
const cliInstalled = globalCli.ok;
|
|
13287
|
+
const githubToken = Boolean(
|
|
13288
|
+
process.env.GITHUB_TOKEN?.trim() || process.env.GH_TOKEN?.trim()
|
|
13289
|
+
);
|
|
13290
|
+
const vercelToken = Boolean(process.env.VERCEL_TOKEN?.trim());
|
|
12977
13291
|
return {
|
|
12978
|
-
id: "
|
|
12979
|
-
label: "Vercel
|
|
13292
|
+
id: "vercel_deploy_evidence",
|
|
13293
|
+
label: "Vercel deploy evidence",
|
|
12980
13294
|
checks: [
|
|
12981
13295
|
check2({
|
|
12982
|
-
id: "
|
|
12983
|
-
label: "Vercel CLI installed",
|
|
12984
|
-
status:
|
|
12985
|
-
summary:
|
|
12986
|
-
remediation:
|
|
12987
|
-
details: {
|
|
13296
|
+
id: "vercel_global_cli_absent",
|
|
13297
|
+
label: "Global Vercel CLI not installed",
|
|
13298
|
+
status: cliInstalled ? "warn" : "pass",
|
|
13299
|
+
summary: cliInstalled ? `Global Vercel CLI found (${globalCli.stdout || "on PATH"}) \u2014 uninstall after operator approval` : "No global Vercel CLI on PATH",
|
|
13300
|
+
remediation: cliInstalled ? "Uninstall global Vercel CLI (`npm uninstall -g vercel`) \u2014 use GitHub commit status or scoped VERCEL_TOKEN + REST API instead." : void 0,
|
|
13301
|
+
details: { path: cliInstalled ? globalCli.stdout || null : null }
|
|
13302
|
+
}),
|
|
13303
|
+
check2({
|
|
13304
|
+
id: "github_token_for_vercel_status",
|
|
13305
|
+
label: "GitHub token for Vercel status",
|
|
13306
|
+
status: githubToken ? "pass" : "warn",
|
|
13307
|
+
summary: githubToken ? "GITHUB_TOKEN/GH_TOKEN present for GitHub Vercel StatusContext evidence" : "No GITHUB_TOKEN \u2014 merge-gate Vercel evidence requires GitHub commit status API",
|
|
13308
|
+
remediation: githubToken ? void 0 : "Export GITHUB_TOKEN (or GH_TOKEN) for PR head commit status lookups."
|
|
12988
13309
|
}),
|
|
12989
13310
|
check2({
|
|
12990
|
-
id: "
|
|
12991
|
-
label: "Vercel
|
|
12992
|
-
status:
|
|
12993
|
-
summary:
|
|
12994
|
-
remediation:
|
|
12995
|
-
details: { account: whoami.ok ? whoami.stdout : null }
|
|
13311
|
+
id: "vercel_api_token_optional",
|
|
13312
|
+
label: "Vercel API token (optional fallback)",
|
|
13313
|
+
status: vercelToken ? "pass" : "warn",
|
|
13314
|
+
summary: vercelToken ? "VERCEL_TOKEN configured for optional REST API deployment lookup" : "VERCEL_TOKEN unset \u2014 GitHub status is the default path; API fallback disabled",
|
|
13315
|
+
remediation: vercelToken ? void 0 : "Set ephemeral/scoped VERCEL_TOKEN only when GitHub status is insufficient; avoid persistent ~/.vercel auth on runner hosts."
|
|
12996
13316
|
})
|
|
12997
13317
|
]
|
|
12998
13318
|
};
|
|
12999
13319
|
}
|
|
13000
13320
|
function assessHarnessDirs(probes) {
|
|
13001
13321
|
const harnessRoot = probes.harnessRoot();
|
|
13002
|
-
const runsDir =
|
|
13003
|
-
const worktreesDir =
|
|
13322
|
+
const runsDir = path67.join(harnessRoot, "runs");
|
|
13323
|
+
const worktreesDir = path67.join(harnessRoot, "worktrees");
|
|
13004
13324
|
const displayHarnessRoot = redactHomePath(harnessRoot);
|
|
13005
13325
|
const displayRunsDir = redactHomePath(runsDir);
|
|
13006
13326
|
const displayWorktreesDir = redactHomePath(worktreesDir);
|
|
@@ -13131,7 +13451,7 @@ function assessRuntimeTakeoverReadiness(probes = defaultRuntimeTakeoverProbes) {
|
|
|
13131
13451
|
assessCliPackage(probes),
|
|
13132
13452
|
assessUserConfig(probes),
|
|
13133
13453
|
assessRunnerToken(probes),
|
|
13134
|
-
|
|
13454
|
+
assessVercelDeployEvidence(probes),
|
|
13135
13455
|
assessHarnessDirs(probes),
|
|
13136
13456
|
assessCallbackAuth(probes),
|
|
13137
13457
|
assessOpenclawHotspots(probes)
|
|
@@ -13264,9 +13584,9 @@ function applySchedulerCutoverAttestation(config) {
|
|
|
13264
13584
|
}
|
|
13265
13585
|
|
|
13266
13586
|
// src/scheduler-cutover-cli.ts
|
|
13267
|
-
import
|
|
13587
|
+
import path68 from "node:path";
|
|
13268
13588
|
import { homedir as homedir16 } from "node:os";
|
|
13269
|
-
var CONFIG_FILE3 =
|
|
13589
|
+
var CONFIG_FILE3 = path68.join(homedir16(), ".kynver", "config.json");
|
|
13270
13590
|
function runSchedulerCutoverCheckCli(json = false) {
|
|
13271
13591
|
const config = loadUserConfig();
|
|
13272
13592
|
const report = assessSchedulerCutover(config);
|
|
@@ -13478,10 +13798,22 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
13478
13798
|
if (action && isHelpFlag(action) || rest.some(isHelpFlag)) return usage(0);
|
|
13479
13799
|
const args = parseArgs(rest);
|
|
13480
13800
|
const { runsDir, worktreesDir } = getPaths();
|
|
13481
|
-
|
|
13482
|
-
|
|
13801
|
+
mkdirSync10(runsDir, { recursive: true });
|
|
13802
|
+
mkdirSync10(worktreesDir, { recursive: true });
|
|
13483
13803
|
if (shouldEnforceMemoryCostPackageGuardCli(scope, action)) {
|
|
13484
|
-
|
|
13804
|
+
let repoRoot;
|
|
13805
|
+
const runId = args.run ? String(args.run).trim() : "";
|
|
13806
|
+
if (runId) {
|
|
13807
|
+
try {
|
|
13808
|
+
repoRoot = loadRun(runId).repo;
|
|
13809
|
+
} catch {
|
|
13810
|
+
repoRoot = void 0;
|
|
13811
|
+
}
|
|
13812
|
+
}
|
|
13813
|
+
await enforceMemoryCostPackageGuardAtStartup({
|
|
13814
|
+
repoRoot,
|
|
13815
|
+
cwd: repoRoot
|
|
13816
|
+
});
|
|
13485
13817
|
}
|
|
13486
13818
|
if (scope === "login") return void await runLogin(args);
|
|
13487
13819
|
if (scope === "runner" && action === "credential") return void await mintRunnerCredential(args);
|