@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/cli.js CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli.ts
4
- import { mkdirSync as mkdirSync8, realpathSync } from "node:fs";
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 readFileSync7, writeFileSync as writeFileSync2 } from "node:fs";
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 path67 = options.wslHostMount?.trim() || process.env.KYNVER_WSL_HOST_MOUNT?.trim() || DEFAULT_WSL_HOST_MOUNT;
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(path67);
495
+ stats = statfs(path69);
495
496
  } catch (error) {
496
497
  return {
497
498
  ok: false,
498
- path: path67,
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 ${path67}: ${error.message}`,
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 ${path67} at ${tag}: ${freeGiB} GiB free (<${(criticalFree ? criticalBelowBytes : warnBelowBytes) / 1024 / 1024 / 1024} GiB); WSL VHDX cannot grow safely. ${summarizeWslRecoverySteps()}`;
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: path67,
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 path67 = input.diskPath?.trim() || "/";
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(path67);
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: path67,
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(readFileSync7(CONFIG_FILE, "utf8"));
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(readFileSync7(CREDENTIALS_FILE, "utf8"));
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
- const res = await withTimeout(
2498
- (signal) => fetch(url, {
2499
- method: "POST",
2500
- headers: buildHarnessCallbackHeaders(secret),
2501
- body: JSON.stringify(body),
2502
- signal
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
- const res = await withTimeout(
2523
- (signal) => fetch(url, {
2524
- method: "GET",
2525
- headers: buildHarnessCallbackHeaders(secret),
2526
- signal
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 readFileSync8 } from "node:fs";
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 = readFileSync8(envPath, "utf8");
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 path67 = normalizeRelativePath(pathFromGitStatusLine(line));
4986
- return removedSet.has(path67);
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 || !isPidAlive(worker.pid)) continue;
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 readFileSync9,
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(readFileSync9(jsonPath, "utf8"));
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 readFileSync9(bodyFile, "utf8");
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 readFileSync10 } from "node:fs";
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 readFileSync10(heartbeatPath, "utf8").trim().length;
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 readFileSync11, unlinkSync as unlinkSync3, writeFileSync as writeFileSync4 } from "node:fs";
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(readFileSync11(lockPath, "utf8"));
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 = (path67, reason, detail) => {
9212
- const key = `${path67}\0${reason}`;
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: path67, reason, ...detail ? { detail } : {} });
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 readFileSync12 } from "node:fs";
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(readFileSync12(packageJsonPath, "utf8"));
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 path57 from "node:path";
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 path56 from "node:path";
11552
+ import path58 from "node:path";
11293
11553
  function isPathUnderHarnessWorktree(cwd) {
11294
11554
  const worktreesDir = harnessWorktreesDir(resolveHarnessRoot());
11295
- const rel = path56.relative(worktreesDir, path56.resolve(cwd));
11296
- return rel.length > 0 && !rel.startsWith("..") && !path56.isAbsolute(rel);
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 = spawnSync7(argv[0], argv.slice(1), {
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 = path57.resolve(worktree);
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 path58 from "node:path";
11817
+ import path60 from "node:path";
11531
11818
  function runHarnessVerifyCli(args) {
11532
- const cwd = path58.resolve(required(args.worktree ? String(args.worktree) : void 0, "worktree"));
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 readFileSync13 } from "node:fs";
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: readFileSync13(bodyFile, "utf8"), bodyPathHint: bodyFile };
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 path60 from "node:path";
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 existsSync41, mkdirSync as mkdirSync7, readdirSync as readdirSync15, unlinkSync as unlinkSync4 } from "node:fs";
11792
- import path59 from "node:path";
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 = path59.join(harnessRoot, "monitors");
11796
- mkdirSync7(dir, { recursive: true });
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 path59.join(monitorsDir(), `${monitorId}.json`);
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 (!existsSync41(file)) return false;
11814
- unlinkSync4(file);
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 (!existsSync41(dir)) return [];
12107
+ if (!existsSync42(dir)) return [];
11820
12108
  const entries = [];
11821
- for (const name of readdirSync15(dir)) {
12109
+ for (const name of readdirSync16(dir)) {
11822
12110
  if (!name.endsWith(".json")) continue;
11823
12111
  const session = readJson(
11824
- path59.join(dir, name),
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
- path60.join(runDirectory(runId), "workers", safeSlug(name), "worker.json"),
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 closeSync7, existsSync as existsSync42, openSync as openSync7 } from "node:fs";
12122
- import path61 from "node:path";
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 path61.join(fileURLToPath3(new URL(".", import.meta.url)), "cli.js");
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 (!existsSync42(cliPath)) return void 0;
12417
+ if (!existsSync43(cliPath)) return void 0;
12130
12418
  const monitorId = monitorIdFor(opts.runId, opts.workerName);
12131
12419
  const { harnessRoot } = getHarnessPaths();
12132
- const logPath = path61.join(harnessRoot, "monitors", `${monitorId}.log`);
12420
+ const logPath = path63.join(harnessRoot, "monitors", `${monitorId}.log`);
12133
12421
  let logFd;
12134
12422
  try {
12135
- logFd = openSync7(logPath, "a");
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) closeSync7(logFd);
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
- closeSync7(logFd);
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 existsSync43, readFileSync as readFileSync14 } from "node:fs";
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 (existsSync43(join(dir, "package.json"))) return dir;
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(readFileSync14(pkgPath, "utf8"));
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 path62 from "node:path";
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 = path62.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json");
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 path63 from "node:path";
12747
+ import path65 from "node:path";
12460
12748
  import { homedir as homedir14 } from "node:os";
12461
- var CONFIG_FILE2 = path63.join(homedir14(), ".kynver", "config.json");
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 path65 from "node:path";
12830
+ import path67 from "node:path";
12543
12831
 
12544
12832
  // src/doctor/runtime-takeover.probes.ts
12545
- import { accessSync, constants, existsSync as existsSync44, readFileSync as readFileSync15 } from "node:fs";
12833
+ import { accessSync, constants, existsSync as existsSync45, readFileSync as readFileSync17 } from "node:fs";
12546
12834
  import { homedir as homedir15 } from "node:os";
12547
- import path64 from "node:path";
12548
- import { spawnSync as spawnSync8 } from "node:child_process";
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 = spawnSync8(bin, args, { encoding: "utf8" });
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 (!existsSync44(target)) return false;
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: () => path64.join(homedir15(), ".kynver", "config.json"),
12590
- credentialsFilePath: () => path64.join(homedir15(), ".kynver", "credentials"),
12877
+ configFilePath: () => path66.join(homedir15(), ".kynver", "config.json"),
12878
+ credentialsFilePath: () => path66.join(homedir15(), ".kynver", "credentials"),
12591
12879
  readCredentials: () => {
12592
- const credPath = path64.join(homedir15(), ".kynver", "credentials");
12593
- if (!existsSync44(credPath)) {
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(readFileSync15(credPath, "utf8"));
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: () => path64.join(homedir15(), ".openclaw", "harness"),
12628
- pathExists: (target) => existsSync44(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 = path65.join(harnessRoot, "runs");
13035
- const worktreesDir = path65.join(harnessRoot, "worktrees");
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 path66 from "node:path";
13587
+ import path68 from "node:path";
13300
13588
  import { homedir as homedir16 } from "node:os";
13301
- var CONFIG_FILE3 = path66.join(homedir16(), ".kynver", "config.json");
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
- mkdirSync8(runsDir, { recursive: true });
13514
- mkdirSync8(worktreesDir, { recursive: true });
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() : "";