@kynver-app/runtime 0.1.119 → 0.1.122

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -532,23 +532,23 @@ function isWslHost() {
532
532
  function observeWslHostDisk(options = {}) {
533
533
  const wsl = options.forceWsl === void 0 ? isWslHost() : options.forceWsl;
534
534
  if (!wsl) return null;
535
- const path79 = options.wslHostMount?.trim() || process.env.KYNVER_WSL_HOST_MOUNT?.trim() || DEFAULT_WSL_HOST_MOUNT;
535
+ const path81 = options.wslHostMount?.trim() || process.env.KYNVER_WSL_HOST_MOUNT?.trim() || DEFAULT_WSL_HOST_MOUNT;
536
536
  const warnBelowBytes = options.wslHostFreeWarnBytes ?? DEFAULT_WSL_HOST_WARN_FREE_BYTES;
537
537
  const criticalBelowBytes = options.wslHostFreeCriticalBytes ?? DEFAULT_WSL_HOST_CRITICAL_FREE_BYTES;
538
538
  const statfs = options.statfs ?? statfsSync;
539
539
  let stats;
540
540
  try {
541
- stats = statfs(path79);
541
+ stats = statfs(path81);
542
542
  } catch (error) {
543
543
  return {
544
544
  ok: false,
545
- path: path79,
545
+ path: path81,
546
546
  freeBytes: 0,
547
547
  totalBytes: 0,
548
548
  usedPercent: 100,
549
549
  warnBelowBytes,
550
550
  criticalBelowBytes,
551
- reason: `Windows host disk probe failed at ${path79}: ${error.message}`,
551
+ reason: `Windows host disk probe failed at ${path81}: ${error.message}`,
552
552
  probeError: error.message
553
553
  };
554
554
  }
@@ -562,11 +562,11 @@ function observeWslHostDisk(options = {}) {
562
562
  let reason = null;
563
563
  if (!ok) {
564
564
  const tag = criticalFree ? "critical" : "warning";
565
- reason = `Windows host disk ${path79} at ${tag}: ${freeGiB} GiB free (<${(criticalFree ? criticalBelowBytes : warnBelowBytes) / 1024 / 1024 / 1024} GiB); WSL VHDX cannot grow safely. ${summarizeWslRecoverySteps()}`;
565
+ reason = `Windows host disk ${path81} at ${tag}: ${freeGiB} GiB free (<${(criticalFree ? criticalBelowBytes : warnBelowBytes) / 1024 / 1024 / 1024} GiB); WSL VHDX cannot grow safely. ${summarizeWslRecoverySteps()}`;
566
566
  }
567
567
  return {
568
568
  ok,
569
- path: path79,
569
+ path: path81,
570
570
  freeBytes,
571
571
  totalBytes,
572
572
  usedPercent,
@@ -592,12 +592,12 @@ var init_wsl_host = __esm({
592
592
  // src/disk-gate.ts
593
593
  import { statfsSync as statfsSync2 } from "node:fs";
594
594
  function observeRunnerDiskGate(input = {}) {
595
- const path79 = input.diskPath?.trim() || "/";
595
+ const path81 = input.diskPath?.trim() || "/";
596
596
  const warnBelowBytes = input.diskFreeWarnBytes ?? DEFAULT_WARN_FREE_BYTES;
597
597
  const criticalBelowBytes = input.diskFreeCriticalBytes ?? DEFAULT_CRITICAL_FREE_BYTES;
598
598
  const maxUsedPercent = input.diskMaxUsedPercent ?? DEFAULT_MAX_USED_PERCENT;
599
599
  const hardMaxUsedPercent = input.diskHardMaxUsedPercent ?? DEFAULT_HARD_MAX_USED_PERCENT;
600
- const stats = statfsSync2(path79);
600
+ const stats = statfsSync2(path81);
601
601
  const freeBytes = Number(stats.bavail) * Number(stats.bsize);
602
602
  const totalBytes = Number(stats.blocks) * Number(stats.bsize);
603
603
  const usedPercent = totalBytes > 0 ? (totalBytes - freeBytes) / totalBytes * 100 : 100;
@@ -620,7 +620,7 @@ function observeRunnerDiskGate(input = {}) {
620
620
  }
621
621
  return {
622
622
  ok,
623
- path: path79,
623
+ path: path81,
624
624
  freeBytes,
625
625
  totalBytes,
626
626
  usedPercent,
@@ -2635,23 +2635,29 @@ function resolveCallbackSecret(argsSecret, agentOsId) {
2635
2635
  "requires --secret, KYNVER_RUNNER_TOKEN, a scoped runner token (`kynver runner credential`), ~/.kynver/credentials runnerToken, KYNVER_API_KEY with an API base URL to mint one, or (legacy) KYNVER_RUNTIME_SECRET / KYNVER_CRON_SECRET / OPENCLAW_CRON_SECRET"
2636
2636
  );
2637
2637
  }
2638
- async function resolveCallbackSecretWithMint(argsSecret, agentOsId, opts) {
2638
+ async function tryResolveCallbackSecretWithMint(argsSecret, agentOsId, opts) {
2639
2639
  const configured = resolveConfiguredCallbackSecret(argsSecret, agentOsId);
2640
- if (configured) return configured;
2640
+ if (configured) return { ok: true, secret: configured };
2641
2641
  const apiKey = loadApiKey();
2642
2642
  const baseUrl = resolveConfiguredBaseUrl(opts?.baseUrl);
2643
2643
  if (apiKey && agentOsId && baseUrl) {
2644
2644
  try {
2645
2645
  const token = await fetchRunnerCredential(agentOsId, { baseUrl, apiKey });
2646
2646
  saveRunnerToken(agentOsId, token);
2647
- return token;
2647
+ return { ok: true, secret: token };
2648
2648
  } catch (error) {
2649
- failConfig(`runner credential mint failed: ${error.message}`);
2649
+ return { ok: false, reason: `runner credential mint failed: ${error.message}` };
2650
2650
  }
2651
2651
  }
2652
- failConfig(
2653
- "requires --secret, KYNVER_RUNNER_TOKEN, a scoped runner token (`kynver runner credential`), ~/.kynver/credentials runnerToken, KYNVER_API_KEY with an API base URL to mint one, or (legacy) KYNVER_RUNTIME_SECRET / KYNVER_CRON_SECRET / OPENCLAW_CRON_SECRET"
2654
- );
2652
+ return {
2653
+ ok: false,
2654
+ reason: "no runner credential: requires --secret, KYNVER_RUNNER_TOKEN, a scoped runner token (`kynver runner credential`), ~/.kynver/credentials runnerToken, or KYNVER_API_KEY + API base URL to mint one"
2655
+ };
2656
+ }
2657
+ async function resolveCallbackSecretWithMint(argsSecret, agentOsId, opts) {
2658
+ const result = await tryResolveCallbackSecretWithMint(argsSecret, agentOsId, opts);
2659
+ if (result.ok) return result.secret;
2660
+ failConfig(result.reason);
2655
2661
  }
2656
2662
  async function refreshRunnerToken(agentOsId, opts) {
2657
2663
  const apiKey = loadApiKey();
@@ -2771,7 +2777,10 @@ async function runSetup(args) {
2771
2777
  ...existing,
2772
2778
  ...inferSetupFields(existing, args),
2773
2779
  ...workerConfig,
2774
- workerProvider: typeof args.provider === "string" ? args.provider : existing.workerProvider || "cursor"
2780
+ workerProvider: typeof args.provider === "string" ? args.provider : existing.workerProvider || "cursor",
2781
+ // M5.4 chat-turn delegation: `--chat-oauth` persists consent to use the
2782
+ // Claude Code CLI's local OAuth token for delegated chat turns.
2783
+ ...args.chatOauth === true ? { chatUseClaudeOauth: true } : {}
2775
2784
  });
2776
2785
  saveUserConfig(config);
2777
2786
  const boxIdentity = resolveBoxIdentity(process.env, config);
@@ -5858,8 +5867,8 @@ function dirtyPathsCoveredByDisposableRemoval(changedFiles, removed) {
5858
5867
  if (removed.length === 0) return false;
5859
5868
  const removedSet = new Set(removed.map((p) => normalizeRelativePath(p)));
5860
5869
  return material.every((line) => {
5861
- const path79 = normalizeRelativePath(pathFromGitStatusLine(line));
5862
- return removedSet.has(path79);
5870
+ const path81 = normalizeRelativePath(pathFromGitStatusLine(line));
5871
+ return removedSet.has(path81);
5863
5872
  });
5864
5873
  }
5865
5874
 
@@ -6709,6 +6718,9 @@ function buildBoard(run, workers, compact) {
6709
6718
  }
6710
6719
  return board;
6711
6720
  }
6721
+ function isTerminalDoneBoardWorker(worker) {
6722
+ return worker.status === "done" && worker.attention === "done";
6723
+ }
6712
6724
  function buildRunBoard(runId) {
6713
6725
  const run = loadRun(runId);
6714
6726
  const names = Object.keys(run.workers || {});
@@ -6729,7 +6741,7 @@ function buildRunBoard(runId) {
6729
6741
  function buildCompactRunBoard(runId) {
6730
6742
  const run = loadRun(runId);
6731
6743
  const names = Object.keys(run.workers || {});
6732
- const workers = names.map((name) => {
6744
+ const allWorkers = names.map((name) => {
6733
6745
  const worker = readJson(
6734
6746
  path21.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
6735
6747
  void 0
@@ -6740,7 +6752,17 @@ function buildCompactRunBoard(runId) {
6740
6752
  if (isMetadataTerminalDone(worker)) return buildCompactDoneEntry(name, worker);
6741
6753
  return buildWorkerBoardEntry({ run, workerName: name, worker });
6742
6754
  });
6755
+ const workers = allWorkers.filter((worker) => !isTerminalDoneBoardWorker(worker));
6743
6756
  const board = buildBoard(run, workers, true);
6757
+ board.status = deriveRunStatus(run.status, allWorkers);
6758
+ board.summary = {
6759
+ ...board.summary ?? {},
6760
+ totalWorkerCount: allWorkers.length,
6761
+ shownWorkerCount: workers.length,
6762
+ omittedTerminalDoneWorkerCount: allWorkers.length - workers.length,
6763
+ allStatusCounts: countBy(allWorkers, "status"),
6764
+ allAttentionCounts: countBy(allWorkers, "attention")
6765
+ };
6744
6766
  writeJson(path21.join(runDirectory(run.id), "last-board-compact.json"), board);
6745
6767
  return board;
6746
6768
  }
@@ -9355,7 +9377,7 @@ function applyProductionDatabaseToProcess(options = {}) {
9355
9377
  // src/worktree.ts
9356
9378
  init_git();
9357
9379
  init_run_store();
9358
- import { existsSync as existsSync29, mkdirSync as mkdirSync6 } from "node:fs";
9380
+ import { existsSync as existsSync29, mkdirSync as mkdirSync7 } from "node:fs";
9359
9381
  import path38 from "node:path";
9360
9382
 
9361
9383
  // src/run-list.ts
@@ -9438,7 +9460,7 @@ init_util();
9438
9460
  // src/worker-metadata-reconcile.ts
9439
9461
  init_heartbeat();
9440
9462
  init_stream();
9441
- import { existsSync as existsSync27, lstatSync, readdirSync as readdirSync7, readlinkSync, renameSync as renameSync2, rmSync } from "node:fs";
9463
+ import { existsSync as existsSync27, lstatSync, readdirSync as readdirSync7, readlinkSync, renameSync as renameSync3, rmSync } from "node:fs";
9442
9464
  import path34 from "node:path";
9443
9465
 
9444
9466
  // src/worker-metadata-paths.ts
@@ -9497,7 +9519,7 @@ function resolveWorkerJsonPath(input) {
9497
9519
  }
9498
9520
 
9499
9521
  // src/run-metadata-retention.ts
9500
- import { existsSync as existsSync26, readdirSync as readdirSync6, statSync as statSync5 } from "node:fs";
9522
+ import { existsSync as existsSync26, mkdirSync as mkdirSync6, readdirSync as readdirSync6, renameSync as renameSync2, statSync as statSync5 } from "node:fs";
9501
9523
  import path33 from "node:path";
9502
9524
 
9503
9525
  // src/default-repo.ts
@@ -9578,6 +9600,7 @@ init_paths();
9578
9600
  init_run_store();
9579
9601
  init_util();
9580
9602
  var RUN_METADATA_ACTIVE_SIGNAL_MS = 15 * 60 * 1e3;
9603
+ var TERMINAL_WORKER_ARCHIVE_AGE_MS = 60 * 60 * 1e3;
9581
9604
  function isHarnessRunMetadataPath(targetPath, harnessRoot) {
9582
9605
  const resolved = path33.resolve(targetPath);
9583
9606
  const runsDir = path33.resolve(harnessRunsDir(harnessRoot));
@@ -9601,6 +9624,14 @@ function listWorkerNamesOnDisk(runDir2) {
9601
9624
  return [];
9602
9625
  }
9603
9626
  }
9627
+ function workerArchiveDir(runDir2) {
9628
+ return path33.join(runDir2, "archived-workers");
9629
+ }
9630
+ function uniqueArchivePath(runDir2, workerName) {
9631
+ const base = path33.join(workerArchiveDir(runDir2), safeSlug(workerName));
9632
+ if (!existsSync26(base)) return base;
9633
+ return `${base}-${Date.now()}`;
9634
+ }
9604
9635
  function pathRecentlyTouched(target, now, windowMs) {
9605
9636
  if (!existsSync26(target)) return false;
9606
9637
  try {
@@ -9627,6 +9658,41 @@ function workerDirHasActiveRetentionSignals(workerDir, now = Date.now(), windowM
9627
9658
  if (pathRecentlyTouched(artifacts.heartbeatPath, now, windowMs)) return true;
9628
9659
  return false;
9629
9660
  }
9661
+ function workerTerminalArchiveAgeMs(workerDir, worker, now) {
9662
+ const completionReportedAt = typeof worker.completionReportedAt === "string" ? Date.parse(worker.completionReportedAt) : NaN;
9663
+ if (Number.isFinite(completionReportedAt)) return now - completionReportedAt;
9664
+ const completionSnapshotAt = (() => {
9665
+ const raw = worker.completionResponse;
9666
+ if (!raw || typeof raw !== "object") return NaN;
9667
+ const task = raw.task;
9668
+ if (!task || typeof task !== "object") return NaN;
9669
+ const updatedAt = task.updatedAt;
9670
+ return typeof updatedAt === "string" ? Date.parse(updatedAt) : NaN;
9671
+ })();
9672
+ if (Number.isFinite(completionSnapshotAt)) return now - completionSnapshotAt;
9673
+ try {
9674
+ return now - statSync5(path33.join(workerDir, "worker.json")).mtimeMs;
9675
+ } catch {
9676
+ return 0;
9677
+ }
9678
+ }
9679
+ function isArchiveEligibleTerminalWorker(workerDir, worker, now, archiveAgeMs) {
9680
+ if (workerDirHasActiveRetentionSignals(workerDir, now)) {
9681
+ return { eligible: false, reason: "worker has active/recent retention signals" };
9682
+ }
9683
+ const status = typeof worker.status === "string" ? worker.status : "";
9684
+ const completionBlocker = typeof worker.completionBlocker === "string" && worker.completionBlocker.trim().length > 0;
9685
+ if (completionBlocker) return { eligible: false, reason: "worker has completion blocker" };
9686
+ const completionAcknowledged = typeof worker.completionReportedAt === "string" || worker.completionOutcome === "acknowledged";
9687
+ if (status !== "done" && !completionAcknowledged) {
9688
+ return { eligible: false, reason: `worker status is ${status || "unknown"}` };
9689
+ }
9690
+ const age = workerTerminalArchiveAgeMs(workerDir, worker, now);
9691
+ if (!Number.isFinite(age) || age < archiveAgeMs) {
9692
+ return { eligible: false, reason: "terminal worker is still within archive grace window" };
9693
+ }
9694
+ return { eligible: true, reason: "terminal worker metadata archived" };
9695
+ }
9630
9696
  function runDirHasActiveRetentionSignals(runDir2, now = Date.now(), windowMs = RUN_METADATA_ACTIVE_SIGNAL_MS) {
9631
9697
  for (const name of listWorkerNamesOnDisk(runDir2)) {
9632
9698
  if (workerDirHasActiveRetentionSignals(path33.join(runDir2, "workers", name), now, windowMs)) {
@@ -9704,6 +9770,59 @@ function repairMissingRunMetadata(harnessRootInput) {
9704
9770
  }
9705
9771
  return { runs: outcomes };
9706
9772
  }
9773
+ function archiveTerminalWorkerMetadata(harnessRootInput, options = {}) {
9774
+ const harnessRoot = normalizeHarnessRoot(harnessRootInput ?? resolveHarnessRoot());
9775
+ const runsDir = harnessRunsDir(harnessRoot);
9776
+ const now = options.now ?? Date.now();
9777
+ const archiveAgeMs = options.archiveAgeMs ?? TERMINAL_WORKER_ARCHIVE_AGE_MS;
9778
+ const outcomes = [];
9779
+ repairMissingRunMetadata(harnessRoot);
9780
+ for (const runId of listRunDirIds(runsDir)) {
9781
+ const runDir2 = path33.join(runsDir, runId);
9782
+ const runJsonPath = path33.join(runDir2, "run.json");
9783
+ const run = readJson(runJsonPath, void 0);
9784
+ if (!run?.id) continue;
9785
+ const names = /* @__PURE__ */ new Set([...Object.keys(run.workers || {}), ...listWorkerNamesOnDisk(runDir2)]);
9786
+ let changed = false;
9787
+ for (const name of names) {
9788
+ const workerDir = path33.join(runDir2, "workers", safeSlug(name));
9789
+ const workerJsonPath = path33.join(workerDir, "worker.json");
9790
+ const worker = readJson(workerJsonPath, void 0);
9791
+ if (!worker) {
9792
+ const archivedWorkerDir = path33.join(workerArchiveDir(runDir2), safeSlug(name));
9793
+ if (existsSync26(archivedWorkerDir) && (run.workers[safeSlug(name)] || run.workers[name])) {
9794
+ delete run.workers[safeSlug(name)];
9795
+ delete run.workers[name];
9796
+ changed = true;
9797
+ outcomes.push({
9798
+ runId: run.id,
9799
+ worker: name,
9800
+ action: "archived",
9801
+ reason: "removed stale live index entry for archived worker metadata",
9802
+ archivePath: archivedWorkerDir
9803
+ });
9804
+ continue;
9805
+ }
9806
+ outcomes.push({ runId: run.id, worker: name, action: "skipped", reason: "worker.json missing" });
9807
+ continue;
9808
+ }
9809
+ const eligibility = isArchiveEligibleTerminalWorker(workerDir, worker, now, archiveAgeMs);
9810
+ if (!eligibility.eligible) {
9811
+ outcomes.push({ runId: run.id, worker: name, action: "skipped", reason: eligibility.reason });
9812
+ continue;
9813
+ }
9814
+ const archivePath = uniqueArchivePath(runDir2, name);
9815
+ mkdirSync6(path33.dirname(archivePath), { recursive: true });
9816
+ renameSync2(workerDir, archivePath);
9817
+ delete run.workers[safeSlug(name)];
9818
+ delete run.workers[name];
9819
+ changed = true;
9820
+ outcomes.push({ runId: run.id, worker: name, action: "archived", reason: eligibility.reason, archivePath });
9821
+ }
9822
+ if (changed) saveRun(run);
9823
+ }
9824
+ return { workers: outcomes };
9825
+ }
9707
9826
  function collectFilesystemLiveRunKeys(harnessRoot, now = Date.now()) {
9708
9827
  const keys = /* @__PURE__ */ new Set();
9709
9828
  const runsDir = harnessRunsDir(harnessRoot);
@@ -9733,9 +9852,9 @@ function materializeSymlinkedRunDir(harnessRoot, runId) {
9733
9852
  return null;
9734
9853
  }
9735
9854
  const staging = `${canonical}.materialize-${Date.now()}`;
9736
- renameSync2(linkedTarget, staging);
9855
+ renameSync3(linkedTarget, staging);
9737
9856
  rmSync(canonical);
9738
- renameSync2(staging, canonical);
9857
+ renameSync3(staging, canonical);
9739
9858
  return linkedTarget;
9740
9859
  }
9741
9860
  function relocateArtifacts(input) {
@@ -9744,7 +9863,7 @@ function relocateArtifacts(input) {
9744
9863
  const from = path34.join(input.fromDir, fileName);
9745
9864
  const to = path34.join(input.toDir, fileName);
9746
9865
  if (!existsSync27(from) || existsSync27(to)) continue;
9747
- renameSync2(from, to);
9866
+ renameSync3(from, to);
9748
9867
  moved.push(fileName);
9749
9868
  }
9750
9869
  return moved;
@@ -10225,7 +10344,14 @@ function reconcileStaleWorkers() {
10225
10344
  const metadataReconcile = reconcileWorkerMetadata();
10226
10345
  if (staleReconcileDisabled()) {
10227
10346
  const localPrAttentionReconcile2 = reconcileLocalOnlyMergedPrAttention();
10228
- return { workers: [], finalizedRuns: finalizeStaleRuns(), metadataReconcile, localPrAttentionReconcile: localPrAttentionReconcile2 };
10347
+ const terminalWorkerArchive2 = archiveTerminalWorkerMetadata();
10348
+ return {
10349
+ workers: [],
10350
+ finalizedRuns: finalizeStaleRuns(),
10351
+ metadataReconcile,
10352
+ localPrAttentionReconcile: localPrAttentionReconcile2,
10353
+ terminalWorkerArchive: terminalWorkerArchive2
10354
+ };
10229
10355
  }
10230
10356
  const outcomes = [];
10231
10357
  const now = Date.now();
@@ -10304,7 +10430,8 @@ function reconcileStaleWorkers() {
10304
10430
  }
10305
10431
  }
10306
10432
  const localPrAttentionReconcile = reconcileLocalOnlyMergedPrAttention();
10307
- return { workers: outcomes, finalizedRuns: finalizeStaleRuns(), metadataReconcile, localPrAttentionReconcile };
10433
+ const terminalWorkerArchive = archiveTerminalWorkerMetadata();
10434
+ return { workers: outcomes, finalizedRuns: finalizeStaleRuns(), metadataReconcile, localPrAttentionReconcile, terminalWorkerArchive };
10308
10435
  }
10309
10436
  function reconcileRunsCli() {
10310
10437
  const result = reconcileStaleWorkers();
@@ -10323,6 +10450,10 @@ function reconcileRunsCli() {
10323
10450
  acc[row.action] = (acc[row.action] ?? 0) + 1;
10324
10451
  return acc;
10325
10452
  }, {});
10453
+ const archiveTotals = result.terminalWorkerArchive.workers.reduce((acc, row) => {
10454
+ acc[row.action] = (acc[row.action] ?? 0) + 1;
10455
+ return acc;
10456
+ }, {});
10326
10457
  console.log(
10327
10458
  JSON.stringify(
10328
10459
  {
@@ -10340,11 +10471,16 @@ function reconcileRunsCli() {
10340
10471
  totals: localPrAttentionTotals,
10341
10472
  total: result.localPrAttentionReconcile.workers.length
10342
10473
  },
10474
+ terminalWorkerArchive: {
10475
+ totals: archiveTotals,
10476
+ total: result.terminalWorkerArchive.workers.length
10477
+ },
10343
10478
  finalizedRuns: result.finalizedRuns.length,
10344
10479
  details: {
10345
10480
  workers: result.workers,
10346
10481
  metadataReconcile: result.metadataReconcile.workers,
10347
10482
  localPrAttentionReconcile: result.localPrAttentionReconcile.workers,
10483
+ terminalWorkerArchive: result.terminalWorkerArchive.workers,
10348
10484
  runMetadataRetention: result.metadataReconcile.runMetadataRetention.runs,
10349
10485
  finalizedRuns: result.finalizedRuns
10350
10486
  }
@@ -10488,7 +10624,7 @@ function createRun(args) {
10488
10624
  const id = args.id ? validateRunId(String(args.id)) : timestampSlug(String(args.name || "run"));
10489
10625
  const dir = runDirectory(id);
10490
10626
  if (existsSync29(dir)) failExists(`run already exists: ${id}`);
10491
- mkdirSync6(dir, { recursive: true });
10627
+ mkdirSync7(dir, { recursive: true });
10492
10628
  const base = String(args.base || "origin/main");
10493
10629
  const baseCommit = git(repo, ["rev-parse", base]).trim();
10494
10630
  const run = {
@@ -10742,11 +10878,11 @@ function harnessStorageSnapshot(opts = {}) {
10742
10878
 
10743
10879
  // src/cleanup.ts
10744
10880
  init_paths();
10745
- import path53 from "node:path";
10881
+ import path55 from "node:path";
10746
10882
 
10747
10883
  // src/cleanup-guards.ts
10748
10884
  init_landing_gate();
10749
- import path42 from "node:path";
10885
+ import path43 from "node:path";
10750
10886
 
10751
10887
  // src/cleanup-index-status.ts
10752
10888
  init_git();
@@ -10889,6 +11025,44 @@ init_status();
10889
11025
  // src/cleanup-run-liveness.ts
10890
11026
  init_status();
10891
11027
 
11028
+ // src/cleanup-worker-harness-live.ts
11029
+ init_heartbeat();
11030
+ init_util();
11031
+ function heartbeatContentIsFresh(worker, now = Date.now(), windowMs = RUN_METADATA_ACTIVE_SIGNAL_MS) {
11032
+ const heartbeat = parseHeartbeat(worker.heartbeatPath);
11033
+ if (!heartbeat.lastHeartbeatAt) return false;
11034
+ const age = now - Date.parse(heartbeat.lastHeartbeatAt);
11035
+ return Number.isFinite(age) && age >= 0 && age < windowMs;
11036
+ }
11037
+ function isHarnessWorkerHarnessLive(worker, now = Date.now(), windowMs = RUN_METADATA_ACTIVE_SIGNAL_MS) {
11038
+ if (isPidAlive(worker.pid)) return true;
11039
+ return heartbeatContentIsFresh(worker, now, windowMs);
11040
+ }
11041
+
11042
+ // src/cleanup-run-liveness.ts
11043
+ function deriveRunTerminal(indexed, ctx) {
11044
+ if (ctx) return ctx.runTerminalCache.derive(indexed.run);
11045
+ return deriveTerminalRunStatus(indexed.run);
11046
+ }
11047
+ function isWorkerProcessLive(indexed, now = Date.now()) {
11048
+ return isHarnessWorkerHarnessLive(indexed.worker, now);
11049
+ }
11050
+ function isRunStaleActive(indexed, ctx) {
11051
+ if (TERMINAL_RUN_STATUSES.has(indexed.run.status)) return false;
11052
+ return deriveRunTerminal(indexed, ctx) !== null;
11053
+ }
11054
+ function runBlocksWorktreeRemoval(indexed, ctx, now = Date.now()) {
11055
+ if (isWorkerProcessLive(indexed, now)) return true;
11056
+ if (TERMINAL_RUN_STATUSES.has(indexed.run.status)) return false;
11057
+ if (isRunStaleActive(indexed, ctx)) return false;
11058
+ const status = indexedWorktreeStatus(indexed);
11059
+ if (!isFinishedWorkerStatus(status)) {
11060
+ if (!isWorkerProcessLive(indexed, now)) return false;
11061
+ return true;
11062
+ }
11063
+ return false;
11064
+ }
11065
+
10892
11066
  // src/cleanup-completion-blocker.ts
10893
11067
  init_landing_gate();
10894
11068
  init_status();
@@ -10910,51 +11084,80 @@ function completionBlockerBlocksWorktreeRemoval(indexed, status) {
10910
11084
  return false;
10911
11085
  }
10912
11086
 
10913
- // src/cleanup-run-liveness.ts
11087
+ // src/cleanup-salvage-evidence.ts
11088
+ init_git();
10914
11089
  init_util();
10915
- var TERMINAL_WORKER_JSON_STATUSES = /* @__PURE__ */ new Set([
10916
- "done",
10917
- "exited",
10918
- "blocked",
10919
- "failed",
10920
- "abandoned"
10921
- ]);
10922
- function deriveRunTerminal(indexed, ctx) {
10923
- if (ctx) return ctx.runTerminalCache.derive(indexed.run);
10924
- return deriveTerminalRunStatus(indexed.run);
10925
- }
10926
- function isWorkerProcessLive(indexed) {
10927
- if (isPidAlive(indexed.worker.pid)) return true;
10928
- if (typeof indexed.worker.completionReportedAt === "string" && indexed.worker.completionReportedAt.trim().length > 0) {
10929
- return false;
10930
- }
10931
- const workerStatus2 = indexed.worker.status;
10932
- if (workerStatus2 && TERMINAL_WORKER_JSON_STATUSES.has(workerStatus2)) return false;
10933
- if (!indexed.worker.pid) {
10934
- if (workerStatus2 !== "running") return false;
10935
- return indexedWorktreeStatus(indexed).alive;
10936
- }
10937
- return false;
11090
+ import { existsSync as existsSync32, mkdirSync as mkdirSync8, writeFileSync as writeFileSync4 } from "node:fs";
11091
+ import path42 from "node:path";
11092
+ function salvageEvidenceDir(harnessRoot, runId, workerName) {
11093
+ return path42.join(harnessRoot, "salvage", safeSlug(runId), safeSlug(workerName));
10938
11094
  }
10939
- function isRunStaleActive(indexed, ctx) {
10940
- if (TERMINAL_RUN_STATUSES.has(indexed.run.status)) return false;
10941
- return deriveRunTerminal(indexed, ctx) !== null;
11095
+ function hasSalvageEvidence(input) {
11096
+ return existsSync32(path42.join(salvageEvidenceDir(input.harnessRoot, input.runId, input.workerName), "evidence.json"));
10942
11097
  }
10943
- function runBlocksWorktreeRemoval(indexed, ctx) {
10944
- if (isWorkerProcessLive(indexed)) return true;
10945
- const workerStatus2 = indexed.worker.status;
10946
- if (workerStatus2 && TERMINAL_WORKER_JSON_STATUSES.has(workerStatus2) && !indexed.worker.completionBlocker) {
10947
- return false;
10948
- }
10949
- const status = indexedWorktreeStatus(indexed);
10950
- if (completionBlockerBlocksWorktreeRemoval(indexed, status)) return true;
10951
- if (isFinishedWorkerStatus(status)) return false;
10952
- if (TERMINAL_RUN_STATUSES.has(indexed.run.status)) return false;
10953
- if (isRunStaleActive(indexed, ctx)) return false;
10954
- return deriveRunTerminal(indexed, ctx) === null;
11098
+ function writeWorktreeSalvageEvidence(input) {
11099
+ const dir = salvageEvidenceDir(input.harnessRoot, input.indexed.runId, input.indexed.workerName);
11100
+ mkdirSync8(dir, { recursive: true });
11101
+ const patchPath = path42.join(dir, "salvage.patch");
11102
+ let wrotePatch = false;
11103
+ if (existsSync32(input.indexed.worktreePath)) {
11104
+ const diff = gitCapture(input.indexed.worktreePath, ["diff", "HEAD"]);
11105
+ const staged = gitCapture(input.indexed.worktreePath, ["diff", "--cached"]);
11106
+ const patch = [diff.stdout, staged.stdout].filter((chunk) => chunk.trim()).join("\n");
11107
+ if (patch.trim()) {
11108
+ writeFileSync4(patchPath, patch.endsWith("\n") ? patch : `${patch}
11109
+ `);
11110
+ wrotePatch = true;
11111
+ }
11112
+ }
11113
+ const record3 = {
11114
+ capturedAt: new Date(input.now ?? Date.now()).toISOString(),
11115
+ skipReason: input.skipReason,
11116
+ runId: input.indexed.runId,
11117
+ workerName: input.indexed.workerName,
11118
+ worktreePath: input.indexed.worktreePath,
11119
+ taskId: input.indexed.worker.taskId,
11120
+ agentOsId: input.indexed.worker.agentOsId,
11121
+ branch: input.indexed.worker.branch,
11122
+ completionBlocker: input.indexed.worker.completionBlocker,
11123
+ finalResult: input.status.finalResult,
11124
+ changedFiles: input.status.changedFiles,
11125
+ gitAncestry: input.status.gitAncestry,
11126
+ prUrl: input.status.prUrl ?? null,
11127
+ ...wrotePatch ? { patchPath } : {}
11128
+ };
11129
+ writeFileSync4(path42.join(dir, "evidence.json"), `${JSON.stringify(record3, null, 2)}
11130
+ `);
11131
+ return record3;
10955
11132
  }
10956
11133
 
10957
11134
  // src/cleanup-guards.ts
11135
+ var SALVAGE_ELIGIBLE_SKIP_REASONS = /* @__PURE__ */ new Set([
11136
+ "completion_blocked",
11137
+ "dirty_worktree",
11138
+ "pr_or_unmerged_commits",
11139
+ "landing_blocked"
11140
+ ]);
11141
+ function maybeSalvageBlockedWorktree(input) {
11142
+ if (!SALVAGE_ELIGIBLE_SKIP_REASONS.has(input.skipReason)) return false;
11143
+ if (isWorkerProcessLive(input.indexed, input.now)) return false;
11144
+ if (hasSalvageEvidence({
11145
+ harnessRoot: input.harnessRoot,
11146
+ runId: input.indexed.runId,
11147
+ workerName: input.indexed.workerName
11148
+ })) {
11149
+ return true;
11150
+ }
11151
+ if (!input.writeSalvageEvidence) return false;
11152
+ writeWorktreeSalvageEvidence({
11153
+ harnessRoot: input.harnessRoot,
11154
+ indexed: input.indexed,
11155
+ skipReason: input.skipReason,
11156
+ status: input.status,
11157
+ now: input.now
11158
+ });
11159
+ return true;
11160
+ }
10958
11161
  function effectiveWorktreeAgeMs(input) {
10959
11162
  const { indexed, includeOrphans, worktreesAgeMs, terminalWorktreesAgeMs } = input;
10960
11163
  if (!indexed) return includeOrphans ? terminalWorktreesAgeMs : worktreesAgeMs;
@@ -10969,8 +11172,18 @@ function effectiveWorktreeAgeMs(input) {
10969
11172
  }
10970
11173
  return worktreesAgeMs;
10971
11174
  }
11175
+ function resolveHarnessRoot2(input, indexed) {
11176
+ if (input.harnessRoot?.trim()) return path43.resolve(input.harnessRoot);
11177
+ const workerDir = indexed.worker.workerDir;
11178
+ if (!workerDir) return null;
11179
+ const runsMarker = `${path43.sep}runs${path43.sep}`;
11180
+ const idx = workerDir.indexOf(runsMarker);
11181
+ if (idx < 0) return null;
11182
+ return workerDir.slice(0, idx + runsMarker.length - 1);
11183
+ }
10972
11184
  function skipWorktreeRemoval(input) {
10973
11185
  const { indexed, includeOrphans, worktreesAgeMs, ageMs, orphanSafety, worktreeRemovalGuard } = input;
11186
+ const now = input.now ?? Date.now();
10974
11187
  if (!indexed) {
10975
11188
  if (!includeOrphans) return "orphan_without_flag";
10976
11189
  return orphanSafety ?? null;
@@ -10978,25 +11191,55 @@ function skipWorktreeRemoval(input) {
10978
11191
  const ageThresholdMs = effectiveWorktreeAgeMs(input);
10979
11192
  if (worktreesAgeMs <= 0 && !includeOrphans && ageThresholdMs <= 0) return "worktrees_disabled";
10980
11193
  if (ageThresholdMs > 0 && ageMs < ageThresholdMs) return "below_age_threshold";
10981
- if (isWorkerProcessLive(indexed)) return "active_worker";
11194
+ if (isWorkerProcessLive(indexed, now)) return "active_worker";
11195
+ const status = resolveWorktreeGuardStatus(indexed, input.liveness);
11196
+ const salvageHarnessRoot = resolveHarnessRoot2(input, indexed);
11197
+ const salvageOrBlock = (skipReason) => {
11198
+ if (salvageHarnessRoot && maybeSalvageBlockedWorktree({
11199
+ indexed,
11200
+ harnessRoot: salvageHarnessRoot,
11201
+ skipReason,
11202
+ status,
11203
+ now,
11204
+ writeSalvageEvidence: input.writeSalvageEvidence === true
11205
+ })) {
11206
+ return null;
11207
+ }
11208
+ return skipReason;
11209
+ };
11210
+ if (completionBlockerBlocksWorktreeRemoval(indexed, status)) {
11211
+ const blocked = salvageOrBlock("completion_blocked");
11212
+ if (blocked) return blocked;
11213
+ }
10982
11214
  if (indexedWorktreeHasMaterialChanges(indexed, input.liveness?.gitStatusCache)) {
10983
- return "dirty_worktree";
11215
+ const blocked = salvageOrBlock("dirty_worktree");
11216
+ if (blocked) return blocked;
10984
11217
  }
10985
11218
  const ahead = input.liveness?.gitRevCache?.countAheadOfMain(input.worktreePath);
10986
- if (ahead !== null && ahead !== void 0 && ahead > 0) return "pr_or_unmerged_commits";
10987
- const status = resolveWorktreeGuardStatus(indexed, input.liveness);
10988
- if (completionBlockerBlocksWorktreeRemoval(indexed, status)) return "completion_blocked";
10989
- if (runBlocksWorktreeRemoval(indexed, input.liveness)) return "run_still_active";
11219
+ if (ahead !== null && ahead !== void 0 && ahead > 0) {
11220
+ const blocked = salvageOrBlock("pr_or_unmerged_commits");
11221
+ if (blocked) return blocked;
11222
+ }
11223
+ if (runBlocksWorktreeRemoval(indexed, input.liveness, now)) return "run_still_active";
10990
11224
  if (!isFinishedWorkerStatus(status)) return "run_still_active";
10991
- if (isPrOrUnmergedWork(status)) return "pr_or_unmerged_commits";
10992
- if (materialWorktreeChanges2(status.changedFiles).length > 0) return "dirty_worktree";
11225
+ if (isPrOrUnmergedWork(status)) {
11226
+ const blocked = salvageOrBlock("pr_or_unmerged_commits");
11227
+ if (blocked) return blocked;
11228
+ }
11229
+ if (materialWorktreeChanges2(status.changedFiles).length > 0) {
11230
+ const blocked = salvageOrBlock("dirty_worktree");
11231
+ if (blocked) return blocked;
11232
+ }
10993
11233
  const landing = assessWorkerLanding({
10994
11234
  finalResult: status.finalResult,
10995
11235
  changedFiles: status.changedFiles,
10996
11236
  gitAncestry: status.gitAncestry,
10997
11237
  prUrl: prUrlFromFinalResult(status.finalResult)
10998
11238
  });
10999
- if (landing.blocked) return "landing_blocked";
11239
+ if (landing.blocked) {
11240
+ const blocked = salvageOrBlock("landing_blocked");
11241
+ if (blocked) return blocked;
11242
+ }
11000
11243
  if (worktreeRemovalGuard && input.worktreePath) {
11001
11244
  const overlay = worktreeRemovalGuard({
11002
11245
  worktreePath: input.worktreePath,
@@ -11013,7 +11256,7 @@ function skipWorktreeRemoval(input) {
11013
11256
  function skipDependencyCacheRemoval(input) {
11014
11257
  const { indexed, nodeModulesAgeMs, ageMs, worktreePath, activeWorktreePaths, diskPressure } = input;
11015
11258
  if (!diskPressure && ageMs < nodeModulesAgeMs) return "below_age_threshold";
11016
- if (activeWorktreePaths.has(path42.resolve(worktreePath))) return "active_worker";
11259
+ if (activeWorktreePaths.has(path43.resolve(worktreePath))) return "active_worker";
11017
11260
  if (indexed && isWorkerProcessLive(indexed)) return "active_worker";
11018
11261
  if (indexed && indexedWorktreeHasMaterialChanges(indexed, input.gitStatusCache)) {
11019
11262
  return "dirty_worktree";
@@ -11042,11 +11285,11 @@ var LIVE_SKIP_REASONS = /* @__PURE__ */ new Set([
11042
11285
  function collectPreservedLivePaths(actions, skips) {
11043
11286
  const out = [];
11044
11287
  const seen = /* @__PURE__ */ new Set();
11045
- const push = (path79, reason, detail) => {
11046
- const key = `${path79}\0${reason}`;
11288
+ const push = (path81, reason, detail) => {
11289
+ const key = `${path81}\0${reason}`;
11047
11290
  if (seen.has(key) || out.length >= MAX_PRESERVED_LIVE_PATH_SAMPLES) return;
11048
11291
  seen.add(key);
11049
- out.push({ path: path79, reason, ...detail ? { detail } : {} });
11292
+ out.push({ path: path81, reason, ...detail ? { detail } : {} });
11050
11293
  };
11051
11294
  for (const skip2 of skips) {
11052
11295
  if (!LIVE_SKIP_REASONS.has(skip2.reason)) continue;
@@ -11061,31 +11304,16 @@ function collectPreservedLivePaths(actions, skips) {
11061
11304
  }
11062
11305
 
11063
11306
  // src/cleanup-run-directory.ts
11064
- import { existsSync as existsSync33, readdirSync as readdirSync11, statSync as statSync9 } from "node:fs";
11065
- import path44 from "node:path";
11307
+ import { existsSync as existsSync33, readdirSync as readdirSync10, statSync as statSync8 } from "node:fs";
11308
+ import path45 from "node:path";
11066
11309
 
11067
11310
  // src/cleanup-active-worktrees.ts
11068
11311
  init_run_store();
11069
11312
  init_paths();
11070
- import { existsSync as existsSync32, readdirSync as readdirSync10, statSync as statSync8 } from "node:fs";
11071
- import path43 from "node:path";
11313
+ import path44 from "node:path";
11072
11314
  init_util();
11073
- function workerHasRecentHarnessActivity(worker, now) {
11074
- const paths = [worker.heartbeatPath, worker.stdoutPath, worker.stderrPath];
11075
- for (const target of paths) {
11076
- if (!existsSync32(target)) continue;
11077
- try {
11078
- const age = now - statSync8(target).mtimeMs;
11079
- if (Number.isFinite(age) && age >= 0 && age < RUN_METADATA_ACTIVE_SIGNAL_MS) return true;
11080
- } catch {
11081
- }
11082
- }
11083
- return false;
11084
- }
11085
11315
  function isActiveHarnessWorker2(worker, now) {
11086
- if (isPidAlive(worker.pid)) return true;
11087
- if (worker.status === "running" && workerHasRecentHarnessActivity(worker, now)) return true;
11088
- return false;
11316
+ return isHarnessWorkerHarnessLive(worker, now);
11089
11317
  }
11090
11318
  function collectActiveWorktreeGuards(harnessRoots, now = Date.now()) {
11091
11319
  const activeWorktreePaths = /* @__PURE__ */ new Set();
@@ -11095,11 +11323,11 @@ function collectActiveWorktreeGuards(harnessRoots, now = Date.now()) {
11095
11323
  let runHasLive = false;
11096
11324
  for (const name of Object.keys(run.workers || {})) {
11097
11325
  const worker = readJson(
11098
- path43.join(runDirectoryAt(harnessRoot, run.id), "workers", safeSlug(name), "worker.json"),
11326
+ path44.join(runDirectoryAt(harnessRoot, run.id), "workers", safeSlug(name), "worker.json"),
11099
11327
  void 0
11100
11328
  );
11101
11329
  if (!worker?.worktreePath) continue;
11102
- const worktreePath = path43.resolve(worker.worktreePath);
11330
+ const worktreePath = path44.resolve(worker.worktreePath);
11103
11331
  if (!isActiveHarnessWorker2(worker, now)) continue;
11104
11332
  runHasLive = true;
11105
11333
  activeWorktreePaths.add(worktreePath);
@@ -11121,20 +11349,20 @@ function isWorktreeOnLiveRun(worktreePath, harnessRoot, runId, liveRunKeys) {
11121
11349
  init_util();
11122
11350
  function pathAgeMs(target, now) {
11123
11351
  try {
11124
- const mtime = statSync9(target).mtimeMs;
11352
+ const mtime = statSync8(target).mtimeMs;
11125
11353
  return Math.max(0, now - mtime);
11126
11354
  } catch {
11127
11355
  return 0;
11128
11356
  }
11129
11357
  }
11130
11358
  function loadRunStatus(harnessRoot, runId) {
11131
- const runPath = path44.join(harnessRoot, "runs", runId, "run.json");
11359
+ const runPath = path45.join(harnessRoot, "runs", runId, "run.json");
11132
11360
  if (!existsSync33(runPath)) return null;
11133
11361
  return readJson(runPath, null);
11134
11362
  }
11135
11363
  function runDirectoryIsEmpty(runPath) {
11136
11364
  try {
11137
- const entries = readdirSync11(runPath);
11365
+ const entries = readdirSync10(runPath);
11138
11366
  return entries.length === 0;
11139
11367
  } catch {
11140
11368
  return false;
@@ -11158,7 +11386,7 @@ function scanStaleRunDirectoryCandidates(opts) {
11158
11386
  const candidates = [];
11159
11387
  let entries;
11160
11388
  try {
11161
- entries = readdirSync11(opts.worktreesDir, { withFileTypes: true });
11389
+ entries = readdirSync10(opts.worktreesDir, { withFileTypes: true });
11162
11390
  } catch {
11163
11391
  return [];
11164
11392
  }
@@ -11166,7 +11394,7 @@ function scanStaleRunDirectoryCandidates(opts) {
11166
11394
  if (!runEntry.isDirectory()) continue;
11167
11395
  const runId = runEntry.name;
11168
11396
  if (opts.runIdFilter && runId !== opts.runIdFilter) continue;
11169
- const runPath = path44.join(opts.worktreesDir, runId);
11397
+ const runPath = path45.join(opts.worktreesDir, runId);
11170
11398
  if (!runDirectoryIsEmpty(runPath)) continue;
11171
11399
  candidates.push({
11172
11400
  kind: "remove_run_directory",
@@ -11189,7 +11417,7 @@ import { existsSync as existsSync34, rmSync as rmSync2 } from "node:fs";
11189
11417
  init_paths();
11190
11418
 
11191
11419
  // src/cleanup-path-ownership.ts
11192
- import { lstatSync as lstatSync2, readdirSync as readdirSync12 } from "node:fs";
11420
+ import { lstatSync as lstatSync2, readdirSync as readdirSync11 } from "node:fs";
11193
11421
  function readPathOwnership(targetPath) {
11194
11422
  try {
11195
11423
  const st = lstatSync2(targetPath);
@@ -11206,7 +11434,7 @@ function pathHasForeignOwnedEntry(targetPath, maxEntries = 32) {
11206
11434
  if (!root) return false;
11207
11435
  if (root.foreign) return true;
11208
11436
  try {
11209
- const names = readdirSync12(targetPath);
11437
+ const names = readdirSync11(targetPath);
11210
11438
  let checked = 0;
11211
11439
  for (const name of names) {
11212
11440
  if (checked >= maxEntries) break;
@@ -11222,20 +11450,20 @@ function pathHasForeignOwnedEntry(targetPath, maxEntries = 32) {
11222
11450
 
11223
11451
  // src/cleanup-privileged-remove.ts
11224
11452
  import { spawnSync as spawnSync7 } from "node:child_process";
11225
- import path46 from "node:path";
11453
+ import path47 from "node:path";
11226
11454
 
11227
11455
  // src/cleanup-harness-path-validate.ts
11228
- import path45 from "node:path";
11456
+ import path46 from "node:path";
11229
11457
  function isHarnessDependencyCachePath(targetPath, harnessRoot, worktreesDir, cacheDirName) {
11230
- const resolved = path45.resolve(targetPath);
11231
- const suffix = `${path45.sep}${cacheDirName}`;
11458
+ const resolved = path46.resolve(targetPath);
11459
+ const suffix = `${path46.sep}${cacheDirName}`;
11232
11460
  const cachePath = resolved.endsWith(suffix) ? resolved : null;
11233
11461
  if (!cachePath) return "path_outside_harness";
11234
- const rel = path45.relative(worktreesDir, cachePath);
11235
- if (rel.startsWith("..") || path45.isAbsolute(rel)) return "path_outside_harness";
11236
- const parts = rel.split(path45.sep);
11462
+ const rel = path46.relative(worktreesDir, cachePath);
11463
+ if (rel.startsWith("..") || path46.isAbsolute(rel)) return "path_outside_harness";
11464
+ const parts = rel.split(path46.sep);
11237
11465
  if (parts.length < 3 || parts[parts.length - 1] !== cacheDirName) return "path_outside_harness";
11238
- if (!resolved.startsWith(path45.resolve(harnessRoot))) return "path_outside_harness";
11466
+ if (!resolved.startsWith(path46.resolve(harnessRoot))) return "path_outside_harness";
11239
11467
  return null;
11240
11468
  }
11241
11469
  function isHarnessNodeModulesPath(targetPath, harnessRoot, worktreesDir) {
@@ -11245,16 +11473,16 @@ function isHarnessNextCachePath(targetPath, harnessRoot, worktreesDir) {
11245
11473
  return isHarnessDependencyCachePath(targetPath, harnessRoot, worktreesDir, ".next");
11246
11474
  }
11247
11475
  function isHarnessBuildCachePath(targetPath, harnessRoot, worktreesDir) {
11248
- const resolved = path45.resolve(targetPath);
11249
- const relToWt = path45.relative(worktreesDir, resolved);
11250
- if (relToWt.startsWith("..") || path45.isAbsolute(relToWt)) return "path_outside_harness";
11251
- const parts = relToWt.split(path45.sep);
11476
+ const resolved = path46.resolve(targetPath);
11477
+ const relToWt = path46.relative(worktreesDir, resolved);
11478
+ if (relToWt.startsWith("..") || path46.isAbsolute(relToWt)) return "path_outside_harness";
11479
+ const parts = relToWt.split(path46.sep);
11252
11480
  if (parts.length < 3) return "path_outside_harness";
11253
- if (!resolved.startsWith(path45.resolve(harnessRoot))) return "path_outside_harness";
11481
+ if (!resolved.startsWith(path46.resolve(harnessRoot))) return "path_outside_harness";
11254
11482
  return null;
11255
11483
  }
11256
11484
  function isHarnessGeneratedCachePath(targetPath, harnessRoot, worktreesDir) {
11257
- const resolved = path45.resolve(targetPath);
11485
+ const resolved = path46.resolve(targetPath);
11258
11486
  return isHarnessNodeModulesPath(resolved, harnessRoot, worktreesDir) === null || isHarnessNextCachePath(resolved, harnessRoot, worktreesDir) === null || isHarnessBuildCachePath(resolved, harnessRoot, worktreesDir) === null;
11259
11487
  }
11260
11488
 
@@ -11288,12 +11516,12 @@ function tryPrivilegedReclaimHarnessCache(targetPath, harnessRoot, worktreesDir)
11288
11516
  "chown",
11289
11517
  "-R",
11290
11518
  `${effectiveUid}:${effectiveGid}`,
11291
- path46.resolve(targetPath)
11519
+ path47.resolve(targetPath)
11292
11520
  ]);
11293
11521
  if (chown.ok) {
11294
11522
  return { ok: true, method: "chown_then_rm" };
11295
11523
  }
11296
- const rm = runSudoNonInteractive(["rm", "-rf", path46.resolve(targetPath)]);
11524
+ const rm = runSudoNonInteractive(["rm", "-rf", path47.resolve(targetPath)]);
11297
11525
  if (rm.ok) {
11298
11526
  return { ok: true, method: "sudo_rm" };
11299
11527
  }
@@ -11494,27 +11722,27 @@ function removeWorktree(candidate, execute) {
11494
11722
  }
11495
11723
 
11496
11724
  // src/cleanup-scan.ts
11497
- import { existsSync as existsSync36, readdirSync as readdirSync13, statSync as statSync10 } from "node:fs";
11498
- import path47 from "node:path";
11725
+ import { existsSync as existsSync36, readdirSync as readdirSync12, statSync as statSync9 } from "node:fs";
11726
+ import path48 from "node:path";
11499
11727
  function pathAgeMs2(target, now) {
11500
11728
  try {
11501
- const mtime = statSync10(target).mtimeMs;
11729
+ const mtime = statSync9(target).mtimeMs;
11502
11730
  return Math.max(0, now - mtime);
11503
11731
  } catch {
11504
11732
  return 0;
11505
11733
  }
11506
11734
  }
11507
11735
  function isPathInside(child, parent) {
11508
- const rel = path47.relative(parent, child);
11509
- return rel === "" || !rel.startsWith("..") && !path47.isAbsolute(rel);
11736
+ const rel = path48.relative(parent, child);
11737
+ return rel === "" || !rel.startsWith("..") && !path48.isAbsolute(rel);
11510
11738
  }
11511
11739
  function collectBuildCacheForWorktree(worktreePath, opts, seen, meta) {
11512
11740
  const out = [];
11513
11741
  for (const rel of HARNESS_BUILD_CACHE_RELATIVE_PATHS) {
11514
11742
  if (rel === ".next") continue;
11515
- const target = path47.join(worktreePath, rel);
11743
+ const target = path48.join(worktreePath, rel);
11516
11744
  if (!existsSync36(target)) continue;
11517
- const resolved = path47.resolve(target);
11745
+ const resolved = path48.resolve(target);
11518
11746
  if (seen.has(resolved)) continue;
11519
11747
  if (!isPathInside(resolved, opts.harnessRoot)) continue;
11520
11748
  seen.add(resolved);
@@ -11544,12 +11772,12 @@ function scanBuildCacheCandidates(opts) {
11544
11772
  );
11545
11773
  }
11546
11774
  if (!opts.includeOrphans || !existsSync36(opts.worktreesDir)) return candidates;
11547
- for (const runEntry of readdirSync13(opts.worktreesDir, { withFileTypes: true })) {
11775
+ for (const runEntry of readdirSync12(opts.worktreesDir, { withFileTypes: true })) {
11548
11776
  if (!runEntry.isDirectory()) continue;
11549
- const runPath = path47.join(opts.worktreesDir, runEntry.name);
11550
- for (const workerEntry of readdirSync13(runPath, { withFileTypes: true })) {
11777
+ const runPath = path48.join(opts.worktreesDir, runEntry.name);
11778
+ for (const workerEntry of readdirSync12(runPath, { withFileTypes: true })) {
11551
11779
  if (!workerEntry.isDirectory()) continue;
11552
- const worktreePath = path47.join(runPath, workerEntry.name);
11780
+ const worktreePath = path48.join(runPath, workerEntry.name);
11553
11781
  candidates.push(
11554
11782
  ...collectBuildCacheForWorktree(worktreePath, opts, seen, {
11555
11783
  runId: runEntry.name,
@@ -11587,21 +11815,21 @@ function scanWorktreeCandidates(opts) {
11587
11815
  if (!orphanEnabled || !existsSync36(opts.worktreesDir)) return candidates;
11588
11816
  const indexedPaths = /* @__PURE__ */ new Set();
11589
11817
  for (const entry of opts.index.values()) {
11590
- indexedPaths.add(path47.resolve(entry.worktreePath));
11818
+ indexedPaths.add(path48.resolve(entry.worktreePath));
11591
11819
  }
11592
- for (const runEntry of readdirSync13(opts.worktreesDir, { withFileTypes: true })) {
11820
+ for (const runEntry of readdirSync12(opts.worktreesDir, { withFileTypes: true })) {
11593
11821
  if (!runEntry.isDirectory()) continue;
11594
11822
  if (opts.runIdFilter && runEntry.name !== opts.runIdFilter) continue;
11595
- const runPath = path47.join(opts.worktreesDir, runEntry.name);
11823
+ const runPath = path48.join(opts.worktreesDir, runEntry.name);
11596
11824
  let workerEntries;
11597
11825
  try {
11598
- workerEntries = readdirSync13(runPath, { withFileTypes: true });
11826
+ workerEntries = readdirSync12(runPath, { withFileTypes: true });
11599
11827
  } catch {
11600
11828
  continue;
11601
11829
  }
11602
11830
  for (const workerEntry of workerEntries) {
11603
11831
  if (!workerEntry.isDirectory()) continue;
11604
- const worktreePath = path47.resolve(path47.join(runPath, workerEntry.name));
11832
+ const worktreePath = path48.resolve(path48.join(runPath, workerEntry.name));
11605
11833
  if (seen.has(worktreePath)) continue;
11606
11834
  if (indexedPaths.has(worktreePath)) continue;
11607
11835
  if (!isPathInside(worktreePath, opts.harnessRoot)) continue;
@@ -11620,27 +11848,27 @@ function scanWorktreeCandidates(opts) {
11620
11848
  }
11621
11849
 
11622
11850
  // src/cleanup-dependency-scan.ts
11623
- import { existsSync as existsSync37, readdirSync as readdirSync14, statSync as statSync11 } from "node:fs";
11624
- import path48 from "node:path";
11851
+ import { existsSync as existsSync37, readdirSync as readdirSync13, statSync as statSync10 } from "node:fs";
11852
+ import path49 from "node:path";
11625
11853
  var DEPENDENCY_CACHE_DIRS = [
11626
11854
  { dirName: "node_modules", kind: "remove_node_modules" },
11627
11855
  { dirName: ".next", kind: "remove_next_cache" }
11628
11856
  ];
11629
11857
  function pathAgeMs3(target, now) {
11630
11858
  try {
11631
- const mtime = statSync11(target).mtimeMs;
11859
+ const mtime = statSync10(target).mtimeMs;
11632
11860
  return Math.max(0, now - mtime);
11633
11861
  } catch {
11634
11862
  return 0;
11635
11863
  }
11636
11864
  }
11637
11865
  function isPathInside2(child, parent) {
11638
- const rel = path48.relative(parent, child);
11639
- return rel === "" || !rel.startsWith("..") && !path48.isAbsolute(rel);
11866
+ const rel = path49.relative(parent, child);
11867
+ return rel === "" || !rel.startsWith("..") && !path49.isAbsolute(rel);
11640
11868
  }
11641
11869
  function pushCandidate2(candidates, seen, opts, targetPath, kind, meta) {
11642
11870
  if (!existsSync37(targetPath)) return;
11643
- const resolved = path48.resolve(targetPath);
11871
+ const resolved = path49.resolve(targetPath);
11644
11872
  if (seen.has(resolved)) return;
11645
11873
  if (!isPathInside2(resolved, opts.harnessRoot)) return;
11646
11874
  seen.add(resolved);
@@ -11657,7 +11885,7 @@ function pushCandidate2(candidates, seen, opts, targetPath, kind, meta) {
11657
11885
  }
11658
11886
  function scanWorktreeDependencyCaches(candidates, seen, opts, worktreePath, meta) {
11659
11887
  for (const entry of DEPENDENCY_CACHE_DIRS) {
11660
- pushCandidate2(candidates, seen, opts, path48.join(worktreePath, entry.dirName), entry.kind, meta);
11888
+ pushCandidate2(candidates, seen, opts, path49.join(worktreePath, entry.dirName), entry.kind, meta);
11661
11889
  }
11662
11890
  }
11663
11891
  function scanDependencyCacheCandidates(opts) {
@@ -11672,19 +11900,19 @@ function scanDependencyCacheCandidates(opts) {
11672
11900
  });
11673
11901
  }
11674
11902
  if (!opts.includeOrphans || !existsSync37(opts.worktreesDir)) return candidates;
11675
- for (const runEntry of readdirSync14(opts.worktreesDir, { withFileTypes: true })) {
11903
+ for (const runEntry of readdirSync13(opts.worktreesDir, { withFileTypes: true })) {
11676
11904
  if (!runEntry.isDirectory()) continue;
11677
11905
  if (opts.runIdFilter && runEntry.name !== opts.runIdFilter) continue;
11678
- const runPath = path48.join(opts.worktreesDir, runEntry.name);
11906
+ const runPath = path49.join(opts.worktreesDir, runEntry.name);
11679
11907
  let workerEntries;
11680
11908
  try {
11681
- workerEntries = readdirSync14(runPath, { withFileTypes: true });
11909
+ workerEntries = readdirSync13(runPath, { withFileTypes: true });
11682
11910
  } catch {
11683
11911
  continue;
11684
11912
  }
11685
11913
  for (const workerEntry of workerEntries) {
11686
11914
  if (!workerEntry.isDirectory()) continue;
11687
- const worktreePath = path48.join(runPath, workerEntry.name);
11915
+ const worktreePath = path49.join(runPath, workerEntry.name);
11688
11916
  scanWorktreeDependencyCaches(candidates, seen, opts, worktreePath, {
11689
11917
  runId: runEntry.name,
11690
11918
  worker: workerEntry.name
@@ -11696,11 +11924,11 @@ function scanDependencyCacheCandidates(opts) {
11696
11924
 
11697
11925
  // src/cleanup-duplicate-worktrees.ts
11698
11926
  init_git();
11699
- import { existsSync as existsSync38, statSync as statSync12 } from "node:fs";
11700
- import path49 from "node:path";
11927
+ import { existsSync as existsSync38, statSync as statSync11 } from "node:fs";
11928
+ import path50 from "node:path";
11701
11929
  function pathAgeMs4(target, now) {
11702
11930
  try {
11703
- const mtime = statSync12(target).mtimeMs;
11931
+ const mtime = statSync11(target).mtimeMs;
11704
11932
  return Math.max(0, now - mtime);
11705
11933
  } catch {
11706
11934
  return 0;
@@ -11727,32 +11955,24 @@ function parseWorktreePorcelain(output) {
11727
11955
  return records;
11728
11956
  }
11729
11957
  function isUnderWorktreesDir(worktreePath, worktreesDir) {
11730
- const rel = path49.relative(path49.resolve(worktreesDir), path49.resolve(worktreePath));
11731
- return rel !== "" && !rel.startsWith("..") && !path49.isAbsolute(rel);
11732
- }
11733
- function isCleanWorktree(worktreePath, repoRoot) {
11734
- try {
11735
- const porcelain = git(repoRoot, ["-C", worktreePath, "status", "--porcelain"], {
11736
- allowFailure: true
11737
- });
11738
- return !String(porcelain || "").trim();
11739
- } catch {
11740
- return false;
11741
- }
11958
+ const rel = path50.relative(path50.resolve(worktreesDir), path50.resolve(worktreePath));
11959
+ return rel !== "" && !rel.startsWith("..") && !path50.isAbsolute(rel);
11742
11960
  }
11961
+ var MAX_DUPLICATE_WORKTREE_CANDIDATES_PER_REPO = 200;
11743
11962
  function scanDuplicateWorktreeCandidates(opts) {
11744
11963
  if (!opts.includeOrphans || !existsSync38(opts.worktreesDir)) return [];
11745
11964
  const repos = /* @__PURE__ */ new Set();
11746
11965
  for (const entry of opts.index.values()) {
11747
- if (entry.run.repo) repos.add(path49.resolve(entry.run.repo));
11966
+ if (entry.run.repo) repos.add(path50.resolve(entry.run.repo));
11748
11967
  }
11749
11968
  const indexedPaths = /* @__PURE__ */ new Set();
11750
11969
  for (const entry of opts.index.values()) {
11751
- indexedPaths.add(path49.resolve(entry.worktreePath));
11970
+ indexedPaths.add(path50.resolve(entry.worktreePath));
11752
11971
  }
11753
11972
  const candidates = [];
11754
11973
  const seen = /* @__PURE__ */ new Set();
11755
11974
  for (const repoRoot of repos) {
11975
+ let repoCandidateCount = 0;
11756
11976
  let porcelain;
11757
11977
  try {
11758
11978
  porcelain = git(repoRoot, ["worktree", "list", "--porcelain"], { allowFailure: true });
@@ -11761,18 +11981,19 @@ function scanDuplicateWorktreeCandidates(opts) {
11761
11981
  }
11762
11982
  const worktrees = parseWorktreePorcelain(porcelain);
11763
11983
  for (const wt of worktrees) {
11764
- const resolved = path49.resolve(wt.path);
11765
- if (resolved === path49.resolve(repoRoot)) continue;
11984
+ if (repoCandidateCount >= MAX_DUPLICATE_WORKTREE_CANDIDATES_PER_REPO) break;
11985
+ const resolved = path50.resolve(wt.path);
11986
+ if (resolved === path50.resolve(repoRoot)) continue;
11766
11987
  if (!isUnderWorktreesDir(resolved, opts.worktreesDir)) continue;
11767
11988
  if (indexedPaths.has(resolved)) continue;
11768
11989
  if (seen.has(resolved)) continue;
11769
11990
  if (!existsSync38(resolved)) continue;
11770
- if (!isCleanWorktree(resolved, repoRoot)) continue;
11771
- const rel = path49.relative(opts.worktreesDir, resolved);
11772
- const parts = rel.split(path49.sep);
11991
+ const rel = path50.relative(opts.worktreesDir, resolved);
11992
+ const parts = rel.split(path50.sep);
11773
11993
  const runId = parts[0];
11774
11994
  const worker = parts[1] ?? "unknown";
11775
11995
  seen.add(resolved);
11996
+ repoCandidateCount += 1;
11776
11997
  candidates.push({
11777
11998
  kind: "remove_worktree",
11778
11999
  path: resolved,
@@ -11790,12 +12011,22 @@ function scanDuplicateWorktreeCandidates(opts) {
11790
12011
  // src/cleanup-worktree-index.ts
11791
12012
  init_run_store();
11792
12013
  init_util();
11793
- import path50 from "node:path";
12014
+ import path51 from "node:path";
12015
+ function filterWorktreeIndexForRoot(index, harnessRoot) {
12016
+ const resolvedRoot = path51.resolve(harnessRoot);
12017
+ const scoped = /* @__PURE__ */ new Map();
12018
+ for (const [key, entry] of index) {
12019
+ const entryRoot = entry.harnessRoot ? path51.resolve(entry.harnessRoot) : null;
12020
+ if (entryRoot && entryRoot !== resolvedRoot) continue;
12021
+ scoped.set(key, entry);
12022
+ }
12023
+ return scoped;
12024
+ }
11794
12025
  function buildWorktreeIndexAt(harnessRoot) {
11795
12026
  const index = /* @__PURE__ */ new Map();
11796
12027
  for (const run of listRunRecordsForHarnessRoot(harnessRoot)) {
11797
12028
  for (const name of Object.keys(run.workers || {})) {
11798
- const workerPath = path50.join(
12029
+ const workerPath = path51.join(
11799
12030
  runDirectoryAt(harnessRoot, run.id),
11800
12031
  "workers",
11801
12032
  safeSlug(name),
@@ -11803,9 +12034,9 @@ function buildWorktreeIndexAt(harnessRoot) {
11803
12034
  );
11804
12035
  const worker = readJson(workerPath, void 0);
11805
12036
  if (!worker?.worktreePath) continue;
11806
- index.set(path50.resolve(worker.worktreePath), {
12037
+ index.set(path51.resolve(worker.worktreePath), {
11807
12038
  harnessRoot,
11808
- worktreePath: path50.resolve(worker.worktreePath),
12039
+ worktreePath: path51.resolve(worker.worktreePath),
11809
12040
  runId: run.id,
11810
12041
  workerName: name,
11811
12042
  run,
@@ -11831,6 +12062,7 @@ function resolveHarnessRetention(options = {}) {
11831
12062
  const execute = options.execute === true || options.execute !== false && envFlag("KYNVER_CLEANUP_EXECUTE");
11832
12063
  const finalizeStaleRuns2 = options.finalizeStaleRuns !== false && !envFlag("KYNVER_CLEANUP_SKIP_FINALIZE");
11833
12064
  const nodeModulesAgeMs = options.nodeModulesAgeMs ?? envMs("KYNVER_CLEANUP_NODE_MODULES_AGE_MS", DEFAULT_NODE_MODULES_AGE_MS);
12065
+ const scanDependencyCaches = options.scanDependencyCaches ?? (options.nodeModulesAgeMs !== void 0 || process.env.KYNVER_CLEANUP_NODE_MODULES_AGE_MS != null);
11834
12066
  const worktreesAgeMs = options.worktreesAgeMs ?? envMs("KYNVER_CLEANUP_WORKTREES_AGE_MS", 0);
11835
12067
  const terminalWorktreesAgeMs = options.terminalWorktreesAgeMs ?? envMs("KYNVER_CLEANUP_TERMINAL_WORKTREES_AGE_MS", DEFAULT_TERMINAL_WORKTREES_AGE_MS);
11836
12068
  const runDirectoriesAgeMs = options.runDirectoriesAgeMs ?? envMs("KYNVER_CLEANUP_RUN_DIRECTORIES_AGE_MS", DEFAULT_RUN_DIRECTORIES_AGE_MS);
@@ -11846,6 +12078,7 @@ function resolveHarnessRetention(options = {}) {
11846
12078
  return {
11847
12079
  execute,
11848
12080
  finalizeStaleRuns: finalizeStaleRuns2,
12081
+ scanDependencyCaches,
11849
12082
  nodeModulesAgeMs,
11850
12083
  worktreesAgeMs: worktreesAgeMs > 0 ? worktreesAgeMs : 0,
11851
12084
  terminalWorktreesAgeMs: terminalWorktreesAgeMs >= 0 ? terminalWorktreesAgeMs : 0,
@@ -11869,35 +12102,38 @@ function resolvePipelineHarnessRetention(runId) {
11869
12102
  runDirectoriesAgeMs: scopeAll ? DEFAULT_RUN_DIRECTORIES_AGE_MS : void 0,
11870
12103
  includeOrphans: scopeAll ? true : void 0,
11871
12104
  finalizeStaleRuns: true,
11872
- accountBytes: true
12105
+ accountBytes: true,
12106
+ scanDependencyCaches: true
11873
12107
  });
11874
12108
  }
11875
12109
 
11876
12110
  // src/cleanup-orphan-safety.ts
11877
12111
  init_git();
11878
- import { existsSync as existsSync39, statSync as statSync13 } from "node:fs";
11879
- import path51 from "node:path";
12112
+ import { existsSync as existsSync39 } from "node:fs";
12113
+ import path52 from "node:path";
12114
+ init_util();
11880
12115
  var DEFAULT_HEARTBEAT_FRESH_MS = 30 * 60 * 1e3;
11881
12116
  function assessOrphanWorktreeSafety(input) {
11882
12117
  const now = input.now ?? Date.now();
11883
12118
  const heartbeatFreshMs = input.heartbeatFreshMs ?? DEFAULT_HEARTBEAT_FRESH_MS;
11884
12119
  if (!existsSync39(input.worktreePath)) return null;
11885
12120
  if (input.runId && input.workerName) {
11886
- const heartbeatPath = path51.join(
12121
+ const workerDir = path52.join(
11887
12122
  input.harnessRoot,
11888
12123
  "runs",
11889
12124
  input.runId,
11890
12125
  "workers",
11891
- input.workerName,
11892
- "heartbeat.jsonl"
12126
+ input.workerName
11893
12127
  );
11894
- try {
11895
- const mtime = statSync13(heartbeatPath).mtimeMs;
11896
- if (now - mtime < heartbeatFreshMs) return "active_worker";
11897
- } catch {
12128
+ const worker = readJson(
12129
+ path52.join(workerDir, "worker.json"),
12130
+ void 0
12131
+ );
12132
+ if (worker && heartbeatContentIsFresh(worker, now, heartbeatFreshMs)) {
12133
+ return "active_worker";
11898
12134
  }
11899
12135
  }
11900
- const gitDir = path51.join(input.worktreePath, ".git");
12136
+ const gitDir = path52.join(input.worktreePath, ".git");
11901
12137
  if (!existsSync39(gitDir)) return null;
11902
12138
  const porcelain = gitCapture(input.worktreePath, ["status", "--porcelain"]);
11903
12139
  if (porcelain.status !== 0) return "pr_or_unmerged_commits";
@@ -11930,10 +12166,10 @@ function assessOrphanWorktreeSafety(input) {
11930
12166
  init_paths();
11931
12167
  import { existsSync as existsSync40 } from "node:fs";
11932
12168
  import { homedir as homedir13 } from "node:os";
11933
- import path52 from "node:path";
12169
+ import path53 from "node:path";
11934
12170
  var WELL_KNOWN_HARNESS_SCAN_ROOTS = [
11935
12171
  "/var/tmp/kynver-harness",
11936
- path52.join(homedir13(), ".openclaw", "harness")
12172
+ path53.join(homedir13(), ".openclaw", "harness")
11937
12173
  ];
11938
12174
  function addRoot(seen, roots, candidate) {
11939
12175
  if (!candidate?.trim()) return;
@@ -11955,7 +12191,7 @@ function resolveHarnessScanRoots(options = {}) {
11955
12191
  for (const candidate of extra ?? []) addRoot(seen, roots, candidate);
11956
12192
  if (shouldScanWellKnownRoots(options)) {
11957
12193
  for (const candidate of WELL_KNOWN_HARNESS_SCAN_ROOTS) {
11958
- const resolved = path52.resolve(candidate);
12194
+ const resolved = path53.resolve(candidate);
11959
12195
  if (!seen.has(resolved) && existsSync40(resolved)) addRoot(seen, roots, resolved);
11960
12196
  }
11961
12197
  }
@@ -12034,15 +12270,52 @@ var CleanupGitRevCache = class {
12034
12270
  }
12035
12271
  };
12036
12272
 
12273
+ // src/cleanup-git-probe.ts
12274
+ import { spawnSync as spawnSync8 } from "node:child_process";
12275
+ import { existsSync as existsSync41 } from "node:fs";
12276
+ import path54 from "node:path";
12277
+ var CLEANUP_GIT_PROBE_TIMEOUT_MS = 5e3;
12278
+ function cleanupGitCapture(cwd, args) {
12279
+ if (!existsSync41(path54.join(cwd, ".git"))) {
12280
+ return { status: null, stdout: "", stderr: "", error: "not_a_git_repo" };
12281
+ }
12282
+ try {
12283
+ const res = spawnSync8("git", args, {
12284
+ cwd,
12285
+ encoding: "utf8",
12286
+ timeout: CLEANUP_GIT_PROBE_TIMEOUT_MS
12287
+ });
12288
+ const timedOut = res.error?.message?.includes("ETIMEDOUT") === true;
12289
+ return {
12290
+ status: timedOut ? null : res.status,
12291
+ stdout: res.stdout || "",
12292
+ stderr: res.stderr || "",
12293
+ error: timedOut ? "git_timeout" : res.error ? res.error.message : null
12294
+ };
12295
+ } catch (error) {
12296
+ return {
12297
+ status: null,
12298
+ stdout: "",
12299
+ stderr: "",
12300
+ error: error.message
12301
+ };
12302
+ }
12303
+ }
12304
+ function gitStatusShortForCleanup(worktreePath) {
12305
+ const captured = cleanupGitCapture(worktreePath, ["status", "--short"]);
12306
+ if (captured.error === "not_a_git_repo") return [];
12307
+ if (captured.error === "git_timeout" || captured.status !== 0) return null;
12308
+ return captured.stdout.split("\n").map((line) => line.trim()).filter(Boolean);
12309
+ }
12310
+
12037
12311
  // src/cleanup-git-status-cache.ts
12038
- init_git();
12039
12312
  var CleanupGitStatusCache = class {
12040
12313
  cache = /* @__PURE__ */ new Map();
12041
12314
  porcelain(worktreePath) {
12042
12315
  const resolved = worktreePath;
12043
12316
  const cached = this.cache.get(resolved);
12044
12317
  if (cached !== void 0) return cached;
12045
- const lines = gitStatusShort(resolved);
12318
+ const lines = gitStatusShortForCleanup(resolved) ?? [];
12046
12319
  this.cache.set(resolved, lines);
12047
12320
  return lines;
12048
12321
  }
@@ -12147,9 +12420,9 @@ function mergeWorktreeIndexes(scanRoots) {
12147
12420
  }
12148
12421
  function worktreePathForCandidate(candidate, worktreesDir) {
12149
12422
  if (candidate.runId && candidate.worker) {
12150
- return path53.join(worktreesDir, candidate.runId, candidate.worker);
12423
+ return path55.join(worktreesDir, candidate.runId, candidate.worker);
12151
12424
  }
12152
- return path53.resolve(candidate.path, "..");
12425
+ return path55.resolve(candidate.path, "..");
12153
12426
  }
12154
12427
  function runHarnessCleanup(options = {}) {
12155
12428
  let retention = resolveHarnessRetention(options);
@@ -12178,7 +12451,8 @@ function runHarnessCleanup(options = {}) {
12178
12451
  for (const harnessRoot of paths.scanRoots) {
12179
12452
  if (atSweepCap()) break;
12180
12453
  emitCleanupProgress("root", harnessRoot);
12181
- const worktreesDir = path53.join(harnessRoot, "worktrees");
12454
+ const worktreesDir = path55.join(harnessRoot, "worktrees");
12455
+ const rootIndex = filterWorktreeIndexForRoot(index, harnessRoot);
12182
12456
  const scanOpts = {
12183
12457
  harnessRoot,
12184
12458
  worktreesDir,
@@ -12186,11 +12460,14 @@ function runHarnessCleanup(options = {}) {
12186
12460
  worktreesAgeMs: retention.worktreesAgeMs,
12187
12461
  includeOrphans: retention.includeOrphans,
12188
12462
  runIdFilter: retention.runIdFilter,
12189
- index,
12463
+ index: rootIndex,
12190
12464
  now: paths.now
12191
12465
  };
12192
- const dependencyCandidates = scanDependencyCacheCandidates(scanOpts);
12193
- emitCleanupProgress("dependency", `${dependencyCandidates.length} cache candidate(s) at ${harnessRoot}`);
12466
+ const dependencyCandidates = retention.scanDependencyCaches ? scanDependencyCacheCandidates(scanOpts) : [];
12467
+ emitCleanupProgress(
12468
+ "dependency",
12469
+ retention.scanDependencyCaches ? `${dependencyCandidates.length} cache candidate(s) at ${harnessRoot}` : "skipped (worktree-only sweep)"
12470
+ );
12194
12471
  let dependencyProcessed = 0;
12195
12472
  for (const raw of dependencyCandidates) {
12196
12473
  if (atSweepCap()) break;
@@ -12198,7 +12475,7 @@ function runHarnessCleanup(options = {}) {
12198
12475
  if (dependencyProcessed % 50 === 0) {
12199
12476
  emitCleanupProgress("dependency", `${dependencyProcessed}/${dependencyCandidates.length} evaluated`);
12200
12477
  }
12201
- const resolved = path53.resolve(raw.path);
12478
+ const resolved = path55.resolve(raw.path);
12202
12479
  if (processedPaths.has(resolved)) continue;
12203
12480
  processedPaths.add(resolved);
12204
12481
  const candidate = { ...raw, path: resolved };
@@ -12209,7 +12486,7 @@ function runHarnessCleanup(options = {}) {
12209
12486
  continue;
12210
12487
  }
12211
12488
  const worktreePath = worktreePathForCandidate(candidate, worktreesDir);
12212
- const indexed = index.get(path53.resolve(worktreePath)) ?? null;
12489
+ const indexed = rootIndex.get(path55.resolve(worktreePath)) ?? null;
12213
12490
  const guardReason = skipDependencyCacheRemoval({
12214
12491
  indexed,
12215
12492
  includeOrphans: true,
@@ -12232,9 +12509,9 @@ function runHarnessCleanup(options = {}) {
12232
12509
  )
12233
12510
  );
12234
12511
  }
12235
- for (const raw of scanBuildCacheCandidates(scanOpts)) {
12512
+ if (retention.scanDependencyCaches) for (const raw of scanBuildCacheCandidates(scanOpts)) {
12236
12513
  if (atSweepCap()) break;
12237
- const resolved = path53.resolve(raw.path);
12514
+ const resolved = path55.resolve(raw.path);
12238
12515
  if (processedPaths.has(resolved)) continue;
12239
12516
  processedPaths.add(resolved);
12240
12517
  const candidate = { ...raw, path: resolved };
@@ -12245,7 +12522,7 @@ function runHarnessCleanup(options = {}) {
12245
12522
  continue;
12246
12523
  }
12247
12524
  const worktreePath = worktreePathForCandidate(candidate, worktreesDir);
12248
- const indexed = index.get(path53.resolve(worktreePath)) ?? null;
12525
+ const indexed = rootIndex.get(path55.resolve(worktreePath)) ?? null;
12249
12526
  const guardReason = skipBuildCacheRemoval({
12250
12527
  indexed,
12251
12528
  includeOrphans: true,
@@ -12281,11 +12558,11 @@ function runHarnessCleanup(options = {}) {
12281
12558
  if (worktreeProcessed % 50 === 0) {
12282
12559
  emitCleanupProgress("worktrees", `${worktreeProcessed}/${worktreeCandidates.length} evaluated`);
12283
12560
  }
12284
- const resolved = path53.resolve(raw.path);
12561
+ const resolved = path55.resolve(raw.path);
12285
12562
  if (worktreeSeen.has(resolved)) continue;
12286
12563
  worktreeSeen.add(resolved);
12287
12564
  const candidate = { ...raw, path: resolved };
12288
- const indexed = index.get(path53.resolve(candidate.path)) ?? null;
12565
+ const indexed = rootIndex.get(path55.resolve(candidate.path)) ?? null;
12289
12566
  const orphanSafety = indexed ? null : assessOrphanWorktreeSafety({
12290
12567
  worktreePath: candidate.path,
12291
12568
  harnessRoot,
@@ -12295,14 +12572,17 @@ function runHarnessCleanup(options = {}) {
12295
12572
  });
12296
12573
  const guardSkip = skipWorktreeRemoval({
12297
12574
  indexed,
12298
- worktreePath: path53.resolve(candidate.path),
12575
+ worktreePath: path55.resolve(candidate.path),
12299
12576
  includeOrphans: retention.includeOrphans,
12300
12577
  worktreesAgeMs: retention.worktreesAgeMs,
12301
12578
  terminalWorktreesAgeMs: retention.terminalWorktreesAgeMs,
12302
12579
  ageMs: candidate.ageMs,
12303
12580
  orphanSafety,
12304
12581
  worktreeRemovalGuard: options.worktreeRemovalGuard,
12305
- liveness
12582
+ liveness,
12583
+ now: paths.now,
12584
+ harnessRoot,
12585
+ writeSalvageEvidence: retention.execute
12306
12586
  });
12307
12587
  if (guardSkip) {
12308
12588
  const { reason: guardReason, detail: guardDetail } = normalizeGuardSkip(guardSkip);
@@ -12327,11 +12607,11 @@ function runHarnessCleanup(options = {}) {
12327
12607
  now: paths.now
12328
12608
  })) {
12329
12609
  if (atSweepCap()) break;
12330
- const resolved = path53.resolve(raw.path);
12610
+ const resolved = path55.resolve(raw.path);
12331
12611
  if (processedPaths.has(resolved)) continue;
12332
12612
  processedPaths.add(resolved);
12333
12613
  const candidate = { ...raw, path: resolved };
12334
- const runId = candidate.runId ?? path53.basename(resolved);
12614
+ const runId = candidate.runId ?? path55.basename(resolved);
12335
12615
  const dirSkip = skipRunDirectoryRemoval({
12336
12616
  harnessRoot,
12337
12617
  runId,
@@ -12466,7 +12746,7 @@ function isPipelineCleanupEnabled() {
12466
12746
 
12467
12747
  // src/cli.ts
12468
12748
  init_config();
12469
- import { mkdirSync as mkdirSync13, realpathSync } from "node:fs";
12749
+ import { mkdirSync as mkdirSync15, realpathSync } from "node:fs";
12470
12750
  import { fileURLToPath as fileURLToPath5 } from "node:url";
12471
12751
 
12472
12752
  // src/bootstrap.ts
@@ -12582,17 +12862,17 @@ function validateDaemonInstallIdentity(config = loadUserConfig(), env = process.
12582
12862
  }
12583
12863
 
12584
12864
  // src/daemon-heartbeat.ts
12585
- import { mkdirSync as mkdirSync7, readFileSync as readFileSync16, renameSync as renameSync3, writeFileSync as writeFileSync4 } from "node:fs";
12865
+ import { mkdirSync as mkdirSync9, readFileSync as readFileSync16, renameSync as renameSync4, writeFileSync as writeFileSync5 } from "node:fs";
12586
12866
  import { homedir as homedir14 } from "node:os";
12587
- import path54 from "node:path";
12867
+ import path56 from "node:path";
12588
12868
  function daemonHeartbeatPath(agentOsId) {
12589
12869
  const safe = agentOsId.replace(/[^A-Za-z0-9_-]/g, "_");
12590
- return path54.join(homedir14(), ".kynver", `daemon-heartbeat-${safe}.json`);
12870
+ return path56.join(homedir14(), ".kynver", `daemon-heartbeat-${safe}.json`);
12591
12871
  }
12592
12872
  function writeDaemonHeartbeat(input) {
12593
12873
  try {
12594
12874
  const file = daemonHeartbeatPath(input.agentOsId);
12595
- mkdirSync7(path54.dirname(file), { recursive: true });
12875
+ mkdirSync9(path56.dirname(file), { recursive: true });
12596
12876
  const beat = {
12597
12877
  observedAt: (input.now ?? /* @__PURE__ */ new Date()).toISOString(),
12598
12878
  pid: process.pid,
@@ -12600,8 +12880,8 @@ function writeDaemonHeartbeat(input) {
12600
12880
  agentOsId: input.agentOsId
12601
12881
  };
12602
12882
  const tmp = `${file}.tmp-${process.pid}`;
12603
- writeFileSync4(tmp, JSON.stringify(beat), "utf8");
12604
- renameSync3(tmp, file);
12883
+ writeFileSync5(tmp, JSON.stringify(beat), "utf8");
12884
+ renameSync4(tmp, file);
12605
12885
  } catch {
12606
12886
  }
12607
12887
  }
@@ -12642,9 +12922,9 @@ function assertNativeDaemonAllowed() {
12642
12922
 
12643
12923
  // src/cron/cron-env.ts
12644
12924
  init_config();
12645
- import { existsSync as existsSync41 } from "node:fs";
12925
+ import { existsSync as existsSync42 } from "node:fs";
12646
12926
  import { homedir as homedir15 } from "node:os";
12647
- import path55 from "node:path";
12927
+ import path57 from "node:path";
12648
12928
  function envFlag4(name, defaultValue) {
12649
12929
  const raw = process.env[name]?.trim().toLowerCase();
12650
12930
  if (!raw) return defaultValue;
@@ -12660,7 +12940,7 @@ function envInt(name, fallback, min = 1) {
12660
12940
  function defaultKynverCronStorePath() {
12661
12941
  const explicit = process.env.KYNVER_CRON_STORE_PATH?.trim() || process.env.OPENCLAW_CRON_STORE_PATH?.trim();
12662
12942
  if (explicit) return explicit;
12663
- return path55.join(homedir15(), ".kynver", "agent-os-cron.json");
12943
+ return path57.join(homedir15(), ".kynver", "agent-os-cron.json");
12664
12944
  }
12665
12945
  function defaultKynverCronStatePath(storePath = defaultKynverCronStorePath()) {
12666
12946
  const explicit = process.env.KYNVER_CRON_TICK_STATE_PATH?.trim();
@@ -12680,7 +12960,7 @@ function resolveKynverCronEnv() {
12680
12960
  const fireBaseUrl = resolveKynverCronFireBaseUrl();
12681
12961
  const secret = resolveKynverCronSecret();
12682
12962
  const credsReady = Boolean(fireBaseUrl && secret);
12683
- const storeExists = existsSync41(storePath);
12963
+ const storeExists = existsSync42(storePath);
12684
12964
  const defaultEnabled = credsReady && (storeExists || envFlag4("KYNVER_CRON_TICK_FORCE", false));
12685
12965
  return {
12686
12966
  storePath,
@@ -12734,10 +13014,10 @@ async function fireKynverCronJob(input) {
12734
13014
 
12735
13015
  // src/cron/cron-lock.ts
12736
13016
  init_util();
12737
- import { closeSync as closeSync6, existsSync as existsSync42, openSync as openSync6, readFileSync as readFileSync17, unlinkSync as unlinkSync3, writeFileSync as writeFileSync5 } from "node:fs";
13017
+ import { closeSync as closeSync6, existsSync as existsSync43, openSync as openSync6, readFileSync as readFileSync17, unlinkSync as unlinkSync3, writeFileSync as writeFileSync6 } from "node:fs";
12738
13018
  var STALE_LOCK_MS = 10 * 6e4;
12739
13019
  function readLockInfo(lockPath) {
12740
- if (!existsSync42(lockPath)) return null;
13020
+ if (!existsSync43(lockPath)) return null;
12741
13021
  try {
12742
13022
  const parsed = JSON.parse(readFileSync17(lockPath, "utf8"));
12743
13023
  if (typeof parsed.pid === "number" && typeof parsed.at === "string") return parsed;
@@ -12755,14 +13035,14 @@ function lockIsStale(lockPath) {
12755
13035
  return Date.now() - atMs > STALE_LOCK_MS;
12756
13036
  }
12757
13037
  function tryAcquireCronTickLock(lockPath) {
12758
- if (existsSync42(lockPath) && !lockIsStale(lockPath)) {
13038
+ if (existsSync43(lockPath) && !lockIsStale(lockPath)) {
12759
13039
  const info = readLockInfo(lockPath);
12760
13040
  return {
12761
13041
  acquired: false,
12762
13042
  reason: info ? `held by pid ${info.pid}` : "held by another process"
12763
13043
  };
12764
13044
  }
12765
- if (existsSync42(lockPath)) {
13045
+ if (existsSync43(lockPath)) {
12766
13046
  try {
12767
13047
  unlinkSync3(lockPath);
12768
13048
  } catch {
@@ -12770,7 +13050,7 @@ function tryAcquireCronTickLock(lockPath) {
12770
13050
  }
12771
13051
  try {
12772
13052
  const fd = openSync6(lockPath, "wx");
12773
- writeFileSync5(
13053
+ writeFileSync6(
12774
13054
  fd,
12775
13055
  JSON.stringify({ pid: process.pid, at: (/* @__PURE__ */ new Date()).toISOString() }),
12776
13056
  "utf8"
@@ -12926,7 +13206,7 @@ async function ensureCronStoreInitialized(storePath = defaultKynverCronStorePath
12926
13206
  // src/cron/cron-tick-state.ts
12927
13207
  import { randomBytes } from "node:crypto";
12928
13208
  import { promises as fs4 } from "node:fs";
12929
- import path56 from "node:path";
13209
+ import path58 from "node:path";
12930
13210
  var EMPTY = { version: 1, jobs: {} };
12931
13211
  async function readFileIfExists2(filePath) {
12932
13212
  try {
@@ -12953,7 +13233,7 @@ async function loadCronTickState(statePath) {
12953
13233
  return parseCronTickState(raw);
12954
13234
  }
12955
13235
  async function writeStateAtomic(statePath, state) {
12956
- await fs4.mkdir(path56.dirname(statePath), { recursive: true });
13236
+ await fs4.mkdir(path58.dirname(statePath), { recursive: true });
12957
13237
  const suffix = randomBytes(6).toString("hex");
12958
13238
  const tmp = `${statePath}.tmp-${process.pid}-${Date.now()}-${suffix}`;
12959
13239
  await fs4.writeFile(tmp, `${JSON.stringify(state, null, 2)}
@@ -13133,7 +13413,7 @@ async function runKynverCronTick(opts = {}) {
13133
13413
  init_util();
13134
13414
 
13135
13415
  // src/pipeline-tick.ts
13136
- import path59 from "node:path";
13416
+ import path61 from "node:path";
13137
13417
  init_config();
13138
13418
 
13139
13419
  // src/pipeline-dispatch.ts
@@ -13275,7 +13555,7 @@ init_util();
13275
13555
  init_status();
13276
13556
  init_run_store();
13277
13557
  init_util();
13278
- import path57 from "node:path";
13558
+ import path59 from "node:path";
13279
13559
 
13280
13560
  // src/plan-progress-sync.ts
13281
13561
  init_config();
@@ -13300,7 +13580,7 @@ async function syncActiveWorkerPlanProgress(runId, args) {
13300
13580
  const outcomes = [];
13301
13581
  for (const name of Object.keys(run.workers || {})) {
13302
13582
  const worker = readJson(
13303
- path57.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
13583
+ path59.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
13304
13584
  void 0
13305
13585
  );
13306
13586
  if (!worker?.dispatched || !worker.taskId) continue;
@@ -13363,12 +13643,12 @@ init_config();
13363
13643
  init_box_identity();
13364
13644
 
13365
13645
  // src/provider-evidence/exec.ts
13366
- import { spawnSync as spawnSync8 } from "node:child_process";
13646
+ import { spawnSync as spawnSync9 } from "node:child_process";
13367
13647
  var DEFAULT_CLI_TIMEOUT_MS = 1e4;
13368
13648
  var MAX_CLI_BUFFER_BYTES = 4 * 1024 * 1024;
13369
13649
  var defaultCliRunner = (cmd, args, opts) => {
13370
13650
  try {
13371
- const result = spawnSync8(cmd, args, {
13651
+ const result = spawnSync9(cmd, args, {
13372
13652
  encoding: "utf8",
13373
13653
  stdio: ["ignore", "pipe", "pipe"],
13374
13654
  timeout: opts?.timeoutMs ?? DEFAULT_CLI_TIMEOUT_MS,
@@ -13668,10 +13948,10 @@ function collectProviderEvidence(wanted, opts = {}) {
13668
13948
  // src/provider-evidence/wanted-store.ts
13669
13949
  init_run_store();
13670
13950
  init_util();
13671
- import path58 from "node:path";
13951
+ import path60 from "node:path";
13672
13952
  var WANTED_FILE = "provider-evidence-wanted.json";
13673
13953
  function wantedFilePath(runId) {
13674
- return path58.join(runDirectory(runId), WANTED_FILE);
13954
+ return path60.join(runDirectory(runId), WANTED_FILE);
13675
13955
  }
13676
13956
  function parseWantedItems(value) {
13677
13957
  if (!Array.isArray(value)) return [];
@@ -13710,7 +13990,7 @@ async function completeFinishedWorkers(runId, args) {
13710
13990
  const outcomes = [];
13711
13991
  for (const name of Object.keys(run.workers || {})) {
13712
13992
  const worker = readJson(
13713
- path59.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
13993
+ path61.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
13714
13994
  void 0
13715
13995
  );
13716
13996
  if (!worker?.taskId || worker.localOnly) continue;
@@ -13885,7 +14165,7 @@ import os11 from "node:os";
13885
14165
  // src/chat/anthropic-credentials.ts
13886
14166
  import { readFileSync as readFileSync18 } from "node:fs";
13887
14167
  import { homedir as homedir16, platform } from "node:os";
13888
- import path60 from "node:path";
14168
+ import path62 from "node:path";
13889
14169
  import { execFileSync as execFileSync4 } from "node:child_process";
13890
14170
  function parseClaudeCredentials(raw, now = Date.now()) {
13891
14171
  try {
@@ -13913,17 +14193,18 @@ function readClaudeCliToken() {
13913
14193
  }
13914
14194
  }
13915
14195
  try {
13916
- const raw = readFileSync18(path60.join(homedir16(), ".claude", ".credentials.json"), "utf8");
14196
+ const raw = readFileSync18(path62.join(homedir16(), ".claude", ".credentials.json"), "utf8");
13917
14197
  return parseClaudeCredentials(raw);
13918
14198
  } catch {
13919
14199
  return null;
13920
14200
  }
13921
14201
  }
13922
- function resolveLocalAnthropicCredentials(env = process.env) {
14202
+ function resolveLocalAnthropicCredentials(env = process.env, opts = {}) {
13923
14203
  const apiKey = env.ANTHROPIC_API_KEY?.trim();
13924
14204
  if (apiKey) return { kind: "api_key", key: apiKey };
13925
- const optIn = env.KYNVER_CHAT_USE_CLAUDE_OAUTH;
13926
- if (optIn === "1" || optIn === "true" || optIn === "yes") {
14205
+ const envOptIn = env.KYNVER_CHAT_USE_CLAUDE_OAUTH;
14206
+ const optedIn = opts.oauthOptIn === true || envOptIn === "1" || envOptIn === "true" || envOptIn === "yes";
14207
+ if (optedIn) {
13927
14208
  const token = readClaudeCliToken();
13928
14209
  if (token) return { kind: "oauth", token };
13929
14210
  }
@@ -14109,20 +14390,43 @@ var CLAIM_WAIT_MS = 25e3;
14109
14390
  var CLAIM_FETCH_TIMEOUT_MS = 32e3;
14110
14391
  var ERROR_BACKOFF_MS = 5e3;
14111
14392
  var AUTH_BACKOFF_MS = 6e4;
14393
+ var BRIDGE_REDISCOVER_MS = 5 * 6e4;
14394
+ var DISCOVERY_TIMEOUT_MS = 5e3;
14112
14395
  var DEFAULT_CHAT_MODEL = "claude-sonnet-4-6";
14113
- function resolveChatBridgeTarget(env = process.env) {
14114
- const bridgeUrl = env.KYNVER_RUNTIME_CHAT_BRIDGE_URL?.trim();
14115
- if (!bridgeUrl) return null;
14396
+ async function discoverBridgeUrl(apiBaseUrl, apiKey, env) {
14397
+ const override = env.KYNVER_RUNTIME_CHAT_BRIDGE_URL?.trim();
14398
+ if (override) return override;
14399
+ if (!apiBaseUrl) return null;
14400
+ const controller = new AbortController();
14401
+ const timer = setTimeout(() => controller.abort(), DISCOVERY_TIMEOUT_MS);
14402
+ try {
14403
+ const res = await fetch(`${apiBaseUrl.replace(/\/$/, "")}/api/runtime/chat-bridge`, {
14404
+ headers: { Authorization: `Bearer ${apiKey}` },
14405
+ signal: controller.signal
14406
+ });
14407
+ if (!res.ok) return null;
14408
+ const body = await res.json().catch(() => null);
14409
+ return typeof body?.bridgeUrl === "string" && body.bridgeUrl.trim() ? body.bridgeUrl.trim() : null;
14410
+ } catch {
14411
+ return null;
14412
+ } finally {
14413
+ clearTimeout(timer);
14414
+ }
14415
+ }
14416
+ async function resolveChatBridgeTarget(env = process.env) {
14116
14417
  const config = loadUserConfig();
14117
14418
  const agentOsId = config.agentOsId?.trim();
14118
14419
  const apiKey = loadApiKey();
14119
14420
  if (!agentOsId || !apiKey) return null;
14421
+ const bridgeUrl = await discoverBridgeUrl(config.apiBaseUrl, apiKey, env);
14422
+ if (!bridgeUrl) return null;
14120
14423
  return {
14121
14424
  bridgeUrl: bridgeUrl.replace(/\/$/, ""),
14122
14425
  agentOsId,
14123
14426
  apiKey,
14124
14427
  boxId: os11.hostname(),
14125
- model: env.KYNVER_CHAT_MODEL?.trim() || config.defaultModel?.trim() || DEFAULT_CHAT_MODEL
14428
+ model: env.KYNVER_CHAT_MODEL?.trim() || config.defaultModel?.trim() || DEFAULT_CHAT_MODEL,
14429
+ useClaudeOauth: config.chatUseClaudeOauth === true
14126
14430
  };
14127
14431
  }
14128
14432
  async function claimOnce(target, shouldStop) {
@@ -14183,7 +14487,7 @@ async function executeChatTurn(target, turn) {
14183
14487
  });
14184
14488
  };
14185
14489
  const batcher = new DeltaBatcher(sendBatch);
14186
- const creds = resolveLocalAnthropicCredentials();
14490
+ const creds = resolveLocalAnthropicCredentials(process.env, { oauthOptIn: target.useClaudeOauth });
14187
14491
  if (!creds) {
14188
14492
  await pushEvents(target, turn.turnId, [
14189
14493
  { seq: 0, kind: "error", error: "no_local_credentials" }
@@ -14228,15 +14532,22 @@ async function sleep2(ms, shouldStop) {
14228
14532
  }
14229
14533
  }
14230
14534
  async function runChatClaimLoop(opts) {
14231
- const target = resolveChatBridgeTarget();
14232
- if (!target) return;
14535
+ let target = await resolveChatBridgeTarget();
14536
+ while (!target && !opts.shouldStop()) {
14537
+ if (!loadApiKey() || !loadUserConfig().agentOsId?.trim()) return;
14538
+ await sleep2(BRIDGE_REDISCOVER_MS, opts.shouldStop);
14539
+ if (opts.shouldStop()) return;
14540
+ target = await resolveChatBridgeTarget();
14541
+ }
14542
+ if (!target || opts.shouldStop()) return;
14233
14543
  console.error(
14234
14544
  JSON.stringify({
14235
14545
  event: "chat_claim_loop_start",
14236
14546
  bridgeUrl: target.bridgeUrl,
14237
14547
  agentOsId: target.agentOsId,
14238
14548
  boxId: target.boxId,
14239
- model: target.model
14549
+ model: target.model,
14550
+ useClaudeOauth: target.useClaudeOauth
14240
14551
  })
14241
14552
  );
14242
14553
  while (!opts.shouldStop()) {
@@ -14321,9 +14632,33 @@ async function runDaemon(args) {
14321
14632
  })
14322
14633
  );
14323
14634
  });
14635
+ let credentialMissingLogged = false;
14324
14636
  while (!stopping) {
14325
14637
  try {
14326
14638
  writeDaemonHeartbeat({ agentOsId, runId });
14639
+ const credential = await tryResolveCallbackSecretWithMint(
14640
+ args.secret ? String(args.secret) : void 0,
14641
+ agentOsId
14642
+ );
14643
+ if (!credential.ok) {
14644
+ if (!credentialMissingLogged) {
14645
+ credentialMissingLogged = true;
14646
+ console.error(
14647
+ JSON.stringify({
14648
+ event: "daemon_runner_credential_missing",
14649
+ agentOsId,
14650
+ reason: credential.reason,
14651
+ remedy: `run \`kynver runner credential --agent-os-id ${agentOsId}\` (or \`kynver bootstrap\`); ticks resume automatically once the credential exists`
14652
+ })
14653
+ );
14654
+ }
14655
+ await awaitDaemonBackoff(intervalMs, () => stopping);
14656
+ continue;
14657
+ }
14658
+ if (credentialMissingLogged) {
14659
+ credentialMissingLogged = false;
14660
+ console.error(JSON.stringify({ event: "daemon_runner_credential_recovered", agentOsId }));
14661
+ }
14327
14662
  if (cronEnv.tickEnabled) {
14328
14663
  const cronTick = await runKynverCronTick({
14329
14664
  env: cronEnv,
@@ -14351,108 +14686,6 @@ async function runDaemon(args) {
14351
14686
  console.error(JSON.stringify({ event: "daemon_stop", runId, agentOsId }));
14352
14687
  }
14353
14688
 
14354
- // src/start.ts
14355
- init_run_store();
14356
- function resolveStartRunId(runs, repo) {
14357
- const candidates = runs.filter((r) => r.repo === repo && !TERMINAL_RUN_STATUSES.has(r.status)).sort((a, b) => (b.createdAt ?? "").localeCompare(a.createdAt ?? ""));
14358
- return candidates[0]?.id ?? null;
14359
- }
14360
- async function runStart(args) {
14361
- assertNativeDaemonAllowed();
14362
- let config = loadUserConfig();
14363
- if (!loadApiKey() || !config.agentOsId?.trim()) {
14364
- console.log(" This machine isn't linked yet \u2014 running bootstrap first.");
14365
- await runBootstrap(args);
14366
- config = loadUserConfig();
14367
- }
14368
- const agentOsId = (typeof args.agentOsId === "string" ? args.agentOsId.trim() : "") || config.agentOsId?.trim() || "";
14369
- if (!agentOsId) {
14370
- console.error("No AgentOS workspace configured \u2014 run `kynver bootstrap` (or pass --agent-os-id).");
14371
- process.exit(1);
14372
- }
14373
- const repo = (typeof args.repo === "string" ? args.repo.trim() : "") || config.defaultRepo?.trim() || resolveDefaultRepo()?.repo || "";
14374
- if (!repo) {
14375
- console.error("No repo configured \u2014 pass --repo /path/to/repo or run `kynver setup --discover-repo`.");
14376
- process.exit(1);
14377
- }
14378
- let runId = typeof args.run === "string" && args.run.trim() ? args.run.trim() : "";
14379
- if (!runId) {
14380
- runId = resolveStartRunId(listRunRecords(), repo) ?? "";
14381
- if (runId) {
14382
- console.log(` Reusing run ${runId} for ${repo}.`);
14383
- } else {
14384
- runId = createRun({ ...args, repo, name: "agent" }).runId;
14385
- }
14386
- }
14387
- console.log("");
14388
- console.log(` ${os12.hostname()} \u2014 agent coming online`);
14389
- console.log(` workspace: ${agentOsId}`);
14390
- console.log(` repo: ${repo}`);
14391
- console.log(` run: ${runId}`);
14392
- console.log(" Ctrl-C stops the agent. (Advanced control: `kynver daemon --help`.)");
14393
- console.log("");
14394
- await runDaemon({ ...args, run: runId, agentOsId });
14395
- }
14396
-
14397
- // src/cli.ts
14398
- init_run_store();
14399
-
14400
- // src/discard-disposable.ts
14401
- init_run_store();
14402
- init_status();
14403
- import { existsSync as existsSync43, rmSync as rmSync4 } from "node:fs";
14404
- import path61 from "node:path";
14405
- function normalizeRelativePath2(value) {
14406
- const normalized = value.replace(/\\/g, "/").replace(/^\.\//, "").trim();
14407
- if (!normalized || normalized.startsWith("/") || normalized.includes("..")) {
14408
- throw new Error(`unsafe path: ${value}`);
14409
- }
14410
- return normalized;
14411
- }
14412
- function parsePathsArg(raw) {
14413
- if (typeof raw !== "string" || !raw.trim()) return [];
14414
- return raw.split(",").map((p) => p.trim()).filter(Boolean);
14415
- }
14416
- function discardDisposableArtifacts(args) {
14417
- const { runId, workerName } = resolveWorkerTargetArgs(args);
14418
- const worker = loadWorker(runId, workerName);
14419
- const paths = [
14420
- ...parsePathsArg(args.path),
14421
- ...Array.isArray(args.paths) ? args.paths : []
14422
- ];
14423
- if (paths.length === 0) {
14424
- return { ok: false, removed: [], reason: "requires at least one --path" };
14425
- }
14426
- const worktreeRoot = path61.resolve(worker.worktreePath);
14427
- const removed = [];
14428
- for (const raw of paths) {
14429
- const rel = normalizeRelativePath2(raw);
14430
- const abs = path61.resolve(worktreeRoot, rel);
14431
- if (!abs.startsWith(worktreeRoot + path61.sep) && abs !== worktreeRoot) {
14432
- return { ok: false, removed, reason: `path escapes worktree: ${raw}` };
14433
- }
14434
- if (!existsSync43(abs)) {
14435
- return { ok: false, removed, reason: `path not found: ${raw}` };
14436
- }
14437
- rmSync4(abs, { recursive: true, force: true });
14438
- removed.push(rel);
14439
- }
14440
- const prior = Array.isArray(worker.disposableArtifactsRemoved) ? worker.disposableArtifactsRemoved.filter((p) => typeof p === "string") : [];
14441
- worker.disposableArtifactsRemoved = [.../* @__PURE__ */ new Set([...prior, ...removed])];
14442
- saveWorker(worker.runId, worker);
14443
- const status = computeWorkerStatus(worker);
14444
- return {
14445
- ok: true,
14446
- removed,
14447
- ...status.changedFiles.length ? { reason: "worktree still has other changes" } : {}
14448
- };
14449
- }
14450
- function discardDisposableCli(args) {
14451
- const result = discardDisposableArtifacts(args);
14452
- console.log(JSON.stringify(result, null, 2));
14453
- if (!result.ok) process.exit(1);
14454
- }
14455
-
14456
14689
  // src/daemon-keeper.ts
14457
14690
  init_config();
14458
14691
  import { spawn as spawn6 } from "node:child_process";
@@ -14584,9 +14817,134 @@ async function runDaemonKeeper(args, rawArgv = process.argv.slice(2)) {
14584
14817
  keeperLog("stopped", { agentOsId });
14585
14818
  }
14586
14819
 
14820
+ // src/start.ts
14821
+ init_run_store();
14822
+ function resolveStartRunId(runs, repo) {
14823
+ const candidates = runs.filter((r) => r.repo === repo && !TERMINAL_RUN_STATUSES.has(r.status)).sort((a, b) => (b.createdAt ?? "").localeCompare(a.createdAt ?? ""));
14824
+ return candidates[0]?.id ?? null;
14825
+ }
14826
+ async function runStart(args) {
14827
+ assertNativeDaemonAllowed();
14828
+ let config = loadUserConfig();
14829
+ if (!loadApiKey() || !config.agentOsId?.trim()) {
14830
+ console.log(" This machine isn't linked yet \u2014 running bootstrap first.");
14831
+ await runBootstrap(args);
14832
+ config = loadUserConfig();
14833
+ }
14834
+ const agentOsId = (typeof args.agentOsId === "string" ? args.agentOsId.trim() : "") || config.agentOsId?.trim() || "";
14835
+ if (!agentOsId) {
14836
+ console.error("No AgentOS workspace configured \u2014 run `kynver bootstrap` (or pass --agent-os-id).");
14837
+ process.exit(1);
14838
+ }
14839
+ if (args.chatOauth === true && config.chatUseClaudeOauth !== true) {
14840
+ saveUserConfig({ ...config, chatUseClaudeOauth: true });
14841
+ config = loadUserConfig();
14842
+ console.log(" Chat: Claude Code OAuth opt-in saved (delegated turns may use your local subscription).");
14843
+ }
14844
+ const repo = (typeof args.repo === "string" ? args.repo.trim() : "") || config.defaultRepo?.trim() || resolveDefaultRepo()?.repo || "";
14845
+ if (!repo) {
14846
+ console.error("No repo configured \u2014 pass --repo /path/to/repo or run `kynver setup --discover-repo`.");
14847
+ process.exit(1);
14848
+ }
14849
+ let runId = typeof args.run === "string" && args.run.trim() ? args.run.trim() : "";
14850
+ if (!runId) {
14851
+ runId = resolveStartRunId(listRunRecords(), repo) ?? "";
14852
+ if (runId) {
14853
+ console.log(` Reusing run ${runId} for ${repo}.`);
14854
+ } else {
14855
+ runId = createRun({ ...args, repo, name: "agent" }).runId;
14856
+ }
14857
+ }
14858
+ console.log("");
14859
+ console.log(` ${os12.hostname()} \u2014 agent coming online`);
14860
+ console.log(` workspace: ${agentOsId}`);
14861
+ console.log(` repo: ${repo}`);
14862
+ console.log(` run: ${runId}`);
14863
+ console.log(" Ctrl-C stops the agent. (Advanced control: `kynver daemon --help`.)");
14864
+ console.log("");
14865
+ const daemonArgs = { ...args, run: runId, agentOsId };
14866
+ if (shouldRunDaemonKeeper(daemonArgs)) {
14867
+ await runDaemonKeeper(daemonArgs, buildStartDaemonArgv(runId, agentOsId, args));
14868
+ return;
14869
+ }
14870
+ await runDaemon(daemonArgs);
14871
+ }
14872
+ function buildStartDaemonArgv(runId, agentOsId, args) {
14873
+ const argv = ["daemon", "--run", runId, "--agent-os-id", agentOsId];
14874
+ if (typeof args.intervalMs === "string" && args.intervalMs.trim()) {
14875
+ argv.push("--interval-ms", args.intervalMs.trim());
14876
+ }
14877
+ if (args.execute === false || args.execute === "false") {
14878
+ argv.push("--execute", "false");
14879
+ }
14880
+ if (typeof args.stallMs === "string" && args.stallMs.trim()) {
14881
+ argv.push("--stall-ms", args.stallMs.trim());
14882
+ }
14883
+ return argv;
14884
+ }
14885
+
14886
+ // src/cli.ts
14887
+ init_run_store();
14888
+
14889
+ // src/discard-disposable.ts
14890
+ init_run_store();
14891
+ init_status();
14892
+ import { existsSync as existsSync44, rmSync as rmSync4 } from "node:fs";
14893
+ import path63 from "node:path";
14894
+ function normalizeRelativePath2(value) {
14895
+ const normalized = value.replace(/\\/g, "/").replace(/^\.\//, "").trim();
14896
+ if (!normalized || normalized.startsWith("/") || normalized.includes("..")) {
14897
+ throw new Error(`unsafe path: ${value}`);
14898
+ }
14899
+ return normalized;
14900
+ }
14901
+ function parsePathsArg(raw) {
14902
+ if (typeof raw !== "string" || !raw.trim()) return [];
14903
+ return raw.split(",").map((p) => p.trim()).filter(Boolean);
14904
+ }
14905
+ function discardDisposableArtifacts(args) {
14906
+ const { runId, workerName } = resolveWorkerTargetArgs(args);
14907
+ const worker = loadWorker(runId, workerName);
14908
+ const paths = [
14909
+ ...parsePathsArg(args.path),
14910
+ ...Array.isArray(args.paths) ? args.paths : []
14911
+ ];
14912
+ if (paths.length === 0) {
14913
+ return { ok: false, removed: [], reason: "requires at least one --path" };
14914
+ }
14915
+ const worktreeRoot = path63.resolve(worker.worktreePath);
14916
+ const removed = [];
14917
+ for (const raw of paths) {
14918
+ const rel = normalizeRelativePath2(raw);
14919
+ const abs = path63.resolve(worktreeRoot, rel);
14920
+ if (!abs.startsWith(worktreeRoot + path63.sep) && abs !== worktreeRoot) {
14921
+ return { ok: false, removed, reason: `path escapes worktree: ${raw}` };
14922
+ }
14923
+ if (!existsSync44(abs)) {
14924
+ return { ok: false, removed, reason: `path not found: ${raw}` };
14925
+ }
14926
+ rmSync4(abs, { recursive: true, force: true });
14927
+ removed.push(rel);
14928
+ }
14929
+ const prior = Array.isArray(worker.disposableArtifactsRemoved) ? worker.disposableArtifactsRemoved.filter((p) => typeof p === "string") : [];
14930
+ worker.disposableArtifactsRemoved = [.../* @__PURE__ */ new Set([...prior, ...removed])];
14931
+ saveWorker(worker.runId, worker);
14932
+ const status = computeWorkerStatus(worker);
14933
+ return {
14934
+ ok: true,
14935
+ removed,
14936
+ ...status.changedFiles.length ? { reason: "worktree still has other changes" } : {}
14937
+ };
14938
+ }
14939
+ function discardDisposableCli(args) {
14940
+ const result = discardDisposableArtifacts(args);
14941
+ console.log(JSON.stringify(result, null, 2));
14942
+ if (!result.ok) process.exit(1);
14943
+ }
14944
+
14587
14945
  // src/plan-progress.ts
14588
14946
  init_config();
14589
- import path65 from "node:path";
14947
+ import path67 from "node:path";
14590
14948
 
14591
14949
  // src/bounded-build/constants.ts
14592
14950
  var DEFAULT_BUILD_MEM_BUDGET_BYTES = 1536 * 1024 * 1024;
@@ -14627,7 +14985,7 @@ function formatNodeOptionsFlag(mb = resolveNodeOldSpaceSizeMb()) {
14627
14985
  }
14628
14986
 
14629
14987
  // src/bounded-build/systemd-wrap.ts
14630
- import { spawnSync as spawnSync9 } from "node:child_process";
14988
+ import { spawnSync as spawnSync10 } from "node:child_process";
14631
14989
  var systemdAvailableCache;
14632
14990
  function isSystemdRunAvailable() {
14633
14991
  if (process.env.KYNVER_BUILD_SKIP_SYSTEMD === "1" || process.env.KYNVER_BUILD_SKIP_SYSTEMD === "true") {
@@ -14638,7 +14996,7 @@ function isSystemdRunAvailable() {
14638
14996
  systemdAvailableCache = false;
14639
14997
  return false;
14640
14998
  }
14641
- const res = spawnSync9("systemd-run", ["--version"], { encoding: "utf8", stdio: ["ignore", "ignore", "pipe"] });
14999
+ const res = spawnSync10("systemd-run", ["--version"], { encoding: "utf8", stdio: ["ignore", "ignore", "pipe"] });
14642
15000
  systemdAvailableCache = res.status === 0;
14643
15001
  return systemdAvailableCache;
14644
15002
  }
@@ -14663,7 +15021,7 @@ function buildSystemdRunArgv(opts) {
14663
15021
 
14664
15022
  // src/bounded-build/admission.ts
14665
15023
  init_config();
14666
- import { spawnSync as spawnSync10 } from "node:child_process";
15024
+ import { spawnSync as spawnSync11 } from "node:child_process";
14667
15025
  init_meminfo();
14668
15026
  function positiveInt4(value, fallback) {
14669
15027
  const n = Number(value);
@@ -14700,7 +15058,7 @@ function assessBuildAdmission(opts = {}) {
14700
15058
  }
14701
15059
  function sleepMs2(ms) {
14702
15060
  if (ms <= 0) return;
14703
- spawnSync10(process.execPath, ["-e", `const d=Date.now()+${Math.floor(ms)};while(Date.now()<d);`], {
15061
+ spawnSync11(process.execPath, ["-e", `const d=Date.now()+${Math.floor(ms)};while(Date.now()<d);`], {
14704
15062
  stdio: "ignore"
14705
15063
  });
14706
15064
  }
@@ -14721,34 +15079,34 @@ function waitForBuildAdmission(timeoutMs, pollMs = 2e3, opts = {}) {
14721
15079
  }
14722
15080
 
14723
15081
  // src/bounded-build/exec.ts
14724
- import { spawnSync as spawnSync12 } from "node:child_process";
15082
+ import { spawnSync as spawnSync13 } from "node:child_process";
14725
15083
 
14726
15084
  // src/heavy-verification/slot.ts
14727
15085
  init_util();
14728
15086
  import {
14729
15087
  closeSync as closeSync7,
14730
- existsSync as existsSync44,
14731
- mkdirSync as mkdirSync9,
15088
+ existsSync as existsSync45,
15089
+ mkdirSync as mkdirSync11,
14732
15090
  openSync as openSync7,
14733
- readdirSync as readdirSync15,
15091
+ readdirSync as readdirSync14,
14734
15092
  readFileSync as readFileSync19,
14735
15093
  unlinkSync as unlinkSync4,
14736
- writeFileSync as writeFileSync6
15094
+ writeFileSync as writeFileSync7
14737
15095
  } from "node:fs";
14738
- import path63 from "node:path";
15096
+ import path65 from "node:path";
14739
15097
 
14740
15098
  // src/heavy-verification/paths.ts
14741
- import { mkdirSync as mkdirSync8 } from "node:fs";
14742
- import path62 from "node:path";
15099
+ import { mkdirSync as mkdirSync10 } from "node:fs";
15100
+ import path64 from "node:path";
14743
15101
  function resolveHeavyVerificationRoot() {
14744
- return path62.join(resolveKynverStateRoot(), "heavy-verification");
15102
+ return path64.join(resolveKynverStateRoot(), "heavy-verification");
14745
15103
  }
14746
15104
  function heavyVerificationSlotsDir() {
14747
- return path62.join(resolveHeavyVerificationRoot(), "slots");
15105
+ return path64.join(resolveHeavyVerificationRoot(), "slots");
14748
15106
  }
14749
15107
  function ensureHeavyVerificationDirs() {
14750
15108
  const dir = heavyVerificationSlotsDir();
14751
- mkdirSync8(dir, { recursive: true });
15109
+ mkdirSync10(dir, { recursive: true });
14752
15110
  return dir;
14753
15111
  }
14754
15112
 
@@ -14773,10 +15131,10 @@ function indexedSlotId(index) {
14773
15131
  return `slot-${index}`;
14774
15132
  }
14775
15133
  function slotFilePath(slotId, slotsDir = heavyVerificationSlotsDir()) {
14776
- return path63.join(slotsDir, `${slotId}.json`);
15134
+ return path65.join(slotsDir, `${slotId}.json`);
14777
15135
  }
14778
15136
  function readSlotRecord(filePath) {
14779
- if (!existsSync44(filePath)) return null;
15137
+ if (!existsSync45(filePath)) return null;
14780
15138
  try {
14781
15139
  const parsed = JSON.parse(readFileSync19(filePath, "utf8"));
14782
15140
  if (typeof parsed.slotId === "string" && typeof parsed.pid === "number" && typeof parsed.acquiredAt === "string" && typeof parsed.command === "string") {
@@ -14803,19 +15161,19 @@ function reclaimStaleSlot(filePath, staleMs) {
14803
15161
  }
14804
15162
  }
14805
15163
  function ensureSlotsDir(slotsDir) {
14806
- mkdirSync9(slotsDir, { recursive: true });
15164
+ mkdirSync11(slotsDir, { recursive: true });
14807
15165
  return slotsDir;
14808
15166
  }
14809
15167
  function reclaimStaleHeavyVerificationSlots(opts = {}) {
14810
15168
  const slotsDir = ensureSlotsDir(opts.slotsDir ?? ensureHeavyVerificationDirs());
14811
15169
  const staleMs = opts.staleMs ?? DEFAULT_HEAVY_VERIFICATION_STALE_MS;
14812
15170
  let reclaimed = 0;
14813
- for (const name of readdirSync15(slotsDir)) {
15171
+ for (const name of readdirSync14(slotsDir)) {
14814
15172
  if (!name.endsWith(".json")) continue;
14815
- const filePath = path63.join(slotsDir, name);
14816
- const before = existsSync44(filePath);
15173
+ const filePath = path65.join(slotsDir, name);
15174
+ const before = existsSync45(filePath);
14817
15175
  reclaimStaleSlot(filePath, staleMs);
14818
- if (before && !existsSync44(filePath)) reclaimed += 1;
15176
+ if (before && !existsSync45(filePath)) reclaimed += 1;
14819
15177
  }
14820
15178
  return reclaimed;
14821
15179
  }
@@ -14824,9 +15182,9 @@ function listActiveHeavyVerificationSlots(opts = {}) {
14824
15182
  const staleMs = opts.staleMs ?? DEFAULT_HEAVY_VERIFICATION_STALE_MS;
14825
15183
  reclaimStaleHeavyVerificationSlots({ slotsDir, staleMs });
14826
15184
  const active = [];
14827
- for (const name of readdirSync15(slotsDir)) {
15185
+ for (const name of readdirSync14(slotsDir)) {
14828
15186
  if (!name.endsWith(".json")) continue;
14829
- const record3 = readSlotRecord(path63.join(slotsDir, name));
15187
+ const record3 = readSlotRecord(path65.join(slotsDir, name));
14830
15188
  if (record3 && !slotIsStale(record3, staleMs)) active.push(record3);
14831
15189
  }
14832
15190
  return active;
@@ -14868,7 +15226,7 @@ function tryAcquireHeavyVerificationSlot(command, opts = {}) {
14868
15226
  };
14869
15227
  try {
14870
15228
  const fd = openSync7(filePath, "wx");
14871
- writeFileSync6(fd, JSON.stringify(record3, null, 2), "utf8");
15229
+ writeFileSync7(fd, JSON.stringify(record3, null, 2), "utf8");
14872
15230
  closeSync7(fd);
14873
15231
  const activeSlots2 = countActiveHeavyVerificationSlots({ slotsDir, staleMs });
14874
15232
  return {
@@ -14928,10 +15286,10 @@ function assessHeavyVerificationGate(command, opts = {}) {
14928
15286
  }
14929
15287
 
14930
15288
  // src/heavy-verification/gate.ts
14931
- import { spawnSync as spawnSync11 } from "node:child_process";
15289
+ import { spawnSync as spawnSync12 } from "node:child_process";
14932
15290
  function sleepMs3(ms) {
14933
15291
  if (ms <= 0) return;
14934
- spawnSync11(process.execPath, ["-e", `const d=Date.now()+${Math.floor(ms)};while(Date.now()<d);`], {
15292
+ spawnSync12(process.execPath, ["-e", `const d=Date.now()+${Math.floor(ms)};while(Date.now()<d);`], {
14935
15293
  stdio: "ignore"
14936
15294
  });
14937
15295
  }
@@ -14947,11 +15305,11 @@ function waitForHeavyVerificationSlot(command, timeoutMs, pollMs = 2e3, opts = {
14947
15305
 
14948
15306
  // src/harness-worktree-build-guard.ts
14949
15307
  init_paths();
14950
- import path64 from "node:path";
15308
+ import path66 from "node:path";
14951
15309
  function isPathUnderHarnessWorktree(cwd) {
14952
15310
  const worktreesDir = harnessWorktreesDir(resolveHarnessRoot());
14953
- const rel = path64.relative(worktreesDir, path64.resolve(cwd));
14954
- return rel.length > 0 && !rel.startsWith("..") && !path64.isAbsolute(rel);
15311
+ const rel = path66.relative(worktreesDir, path66.resolve(cwd));
15312
+ return rel.length > 0 && !rel.startsWith("..") && !path66.isAbsolute(rel);
14955
15313
  }
14956
15314
  function assessHarnessWorktreeBuildGuard(cwd) {
14957
15315
  if (!isPathUnderHarnessWorktree(cwd)) return { ok: true };
@@ -14975,7 +15333,7 @@ function envArgv(env) {
14975
15333
  return out;
14976
15334
  }
14977
15335
  function runSpawn(argv, opts) {
14978
- const res = spawnSync12(argv[0], argv.slice(1), {
15336
+ const res = spawnSync13(argv[0], argv.slice(1), {
14979
15337
  cwd: opts.cwd,
14980
15338
  env: opts.env,
14981
15339
  encoding: "utf8",
@@ -15164,7 +15522,7 @@ async function emitPlanProgress(args) {
15164
15522
  }
15165
15523
  function verifyPlanLocal(args) {
15166
15524
  const worktree = required(args.worktree ? String(args.worktree) : void 0, "worktree");
15167
- const cwd = path65.resolve(worktree);
15525
+ const cwd = path67.resolve(worktree);
15168
15526
  const summary = runHarnessVerifyCommands(cwd);
15169
15527
  const emitJson = args.json === true || args.json === "true";
15170
15528
  const payload = { passed: summary.passed, worktree: cwd, steps: summary.steps };
@@ -15213,10 +15571,10 @@ async function verifyPlan(args) {
15213
15571
  }
15214
15572
 
15215
15573
  // src/harness-verify-cli.ts
15216
- import path66 from "node:path";
15574
+ import path68 from "node:path";
15217
15575
  init_util();
15218
15576
  function runHarnessVerifyCli(args) {
15219
- const cwd = path66.resolve(required(args.worktree ? String(args.worktree) : void 0, "worktree"));
15577
+ const cwd = path68.resolve(required(args.worktree ? String(args.worktree) : void 0, "worktree"));
15220
15578
  const emitJson = args.json === true || args.json === "true" || args.emitJson === true || args.emitJson === "true";
15221
15579
  const commands = [];
15222
15580
  const rawCmd = args.command;
@@ -15348,7 +15706,9 @@ function runCleanupCli(args) {
15348
15706
  const skipFinalize = args.skipFinalize === true || args.skipFinalize === "true";
15349
15707
  const accountBytes = args.accountBytes === true || args.accountBytes === "true";
15350
15708
  const compact = args.compact === true || args.compact === "true";
15351
- const nodeModulesAgeMs = args.nodeModulesAgeMs ? Number(args.nodeModulesAgeMs) : DEFAULT_NODE_MODULES_AGE_MS;
15709
+ const nodeModulesAgeMsRaw = args.nodeModulesAgeMs;
15710
+ const scanDependencyCaches = nodeModulesAgeMsRaw != null && nodeModulesAgeMsRaw !== "";
15711
+ const nodeModulesAgeMs = scanDependencyCaches ? Number(nodeModulesAgeMsRaw) : void 0;
15352
15712
  const worktreesAgeMs = args.worktreesAgeMs ? Number(args.worktreesAgeMs) : 0;
15353
15713
  const includeOrphans = args.includeOrphans === true || args.includeOrphans === "true";
15354
15714
  const harnessRoot = args.harnessRoot ? String(args.harnessRoot) : void 0;
@@ -15356,7 +15716,8 @@ function runCleanupCli(args) {
15356
15716
  execute,
15357
15717
  finalizeStaleRuns: !skipFinalize,
15358
15718
  accountBytes,
15359
- nodeModulesAgeMs: Number.isFinite(nodeModulesAgeMs) ? nodeModulesAgeMs : DEFAULT_NODE_MODULES_AGE_MS,
15719
+ scanDependencyCaches,
15720
+ nodeModulesAgeMs: nodeModulesAgeMs !== void 0 && Number.isFinite(nodeModulesAgeMs) ? nodeModulesAgeMs : scanDependencyCaches ? DEFAULT_NODE_MODULES_AGE_MS : void 0,
15360
15721
  worktreesAgeMs: Number.isFinite(worktreesAgeMs) ? worktreesAgeMs : 0,
15361
15722
  includeOrphans,
15362
15723
  harnessRoot
@@ -15655,7 +16016,7 @@ ${text.slice(0, 800)}`,
15655
16016
  }
15656
16017
 
15657
16018
  // src/monitor/monitor.service.ts
15658
- import path68 from "node:path";
16019
+ import path70 from "node:path";
15659
16020
  init_run_store();
15660
16021
  init_status();
15661
16022
  init_util();
@@ -15714,19 +16075,19 @@ function classifyWorkerHealth(input) {
15714
16075
  // src/monitor/monitor.store.ts
15715
16076
  init_paths();
15716
16077
  init_util();
15717
- import { existsSync as existsSync45, mkdirSync as mkdirSync10, readdirSync as readdirSync16, unlinkSync as unlinkSync5 } from "node:fs";
15718
- import path67 from "node:path";
16078
+ import { existsSync as existsSync46, mkdirSync as mkdirSync12, readdirSync as readdirSync15, unlinkSync as unlinkSync5 } from "node:fs";
16079
+ import path69 from "node:path";
15719
16080
  function monitorsDir() {
15720
16081
  const { harnessRoot } = getHarnessPaths();
15721
- const dir = path67.join(harnessRoot, "monitors");
15722
- mkdirSync10(dir, { recursive: true });
16082
+ const dir = path69.join(harnessRoot, "monitors");
16083
+ mkdirSync12(dir, { recursive: true });
15723
16084
  return dir;
15724
16085
  }
15725
16086
  function monitorIdFor(runId, workerName) {
15726
16087
  return workerName ? `${safeSlug(runId)}--${safeSlug(workerName)}` : safeSlug(runId);
15727
16088
  }
15728
16089
  function monitorPath(monitorId) {
15729
- return path67.join(monitorsDir(), `${monitorId}.json`);
16090
+ return path69.join(monitorsDir(), `${monitorId}.json`);
15730
16091
  }
15731
16092
  function loadMonitorSession(monitorId) {
15732
16093
  return readJson(monitorPath(monitorId), void 0);
@@ -15736,18 +16097,18 @@ function saveMonitorSession(session) {
15736
16097
  }
15737
16098
  function deleteMonitorSession(monitorId) {
15738
16099
  const file = monitorPath(monitorId);
15739
- if (!existsSync45(file)) return false;
16100
+ if (!existsSync46(file)) return false;
15740
16101
  unlinkSync5(file);
15741
16102
  return true;
15742
16103
  }
15743
16104
  function listMonitorSessions() {
15744
16105
  const dir = monitorsDir();
15745
- if (!existsSync45(dir)) return [];
16106
+ if (!existsSync46(dir)) return [];
15746
16107
  const entries = [];
15747
- for (const name of readdirSync16(dir)) {
16108
+ for (const name of readdirSync15(dir)) {
15748
16109
  if (!name.endsWith(".json")) continue;
15749
16110
  const session = readJson(
15750
- path67.join(dir, name),
16111
+ path69.join(dir, name),
15751
16112
  void 0
15752
16113
  );
15753
16114
  if (!session?.monitorId) continue;
@@ -15840,7 +16201,7 @@ async function fetchTaskLeasesForWorkers(input) {
15840
16201
  // src/monitor/monitor.service.ts
15841
16202
  function workerRecord2(runId, name) {
15842
16203
  return readJson(
15843
- path68.join(runDirectory(runId), "workers", safeSlug(name), "worker.json"),
16204
+ path70.join(runDirectory(runId), "workers", safeSlug(name), "worker.json"),
15844
16205
  void 0
15845
16206
  );
15846
16207
  }
@@ -16049,18 +16410,18 @@ async function runMonitorLoop(args) {
16049
16410
  init_util();
16050
16411
  init_paths();
16051
16412
  import { spawn as spawn7 } from "node:child_process";
16052
- import { closeSync as closeSync8, existsSync as existsSync46, openSync as openSync8 } from "node:fs";
16053
- import path69 from "node:path";
16413
+ import { closeSync as closeSync8, existsSync as existsSync47, openSync as openSync8 } from "node:fs";
16414
+ import path71 from "node:path";
16054
16415
  import { fileURLToPath as fileURLToPath4 } from "node:url";
16055
16416
  function resolveDefaultCliPath2() {
16056
- return path69.join(fileURLToPath4(new URL(".", import.meta.url)), "cli.js");
16417
+ return path71.join(fileURLToPath4(new URL(".", import.meta.url)), "cli.js");
16057
16418
  }
16058
16419
  function spawnMonitorSidecar(opts) {
16059
16420
  const cliPath = opts.cliPath ?? resolveDefaultCliPath2();
16060
- if (!existsSync46(cliPath)) return void 0;
16421
+ if (!existsSync47(cliPath)) return void 0;
16061
16422
  const monitorId = monitorIdFor(opts.runId, opts.workerName);
16062
16423
  const { harnessRoot } = getHarnessPaths();
16063
- const logPath = path69.join(harnessRoot, "monitors", `${monitorId}.log`);
16424
+ const logPath = path71.join(harnessRoot, "monitors", `${monitorId}.log`);
16064
16425
  let logFd;
16065
16426
  try {
16066
16427
  logFd = openSync8(logPath, "a");
@@ -16185,7 +16546,7 @@ init_run_store();
16185
16546
  init_status();
16186
16547
  init_util();
16187
16548
  init_config();
16188
- import path70 from "node:path";
16549
+ import path72 from "node:path";
16189
16550
  function skip(runId, worker, taskId, agentOsId, leaseOwner, reason) {
16190
16551
  return { runId, worker, taskId, agentOsId, leaseOwner, action: "skipped", reason };
16191
16552
  }
@@ -16198,7 +16559,7 @@ async function postRestartUnblock(args) {
16198
16559
  const errors = [];
16199
16560
  for (const run of listRunRecords()) {
16200
16561
  for (const name of Object.keys(run.workers ?? {})) {
16201
- const workerPath = path70.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json");
16562
+ const workerPath = path72.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json");
16202
16563
  const worker = readJson(workerPath, void 0);
16203
16564
  if (!worker) {
16204
16565
  skipped.push(skip(run.id, name, "", "", "", "worker.json missing"));
@@ -16312,9 +16673,9 @@ async function postRestartUnblockCli(args) {
16312
16673
  // src/default-repo-cli.ts
16313
16674
  init_path_values();
16314
16675
  init_config();
16315
- import path71 from "node:path";
16676
+ import path73 from "node:path";
16316
16677
  import { homedir as homedir17 } from "node:os";
16317
- var CONFIG_FILE2 = path71.join(homedir17(), ".kynver", "config.json");
16678
+ var CONFIG_FILE2 = path73.join(homedir17(), ".kynver", "config.json");
16318
16679
  function ensureDefaultRepo(opts) {
16319
16680
  const existing = loadUserConfig();
16320
16681
  const resolved = resolveDefaultRepo({ ...opts, config: existing });
@@ -16395,19 +16756,19 @@ function summarizeResolvedDefaultRepo(resolved) {
16395
16756
  }
16396
16757
 
16397
16758
  // src/doctor/runtime-takeover.ts
16398
- import path73 from "node:path";
16759
+ import path75 from "node:path";
16399
16760
  init_path_values();
16400
16761
 
16401
16762
  // src/doctor/runtime-takeover.probes.ts
16402
16763
  init_config();
16403
- import { accessSync, constants, existsSync as existsSync47, readFileSync as readFileSync21 } from "node:fs";
16764
+ import { accessSync, constants, existsSync as existsSync48, readFileSync as readFileSync21 } from "node:fs";
16404
16765
  import { homedir as homedir18 } from "node:os";
16405
- import path72 from "node:path";
16406
- import { spawnSync as spawnSync13 } from "node:child_process";
16766
+ import path74 from "node:path";
16767
+ import { spawnSync as spawnSync14 } from "node:child_process";
16407
16768
  init_paths();
16408
16769
  function captureCommand(bin, args) {
16409
16770
  try {
16410
- const res = spawnSync13(bin, args, { encoding: "utf8" });
16771
+ const res = spawnSync14(bin, args, { encoding: "utf8" });
16411
16772
  const stdout = (res.stdout || "").trim();
16412
16773
  const stderr = (res.stderr || "").trim();
16413
16774
  const ok = res.status === 0;
@@ -16432,7 +16793,7 @@ function tokenPrefix(token) {
16432
16793
  return trimmed.length <= 12 ? `${trimmed}\u2026` : `${trimmed.slice(0, 12)}\u2026`;
16433
16794
  }
16434
16795
  function isWritable(target) {
16435
- if (!existsSync47(target)) return false;
16796
+ if (!existsSync48(target)) return false;
16436
16797
  try {
16437
16798
  accessSync(target, constants.W_OK);
16438
16799
  return true;
@@ -16445,11 +16806,11 @@ var defaultRuntimeTakeoverProbes = {
16445
16806
  commandOnPath: (bin) => captureCommand(process.platform === "win32" ? "where" : "which", [bin]),
16446
16807
  kynverVersion: (bin) => captureCommand(bin, ["--version"]),
16447
16808
  loadConfig: () => loadUserConfig(),
16448
- configFilePath: () => path72.join(homedir18(), ".kynver", "config.json"),
16449
- credentialsFilePath: () => path72.join(homedir18(), ".kynver", "credentials"),
16809
+ configFilePath: () => path74.join(homedir18(), ".kynver", "config.json"),
16810
+ credentialsFilePath: () => path74.join(homedir18(), ".kynver", "credentials"),
16450
16811
  readCredentials: () => {
16451
- const credPath = path72.join(homedir18(), ".kynver", "credentials");
16452
- if (!existsSync47(credPath)) {
16812
+ const credPath = path74.join(homedir18(), ".kynver", "credentials");
16813
+ if (!existsSync48(credPath)) {
16453
16814
  return { hasApiKey: false };
16454
16815
  }
16455
16816
  try {
@@ -16483,8 +16844,8 @@ var defaultRuntimeTakeoverProbes = {
16483
16844
  })()
16484
16845
  }),
16485
16846
  harnessRoot: () => resolveHarnessRoot(),
16486
- legacyOpenclawHarnessRoot: () => path72.join(homedir18(), ".openclaw", "harness"),
16487
- pathExists: (target) => existsSync47(target),
16847
+ legacyOpenclawHarnessRoot: () => path74.join(homedir18(), ".openclaw", "harness"),
16848
+ pathExists: (target) => existsSync48(target),
16488
16849
  pathWritable: (target) => isWritable(target)
16489
16850
  };
16490
16851
 
@@ -16890,8 +17251,8 @@ function assessVercelDeployEvidence(probes) {
16890
17251
  }
16891
17252
  function assessHarnessDirs(probes) {
16892
17253
  const harnessRoot = probes.harnessRoot();
16893
- const runsDir = path73.join(harnessRoot, "runs");
16894
- const worktreesDir = path73.join(harnessRoot, "worktrees");
17254
+ const runsDir = path75.join(harnessRoot, "runs");
17255
+ const worktreesDir = path75.join(harnessRoot, "worktrees");
16895
17256
  const displayHarnessRoot = redactHomePath(harnessRoot);
16896
17257
  const displayRunsDir = redactHomePath(runsDir);
16897
17258
  const displayWorktreesDir = redactHomePath(worktreesDir);
@@ -17160,9 +17521,9 @@ function applySchedulerCutoverAttestation(config) {
17160
17521
 
17161
17522
  // src/scheduler-cutover-cli.ts
17162
17523
  init_config();
17163
- import path74 from "node:path";
17524
+ import path76 from "node:path";
17164
17525
  import { homedir as homedir19 } from "node:os";
17165
- var CONFIG_FILE3 = path74.join(homedir19(), ".kynver", "config.json");
17526
+ var CONFIG_FILE3 = path76.join(homedir19(), ".kynver", "config.json");
17166
17527
  function runSchedulerCutoverCheckCli(json = false) {
17167
17528
  const config = loadUserConfig();
17168
17529
  const report = assessSchedulerCutover(config);
@@ -17306,7 +17667,7 @@ init_config();
17306
17667
  init_config();
17307
17668
  init_path_values();
17308
17669
  init_util();
17309
- import { existsSync as existsSync51 } from "node:fs";
17670
+ import { existsSync as existsSync52 } from "node:fs";
17310
17671
 
17311
17672
  // src/cron/cron-id.ts
17312
17673
  import { createHash as createHash5 } from "node:crypto";
@@ -17325,13 +17686,13 @@ function deterministicCronProviderId(spec) {
17325
17686
 
17326
17687
  // src/cron/cron-install-plan.ts
17327
17688
  import { homedir as homedir21 } from "node:os";
17328
- import path76 from "node:path";
17689
+ import path78 from "node:path";
17329
17690
 
17330
17691
  // src/cron/cron-env-file.ts
17331
- import { existsSync as existsSync48, mkdirSync as mkdirSync11, readFileSync as readFileSync22, writeFileSync as writeFileSync7 } from "node:fs";
17692
+ import { existsSync as existsSync49, mkdirSync as mkdirSync13, readFileSync as readFileSync22, writeFileSync as writeFileSync8 } from "node:fs";
17332
17693
  import { homedir as homedir20 } from "node:os";
17333
- import path75 from "node:path";
17334
- var DEFAULT_KYNVER_ENV_FILE = path75.join(homedir20(), ".kynver", ".env");
17694
+ import path77 from "node:path";
17695
+ var DEFAULT_KYNVER_ENV_FILE = path77.join(homedir20(), ".kynver", ".env");
17335
17696
  function parseEnvFile(content) {
17336
17697
  const map = /* @__PURE__ */ new Map();
17337
17698
  for (const line of content.split(/\r?\n/)) {
@@ -17358,12 +17719,12 @@ function serializeEnvFile(values, header = "# Managed by kynver cron install \u2
17358
17719
  return lines.join("\n");
17359
17720
  }
17360
17721
  function readEnvFile(filePath = DEFAULT_KYNVER_ENV_FILE) {
17361
- if (!existsSync48(filePath)) return /* @__PURE__ */ new Map();
17722
+ if (!existsSync49(filePath)) return /* @__PURE__ */ new Map();
17362
17723
  return parseEnvFile(readFileSync22(filePath, "utf8"));
17363
17724
  }
17364
17725
  function mergeEnvFile(updates, options = {}) {
17365
17726
  const filePath = options.filePath ?? DEFAULT_KYNVER_ENV_FILE;
17366
- const existing = existsSync48(filePath) ? readFileSync22(filePath, "utf8") : "";
17727
+ const existing = existsSync49(filePath) ? readFileSync22(filePath, "utf8") : "";
17367
17728
  const map = parseEnvFile(existing);
17368
17729
  const keysWritten = [];
17369
17730
  const keysRemoved = [];
@@ -17388,8 +17749,8 @@ function mergeEnvFile(updates, options = {}) {
17388
17749
  }
17389
17750
  const nextContent = serializeEnvFile(map);
17390
17751
  if (changed) {
17391
- mkdirSync11(path75.dirname(filePath), { recursive: true });
17392
- writeFileSync7(filePath, nextContent, { mode: 384 });
17752
+ mkdirSync13(path77.dirname(filePath), { recursive: true });
17753
+ writeFileSync8(filePath, nextContent, { mode: 384 });
17393
17754
  }
17394
17755
  return { path: filePath, changed, keysWritten, keysRemoved };
17395
17756
  }
@@ -17406,7 +17767,7 @@ var VERCEL_KYNVER_CRON_CUTOVER_STEPS = [
17406
17767
  function buildCronInstallPlan(input) {
17407
17768
  const storePath = input.storePath?.trim() || defaultKynverCronStorePath();
17408
17769
  const envFilePath = input.envFilePath?.trim() || DEFAULT_KYNVER_ENV_FILE;
17409
- const configPath = path76.join(homedir21(), ".kynver", "config.json");
17770
+ const configPath = path78.join(homedir21(), ".kynver", "config.json");
17410
17771
  const callbackPath = `/api/agent-os/by-id/${input.agentOsId}/scheduler/fire`;
17411
17772
  const prerequisites = [];
17412
17773
  if (!input.apiBaseUrl?.trim()) prerequisites.push("apiBaseUrl \u2014 run `kynver setup --api-base-url \u2026`");
@@ -17558,13 +17919,13 @@ function resolveCronSecretForInstall(envFilePath = DEFAULT_KYNVER_ENV_FILE) {
17558
17919
  }
17559
17920
 
17560
17921
  // src/cron/cron-install-systemd.ts
17561
- import { existsSync as existsSync49, mkdirSync as mkdirSync12, writeFileSync as writeFileSync8 } from "node:fs";
17922
+ import { existsSync as existsSync50, mkdirSync as mkdirSync14, writeFileSync as writeFileSync9 } from "node:fs";
17562
17923
  import { homedir as homedir22 } from "node:os";
17563
- import path77 from "node:path";
17564
- import { spawnSync as spawnSync14 } from "node:child_process";
17924
+ import path79 from "node:path";
17925
+ import { spawnSync as spawnSync15 } from "node:child_process";
17565
17926
  var KYNVER_CRON_DAEMON_UNIT = "kynver-cron-daemon.service";
17566
17927
  function defaultSystemdUserUnitDir() {
17567
- return path77.join(homedir22(), ".config", "systemd", "user");
17928
+ return path79.join(homedir22(), ".config", "systemd", "user");
17568
17929
  }
17569
17930
  function renderKynverCronDaemonService(input) {
17570
17931
  const kynverBin = input.kynverBin?.trim() || "kynver";
@@ -17597,7 +17958,7 @@ function installSystemdUserDaemon(input, execute) {
17597
17958
  };
17598
17959
  }
17599
17960
  const unitDir = defaultSystemdUserUnitDir();
17600
- const unitPath = path77.join(unitDir, KYNVER_CRON_DAEMON_UNIT);
17961
+ const unitPath = path79.join(unitDir, KYNVER_CRON_DAEMON_UNIT);
17601
17962
  const content = renderKynverCronDaemonService(input);
17602
17963
  if (!execute) {
17603
17964
  return {
@@ -17609,10 +17970,10 @@ function installSystemdUserDaemon(input, execute) {
17609
17970
  note: "Dry-run \u2014 pass --execute to write and enable the user unit."
17610
17971
  };
17611
17972
  }
17612
- mkdirSync12(unitDir, { recursive: true });
17613
- const existed = existsSync49(unitPath);
17614
- writeFileSync8(unitPath, content, "utf8");
17615
- const reload = spawnSync14("systemctl", ["--user", "daemon-reload"], { encoding: "utf8" });
17973
+ mkdirSync14(unitDir, { recursive: true });
17974
+ const existed = existsSync50(unitPath);
17975
+ writeFileSync9(unitPath, content, "utf8");
17976
+ const reload = spawnSync15("systemctl", ["--user", "daemon-reload"], { encoding: "utf8" });
17616
17977
  if (reload.status !== 0) {
17617
17978
  return {
17618
17979
  supported: true,
@@ -17623,7 +17984,7 @@ function installSystemdUserDaemon(input, execute) {
17623
17984
  note: `Wrote ${unitPath} but systemctl --user daemon-reload failed: ${reload.stderr || reload.stdout}`
17624
17985
  };
17625
17986
  }
17626
- const enable = spawnSync14("systemctl", ["--user", "enable", "--now", KYNVER_CRON_DAEMON_UNIT], {
17987
+ const enable = spawnSync15("systemctl", ["--user", "enable", "--now", KYNVER_CRON_DAEMON_UNIT], {
17627
17988
  encoding: "utf8"
17628
17989
  });
17629
17990
  return {
@@ -17637,7 +17998,7 @@ function installSystemdUserDaemon(input, execute) {
17637
17998
  }
17638
17999
 
17639
18000
  // src/cron/cron-install-verify.ts
17640
- import { existsSync as existsSync50 } from "node:fs";
18001
+ import { existsSync as existsSync51 } from "node:fs";
17641
18002
  async function verifyCronInstall(input) {
17642
18003
  const envFilePath = input.envFilePath ?? DEFAULT_KYNVER_ENV_FILE;
17643
18004
  const checks = [];
@@ -17670,14 +18031,14 @@ async function verifyCronInstall(input) {
17670
18031
  });
17671
18032
  checks.push({
17672
18033
  id: "env_file",
17673
- ok: existsSync50(envFilePath) && Boolean(fileEnv.get("KYNVER_CRON_SECRET")),
17674
- summary: existsSync50(envFilePath) ? `~/.kynver/.env present (${fileEnv.size} keys)` : "~/.kynver/.env missing",
18034
+ ok: existsSync51(envFilePath) && Boolean(fileEnv.get("KYNVER_CRON_SECRET")),
18035
+ summary: existsSync51(envFilePath) ? `~/.kynver/.env present (${fileEnv.size} keys)` : "~/.kynver/.env missing",
17675
18036
  remediation: "Run `kynver cron install` to write ~/.kynver/.env."
17676
18037
  });
17677
18038
  checks.push({
17678
18039
  id: "cron_store",
17679
- ok: existsSync50(env.storePath),
17680
- summary: existsSync50(env.storePath) ? `cron store present (${env.storePath})` : `cron store missing (${env.storePath})`,
18040
+ ok: existsSync51(env.storePath),
18041
+ summary: existsSync51(env.storePath) ? `cron store present (${env.storePath})` : `cron store missing (${env.storePath})`,
17681
18042
  remediation: "Run `kynver cron install` to initialize the local store."
17682
18043
  });
17683
18044
  const jobs = await loadCronJobs(env.storePath).catch(() => []);
@@ -17711,7 +18072,7 @@ function resolveDaemonRunId(config, explicit) {
17711
18072
  if (explicit?.trim()) return explicit.trim();
17712
18073
  if (config.defaultDaemonRunId?.trim()) return config.defaultDaemonRunId.trim();
17713
18074
  const runsDir = getPaths().runsDir;
17714
- if (!existsSync51(runsDir)) return null;
18075
+ if (!existsSync52(runsDir)) return null;
17715
18076
  const runs = listRunRecords().sort(
17716
18077
  (a, b) => Date.parse(b.createdAt) - Date.parse(a.createdAt)
17717
18078
  );
@@ -17763,7 +18124,7 @@ async function runCronInstall(opts = {}) {
17763
18124
  process.env.KYNVER_CRON_STORE_PATH = plan.storePath;
17764
18125
  process.env.KYNVER_CRON_TICK_ENABLED = "1";
17765
18126
  const storeInit = await ensureCronStoreInitialized(plan.storePath);
17766
- result.storeInitialized = storeInit.created || existsSync51(plan.storePath);
18127
+ result.storeInitialized = storeInit.created || existsSync52(plan.storePath);
17767
18128
  const apiKey = loadApiKey();
17768
18129
  if (apiKey) {
17769
18130
  try {
@@ -17982,10 +18343,10 @@ var LANDING_MAINTAINER_LANE_SPEC = {
17982
18343
  };
17983
18344
 
17984
18345
  // src/lane/landing-maintainer-local.ts
17985
- import { spawnSync as spawnSync15 } from "node:child_process";
17986
- import path78 from "node:path";
18346
+ import { spawnSync as spawnSync16 } from "node:child_process";
18347
+ import path80 from "node:path";
17987
18348
  function runLandingWrapper(prNumber, repoRoot, execute) {
17988
- const script = path78.join(repoRoot, LANDING_MAINTAINER_LANE_SPEC.landScript);
18349
+ const script = path80.join(repoRoot, LANDING_MAINTAINER_LANE_SPEC.landScript);
17989
18350
  const args = [script, String(prNumber), ...LANDING_MAINTAINER_LANE_SPEC.landScriptArgs];
17990
18351
  if (!execute) {
17991
18352
  return {
@@ -17996,7 +18357,7 @@ function runLandingWrapper(prNumber, repoRoot, execute) {
17996
18357
  stderr: ""
17997
18358
  };
17998
18359
  }
17999
- const result = spawnSync15("node", args, {
18360
+ const result = spawnSync16("node", args, {
18000
18361
  cwd: repoRoot,
18001
18362
  encoding: "utf8",
18002
18363
  timeout: 10 * 60 * 1e3
@@ -18011,7 +18372,7 @@ function runLandingWrapper(prNumber, repoRoot, execute) {
18011
18372
  }
18012
18373
  function resolveLandingMaintainerRepoRoot(args) {
18013
18374
  const explicit = args.repoPath ? String(args.repoPath).trim() : "";
18014
- if (explicit) return path78.resolve(explicit);
18375
+ if (explicit) return path80.resolve(explicit);
18015
18376
  const resolved = resolveDefaultRepo();
18016
18377
  return resolved?.repo ?? process.cwd();
18017
18378
  }
@@ -18136,9 +18497,9 @@ function usage(code = 0) {
18136
18497
  "Usage:",
18137
18498
  " kynver login [--api-key KEY] [--api-base-url URL] (omit --api-key to authorize in the browser)",
18138
18499
  " kynver bootstrap [--api-base-url URL] [--api-key KEY] [--repo PATH] (login + setup + runner credential in one shot)",
18139
- " kynver start [--repo PATH] [--api-base-url URL] [--run RUN_ID] [--interval-ms MS] (bring your agent online: bootstrap if needed + run + daemon)",
18500
+ " kynver start [--repo PATH] [--api-base-url URL] [--run RUN_ID] [--interval-ms MS] [--chat-oauth] (bring your agent online: bootstrap if needed + run + daemon; --chat-oauth lets delegated chat turns use your local Claude subscription)",
18140
18501
  " kynver runner credential [--agent-os-id ID] [--base-url URL]",
18141
- " kynver setup [--api-base-url URL] [--agent-os-id ID] [--agent-os-slug SLUG] [--box-kind forge|ghost] [--repo PATH] [--discover-repo] [--max-workers N] [--provider claude|cursor]",
18502
+ " kynver setup [--api-base-url URL] [--agent-os-id ID] [--agent-os-slug SLUG] [--box-kind forge|ghost] [--repo PATH] [--discover-repo] [--max-workers N] [--provider claude|cursor] [--chat-oauth]",
18142
18503
  " kynver daemon --run RUN_ID --agent-os-id AOS_ID [--execute] [--interval-ms MS] [--stall-ms MS] [--no-supervise]",
18143
18504
  " kynver status --run RUN_ID [--blocked] [--running] [--task TASK_ID] [--worker WORKER] [--full] # top-level compact run status",
18144
18505
  " kynver run create [--repo /path/repo] [--name name] [--base origin/main]",
@@ -18202,8 +18563,8 @@ async function main(argv = process.argv.slice(2)) {
18202
18563
  if (action && isHelpFlag(action) || rest.some(isHelpFlag)) return usage(0);
18203
18564
  const args = parseArgs(rest);
18204
18565
  const { runsDir, worktreesDir } = getPaths();
18205
- mkdirSync13(runsDir, { recursive: true });
18206
- mkdirSync13(worktreesDir, { recursive: true });
18566
+ mkdirSync15(runsDir, { recursive: true });
18567
+ mkdirSync15(worktreesDir, { recursive: true });
18207
18568
  if (scope === "daemon") {
18208
18569
  assertNativeDaemonAllowed();
18209
18570
  }
@@ -18682,9 +19043,11 @@ export {
18682
19043
  ORCHESTRATION_POLICY_MODES,
18683
19044
  PACKAGE_VERSION,
18684
19045
  RUN_METADATA_ACTIVE_SIGNAL_MS,
19046
+ TERMINAL_WORKER_ARCHIVE_AGE_MS,
18685
19047
  TRANSIENT_OPENAI_CODEX_ERROR_CLASSES,
18686
19048
  WORKER_PERSONA_CATALOG,
18687
19049
  applyProductionDatabaseToProcess,
19050
+ archiveTerminalWorkerMetadata,
18688
19051
  assertMemoryCostPackageVersionGuard,
18689
19052
  assessAutoCompleteEligibility,
18690
19053
  assessBuildAdmission,