@kynver-app/runtime 0.1.42 → 0.1.48

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.
Files changed (118) hide show
  1. package/README.md +15 -0
  2. package/dist/auto-complete.d.ts +60 -0
  3. package/dist/bounded-build/admission.d.ts +30 -0
  4. package/dist/bounded-build/constants.d.ts +10 -0
  5. package/dist/bounded-build/exec.d.ts +26 -0
  6. package/dist/bounded-build/index.d.ts +6 -0
  7. package/dist/bounded-build/meminfo.d.ts +5 -0
  8. package/dist/bounded-build/node-options.d.ts +9 -0
  9. package/dist/bounded-build/systemd-wrap.d.ts +17 -0
  10. package/dist/callback-headers.d.ts +2 -0
  11. package/dist/callbacks.d.ts +38 -0
  12. package/dist/cleanup-cli.d.ts +1 -0
  13. package/dist/cleanup-dir-size.d.ts +4 -0
  14. package/dist/cleanup-execute.d.ts +4 -0
  15. package/dist/cleanup-guards.d.ts +18 -0
  16. package/dist/cleanup-scan.d.ts +14 -0
  17. package/dist/cleanup-types.d.ts +56 -0
  18. package/dist/cleanup-worktree-index.d.ts +13 -0
  19. package/dist/cleanup.d.ts +5 -0
  20. package/dist/cli.d.ts +3 -0
  21. package/dist/cli.js +840 -77
  22. package/dist/cli.js.map +4 -4
  23. package/dist/command-center-contract-cli.d.ts +1 -0
  24. package/dist/completion-ack.d.ts +10 -0
  25. package/dist/completion-response.d.ts +15 -0
  26. package/dist/config.d.ts +61 -0
  27. package/dist/daemon.d.ts +5 -0
  28. package/dist/disk-gate.d.ts +9 -0
  29. package/dist/dispatch.d.ts +16 -0
  30. package/dist/doctor/doctor.types.d.ts +25 -0
  31. package/dist/doctor/index.d.ts +4 -0
  32. package/dist/doctor/runtime-takeover-cli.d.ts +1 -0
  33. package/dist/doctor/runtime-takeover.d.ts +3 -0
  34. package/dist/doctor/runtime-takeover.probes.d.ts +37 -0
  35. package/dist/exit-classify.d.ts +12 -0
  36. package/dist/exited-salvage.d.ts +22 -0
  37. package/dist/finalize.d.ts +16 -0
  38. package/dist/fortress-engagement-gate.d.ts +5 -0
  39. package/dist/git.d.ts +37 -0
  40. package/dist/github-repo.d.ts +5 -0
  41. package/dist/harness-expert-review.d.ts +8 -0
  42. package/dist/harness-verify-cli.d.ts +1 -0
  43. package/dist/harness-verify.d.ts +19 -0
  44. package/dist/heartbeat.d.ts +22 -0
  45. package/dist/index.d.ts +33 -0
  46. package/dist/index.js +880 -81
  47. package/dist/index.js.map +4 -4
  48. package/dist/installed-package-versions.d.ts +6 -0
  49. package/dist/landing-contract-gate.d.ts +24 -0
  50. package/dist/landing-gate.d.ts +24 -0
  51. package/dist/lease-renewal.d.ts +15 -0
  52. package/dist/model-routing-task-enrich.d.ts +8 -0
  53. package/dist/model-routing.d.ts +29 -0
  54. package/dist/monitor/index.d.ts +7 -0
  55. package/dist/monitor/monitor-cli.d.ts +9 -0
  56. package/dist/monitor/monitor-loop.d.ts +1 -0
  57. package/dist/monitor/monitor-spawn.d.ts +18 -0
  58. package/dist/monitor/monitor.classify.d.ts +15 -0
  59. package/dist/monitor/monitor.service.d.ts +17 -0
  60. package/dist/monitor/monitor.store.d.ts +6 -0
  61. package/dist/monitor/monitor.task-lease.d.ts +11 -0
  62. package/dist/monitor/monitor.terminal.d.ts +11 -0
  63. package/dist/monitor/monitor.types.d.ts +74 -0
  64. package/dist/package-version.d.ts +5 -0
  65. package/dist/path-values.d.ts +5 -0
  66. package/dist/paths.d.ts +7 -0
  67. package/dist/pipeline-dispatch.d.ts +7 -0
  68. package/dist/pipeline-tick.d.ts +45 -0
  69. package/dist/plan-persist/agentos-api.d.ts +28 -0
  70. package/dist/plan-persist/body-hash.d.ts +3 -0
  71. package/dist/plan-persist/drain.d.ts +7 -0
  72. package/dist/plan-persist/errors.d.ts +9 -0
  73. package/dist/plan-persist/handoff.d.ts +7 -0
  74. package/dist/plan-persist/idempotency.d.ts +2 -0
  75. package/dist/plan-persist/index.d.ts +8 -0
  76. package/dist/plan-persist/outbox-store.d.ts +18 -0
  77. package/dist/plan-persist/paths.d.ts +8 -0
  78. package/dist/plan-persist/persist.d.ts +10 -0
  79. package/dist/plan-persist/readback.d.ts +17 -0
  80. package/dist/plan-persist/types.d.ts +91 -0
  81. package/dist/plan-persist-cli.d.ts +3 -0
  82. package/dist/plan-progress-daemon-sync.d.ts +7 -0
  83. package/dist/plan-progress-sync.d.ts +21 -0
  84. package/dist/plan-progress.d.ts +10 -0
  85. package/dist/pr-handoff/index.d.ts +4 -0
  86. package/dist/pr-handoff/pr-handoff-assess.d.ts +33 -0
  87. package/dist/pr-handoff/pr-handoff-gh.d.ts +44 -0
  88. package/dist/pr-handoff/pr-handoff.d.ts +8 -0
  89. package/dist/pr-handoff/pr-handoff.types.d.ts +45 -0
  90. package/dist/prompt.d.ts +14 -0
  91. package/dist/providers/claude.d.ts +4 -0
  92. package/dist/providers/cursor-windows.d.ts +7 -0
  93. package/dist/providers/cursor.d.ts +11 -0
  94. package/dist/providers/model-preflight.d.ts +31 -0
  95. package/dist/providers/registry.d.ts +4 -0
  96. package/dist/providers/types.d.ts +32 -0
  97. package/dist/redact.d.ts +1 -0
  98. package/dist/resource-gate.d.ts +53 -0
  99. package/dist/retry-limits.d.ts +8 -0
  100. package/dist/run-store.d.ts +30 -0
  101. package/dist/shell-command-outcome.d.ts +32 -0
  102. package/dist/stale-reconcile.d.ts +25 -0
  103. package/dist/status.d.ts +166 -0
  104. package/dist/stream.d.ts +20 -0
  105. package/dist/supervisor.d.ts +29 -0
  106. package/dist/sweep.d.ts +1 -0
  107. package/dist/util.d.ts +22 -0
  108. package/dist/validate.d.ts +5 -0
  109. package/dist/vercel/index.d.ts +3 -0
  110. package/dist/vercel/vercel-evidence.d.ts +48 -0
  111. package/dist/vercel/vercel-github-status.d.ts +19 -0
  112. package/dist/vercel/vercel-url.d.ts +16 -0
  113. package/dist/worker-env.d.ts +15 -0
  114. package/dist/worker-lifecycle.d.ts +28 -0
  115. package/dist/worker-ops.d.ts +20 -0
  116. package/dist/workspace-runtime-config.d.ts +8 -0
  117. package/dist/worktree.d.ts +4 -0
  118. package/package.json +4 -2
package/dist/index.js CHANGED
@@ -508,12 +508,12 @@ var DEFAULT_CRITICAL_FREE_BYTES = 15 * 1024 * 1024 * 1024;
508
508
  var DEFAULT_MAX_USED_PERCENT = 80;
509
509
  var DEFAULT_HARD_MAX_USED_PERCENT = 90;
510
510
  function observeRunnerDiskGate(input = {}) {
511
- const path35 = input.diskPath?.trim() || "/";
511
+ const path38 = input.diskPath?.trim() || "/";
512
512
  const warnBelowBytes = input.diskFreeWarnBytes ?? DEFAULT_WARN_FREE_BYTES;
513
513
  const criticalBelowBytes = input.diskFreeCriticalBytes ?? DEFAULT_CRITICAL_FREE_BYTES;
514
514
  const maxUsedPercent = input.diskMaxUsedPercent ?? DEFAULT_MAX_USED_PERCENT;
515
515
  const hardMaxUsedPercent = input.diskHardMaxUsedPercent ?? DEFAULT_HARD_MAX_USED_PERCENT;
516
- const stats = statfsSync(path35);
516
+ const stats = statfsSync(path38);
517
517
  const freeBytes = Number(stats.bavail) * Number(stats.bsize);
518
518
  const totalBytes = Number(stats.blocks) * Number(stats.bsize);
519
519
  const usedPercent = totalBytes > 0 ? (totalBytes - freeBytes) / totalBytes * 100 : 100;
@@ -533,7 +533,7 @@ function observeRunnerDiskGate(input = {}) {
533
533
  }
534
534
  return {
535
535
  ok,
536
- path: path35,
536
+ path: path38,
537
537
  freeBytes,
538
538
  totalBytes,
539
539
  usedPercent,
@@ -546,8 +546,29 @@ function observeRunnerDiskGate(input = {}) {
546
546
  }
547
547
 
548
548
  // src/resource-gate.ts
549
- import { readFileSync as readFileSync6 } from "node:fs";
549
+ import os2 from "node:os";
550
+
551
+ // src/bounded-build/meminfo.ts
552
+ import { readFileSync as readFileSync4 } from "node:fs";
550
553
  import os from "node:os";
554
+ function readMemAvailableBytes(meminfoText) {
555
+ if (meminfoText !== void 0) {
556
+ const match = meminfoText.match(/^MemAvailable:\s+(\d+)\s*kB/m);
557
+ if (match) return Number(match[1]) * 1024;
558
+ return os.freemem();
559
+ }
560
+ if (process.platform === "linux") {
561
+ try {
562
+ const meminfo = readFileSync4("/proc/meminfo", "utf8");
563
+ const match = meminfo.match(/^MemAvailable:\s+(\d+)\s*kB/m);
564
+ if (match) return Number(match[1]) * 1024;
565
+ } catch {
566
+ }
567
+ }
568
+ return os.freemem();
569
+ }
570
+
571
+ // src/resource-gate.ts
551
572
  import path6 from "node:path";
552
573
 
553
574
  // src/run-store.ts
@@ -623,7 +644,7 @@ function runDirectory(id) {
623
644
  }
624
645
 
625
646
  // src/heartbeat.ts
626
- import { existsSync as existsSync6, readFileSync as readFileSync4 } from "node:fs";
647
+ import { existsSync as existsSync6, readFileSync as readFileSync5 } from "node:fs";
627
648
  var HEARTBEAT_FUTURE_SKEW_MS = 6e4;
628
649
  function isTerminalHeartbeatPhase(phase) {
629
650
  return phase === "complete";
@@ -645,7 +666,7 @@ function parseHeartbeat(file) {
645
666
  if (!existsSync6(file)) return result;
646
667
  const maxFutureMs = Date.now() + HEARTBEAT_FUTURE_SKEW_MS;
647
668
  const clampedTo = new Date(maxFutureMs).toISOString();
648
- const lines = readFileSync4(file, "utf8").split("\n").filter(Boolean);
669
+ const lines = readFileSync5(file, "utf8").split("\n").filter(Boolean);
649
670
  for (const line of lines) {
650
671
  const entry = safeJson(line);
651
672
  if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue;
@@ -672,7 +693,155 @@ function parseHeartbeat(file) {
672
693
  }
673
694
 
674
695
  // src/stream.ts
675
- import { existsSync as existsSync7, readFileSync as readFileSync5 } from "node:fs";
696
+ import { existsSync as existsSync7, readFileSync as readFileSync6 } from "node:fs";
697
+
698
+ // src/shell-command-outcome.ts
699
+ var NPM_AUDIT_RE = /\bnpm\s+audit\b/i;
700
+ function tidy(text, max = 200) {
701
+ const one = text.replace(/\s+/g, " ").trim();
702
+ return one.length > max ? `${one.slice(0, max - 1)}\u2026` : one;
703
+ }
704
+ function extractJsonObject(text) {
705
+ const trimmed = text.trim();
706
+ if (!trimmed) return null;
707
+ if (trimmed.startsWith("{")) {
708
+ try {
709
+ return JSON.parse(trimmed);
710
+ } catch {
711
+ }
712
+ }
713
+ const start = trimmed.indexOf("{");
714
+ const end = trimmed.lastIndexOf("}");
715
+ if (start >= 0 && end > start) {
716
+ try {
717
+ return JSON.parse(trimmed.slice(start, end + 1));
718
+ } catch {
719
+ return null;
720
+ }
721
+ }
722
+ return null;
723
+ }
724
+ function isRecord(value) {
725
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
726
+ }
727
+ function summarizeNpmAuditReport(report) {
728
+ const meta = report.metadata;
729
+ if (!isRecord(meta)) return null;
730
+ const vuln = meta.vulnerabilities;
731
+ if (!isRecord(vuln)) return null;
732
+ const num = (key) => typeof vuln[key] === "number" ? vuln[key] : 0;
733
+ const summary = {
734
+ info: num("info"),
735
+ low: num("low"),
736
+ moderate: num("moderate"),
737
+ high: num("high"),
738
+ critical: num("critical"),
739
+ total: num("total")
740
+ };
741
+ if (typeof vuln.total !== "number" && !summary.critical && !summary.high && !summary.moderate && !summary.low && !summary.info) {
742
+ return null;
743
+ }
744
+ return summary;
745
+ }
746
+ function formatAuditSummaryLine(audit) {
747
+ const parts = [];
748
+ if (audit.critical) parts.push(`${audit.critical} critical`);
749
+ if (audit.high) parts.push(`${audit.high} high`);
750
+ if (audit.moderate) parts.push(`${audit.moderate} moderate`);
751
+ if (audit.low) parts.push(`${audit.low} low`);
752
+ if (audit.info) parts.push(`${audit.info} info`);
753
+ const breakdown = parts.length ? parts.join(", ") : "see report";
754
+ return `npm audit: ${audit.total} vulnerabilit${audit.total === 1 ? "y" : "ies"} (${breakdown}) \u2014 remediation required`;
755
+ }
756
+ function npmAuditFailureReason(report, stderr) {
757
+ const err = report.error;
758
+ if (isRecord(err)) {
759
+ const summary = typeof err.summary === "string" ? err.summary.trim() : "";
760
+ const code = typeof err.code === "string" ? err.code.trim() : "";
761
+ if (summary) return code ? `${code}: ${summary}` : summary;
762
+ if (code) return code;
763
+ }
764
+ const detail = typeof report.message === "string" ? report.message.trim() : "";
765
+ if (detail) return detail;
766
+ const errTail = stderr.trim();
767
+ if (errTail) return tidy(errTail.split("\n").find(Boolean) ?? errTail, 160);
768
+ return "npm audit failed";
769
+ }
770
+ function classifyNpmAuditOutcome(input) {
771
+ const combined = `${input.stdout}
772
+ ${input.stderr}`.trim();
773
+ const parsed = extractJsonObject(combined);
774
+ if (!parsed || !isRecord(parsed)) {
775
+ const tail = tidy(combined || `exit ${input.exitCode}`, 180);
776
+ return {
777
+ kind: "command_failure",
778
+ exitCode: input.exitCode,
779
+ summary: `npm audit failed (invalid or missing JSON): ${tail}`,
780
+ parseError: "invalid_json"
781
+ };
782
+ }
783
+ if (isRecord(parsed.error)) {
784
+ return {
785
+ kind: "command_failure",
786
+ exitCode: input.exitCode,
787
+ summary: `npm audit command failed: ${npmAuditFailureReason(parsed, input.stderr)}`
788
+ };
789
+ }
790
+ const audit = summarizeNpmAuditReport(parsed);
791
+ if (!audit) {
792
+ return {
793
+ kind: "command_failure",
794
+ exitCode: input.exitCode,
795
+ summary: "npm audit failed: JSON response missing vulnerability metadata",
796
+ parseError: "missing_metadata"
797
+ };
798
+ }
799
+ if (input.exitCode === 0 && audit.total === 0) {
800
+ return {
801
+ kind: "success",
802
+ exitCode: 0,
803
+ summary: "npm audit: no vulnerabilities reported",
804
+ audit
805
+ };
806
+ }
807
+ return {
808
+ kind: "audit_findings",
809
+ exitCode: input.exitCode,
810
+ summary: formatAuditSummaryLine(audit),
811
+ audit
812
+ };
813
+ }
814
+ function isNpmAuditCommand(command) {
815
+ return NPM_AUDIT_RE.test(command);
816
+ }
817
+ function classifyShellCommandOutcome(input) {
818
+ const stdout = input.stdout ?? "";
819
+ const stderr = input.stderr ?? "";
820
+ const interleaved = input.interleavedOutput ?? "";
821
+ if (isNpmAuditCommand(input.command)) {
822
+ const body = stdout.trim() || interleaved.trim() || stderr.trim();
823
+ return classifyNpmAuditOutcome({
824
+ exitCode: input.exitCode,
825
+ stdout: body,
826
+ stderr
827
+ });
828
+ }
829
+ if (input.exitCode === 0) {
830
+ return {
831
+ kind: "success",
832
+ exitCode: 0,
833
+ summary: `command succeeded (exit 0)`
834
+ };
835
+ }
836
+ const tail = tidy(interleaved || stdout || stderr || `exit ${input.exitCode}`, 180);
837
+ return {
838
+ kind: "command_failure",
839
+ exitCode: input.exitCode,
840
+ summary: `command failed (exit ${input.exitCode}): ${tail}`
841
+ };
842
+ }
843
+
844
+ // src/stream.ts
676
845
  function eventTimestampIso(event) {
677
846
  const tsMs = event.timestamp_ms;
678
847
  return event.timestamp || event.ts || (tsMs ? new Date(tsMs).toISOString() : void 0);
@@ -693,16 +862,43 @@ function recordStreamResult(result, event) {
693
862
  result.error = String(event.result || event.api_error_status || "stream result error");
694
863
  }
695
864
  }
865
+ function shellPayloadFromCursorEvent(event) {
866
+ if (event.type !== "tool_call" || event.subtype !== "completed") return null;
867
+ const toolCall = event.tool_call && typeof event.tool_call === "object" && !Array.isArray(event.tool_call) ? event.tool_call : null;
868
+ const shell = toolCall?.shellToolCall;
869
+ if (!shell || typeof shell !== "object" || Array.isArray(shell)) return null;
870
+ const shellObj = shell;
871
+ const args = shellObj.args;
872
+ const command = args && typeof args === "object" && !Array.isArray(args) && typeof args.command === "string" ? String(args.command) : "";
873
+ const result = shellObj.result;
874
+ if (!result || typeof result !== "object" || Array.isArray(result)) return null;
875
+ const body = result.success ?? result.failure;
876
+ if (!body || typeof body !== "object" || Array.isArray(body)) return null;
877
+ const row = body;
878
+ const exitCode = typeof row.exitCode === "number" ? row.exitCode : 0;
879
+ return {
880
+ command,
881
+ exitCode,
882
+ stdout: typeof row.stdout === "string" ? row.stdout : "",
883
+ stderr: typeof row.stderr === "string" ? row.stderr : "",
884
+ interleaved: typeof row.interleavedOutput === "string" ? row.interleavedOutput : ""
885
+ };
886
+ }
887
+ function applyShellOutcome(parsed, outcome) {
888
+ if (outcome.kind === "success") return;
889
+ parsed.lastShellOutcome = outcome;
890
+ }
696
891
  function parseHarnessStream(file) {
697
892
  const result = {
698
893
  firstEventAt: null,
699
894
  lastEventAt: null,
700
895
  currentTool: null,
701
896
  finalResult: null,
702
- error: null
897
+ error: null,
898
+ lastShellOutcome: null
703
899
  };
704
900
  if (!existsSync7(file)) return result;
705
- const lines = readFileSync5(file, "utf8").split("\n").filter(Boolean);
901
+ const lines = readFileSync6(file, "utf8").split("\n").filter(Boolean);
706
902
  for (const line of lines) {
707
903
  const event = safeJson(line);
708
904
  if (!event) continue;
@@ -727,6 +923,19 @@ function parseHarnessStream(file) {
727
923
  const name = cursorToolNameFromCall(toolCall);
728
924
  if (name) result.currentTool = name;
729
925
  }
926
+ const shell = shellPayloadFromCursorEvent(event);
927
+ if (shell) {
928
+ applyShellOutcome(
929
+ result,
930
+ classifyShellCommandOutcome({
931
+ command: shell.command,
932
+ exitCode: shell.exitCode,
933
+ stdout: shell.stdout,
934
+ stderr: shell.stderr,
935
+ interleavedOutput: shell.interleaved
936
+ })
937
+ );
938
+ }
730
939
  if (event.type === "result") {
731
940
  recordStreamResult(result, event);
732
941
  }
@@ -736,6 +945,25 @@ function parseHarnessStream(file) {
736
945
  function parseClaudeStream(file) {
737
946
  return parseHarnessStream(file);
738
947
  }
948
+ function summarizeShellToolCallEvent(event) {
949
+ const shell = shellPayloadFromCursorEvent(event);
950
+ if (!shell) return void 0;
951
+ const outcome = classifyShellCommandOutcome({
952
+ command: shell.command,
953
+ exitCode: shell.exitCode,
954
+ stdout: shell.stdout,
955
+ stderr: shell.stderr,
956
+ interleavedOutput: shell.interleaved
957
+ });
958
+ const cmd = oneLine(shell.command).slice(0, 120);
959
+ if (outcome.kind === "audit_findings") {
960
+ return `[audit:findings] ${outcome.summary}${cmd ? ` \xB7 ${cmd}` : ""}`;
961
+ }
962
+ if (outcome.kind === "command_failure") {
963
+ return `[command:failed] ${outcome.summary}${cmd ? ` \xB7 ${cmd}` : ""}`;
964
+ }
965
+ return `[command:ok] exit 0${cmd ? ` \xB7 ${cmd}` : ""}`;
966
+ }
739
967
  function summarizeEvent(event) {
740
968
  if (event.type === "system" && event.subtype) {
741
969
  return `[system:${event.subtype}] ${String(event.status || event.cwd || "")}`.trim();
@@ -768,6 +996,8 @@ function summarizeEvent(event) {
768
996
  }
769
997
  if (event.type === "tool_call") {
770
998
  const subtype = String(event.subtype || "");
999
+ const shellSummary = subtype === "completed" ? summarizeShellToolCallEvent(event) : void 0;
1000
+ if (shellSummary) return shellSummary;
771
1001
  const toolCall = event.tool_call && typeof event.tool_call === "object" && !Array.isArray(event.tool_call) ? event.tool_call : void 0;
772
1002
  const name = cursorToolNameFromCall(toolCall) ?? "tool";
773
1003
  return `[tool:${subtype}] ${name}`;
@@ -809,7 +1039,7 @@ var FAILURE_PATTERNS = [
809
1039
  label: "provider authentication failed"
810
1040
  }
811
1041
  ];
812
- function tidy(errorText, max = 240) {
1042
+ function tidy2(errorText, max = 240) {
813
1043
  const oneLine2 = errorText.replace(/\s+/g, " ").trim();
814
1044
  return oneLine2.length > max ? `${oneLine2.slice(0, max - 1)}\u2026` : oneLine2;
815
1045
  }
@@ -818,7 +1048,7 @@ function classifyExitFailure(errorText) {
818
1048
  if (!text) return null;
819
1049
  for (const pattern of FAILURE_PATTERNS) {
820
1050
  if (pattern.test.test(text)) {
821
- return { blocked: true, reason: `${pattern.label}: ${tidy(text)}` };
1051
+ return { blocked: true, reason: `${pattern.label}: ${tidy2(text)}` };
822
1052
  }
823
1053
  }
824
1054
  return null;
@@ -884,6 +1114,63 @@ function assessExitedWorkerSalvage(input) {
884
1114
 
885
1115
  // src/git.ts
886
1116
  import { spawnSync } from "node:child_process";
1117
+
1118
+ // src/worker-env.ts
1119
+ var FORBIDDEN_WORKER_ENV_KEYS = [
1120
+ "ANTHROPIC_API_KEY",
1121
+ "ANALYST_API_KEY",
1122
+ "RECRUITER_API_KEY",
1123
+ "AUTH_SECRET",
1124
+ "NEXTAUTH_SECRET",
1125
+ "DATABASE_URL",
1126
+ "PRODUCTION_DATABASE_URL",
1127
+ "REDIS_URL",
1128
+ "GOOGLE_CLIENT_SECRET",
1129
+ "GITHUB_CLIENT_SECRET",
1130
+ "KYNVER_API_KEY",
1131
+ "KYNVER_SERVICE_SECRET",
1132
+ "KYNVER_RUNTIME_SECRET",
1133
+ "OPENCLAW_CRON_SECRET",
1134
+ "QSTASH_TOKEN",
1135
+ "QSTASH_CURRENT_SIGNING_KEY",
1136
+ "QSTASH_NEXT_SIGNING_KEY",
1137
+ "TOOL_SECRETS_KEK",
1138
+ "TOOL_EXECUTOR_DISPATCH_SECRET",
1139
+ "CLOUDFLARE_API_TOKEN",
1140
+ "STRIPE_SECRET_KEY",
1141
+ "STRIPE_WEBHOOK_SECRET",
1142
+ "STRIPE_IDENTITY_WEBHOOK_SECRET",
1143
+ "VOYAGE_API_KEY",
1144
+ "PERPLEXITY_API_KEY",
1145
+ "FRED_API_KEY",
1146
+ "FMP_API_KEY",
1147
+ "CURSOR_API_KEY"
1148
+ ];
1149
+ var FORBIDDEN_KEY_SET = new Set(FORBIDDEN_WORKER_ENV_KEYS);
1150
+ var FORBIDDEN_SUFFIXES = ["_SECRET", "_API_KEY"];
1151
+ function isForbiddenWorkerEnvKey(key) {
1152
+ if (FORBIDDEN_KEY_SET.has(key)) return true;
1153
+ return FORBIDDEN_SUFFIXES.some((suffix) => key.endsWith(suffix));
1154
+ }
1155
+ function listForbiddenWorkerEnvKeys(env) {
1156
+ return Object.keys(env).filter(isForbiddenWorkerEnvKey).sort();
1157
+ }
1158
+ function scrubWorkerEnv(env) {
1159
+ const next = { ...env };
1160
+ for (const key of Object.keys(next)) {
1161
+ if (isForbiddenWorkerEnvKey(key)) delete next[key];
1162
+ }
1163
+ return next;
1164
+ }
1165
+ function auditWorkerEnv(env) {
1166
+ const forbiddenPresent = listForbiddenWorkerEnvKeys(env);
1167
+ return { forbiddenPresent, safe: forbiddenPresent.length === 0 };
1168
+ }
1169
+ function scrubClaudeEnv(env) {
1170
+ return scrubWorkerEnv(env);
1171
+ }
1172
+
1173
+ // src/git.ts
887
1174
  function git(cwd, args, options = {}) {
888
1175
  const res = spawnSync("git", args, { cwd, encoding: "utf8" });
889
1176
  if (res.status !== 0 && !options.allowFailure) {
@@ -999,11 +1286,6 @@ function unknownAncestry(base, error, head = null) {
999
1286
  error
1000
1287
  };
1001
1288
  }
1002
- function scrubClaudeEnv(env) {
1003
- const next = { ...env };
1004
- delete next.ANTHROPIC_API_KEY;
1005
- return next;
1006
- }
1007
1289
 
1008
1290
  // src/landing-gate.ts
1009
1291
  function trimOrNull2(value) {
@@ -1353,15 +1635,7 @@ function computeAutoMaxWorkers(totalMemBytes, opts = {}) {
1353
1635
  return Math.min(raw, AUTO_MAX_WORKERS_CEILING);
1354
1636
  }
1355
1637
  function readAvailableMemBytes() {
1356
- if (process.platform === "linux") {
1357
- try {
1358
- const meminfo = readFileSync6("/proc/meminfo", "utf8");
1359
- const match = meminfo.match(/^MemAvailable:\s+(\d+)\s*kB/m);
1360
- if (match) return Number(match[1]) * 1024;
1361
- } catch {
1362
- }
1363
- }
1364
- return os.freemem();
1638
+ return readMemAvailableBytes();
1365
1639
  }
1366
1640
  function isActiveHarnessWorker(worker) {
1367
1641
  const status = computeWorkerStatus(worker);
@@ -1389,7 +1663,7 @@ function observeRunnerResourceGate(input) {
1389
1663
  input.config,
1390
1664
  input.configuredMaxWorkersOverride
1391
1665
  );
1392
- const totalMemBytes = input.totalMemBytes ?? os.totalmem();
1666
+ const totalMemBytes = input.totalMemBytes ?? os2.totalmem();
1393
1667
  const freeMemBytes = input.freeMemBytes ?? readAvailableMemBytes();
1394
1668
  const activeWorkers = input.activeWorkers ?? countActiveWorkersGlobal();
1395
1669
  const budgetBytes = Math.max(0, Math.floor(totalMemBytes * memUtilization) - memReserveBytes);
@@ -1598,7 +1872,7 @@ var claudeProvider = {
1598
1872
  cwd: opts.worktreePath,
1599
1873
  detached: true,
1600
1874
  stdio,
1601
- env: scrubClaudeEnv(process.env)
1875
+ env: scrubWorkerEnv(process.env)
1602
1876
  })
1603
1877
  );
1604
1878
  closeSync(stdoutFd);
@@ -1875,6 +2149,7 @@ function buildPrompt(input) {
1875
2149
  "Structured final result (recommended): record completion as JSON with summary, laneExpertise { whatChanged, why, files, prUrls, verification, risks, blockers, lessonsLearned, laneGuidance }, and targetPrReconciliation [{ prUrl, outcome: merged|skipped|blocked, mergeCommit?, reason? }] for every target PR on landing-only tasks.",
1876
2150
  "Completion handoff (required): before you stop, ensure the harness records a final result \u2014 summarize outcome in your last message and append a heartbeat line with phase `complete`. If you leave uncommitted changes or committed work without a PR, the orchestrator blocks completion until a GitHub PR exists (or you discard/commit cleanly). Exiting with only dirty files and no PR routes to salvage review, not production review.",
1877
2151
  "PR-ready handoff: for substantial implementation work, commit, push, and open a GitHub PR (draft OK) on your branch before finishing \u2014 or rely on the harness to run `gh pr create` at completion when `gh` is authenticated.",
2152
+ "Expert review / production-review workers (Dalton/Lorentz, plan-review-task, scheduledJob reviewer children): do NOT open new implementation PRs \u2014 review the parent task's existing PR and record reviewVerdict in finalResult; landing-contract targetPrReconciliation does not apply.",
1878
2153
  "Worker resource guard: do not run full monorepo verification (`npm run typecheck`, `npm run build`, or equivalent) from this worker lane unless an operator explicitly requests it. Use targeted checks for touched paths and rely on CI/operator lanes for heavy gates.",
1879
2154
  "npm publish boundary: do not run `npm publish`, do not republish `@kynver-app/*` packages, and do not block on an operator to publish. When you need newer runtime code than npm, use this repo checkout (`npm run kynver:build`, `npm run kynver`) and record evidence: packages/kynver-runtime/package.json version + git ref in your completion report.",
1880
2155
  "If verification fails (including OOM), append a heartbeat line immediately with the last command, failure reason, dirty-file status, commit/PR handoff state, and next action so recovery does not require log spelunking.",
@@ -1985,12 +2260,12 @@ function resolveAgentBin() {
1985
2260
  return "agent";
1986
2261
  }
1987
2262
  function cursorWorkerEnv(agentBin, spawnTarget) {
1988
- return {
2263
+ return scrubWorkerEnv({
1989
2264
  ...process.env,
1990
2265
  CI: "1",
1991
2266
  NO_COLOR: "1",
1992
2267
  ...spawnTarget.bundledVersionDir ? { CURSOR_INVOKED_AS: path9.basename(agentBin) || "agent.cmd" } : {}
1993
- };
2268
+ });
1994
2269
  }
1995
2270
  var cursorProvider = {
1996
2271
  name: "cursor",
@@ -2083,6 +2358,65 @@ function persistCompletionAck(worker, runId, fields) {
2083
2358
  // src/worker-ops.ts
2084
2359
  import path11 from "node:path";
2085
2360
 
2361
+ // src/completion-response.ts
2362
+ function asRecord(value) {
2363
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
2364
+ }
2365
+ function asString(value) {
2366
+ if (typeof value !== "string") return null;
2367
+ const trimmed = value.trim();
2368
+ return trimmed.length ? trimmed : null;
2369
+ }
2370
+ var ADVANCED_OUTCOMES = /* @__PURE__ */ new Set([
2371
+ "review_scheduled",
2372
+ "review_already_scheduled"
2373
+ ]);
2374
+ function summarizeHarnessCompletionResponse(parsed) {
2375
+ const record = asRecord(parsed);
2376
+ if (!record) {
2377
+ return { routeOutcome: null, taskAdvanced: false, detail: null };
2378
+ }
2379
+ const outcome = asString(record.outcome);
2380
+ const detail = asString(record.detail) ?? asString(record.error);
2381
+ const task = asRecord(record.task);
2382
+ const taskStatus = task ? asString(task.status) : null;
2383
+ const taskAdvanced = outcome !== null && ADVANCED_OUTCOMES.has(outcome) || taskStatus === "awaiting_review" || taskStatus === "done";
2384
+ return {
2385
+ routeOutcome: outcome,
2386
+ taskAdvanced,
2387
+ detail
2388
+ };
2389
+ }
2390
+ function completionPostSucceeded(summary) {
2391
+ return summary.taskAdvanced;
2392
+ }
2393
+
2394
+ // src/harness-expert-review.ts
2395
+ var EXPERT_LANE_REVIEW_REF = "expert-lane-pr-review:";
2396
+ var PLAN_REVIEW_EXECUTOR_REF = "plan-review-task";
2397
+ var SCHEDULED_JOB_EXECUTOR_REF = "scheduledjob:";
2398
+ function normalizePersonaSlug(value) {
2399
+ if (!value) return null;
2400
+ const t = value.trim().toLowerCase();
2401
+ return t.length ? t : null;
2402
+ }
2403
+ function isHarnessExpertReviewWorker(worker) {
2404
+ const ref = (worker.executorRef ?? "").toLowerCase();
2405
+ if (ref.startsWith(EXPERT_LANE_REVIEW_REF)) return true;
2406
+ if (ref === PLAN_REVIEW_EXECUTOR_REF || ref.startsWith("daemon-review:")) return true;
2407
+ if (ref.startsWith(SCHEDULED_JOB_EXECUTOR_REF) && worker.parentTaskId) {
2408
+ const persona = normalizePersonaSlug(worker.personaSlug);
2409
+ if (persona === "lorentz" || persona === "dalton") return true;
2410
+ }
2411
+ const title = (worker.title ?? "").toLowerCase();
2412
+ if (title.includes("expert pr review")) return true;
2413
+ if (worker.parentTaskId && (title.startsWith("review:") || title.includes("review required") || title.includes("runtime review"))) {
2414
+ const persona = normalizePersonaSlug(worker.personaSlug);
2415
+ if (persona === "lorentz" || persona === "dalton") return true;
2416
+ }
2417
+ return false;
2418
+ }
2419
+
2086
2420
  // src/pr-handoff/pr-handoff-assess.ts
2087
2421
  var REVIEW_LANE_RULE = /^(lane:)?(review|deep_review|planning|landing)(:|$)/i;
2088
2422
  function trimOrNull4(value) {
@@ -2113,6 +2447,14 @@ function assessPrHandoffRequirement(input) {
2113
2447
  if (!input.dispatched) {
2114
2448
  return { required: false, reason: "not_dispatched" };
2115
2449
  }
2450
+ if (isHarnessExpertReviewWorker({
2451
+ title: input.taskTitle ?? void 0,
2452
+ personaSlug: input.personaSlug,
2453
+ parentTaskId: input.parentTaskId,
2454
+ executorRef: input.executorRef
2455
+ })) {
2456
+ return { required: false, reason: "expert_review_task" };
2457
+ }
2116
2458
  const rule = trimOrNull4(input.routingRule) ?? "";
2117
2459
  if (rule && REVIEW_LANE_RULE.test(rule)) {
2118
2460
  return { required: false, reason: "review_lane" };
@@ -2120,7 +2462,7 @@ function assessPrHandoffRequirement(input) {
2120
2462
  if (trimOrNull4(input.patchPath) || trimOrNull4(input.artifactBundlePath)) {
2121
2463
  return { required: false, reason: "patch_or_bundle" };
2122
2464
  }
2123
- const prUrl = trimOrNull4(input.prUrl) ?? trimOrNull4(input.snapshot.prUrl);
2465
+ const prUrl = trimOrNull4(input.prUrl) ?? trimOrNull4(input.taskPrUrl) ?? trimOrNull4(input.snapshot.prUrl);
2124
2466
  if (prUrl) {
2125
2467
  return { required: false, reason: "already_has_pr" };
2126
2468
  }
@@ -2143,6 +2485,36 @@ function buildPrHandoffSnapshotFromStatus(status, extras) {
2143
2485
 
2144
2486
  // src/pr-handoff/pr-handoff-gh.ts
2145
2487
  import { spawnSync as spawnSync2 } from "node:child_process";
2488
+
2489
+ // src/github-repo.ts
2490
+ function parseGithubOwnerRepo(remoteUrl) {
2491
+ const trimmed = remoteUrl.trim();
2492
+ if (!trimmed) return null;
2493
+ const ssh = trimmed.match(/^git@github\.com:([^/]+\/[^/\s]+?)(?:\.git)?$/i);
2494
+ if (ssh) return normalizeOwnerRepo(ssh[1]);
2495
+ const scp = trimmed.match(/^ssh:\/\/git@github\.com\/([^/]+\/[^/\s]+?)(?:\.git)?$/i);
2496
+ if (scp) return normalizeOwnerRepo(scp[1]);
2497
+ try {
2498
+ const url = new URL(trimmed.includes("://") ? trimmed : `https://${trimmed}`);
2499
+ if (url.hostname.toLowerCase() !== "github.com") return null;
2500
+ const parts = url.pathname.replace(/^\/+|\/+$/g, "").split("/");
2501
+ if (parts.length < 2) return null;
2502
+ const [owner, repo] = parts;
2503
+ if (!owner || !repo) return null;
2504
+ return `${owner}/${repo.replace(/\.git$/i, "")}`;
2505
+ } catch {
2506
+ return null;
2507
+ }
2508
+ }
2509
+ function normalizeOwnerRepo(value) {
2510
+ const parts = value.split("/").filter(Boolean);
2511
+ if (parts.length < 2) return null;
2512
+ const owner = parts[0];
2513
+ const repo = parts[1].replace(/\.git$/i, "");
2514
+ return owner && repo ? `${owner}/${repo}` : null;
2515
+ }
2516
+
2517
+ // src/pr-handoff/pr-handoff-gh.ts
2146
2518
  function capture(bin, cwd, args) {
2147
2519
  try {
2148
2520
  const res = spawnSync2(bin, args, { cwd, encoding: "utf8" });
@@ -2165,21 +2537,13 @@ var defaultPrHandoffExec = {
2165
2537
  git: (cwd, args) => gitCapture(cwd, args),
2166
2538
  gh: (cwd, args) => capture("gh", cwd, args)
2167
2539
  };
2168
- function parseGithubRepo(remoteUrl) {
2169
- const trimmed = remoteUrl.trim();
2170
- const ssh = trimmed.match(/git@github\.com:([^/]+\/[^/.]+)(?:\.git)?/i);
2171
- if (ssh) return ssh[1];
2172
- const https = trimmed.match(/github\.com[/:]([^/]+\/[^/.]+?)(?:\.git)?/i);
2173
- if (https) return https[1];
2174
- return null;
2175
- }
2176
2540
  function firstLine(text) {
2177
2541
  return text.split("\n").map((l) => l.trim()).find(Boolean) ?? "";
2178
2542
  }
2179
2543
  function resolveGithubRepo(worktreePath, exec) {
2180
2544
  const remote = exec.git(worktreePath, ["remote", "get-url", "origin"]);
2181
2545
  if (remote.status !== 0) return null;
2182
- return parseGithubRepo(remote.stdout);
2546
+ return parseGithubOwnerRepo(remote.stdout);
2183
2547
  }
2184
2548
  function resolveHeadCommit(worktreePath, exec) {
2185
2549
  const head = exec.git(worktreePath, ["rev-parse", "HEAD"]);
@@ -2315,6 +2679,11 @@ function ensurePrReadyHandoff(input, exec = defaultPrHandoffExec) {
2315
2679
  dispatched: input.worker.dispatched,
2316
2680
  routingRule: input.worker.routingRule,
2317
2681
  prUrl: prUrlHint,
2682
+ taskTitle: input.worker.taskTitle,
2683
+ executorRef: input.worker.executorRef,
2684
+ parentTaskId: input.worker.parentTaskId,
2685
+ personaSlug: input.worker.personaSlug,
2686
+ taskPrUrl: input.worker.taskPrUrl,
2318
2687
  snapshot
2319
2688
  });
2320
2689
  if (!requirement.required) {
@@ -2513,10 +2882,10 @@ function completionErrorText(parsed) {
2513
2882
  }
2514
2883
  return void 0;
2515
2884
  }
2516
- function asRecord(value) {
2885
+ function asRecord2(value) {
2517
2886
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
2518
2887
  }
2519
- function asString(value) {
2888
+ function asString2(value) {
2520
2889
  if (typeof value !== "string") return null;
2521
2890
  const trimmed = value.trim();
2522
2891
  return trimmed.length ? trimmed : null;
@@ -2636,7 +3005,27 @@ async function tryCompleteWorker(args) {
2636
3005
  }
2637
3006
  }
2638
3007
  if (result.ok) {
3008
+ const summary = summarizeHarnessCompletionResponse(result.parsed);
3009
+ if (!completionPostSucceeded(summary)) {
3010
+ const detail2 = summary.detail ?? (summary.routeOutcome ? `harness completion returned ${summary.routeOutcome}` : "harness completion did not advance the linked task");
3011
+ const reason2 = `completion acknowledged but board not advanced: ${detail2}`;
3012
+ persistCompletionBlocker(worker, reason2);
3013
+ const ack2 = {
3014
+ completionReportedAt: (/* @__PURE__ */ new Date()).toISOString(),
3015
+ completionOutcome: "rejected",
3016
+ completionResponse: result.parsed
3017
+ };
3018
+ persistCompletionAck(worker, worker.runId, ack2);
3019
+ return {
3020
+ ok: false,
3021
+ httpStatus: result.status,
3022
+ response: result.parsed,
3023
+ reason: reason2,
3024
+ completionBlocked: true
3025
+ };
3026
+ }
2639
3027
  persistCompletionBlocker(worker, void 0);
3028
+ const routeOutcome = summary.routeOutcome ?? "acknowledged";
2640
3029
  const ack = {
2641
3030
  completionReportedAt: (/* @__PURE__ */ new Date()).toISOString(),
2642
3031
  completionOutcome: "acknowledged",
@@ -2649,6 +3038,7 @@ async function tryCompleteWorker(args) {
2649
3038
  ok: true,
2650
3039
  httpStatus: result.status,
2651
3040
  response: result.parsed,
3041
+ reason: routeOutcome,
2652
3042
  ...prUrl ? { prHandoff: { prUrl } } : {}
2653
3043
  };
2654
3044
  }
@@ -2741,13 +3131,13 @@ function buildRunBoard(runId) {
2741
3131
  const completionBlocker = typeof rawBlocker === "string" && rawBlocker ? rawBlocker : void 0;
2742
3132
  const boardStatus = completionBlocker ? "blocked" : status.status;
2743
3133
  const boardAttention = completionBlocker ? "blocked" : status.attention.state;
2744
- const completionResponse = asRecord(worker.completionResponse);
2745
- const completionTask = asRecord(completionResponse?.task);
2746
- const completionOutcome = asString(completionResponse?.outcome);
2747
- const completionRouteStatus = asString(completionResponse?.status);
3134
+ const completionResponse = asRecord2(worker.completionResponse);
3135
+ const completionTask = asRecord2(completionResponse?.task);
3136
+ const completionOutcome = asString2(completionResponse?.outcome);
3137
+ const completionRouteStatus = asString2(completionResponse?.status);
2748
3138
  const completionWarnings = Array.isArray(completionResponse?.warnings) ? completionResponse.warnings.filter((w) => typeof w === "string" && w.trim().length > 0) : [];
2749
- const prUrl = asString(completionTask?.prUrl) ?? asString(completionResponse?.prUrl);
2750
- const completionReportedAt = asString(worker.completionReportedAt);
3139
+ const prUrl = asString2(completionTask?.prUrl) ?? asString2(completionResponse?.prUrl);
3140
+ const completionReportedAt = asString2(worker.completionReportedAt);
2751
3141
  const lifecycleStage = deriveLifecycleStage({
2752
3142
  finished: isFinishedWorkerStatus(status),
2753
3143
  completionBlocker,
@@ -3173,6 +3563,10 @@ function spawnWorkerProcess(run, opts) {
3173
3563
  ...!opts.agentOsId || !opts.taskId ? { localOnly: true } : {},
3174
3564
  routingRule: routing.rule,
3175
3565
  ...routing.requestedModel ? { requestedModel: routing.requestedModel } : {},
3566
+ ...opts.executorRef ? { executorRef: String(opts.executorRef) } : {},
3567
+ ...opts.parentTaskId ? { parentTaskId: String(opts.parentTaskId) } : {},
3568
+ ...opts.taskTitle ? { taskTitle: String(opts.taskTitle) } : {},
3569
+ ...opts.taskPrUrl ? { taskPrUrl: String(opts.taskPrUrl) } : {},
3176
3570
  startedAt: (/* @__PURE__ */ new Date()).toISOString()
3177
3571
  };
3178
3572
  saveWorker(run.id, worker);
@@ -3867,7 +4261,7 @@ function readHarnessWorkerContext(decision) {
3867
4261
  personaInjectionReady
3868
4262
  };
3869
4263
  }
3870
- function normalizePersonaSlug(value) {
4264
+ function normalizePersonaSlug2(value) {
3871
4265
  if (typeof value !== "string") return null;
3872
4266
  const trimmed = value.trim().toLowerCase();
3873
4267
  return trimmed.length ? trimmed : null;
@@ -3938,7 +4332,8 @@ async function dispatchRun(args) {
3938
4332
  harnessBoardSnapshot: buildRunBoard(run.id),
3939
4333
  ...args.lane ? { lane: String(args.lane) } : {},
3940
4334
  executor: args.executor ? String(args.executor) : "harness",
3941
- ...args.diskPath ? { diskPath: String(args.diskPath) } : {}
4335
+ ...args.diskPath ? { diskPath: String(args.diskPath) } : {},
4336
+ ...args.targetTaskId ? { targetTaskId: String(args.targetTaskId) } : {}
3942
4337
  };
3943
4338
  const dispatch = await postJsonWithCredentialRefresh(dispatchUrl, secret, body, { agentOsId, baseUrl: base });
3944
4339
  const responseBody = dispatch.response;
@@ -3997,7 +4392,7 @@ async function dispatchRun(args) {
3997
4392
  const task = decision.task;
3998
4393
  const harnessContext = readHarnessWorkerContext(decision);
3999
4394
  const taskId = String(task.id);
4000
- const expectedPersona = normalizePersonaSlug(task.personaSlug);
4395
+ const expectedPersona = normalizePersonaSlug2(task.personaSlug);
4001
4396
  if (expectedPersona && (!harnessContext?.personaInjectionReady || !harnessContext.personaMarkdown)) {
4002
4397
  outcomes.push({
4003
4398
  taskId,
@@ -4041,6 +4436,10 @@ async function dispatchRun(args) {
4041
4436
  agentOsId,
4042
4437
  taskId: String(task.id),
4043
4438
  planId,
4439
+ executorRef: task.executorRef ? String(task.executorRef) : void 0,
4440
+ parentTaskId: task.parentTaskId ? String(task.parentTaskId) : void 0,
4441
+ taskTitle: task.title ? String(task.title) : void 0,
4442
+ taskPrUrl: task.prUrl ? String(task.prUrl) : void 0,
4044
4443
  instructionPolicyMarkdown: harnessContext?.instructionPolicyMarkdown ?? null,
4045
4444
  instructionPolicyFingerprint: harnessContext?.instructionPolicyFingerprint ?? null,
4046
4445
  instructionPolicyEvidence: harnessContext?.instructionPolicyEvidence ?? null,
@@ -4117,6 +4516,13 @@ async function dispatchRun(args) {
4117
4516
  }
4118
4517
  }
4119
4518
 
4519
+ // src/fortress-engagement-gate.ts
4520
+ function isEngagementRequiredSkip(skip) {
4521
+ if (skip.skipReason === "engagement_required") return true;
4522
+ const reason = skip.reason ?? "";
4523
+ return reason.includes("engagement_required") || reason.includes("engagement_not_found") || reason.includes("engagement_expired") || reason.includes("engagement_revoked");
4524
+ }
4525
+
4120
4526
  // src/redact.ts
4121
4527
  function redactHarness(text, secret) {
4122
4528
  let out = text;
@@ -4262,7 +4668,7 @@ import { mkdirSync as mkdirSync7, realpathSync } from "node:fs";
4262
4668
  import { fileURLToPath as fileURLToPath4 } from "node:url";
4263
4669
 
4264
4670
  // src/pipeline-tick.ts
4265
- import path29 from "node:path";
4671
+ import path30 from "node:path";
4266
4672
 
4267
4673
  // src/pipeline-dispatch.ts
4268
4674
  var RESERVED_REVIEW_STARTS = 1;
@@ -4968,13 +5374,62 @@ function isPipelineCleanupEnabled() {
4968
5374
  return process.env.KYNVER_PIPELINE_CLEANUP !== "0";
4969
5375
  }
4970
5376
 
5377
+ // src/installed-package-versions.ts
5378
+ import { readFile } from "node:fs/promises";
5379
+ import { homedir as homedir5 } from "node:os";
5380
+ import path29 from "node:path";
5381
+ var MANAGED_PACKAGES = [
5382
+ "@kynver-app/runtime",
5383
+ "@kynver-app/openclaw-agent-os",
5384
+ "@kynver-app/mcp-agent-os"
5385
+ ];
5386
+ function trim(value) {
5387
+ const out = value?.trim();
5388
+ return out ? out : null;
5389
+ }
5390
+ function unique(values) {
5391
+ return [...new Set(values.filter((value) => Boolean(value)))];
5392
+ }
5393
+ function moduleRoots() {
5394
+ const home = homedir5();
5395
+ const openClawPrefix = trim(process.env.KYNVER_OPENCLAW_NPM_ROOT) ?? trim(process.env.OPENCLAW_NPM_ROOT) ?? path29.join(home, ".openclaw", "npm");
5396
+ const npmGlobalRoot = trim(process.env.KYNVER_NPM_GLOBAL_ROOT) ?? trim(process.env.KYNVER_NPM_GLOBAL_MODULES_ROOT) ?? (trim(process.env.NPM_CONFIG_PREFIX) ? path29.join(trim(process.env.NPM_CONFIG_PREFIX), "lib", "node_modules") : path29.join(home, ".npm-global", "lib", "node_modules"));
5397
+ return unique([
5398
+ path29.join(openClawPrefix, "lib", "node_modules"),
5399
+ path29.join(openClawPrefix, "node_modules"),
5400
+ npmGlobalRoot.endsWith("node_modules") ? npmGlobalRoot : path29.join(npmGlobalRoot, "lib", "node_modules")
5401
+ ]);
5402
+ }
5403
+ async function readVersion(packageJsonPath) {
5404
+ try {
5405
+ const parsed = JSON.parse(await readFile(packageJsonPath, "utf8"));
5406
+ return typeof parsed.version === "string" && parsed.version.trim() ? parsed.version.trim() : null;
5407
+ } catch {
5408
+ return null;
5409
+ }
5410
+ }
5411
+ async function collectInstalledPackageVersions(observedAt = (/* @__PURE__ */ new Date()).toISOString()) {
5412
+ const roots = moduleRoots();
5413
+ const out = {};
5414
+ for (const packageName of MANAGED_PACKAGES) {
5415
+ for (const root of roots) {
5416
+ const packageJsonPath = path29.join(root, packageName, "package.json");
5417
+ const version = await readVersion(packageJsonPath);
5418
+ if (!version) continue;
5419
+ out[packageName] = { version, observedAt, path: packageJsonPath };
5420
+ break;
5421
+ }
5422
+ }
5423
+ return out;
5424
+ }
5425
+
4971
5426
  // src/pipeline-tick.ts
4972
5427
  async function completeFinishedWorkers(runId, args) {
4973
5428
  const run = loadRun(runId);
4974
5429
  const outcomes = [];
4975
5430
  for (const name of Object.keys(run.workers || {})) {
4976
5431
  const worker = readJson(
4977
- path29.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
5432
+ path30.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
4978
5433
  void 0
4979
5434
  );
4980
5435
  if (!worker?.taskId || worker.localOnly) continue;
@@ -5005,12 +5460,14 @@ async function postOperatorTick(agentOsId, runId, resourceGate, args) {
5005
5460
  const base = resolveBaseUrl(args.baseUrl ? String(args.baseUrl) : void 0);
5006
5461
  const secret = await resolveCallbackSecretWithMint(args.secret ? String(args.secret) : void 0, agentOsId, { baseUrl: base });
5007
5462
  const url = `${base}/api/agent-os/by-id/${encodeURIComponent(agentOsId)}/operator/tick`;
5463
+ const packageVersions = await collectInstalledPackageVersions();
5008
5464
  const res = await postJson(url, secret, {
5009
5465
  agentOsId,
5010
5466
  runId,
5011
5467
  ingestHarness: true,
5012
5468
  harnessBoardSnapshot: buildRunBoard(runId),
5013
- resourceGate
5469
+ resourceGate,
5470
+ packageVersions
5014
5471
  });
5015
5472
  return { ok: res.ok, httpStatus: res.status, response: res.response };
5016
5473
  }
@@ -5113,6 +5570,231 @@ async function runDaemon(args) {
5113
5570
  console.error(JSON.stringify({ event: "daemon_stop", runId, agentOsId }));
5114
5571
  }
5115
5572
 
5573
+ // src/plan-progress.ts
5574
+ import path31 from "node:path";
5575
+
5576
+ // src/bounded-build/constants.ts
5577
+ var DEFAULT_BUILD_MEM_BUDGET_BYTES = 1536 * 1024 * 1024;
5578
+ var DEFAULT_BUILD_MEM_RESERVE_BYTES = 2 * 1024 * 1024 * 1024;
5579
+ var DEFAULT_NODE_OLD_SPACE_SIZE_MB = 1024;
5580
+ var DEFAULT_SYSTEMD_MEMORY_MAX = "1.5G";
5581
+ var DEFAULT_SYSTEMD_MEMORY_SWAP_MAX = "2G";
5582
+
5583
+ // src/bounded-build/node-options.ts
5584
+ var MAX_OLD_SPACE_RE = /--max-old-space-size=(\d+)/;
5585
+ function parsePositiveInt(value, fallback) {
5586
+ const n = Number(value);
5587
+ if (!Number.isFinite(n) || n <= 0) return fallback;
5588
+ return Math.floor(n);
5589
+ }
5590
+ function resolveNodeOldSpaceSizeMb() {
5591
+ return parsePositiveInt(process.env.KYNVER_NODE_OLD_SPACE_SIZE_MB, DEFAULT_NODE_OLD_SPACE_SIZE_MB);
5592
+ }
5593
+ function mergeNodeOptionsForBuildCheck(baseEnv = process.env) {
5594
+ const env = { ...baseEnv };
5595
+ if (process.env.KYNVER_NODE_OLD_SPACE_SIZE_MB === "0") {
5596
+ return env;
5597
+ }
5598
+ const existing = env.NODE_OPTIONS ?? "";
5599
+ if (MAX_OLD_SPACE_RE.test(existing)) {
5600
+ return env;
5601
+ }
5602
+ const mb = resolveNodeOldSpaceSizeMb();
5603
+ const flag = `--max-old-space-size=${mb}`;
5604
+ env.NODE_OPTIONS = existing.trim() ? `${existing.trim()} ${flag}` : flag;
5605
+ return env;
5606
+ }
5607
+ function formatNodeOptionsFlag(mb = resolveNodeOldSpaceSizeMb()) {
5608
+ return `--max-old-space-size=${mb}`;
5609
+ }
5610
+
5611
+ // src/bounded-build/systemd-wrap.ts
5612
+ import { spawnSync as spawnSync3 } from "node:child_process";
5613
+ var systemdAvailableCache;
5614
+ function isSystemdRunAvailable() {
5615
+ if (process.env.KYNVER_BUILD_SKIP_SYSTEMD === "1" || process.env.KYNVER_BUILD_SKIP_SYSTEMD === "true") {
5616
+ return false;
5617
+ }
5618
+ if (systemdAvailableCache !== void 0) return systemdAvailableCache;
5619
+ if (process.platform !== "linux") {
5620
+ systemdAvailableCache = false;
5621
+ return false;
5622
+ }
5623
+ const res = spawnSync3("systemd-run", ["--version"], { encoding: "utf8", stdio: ["ignore", "ignore", "pipe"] });
5624
+ systemdAvailableCache = res.status === 0;
5625
+ return systemdAvailableCache;
5626
+ }
5627
+ function buildSystemdRunArgv(opts) {
5628
+ const memoryMax = opts.memoryMax ?? process.env.KYNVER_BUILD_SYSTEMD_MEMORY_MAX ?? DEFAULT_SYSTEMD_MEMORY_MAX;
5629
+ const memorySwapMax = opts.memorySwapMax ?? process.env.KYNVER_BUILD_SYSTEMD_MEMORY_SWAP_MAX ?? DEFAULT_SYSTEMD_MEMORY_SWAP_MAX;
5630
+ const argv = [
5631
+ "systemd-run",
5632
+ "--scope",
5633
+ "--collect",
5634
+ "-p",
5635
+ `MemoryMax=${memoryMax}`,
5636
+ "-p",
5637
+ `MemorySwapMax=${memorySwapMax}`
5638
+ ];
5639
+ if (opts.cwd) {
5640
+ argv.push("--working-directory", opts.cwd);
5641
+ }
5642
+ argv.push("--", ...opts.command);
5643
+ return argv;
5644
+ }
5645
+
5646
+ // src/bounded-build/admission.ts
5647
+ import { spawnSync as spawnSync4 } from "node:child_process";
5648
+ function positiveInt3(value, fallback) {
5649
+ const n = Number(value);
5650
+ if (!Number.isFinite(n) || n <= 0) return fallback;
5651
+ return Math.floor(n);
5652
+ }
5653
+ function resolveBuildAdmissionConfig(config = loadUserConfig()) {
5654
+ const envBudget = process.env.KYNVER_BUILD_MEM_BUDGET_BYTES ? positiveInt3(process.env.KYNVER_BUILD_MEM_BUDGET_BYTES, DEFAULT_BUILD_MEM_BUDGET_BYTES) : void 0;
5655
+ const envReserve = process.env.KYNVER_BUILD_MEM_RESERVE_BYTES ? positiveInt3(process.env.KYNVER_BUILD_MEM_RESERVE_BYTES, DEFAULT_BUILD_MEM_RESERVE_BYTES) : void 0;
5656
+ return {
5657
+ perBuildBudgetBytes: envBudget ?? positiveInt3(config.perWorkerMemBytes, DEFAULT_BUILD_MEM_BUDGET_BYTES),
5658
+ reserveBytes: envReserve ?? positiveInt3(config.memReserveBytes, DEFAULT_BUILD_MEM_RESERVE_BYTES)
5659
+ };
5660
+ }
5661
+ var activeBuilds = 0;
5662
+ function registerBuildStart() {
5663
+ activeBuilds += 1;
5664
+ }
5665
+ function registerBuildEnd() {
5666
+ activeBuilds = Math.max(0, activeBuilds - 1);
5667
+ }
5668
+ function assessBuildAdmission(opts = {}) {
5669
+ const cfg = { ...resolveBuildAdmissionConfig(), ...opts };
5670
+ const memAvailableBytes = opts.memAvailableBytes ?? readMemAvailableBytes();
5671
+ const requiredBytes = cfg.perBuildBudgetBytes + cfg.reserveBytes;
5672
+ const admitted = memAvailableBytes >= requiredBytes;
5673
+ return {
5674
+ admitted,
5675
+ memAvailableBytes,
5676
+ requiredBytes,
5677
+ activeBuilds,
5678
+ reason: admitted ? null : `insufficient memory: need ${requiredBytes} bytes available (budget ${cfg.perBuildBudgetBytes} + reserve ${cfg.reserveBytes}), have ${memAvailableBytes}`
5679
+ };
5680
+ }
5681
+ function sleepMs2(ms) {
5682
+ if (ms <= 0) return;
5683
+ spawnSync4(process.execPath, ["-e", `const d=Date.now()+${Math.floor(ms)};while(Date.now()<d);`], {
5684
+ stdio: "ignore"
5685
+ });
5686
+ }
5687
+ function waitForBuildAdmission(timeoutMs, pollMs = 2e3, opts = {}) {
5688
+ const deadline = Date.now() + Math.max(0, timeoutMs);
5689
+ let verdict = assessBuildAdmission({
5690
+ ...opts,
5691
+ memAvailableBytes: opts.memAvailableBytes?.()
5692
+ });
5693
+ while (!verdict.admitted && Date.now() < deadline) {
5694
+ sleepMs2(Math.min(pollMs, deadline - Date.now()));
5695
+ verdict = assessBuildAdmission({
5696
+ ...opts,
5697
+ memAvailableBytes: opts.memAvailableBytes?.()
5698
+ });
5699
+ }
5700
+ return verdict;
5701
+ }
5702
+
5703
+ // src/bounded-build/exec.ts
5704
+ import { spawnSync as spawnSync5 } from "node:child_process";
5705
+ function envArgv(env) {
5706
+ const out = [];
5707
+ for (const [key, value] of Object.entries(env)) {
5708
+ if (value === void 0) continue;
5709
+ out.push(`${key}=${value}`);
5710
+ }
5711
+ return out;
5712
+ }
5713
+ function runSpawn(argv, opts) {
5714
+ const res = spawnSync5(argv[0], argv.slice(1), {
5715
+ cwd: opts.cwd,
5716
+ env: opts.env,
5717
+ encoding: "utf8",
5718
+ stdio: ["ignore", "pipe", "pipe"],
5719
+ shell: opts.shell,
5720
+ timeout: opts.timeoutMs
5721
+ });
5722
+ return {
5723
+ exitCode: res.status ?? 1,
5724
+ stdout: (res.stdout ?? "").trim(),
5725
+ stderr: (res.stderr ?? "").trim()
5726
+ };
5727
+ }
5728
+ function runBoundedBuildCheck(input) {
5729
+ const waitMs = input.waitForAdmissionMs ?? 6e5;
5730
+ const admission = waitMs > 0 ? waitForBuildAdmission(waitMs) : assessBuildAdmission();
5731
+ if (!admission.admitted) {
5732
+ return {
5733
+ ok: false,
5734
+ exitCode: 1,
5735
+ stdout: "",
5736
+ stderr: admission.reason ?? "build admission denied",
5737
+ admitted: false,
5738
+ wrappedWithSystemd: false,
5739
+ nodeOptionsFlag: formatNodeOptionsFlag(),
5740
+ admission,
5741
+ command: input.command
5742
+ };
5743
+ }
5744
+ const env = mergeNodeOptionsForBuildCheck({ ...process.env, ...input.env });
5745
+ const nodeOptionsFlag = formatNodeOptionsFlag();
5746
+ const useSystemd = isSystemdRunAvailable();
5747
+ registerBuildStart();
5748
+ try {
5749
+ let result;
5750
+ if (useSystemd) {
5751
+ const argv = buildSystemdRunArgv({
5752
+ cwd: input.cwd,
5753
+ command: ["/usr/bin/env", ...envArgv(env), "/bin/bash", "-lc", input.command]
5754
+ });
5755
+ result = runSpawn(argv, { cwd: input.cwd, env, timeoutMs: input.timeoutMs });
5756
+ } else {
5757
+ result = runSpawn([input.command], {
5758
+ cwd: input.cwd,
5759
+ env,
5760
+ shell: true,
5761
+ timeoutMs: input.timeoutMs
5762
+ });
5763
+ }
5764
+ return {
5765
+ ok: result.exitCode === 0,
5766
+ exitCode: result.exitCode,
5767
+ stdout: result.stdout,
5768
+ stderr: result.stderr,
5769
+ admitted: true,
5770
+ wrappedWithSystemd: useSystemd,
5771
+ nodeOptionsFlag,
5772
+ admission,
5773
+ command: input.command
5774
+ };
5775
+ } finally {
5776
+ registerBuildEnd();
5777
+ }
5778
+ }
5779
+
5780
+ // src/harness-verify.ts
5781
+ var DEFAULT_HARNESS_VERIFY_COMMANDS = ["npm run typecheck", "npm run test"];
5782
+ function runHarnessVerifyCommands(cwd, commands = DEFAULT_HARNESS_VERIFY_COMMANDS, opts = {}) {
5783
+ const steps = [];
5784
+ let passed = true;
5785
+ for (const command of commands) {
5786
+ const result = runBoundedBuildCheck({
5787
+ cwd,
5788
+ command,
5789
+ waitForAdmissionMs: opts.waitForAdmissionMs,
5790
+ timeoutMs: opts.timeoutMs
5791
+ });
5792
+ steps.push({ command, result });
5793
+ if (!result.ok) passed = false;
5794
+ }
5795
+ return { passed, steps };
5796
+ }
5797
+
5116
5798
  // src/plan-progress.ts
5117
5799
  function parseEvidenceArg(raw) {
5118
5800
  const idx = raw.indexOf(":");
@@ -5173,8 +5855,23 @@ async function emitPlanProgress(args) {
5173
5855
  }
5174
5856
  console.log(JSON.stringify(parsed, null, 2));
5175
5857
  }
5858
+ function verifyPlanLocal(args) {
5859
+ const worktree = required(args.worktree ? String(args.worktree) : void 0, "worktree");
5860
+ const cwd = path31.resolve(worktree);
5861
+ const summary = runHarnessVerifyCommands(cwd);
5862
+ const emitJson = args.json === true || args.json === "true";
5863
+ const payload = { passed: summary.passed, worktree: cwd, steps: summary.steps };
5864
+ if (emitJson) console.log(JSON.stringify(payload, null, 2));
5865
+ else console.log(summary.passed ? "local plan verify passed" : "local plan verify failed");
5866
+ if (!summary.passed) process.exit(1);
5867
+ }
5176
5868
  async function verifyPlan(args) {
5177
5869
  const planId = required(args.plan ? String(args.plan) : void 0, "plan");
5870
+ const localOnly = args.local === true || args.local === "true";
5871
+ if (localOnly) {
5872
+ verifyPlanLocal(args);
5873
+ return;
5874
+ }
5178
5875
  const slug = loadUserConfig().agentOsSlug;
5179
5876
  if (!slug) {
5180
5877
  console.error("requires agentOsSlug in ~/.kynver/config.json for verify (session route)");
@@ -5208,6 +5905,52 @@ async function verifyPlan(args) {
5208
5905
  console.log(JSON.stringify(parsed, null, 2));
5209
5906
  }
5210
5907
 
5908
+ // src/harness-verify-cli.ts
5909
+ import path32 from "node:path";
5910
+ function runHarnessVerifyCli(args) {
5911
+ const cwd = path32.resolve(required(args.worktree ? String(args.worktree) : void 0, "worktree"));
5912
+ const emitJson = args.json === true || args.json === "true" || args.emitJson === true || args.emitJson === "true";
5913
+ const commands = [];
5914
+ const rawCmd = args.command;
5915
+ if (Array.isArray(rawCmd)) {
5916
+ for (const c of rawCmd) commands.push(String(c));
5917
+ } else if (typeof rawCmd === "string") {
5918
+ commands.push(rawCmd);
5919
+ }
5920
+ const summary = runHarnessVerifyCommands(
5921
+ cwd,
5922
+ commands.length ? commands : DEFAULT_HARNESS_VERIFY_COMMANDS,
5923
+ {
5924
+ waitForAdmissionMs: args.waitForAdmissionMs ? Number(args.waitForAdmissionMs) : void 0,
5925
+ timeoutMs: args.timeoutMs ? Number(args.timeoutMs) : void 0
5926
+ }
5927
+ );
5928
+ const payload = {
5929
+ passed: summary.passed,
5930
+ worktree: cwd,
5931
+ steps: summary.steps.map((s) => ({
5932
+ command: s.command,
5933
+ ok: s.result.ok,
5934
+ exitCode: s.result.exitCode,
5935
+ admitted: s.result.admitted,
5936
+ wrappedWithSystemd: s.result.wrappedWithSystemd,
5937
+ nodeOptionsFlag: s.result.nodeOptionsFlag,
5938
+ admission: s.result.admission,
5939
+ stderr: s.result.stderr.slice(0, 4e3)
5940
+ }))
5941
+ };
5942
+ if (emitJson) {
5943
+ console.log(JSON.stringify(payload, null, 2));
5944
+ } else {
5945
+ console.log(summary.passed ? "harness verify passed" : "harness verify failed");
5946
+ for (const step of payload.steps) {
5947
+ console.log(` ${step.ok ? "\u2713" : "\u2717"} ${step.command} (exit ${step.exitCode}, systemd=${step.wrappedWithSystemd})`);
5948
+ if (!step.ok && step.stderr) console.log(` ${step.stderr.split("\n")[0]}`);
5949
+ }
5950
+ }
5951
+ process.exit(summary.passed ? 0 : 1);
5952
+ }
5953
+
5211
5954
  // src/plan-persist-cli.ts
5212
5955
  import { readFileSync as readFileSync8 } from "node:fs";
5213
5956
  var OPERATIONS = ["create", "add_version", "update_metadata"];
@@ -5309,7 +6052,7 @@ function runCleanupCli(args) {
5309
6052
  }
5310
6053
 
5311
6054
  // src/monitor/monitor.service.ts
5312
- import path31 from "node:path";
6055
+ import path34 from "node:path";
5313
6056
 
5314
6057
  // src/monitor/monitor.classify.ts
5315
6058
  function expectedLeaseOwner(runId) {
@@ -5366,10 +6109,10 @@ function classifyWorkerHealth(input) {
5366
6109
 
5367
6110
  // src/monitor/monitor.store.ts
5368
6111
  import { existsSync as existsSync18, mkdirSync as mkdirSync6, readdirSync as readdirSync7, unlinkSync as unlinkSync2 } from "node:fs";
5369
- import path30 from "node:path";
6112
+ import path33 from "node:path";
5370
6113
  function monitorsDir() {
5371
6114
  const { harnessRoot } = getHarnessPaths();
5372
- const dir = path30.join(harnessRoot, "monitors");
6115
+ const dir = path33.join(harnessRoot, "monitors");
5373
6116
  mkdirSync6(dir, { recursive: true });
5374
6117
  return dir;
5375
6118
  }
@@ -5377,7 +6120,7 @@ function monitorIdFor(runId, workerName) {
5377
6120
  return workerName ? `${safeSlug(runId)}--${safeSlug(workerName)}` : safeSlug(runId);
5378
6121
  }
5379
6122
  function monitorPath(monitorId) {
5380
- return path30.join(monitorsDir(), `${monitorId}.json`);
6123
+ return path33.join(monitorsDir(), `${monitorId}.json`);
5381
6124
  }
5382
6125
  function loadMonitorSession(monitorId) {
5383
6126
  return readJson(monitorPath(monitorId), void 0);
@@ -5398,7 +6141,7 @@ function listMonitorSessions() {
5398
6141
  for (const name of readdirSync7(dir)) {
5399
6142
  if (!name.endsWith(".json")) continue;
5400
6143
  const session = readJson(
5401
- path30.join(dir, name),
6144
+ path33.join(dir, name),
5402
6145
  void 0
5403
6146
  );
5404
6147
  if (!session?.monitorId) continue;
@@ -5489,7 +6232,7 @@ async function fetchTaskLeasesForWorkers(input) {
5489
6232
  // src/monitor/monitor.service.ts
5490
6233
  function workerRecord2(runId, name) {
5491
6234
  return readJson(
5492
- path31.join(runDirectory(runId), "workers", safeSlug(name), "worker.json"),
6235
+ path34.join(runDirectory(runId), "workers", safeSlug(name), "worker.json"),
5493
6236
  void 0
5494
6237
  );
5495
6238
  }
@@ -5692,17 +6435,17 @@ async function runMonitorLoop(args) {
5692
6435
  // src/monitor/monitor-spawn.ts
5693
6436
  import { spawn as spawn4 } from "node:child_process";
5694
6437
  import { closeSync as closeSync4, existsSync as existsSync19, openSync as openSync4 } from "node:fs";
5695
- import path32 from "node:path";
6438
+ import path35 from "node:path";
5696
6439
  import { fileURLToPath as fileURLToPath3 } from "node:url";
5697
6440
  function resolveDefaultCliPath2() {
5698
- return path32.join(fileURLToPath3(new URL(".", import.meta.url)), "..", "cli.js");
6441
+ return path35.join(fileURLToPath3(new URL(".", import.meta.url)), "..", "cli.js");
5699
6442
  }
5700
6443
  function spawnMonitorSidecar(opts) {
5701
6444
  const cliPath = opts.cliPath ?? resolveDefaultCliPath2();
5702
6445
  if (!existsSync19(cliPath)) return void 0;
5703
6446
  const monitorId = monitorIdFor(opts.runId, opts.workerName);
5704
6447
  const { harnessRoot } = getHarnessPaths();
5705
- const logPath = path32.join(harnessRoot, "monitors", `${monitorId}.log`);
6448
+ const logPath = path35.join(harnessRoot, "monitors", `${monitorId}.log`);
5706
6449
  let logFd;
5707
6450
  try {
5708
6451
  logFd = openSync4(logPath, "a");
@@ -5822,16 +6565,16 @@ async function monitorTickCli(args) {
5822
6565
  }
5823
6566
 
5824
6567
  // src/doctor/runtime-takeover.ts
5825
- import path34 from "node:path";
6568
+ import path37 from "node:path";
5826
6569
 
5827
6570
  // src/doctor/runtime-takeover.probes.ts
5828
6571
  import { accessSync, constants, existsSync as existsSync20, readFileSync as readFileSync9 } from "node:fs";
5829
- import { homedir as homedir5 } from "node:os";
5830
- import path33 from "node:path";
5831
- import { spawnSync as spawnSync3 } from "node:child_process";
6572
+ import { homedir as homedir6 } from "node:os";
6573
+ import path36 from "node:path";
6574
+ import { spawnSync as spawnSync6 } from "node:child_process";
5832
6575
  function captureCommand(bin, args) {
5833
6576
  try {
5834
- const res = spawnSync3(bin, args, { encoding: "utf8" });
6577
+ const res = spawnSync6(bin, args, { encoding: "utf8" });
5835
6578
  const stdout = (res.stdout || "").trim();
5836
6579
  const stderr = (res.stderr || "").trim();
5837
6580
  const ok = res.status === 0;
@@ -5869,10 +6612,10 @@ var defaultRuntimeTakeoverProbes = {
5869
6612
  commandOnPath: (bin) => captureCommand(process.platform === "win32" ? "where" : "which", [bin]),
5870
6613
  kynverVersion: (bin) => captureCommand(bin, ["--version"]),
5871
6614
  loadConfig: () => loadUserConfig(),
5872
- configFilePath: () => path33.join(homedir5(), ".kynver", "config.json"),
5873
- credentialsFilePath: () => path33.join(homedir5(), ".kynver", "credentials"),
6615
+ configFilePath: () => path36.join(homedir6(), ".kynver", "config.json"),
6616
+ credentialsFilePath: () => path36.join(homedir6(), ".kynver", "credentials"),
5874
6617
  readCredentials: () => {
5875
- const credPath = path33.join(homedir5(), ".kynver", "credentials");
6618
+ const credPath = path36.join(homedir6(), ".kynver", "credentials");
5876
6619
  if (!existsSync20(credPath)) {
5877
6620
  return { hasApiKey: false };
5878
6621
  }
@@ -5898,7 +6641,7 @@ var defaultRuntimeTakeoverProbes = {
5898
6641
  kynverSchedulerProvider: process.env.KYNVER_SCHEDULER_PROVIDER?.trim() || void 0
5899
6642
  }),
5900
6643
  harnessRoot: () => resolveHarnessRoot(),
5901
- legacyOpenclawHarnessRoot: () => path33.join(homedir5(), ".openclaw", "harness"),
6644
+ legacyOpenclawHarnessRoot: () => path36.join(homedir6(), ".openclaw", "harness"),
5902
6645
  pathExists: (target) => existsSync20(target),
5903
6646
  pathWritable: (target) => isWritable(target),
5904
6647
  vercelVersion: () => captureCommand("vercel", ["--version"]),
@@ -6084,8 +6827,8 @@ function assessVercelCli(probes) {
6084
6827
  }
6085
6828
  function assessHarnessDirs(probes) {
6086
6829
  const harnessRoot = probes.harnessRoot();
6087
- const runsDir = path34.join(harnessRoot, "runs");
6088
- const worktreesDir = path34.join(harnessRoot, "worktrees");
6830
+ const runsDir = path37.join(harnessRoot, "runs");
6831
+ const worktreesDir = path37.join(harnessRoot, "worktrees");
6089
6832
  const displayHarnessRoot = redactHomePath(harnessRoot);
6090
6833
  const displayRunsDir = redactHomePath(runsDir);
6091
6834
  const displayWorktreesDir = redactHomePath(worktreesDir);
@@ -6237,6 +6980,37 @@ function runRuntimeTakeoverDoctorCli() {
6237
6980
  }
6238
6981
  }
6239
6982
 
6983
+ // src/command-center-contract-cli.ts
6984
+ async function runCommandCenterContractCli(args) {
6985
+ const config = loadUserConfig();
6986
+ const agentOsId = (args.agentOsId ? String(args.agentOsId) : config.agentOsId) || "";
6987
+ if (!agentOsId) {
6988
+ console.error("requires --agent-os-id or agentOsId in ~/.kynver/config.json");
6989
+ process.exit(1);
6990
+ }
6991
+ const base = resolveBaseUrl(args.baseUrl ? String(args.baseUrl) : config.apiBaseUrl);
6992
+ const secret = await resolveCallbackSecretWithMint(
6993
+ args.secret ? String(args.secret) : void 0,
6994
+ agentOsId,
6995
+ { baseUrl: base }
6996
+ );
6997
+ const qs = new URLSearchParams();
6998
+ if (typeof args.since === "string" && args.since.trim()) qs.set("since", args.since.trim());
6999
+ if (args.limit != null && String(args.limit).trim()) {
7000
+ const n = Number(args.limit);
7001
+ if (Number.isFinite(n) && n > 0) qs.set("limit", String(Math.floor(n)));
7002
+ }
7003
+ const suffix = qs.toString() ? `?${qs.toString()}` : "";
7004
+ const url = `${base}/api/agent-os/by-id/${encodeURIComponent(agentOsId)}/command-center/dashboard-contract${suffix}`;
7005
+ const res = await getJson(url, secret);
7006
+ if (!res.ok) {
7007
+ console.error(`dashboard-contract GET failed: HTTP ${res.status}`);
7008
+ if (res.response) console.error(JSON.stringify(res.response, null, 2));
7009
+ process.exit(1);
7010
+ }
7011
+ console.log(JSON.stringify(res.response, null, 2));
7012
+ }
7013
+
6240
7014
  // src/cli.ts
6241
7015
  function isHelpFlag(arg) {
6242
7016
  return arg === "help" || arg === "--help" || arg === "-h";
@@ -6258,7 +7032,7 @@ function usage(code = 0) {
6258
7032
  " kynver run create --repo /path/repo [--name name] [--base origin/main]",
6259
7033
  " kynver run list",
6260
7034
  " kynver run status --run RUN_ID",
6261
- " kynver run dispatch --run RUN_ID --agent-os-id AOS_ID [--base-url URL] [--secret SECRET] [--execute] [--lane any|implementation|review|landing] [--executor harness] [--max-starts 1] [--lease-ms MS] [--owned path[,path]] [--model claude-opus-4-8] [--disk-path /]",
7035
+ " kynver run dispatch --run RUN_ID --agent-os-id AOS_ID [--base-url URL] [--secret SECRET] [--execute] [--lane any|implementation|review|landing] [--target-task-id TASK_ID] [--executor harness] [--max-starts 1] [--lease-ms MS] [--owned path[,path]] [--model claude-opus-4-8] [--disk-path /]",
6262
7036
  " kynver run sweep --run RUN_ID --agent-os-id AOS_ID [--base-url URL] [--secret SECRET] [--grace-ms MS]",
6263
7037
  ' kynver worker start --run RUN_ID --name worker --task "..." [--owned path[,path]] [--model MODEL] [--provider claude|cursor] [--agent-os-id AOS_ID] [--task-id TASK_ID] [--wait]',
6264
7038
  " kynver worker status --run RUN_ID --name worker",
@@ -6268,7 +7042,8 @@ function usage(code = 0) {
6268
7042
  " kynver worker auto-complete --run RUN_ID --name worker [--agent-os-id AOS_ID] [--poll-ms 5000] [--max-total-ms 21600000] [--complete-attempts 3] [--complete-backoff-ms 5000] [--base-url URL] [--secret SECRET]",
6269
7043
  " kynver run reconcile",
6270
7044
  " kynver plan progress --plan PLAN_ID --row ROW_KEY --role ROLE --status STATUS [--task TASK_ID] [--note NOTE] [--evidence type:value] [--agent-os-id AOS_ID]",
6271
- " kynver plan verify --plan PLAN_ID [--worktree PATH] [--task TASK_ID] [--human-override]",
7045
+ " kynver plan verify --plan PLAN_ID [--worktree PATH] [--task TASK_ID] [--human-override] [--local]",
7046
+ " kynver harness verify --worktree PATH [--command CMD] [--json] [--wait-for-admission-ms MS] [--timeout-ms MS]",
6272
7047
  " kynver plan persist --operation create|add_version|update_metadata --title TITLE (--body-file PATH | --body TEXT) [--slug SLUG] [--plan PLAN_ID] [--summary TEXT] [--failure-kind approval_guard|auth|network|server|tool_interruption]",
6273
7048
  " kynver plan outbox list",
6274
7049
  " kynver plan outbox drain [--max N] [--id OUTBOX_ID]",
@@ -6280,7 +7055,8 @@ function usage(code = 0) {
6280
7055
  " kynver monitor tick --run RUN_ID [--name worker] [--agent-os-id AOS_ID] [--auto-complete] [--renew-leases]",
6281
7056
  " kynver monitor auto-complete --run RUN_ID --name worker [--agent-os-id AOS_ID] [--base-url URL] [--secret SECRET]",
6282
7057
  " kynver monitor run-loop --run RUN_ID --monitor-id ID [--name worker] [--agent-os-id AOS_ID] [--poll-ms MS] [--auto-complete] [--renew-leases]",
6283
- " kynver doctor runtime-takeover"
7058
+ " kynver doctor runtime-takeover",
7059
+ " kynver board contract [--agent-os-id ID] [--base-url URL] [--since ISO] [--limit N]"
6284
7060
  ].join("\n")
6285
7061
  );
6286
7062
  process.exit(code);
@@ -6291,7 +7067,7 @@ async function main(argv = process.argv.slice(2)) {
6291
7067
  const scope = argv.shift();
6292
7068
  let action;
6293
7069
  let rest;
6294
- if (scope === "run" || scope === "worker" || scope === "plan" || scope === "runner" || scope === "monitor" || scope === "doctor") {
7070
+ if (scope === "run" || scope === "worker" || scope === "plan" || scope === "runner" || scope === "harness" || scope === "monitor" || scope === "doctor" || scope === "board") {
6295
7071
  action = argv.shift();
6296
7072
  rest = argv;
6297
7073
  } else {
@@ -6308,6 +7084,7 @@ async function main(argv = process.argv.slice(2)) {
6308
7084
  if (scope === "daemon") return void await runDaemon(args);
6309
7085
  if (scope === "plan" && action === "progress") return void await emitPlanProgress(args);
6310
7086
  if (scope === "plan" && action === "verify") return void await verifyPlan(args);
7087
+ if (scope === "harness" && action === "verify") return runHarnessVerifyCli(args);
6311
7088
  if (scope === "plan" && action === "persist") return void await runPlanPersist(args);
6312
7089
  if (scope === "plan" && action === "outbox") {
6313
7090
  const outboxAction = rest.shift();
@@ -6317,6 +7094,9 @@ async function main(argv = process.argv.slice(2)) {
6317
7094
  }
6318
7095
  if (scope === "cleanup") return runCleanupCli(args);
6319
7096
  if (scope === "doctor" && action === "runtime-takeover") return runRuntimeTakeoverDoctorCli();
7097
+ if (scope === "board" && action === "contract") {
7098
+ return void await runCommandCenterContractCli(args);
7099
+ }
6320
7100
  if (scope === "run" && action === "create") return createRun(args);
6321
7101
  if (scope === "run" && action === "list") return listRuns();
6322
7102
  if (scope === "run" && action === "status") return runStatus(args);
@@ -6443,10 +7223,10 @@ function pickVercelStatusContext(statuses) {
6443
7223
  return 1;
6444
7224
  };
6445
7225
  let best = null;
6446
- let bestScore = -1;
7226
+ let bestScore = Infinity;
6447
7227
  for (const row of vercelRows) {
6448
7228
  const rowScore = score(normalizeGitHubStatusState(row.state));
6449
- if (rowScore > bestScore) {
7229
+ if (rowScore < bestScore) {
6450
7230
  best = row;
6451
7231
  bestScore = rowScore;
6452
7232
  }
@@ -6466,7 +7246,7 @@ function pickVercelStatusContext(statuses) {
6466
7246
  }
6467
7247
 
6468
7248
  // src/vercel/vercel-evidence.ts
6469
- import { spawnSync as spawnSync4 } from "node:child_process";
7249
+ import { spawnSync as spawnSync7 } from "node:child_process";
6470
7250
  var DEFAULT_INSPECT_WAIT_SECONDS = 120;
6471
7251
  function mapGitHubStateToEvidence(state) {
6472
7252
  if (state === "success") return "ready";
@@ -6532,7 +7312,7 @@ function evidenceFromGitHubVercelStatus(statuses, options = {}) {
6532
7312
  }
6533
7313
  function defaultRunVercelInspect(target, waitSeconds) {
6534
7314
  const args = ["inspect", target, "--wait", String(waitSeconds)];
6535
- const result = spawnSync4("vercel", args, {
7315
+ const result = spawnSync7("vercel", args, {
6536
7316
  encoding: "utf8",
6537
7317
  stdio: ["ignore", "pipe", "pipe"]
6538
7318
  });
@@ -6640,16 +7420,23 @@ function collectVercelEvidence(input) {
6640
7420
  }
6641
7421
  export {
6642
7422
  DEFAULT_DISPATCH_LEASE_MS,
7423
+ DEFAULT_HARNESS_VERIFY_COMMANDS,
7424
+ FORBIDDEN_WORKER_ENV_KEYS,
6643
7425
  PACKAGE_VERSION,
6644
7426
  assessAutoCompleteEligibility,
7427
+ assessBuildAdmission,
6645
7428
  assessExitedWorkerSalvage,
6646
7429
  assessPrHandoffRequirement,
6647
7430
  assessWorkerLanding,
6648
7431
  assessWorkerLandingContract,
7432
+ auditWorkerEnv,
6649
7433
  autoCompleteWorker,
6650
7434
  autoCompleteWorkerCli,
6651
7435
  buildDispatchTaskText,
6652
7436
  buildPrompt,
7437
+ buildSystemdRunArgv,
7438
+ classifyNpmAuditOutcome,
7439
+ classifyShellCommandOutcome,
6653
7440
  classifyVercelUrl,
6654
7441
  classifyWorkerHealth,
6655
7442
  collectVercelEvidence,
@@ -6669,16 +7456,21 @@ export {
6669
7456
  getMonitorStatus,
6670
7457
  hashPlanBody,
6671
7458
  isDashboardVercelUrl,
7459
+ isEngagementRequiredSkip,
6672
7460
  isFinishedWorkerStatus,
7461
+ isForbiddenWorkerEnvKey,
6673
7462
  isLandingBlockedWorkerStatus,
7463
+ isSystemdRunAvailable,
6674
7464
  isTerminalHeartbeatPhase,
6675
7465
  isVercelStatusContext,
6676
7466
  landingContractAttentionReason,
7467
+ listForbiddenWorkerEnvKeys,
6677
7468
  listMonitors,
6678
7469
  listOutboxItems,
6679
7470
  listRuns,
6680
7471
  loadUserConfig,
6681
7472
  main,
7473
+ mergeNodeOptionsForBuildCheck,
6682
7474
  normalizeCursorModelAlias,
6683
7475
  observeRunnerDiskGate,
6684
7476
  parseArgs,
@@ -6689,6 +7481,7 @@ export {
6689
7481
  pickVercelStatusContext,
6690
7482
  postJson,
6691
7483
  preflightCursorModel,
7484
+ readMemAvailableBytes,
6692
7485
  reconcileRunsCli,
6693
7486
  reconcileStaleWorkers,
6694
7487
  redactHarness,
@@ -6697,16 +7490,22 @@ export {
6697
7490
  resolveCallbackSecretWithMint,
6698
7491
  resolveHarnessRoot,
6699
7492
  resolveVercelInspectTarget,
7493
+ runBoundedBuildCheck,
6700
7494
  runDaemon,
7495
+ runHarnessVerifyCommands,
6701
7496
  runMonitorTick,
6702
7497
  runStatus,
6703
7498
  saveUserConfig,
7499
+ scrubClaudeEnv,
7500
+ scrubWorkerEnv,
6704
7501
  spawnCompletionSidecar,
6705
7502
  spawnMonitorSidecar,
6706
7503
  spawnWorkerProcess,
6707
7504
  startWorker,
6708
7505
  stopWorker,
6709
7506
  summarizeEvent,
7507
+ summarizeNpmAuditReport,
7508
+ summarizeShellToolCallEvent,
6710
7509
  sweepRun,
6711
7510
  tailWorker,
6712
7511
  terminalFinalResultFromHeartbeat,