@kynver-app/runtime 0.1.42 → 0.1.47

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 (117) 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 +789 -74
  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-verify-cli.d.ts +1 -0
  42. package/dist/harness-verify.d.ts +19 -0
  43. package/dist/heartbeat.d.ts +22 -0
  44. package/dist/index.d.ts +33 -0
  45. package/dist/index.js +829 -78
  46. package/dist/index.js.map +4 -4
  47. package/dist/installed-package-versions.d.ts +6 -0
  48. package/dist/landing-contract-gate.d.ts +24 -0
  49. package/dist/landing-gate.d.ts +24 -0
  50. package/dist/lease-renewal.d.ts +15 -0
  51. package/dist/model-routing-task-enrich.d.ts +8 -0
  52. package/dist/model-routing.d.ts +29 -0
  53. package/dist/monitor/index.d.ts +7 -0
  54. package/dist/monitor/monitor-cli.d.ts +9 -0
  55. package/dist/monitor/monitor-loop.d.ts +1 -0
  56. package/dist/monitor/monitor-spawn.d.ts +18 -0
  57. package/dist/monitor/monitor.classify.d.ts +15 -0
  58. package/dist/monitor/monitor.service.d.ts +17 -0
  59. package/dist/monitor/monitor.store.d.ts +6 -0
  60. package/dist/monitor/monitor.task-lease.d.ts +11 -0
  61. package/dist/monitor/monitor.terminal.d.ts +11 -0
  62. package/dist/monitor/monitor.types.d.ts +74 -0
  63. package/dist/package-version.d.ts +5 -0
  64. package/dist/path-values.d.ts +5 -0
  65. package/dist/paths.d.ts +7 -0
  66. package/dist/pipeline-dispatch.d.ts +7 -0
  67. package/dist/pipeline-tick.d.ts +45 -0
  68. package/dist/plan-persist/agentos-api.d.ts +28 -0
  69. package/dist/plan-persist/body-hash.d.ts +3 -0
  70. package/dist/plan-persist/drain.d.ts +7 -0
  71. package/dist/plan-persist/errors.d.ts +9 -0
  72. package/dist/plan-persist/handoff.d.ts +7 -0
  73. package/dist/plan-persist/idempotency.d.ts +2 -0
  74. package/dist/plan-persist/index.d.ts +8 -0
  75. package/dist/plan-persist/outbox-store.d.ts +18 -0
  76. package/dist/plan-persist/paths.d.ts +8 -0
  77. package/dist/plan-persist/persist.d.ts +10 -0
  78. package/dist/plan-persist/readback.d.ts +17 -0
  79. package/dist/plan-persist/types.d.ts +91 -0
  80. package/dist/plan-persist-cli.d.ts +3 -0
  81. package/dist/plan-progress-daemon-sync.d.ts +7 -0
  82. package/dist/plan-progress-sync.d.ts +21 -0
  83. package/dist/plan-progress.d.ts +10 -0
  84. package/dist/pr-handoff/index.d.ts +4 -0
  85. package/dist/pr-handoff/pr-handoff-assess.d.ts +26 -0
  86. package/dist/pr-handoff/pr-handoff-gh.d.ts +44 -0
  87. package/dist/pr-handoff/pr-handoff.d.ts +8 -0
  88. package/dist/pr-handoff/pr-handoff.types.d.ts +45 -0
  89. package/dist/prompt.d.ts +14 -0
  90. package/dist/providers/claude.d.ts +4 -0
  91. package/dist/providers/cursor-windows.d.ts +7 -0
  92. package/dist/providers/cursor.d.ts +11 -0
  93. package/dist/providers/model-preflight.d.ts +31 -0
  94. package/dist/providers/registry.d.ts +4 -0
  95. package/dist/providers/types.d.ts +32 -0
  96. package/dist/redact.d.ts +1 -0
  97. package/dist/resource-gate.d.ts +53 -0
  98. package/dist/retry-limits.d.ts +8 -0
  99. package/dist/run-store.d.ts +30 -0
  100. package/dist/shell-command-outcome.d.ts +32 -0
  101. package/dist/stale-reconcile.d.ts +25 -0
  102. package/dist/status.d.ts +161 -0
  103. package/dist/stream.d.ts +20 -0
  104. package/dist/supervisor.d.ts +25 -0
  105. package/dist/sweep.d.ts +1 -0
  106. package/dist/util.d.ts +22 -0
  107. package/dist/validate.d.ts +5 -0
  108. package/dist/vercel/index.d.ts +3 -0
  109. package/dist/vercel/vercel-evidence.d.ts +48 -0
  110. package/dist/vercel/vercel-github-status.d.ts +19 -0
  111. package/dist/vercel/vercel-url.d.ts +16 -0
  112. package/dist/worker-env.d.ts +15 -0
  113. package/dist/worker-lifecycle.d.ts +28 -0
  114. package/dist/worker-ops.d.ts +20 -0
  115. package/dist/workspace-runtime-config.d.ts +8 -0
  116. package/dist/worktree.d.ts +4 -0
  117. package/package.json +4 -2
package/dist/cli.js CHANGED
@@ -471,12 +471,12 @@ var DEFAULT_CRITICAL_FREE_BYTES = 15 * 1024 * 1024 * 1024;
471
471
  var DEFAULT_MAX_USED_PERCENT = 80;
472
472
  var DEFAULT_HARD_MAX_USED_PERCENT = 90;
473
473
  function observeRunnerDiskGate(input = {}) {
474
- const path35 = input.diskPath?.trim() || "/";
474
+ const path38 = input.diskPath?.trim() || "/";
475
475
  const warnBelowBytes = input.diskFreeWarnBytes ?? DEFAULT_WARN_FREE_BYTES;
476
476
  const criticalBelowBytes = input.diskFreeCriticalBytes ?? DEFAULT_CRITICAL_FREE_BYTES;
477
477
  const maxUsedPercent = input.diskMaxUsedPercent ?? DEFAULT_MAX_USED_PERCENT;
478
478
  const hardMaxUsedPercent = input.diskHardMaxUsedPercent ?? DEFAULT_HARD_MAX_USED_PERCENT;
479
- const stats = statfsSync(path35);
479
+ const stats = statfsSync(path38);
480
480
  const freeBytes = Number(stats.bavail) * Number(stats.bsize);
481
481
  const totalBytes = Number(stats.blocks) * Number(stats.bsize);
482
482
  const usedPercent = totalBytes > 0 ? (totalBytes - freeBytes) / totalBytes * 100 : 100;
@@ -496,7 +496,7 @@ function observeRunnerDiskGate(input = {}) {
496
496
  }
497
497
  return {
498
498
  ok,
499
- path: path35,
499
+ path: path38,
500
500
  freeBytes,
501
501
  totalBytes,
502
502
  usedPercent,
@@ -509,8 +509,29 @@ function observeRunnerDiskGate(input = {}) {
509
509
  }
510
510
 
511
511
  // src/resource-gate.ts
512
- import { readFileSync as readFileSync5 } from "node:fs";
512
+ import os2 from "node:os";
513
+
514
+ // src/bounded-build/meminfo.ts
515
+ import { readFileSync as readFileSync3 } from "node:fs";
513
516
  import os from "node:os";
517
+ function readMemAvailableBytes(meminfoText) {
518
+ if (meminfoText !== void 0) {
519
+ const match = meminfoText.match(/^MemAvailable:\s+(\d+)\s*kB/m);
520
+ if (match) return Number(match[1]) * 1024;
521
+ return os.freemem();
522
+ }
523
+ if (process.platform === "linux") {
524
+ try {
525
+ const meminfo = readFileSync3("/proc/meminfo", "utf8");
526
+ const match = meminfo.match(/^MemAvailable:\s+(\d+)\s*kB/m);
527
+ if (match) return Number(match[1]) * 1024;
528
+ } catch {
529
+ }
530
+ }
531
+ return os.freemem();
532
+ }
533
+
534
+ // src/resource-gate.ts
514
535
  import path6 from "node:path";
515
536
 
516
537
  // src/run-store.ts
@@ -586,7 +607,7 @@ function runDirectory(id) {
586
607
  }
587
608
 
588
609
  // src/heartbeat.ts
589
- import { existsSync as existsSync5, readFileSync as readFileSync3 } from "node:fs";
610
+ import { existsSync as existsSync5, readFileSync as readFileSync4 } from "node:fs";
590
611
  var HEARTBEAT_FUTURE_SKEW_MS = 6e4;
591
612
  function isTerminalHeartbeatPhase(phase) {
592
613
  return phase === "complete";
@@ -608,7 +629,7 @@ function parseHeartbeat(file) {
608
629
  if (!existsSync5(file)) return result;
609
630
  const maxFutureMs = Date.now() + HEARTBEAT_FUTURE_SKEW_MS;
610
631
  const clampedTo = new Date(maxFutureMs).toISOString();
611
- const lines = readFileSync3(file, "utf8").split("\n").filter(Boolean);
632
+ const lines = readFileSync4(file, "utf8").split("\n").filter(Boolean);
612
633
  for (const line of lines) {
613
634
  const entry = safeJson(line);
614
635
  if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue;
@@ -635,7 +656,155 @@ function parseHeartbeat(file) {
635
656
  }
636
657
 
637
658
  // src/stream.ts
638
- import { existsSync as existsSync6, readFileSync as readFileSync4 } from "node:fs";
659
+ import { existsSync as existsSync6, readFileSync as readFileSync5 } from "node:fs";
660
+
661
+ // src/shell-command-outcome.ts
662
+ var NPM_AUDIT_RE = /\bnpm\s+audit\b/i;
663
+ function tidy(text, max = 200) {
664
+ const one = text.replace(/\s+/g, " ").trim();
665
+ return one.length > max ? `${one.slice(0, max - 1)}\u2026` : one;
666
+ }
667
+ function extractJsonObject(text) {
668
+ const trimmed = text.trim();
669
+ if (!trimmed) return null;
670
+ if (trimmed.startsWith("{")) {
671
+ try {
672
+ return JSON.parse(trimmed);
673
+ } catch {
674
+ }
675
+ }
676
+ const start = trimmed.indexOf("{");
677
+ const end = trimmed.lastIndexOf("}");
678
+ if (start >= 0 && end > start) {
679
+ try {
680
+ return JSON.parse(trimmed.slice(start, end + 1));
681
+ } catch {
682
+ return null;
683
+ }
684
+ }
685
+ return null;
686
+ }
687
+ function isRecord(value) {
688
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
689
+ }
690
+ function summarizeNpmAuditReport(report) {
691
+ const meta = report.metadata;
692
+ if (!isRecord(meta)) return null;
693
+ const vuln = meta.vulnerabilities;
694
+ if (!isRecord(vuln)) return null;
695
+ const num = (key) => typeof vuln[key] === "number" ? vuln[key] : 0;
696
+ const summary = {
697
+ info: num("info"),
698
+ low: num("low"),
699
+ moderate: num("moderate"),
700
+ high: num("high"),
701
+ critical: num("critical"),
702
+ total: num("total")
703
+ };
704
+ if (typeof vuln.total !== "number" && !summary.critical && !summary.high && !summary.moderate && !summary.low && !summary.info) {
705
+ return null;
706
+ }
707
+ return summary;
708
+ }
709
+ function formatAuditSummaryLine(audit) {
710
+ const parts = [];
711
+ if (audit.critical) parts.push(`${audit.critical} critical`);
712
+ if (audit.high) parts.push(`${audit.high} high`);
713
+ if (audit.moderate) parts.push(`${audit.moderate} moderate`);
714
+ if (audit.low) parts.push(`${audit.low} low`);
715
+ if (audit.info) parts.push(`${audit.info} info`);
716
+ const breakdown = parts.length ? parts.join(", ") : "see report";
717
+ return `npm audit: ${audit.total} vulnerabilit${audit.total === 1 ? "y" : "ies"} (${breakdown}) \u2014 remediation required`;
718
+ }
719
+ function npmAuditFailureReason(report, stderr) {
720
+ const err = report.error;
721
+ if (isRecord(err)) {
722
+ const summary = typeof err.summary === "string" ? err.summary.trim() : "";
723
+ const code = typeof err.code === "string" ? err.code.trim() : "";
724
+ if (summary) return code ? `${code}: ${summary}` : summary;
725
+ if (code) return code;
726
+ }
727
+ const detail = typeof report.message === "string" ? report.message.trim() : "";
728
+ if (detail) return detail;
729
+ const errTail = stderr.trim();
730
+ if (errTail) return tidy(errTail.split("\n").find(Boolean) ?? errTail, 160);
731
+ return "npm audit failed";
732
+ }
733
+ function classifyNpmAuditOutcome(input) {
734
+ const combined = `${input.stdout}
735
+ ${input.stderr}`.trim();
736
+ const parsed = extractJsonObject(combined);
737
+ if (!parsed || !isRecord(parsed)) {
738
+ const tail = tidy(combined || `exit ${input.exitCode}`, 180);
739
+ return {
740
+ kind: "command_failure",
741
+ exitCode: input.exitCode,
742
+ summary: `npm audit failed (invalid or missing JSON): ${tail}`,
743
+ parseError: "invalid_json"
744
+ };
745
+ }
746
+ if (isRecord(parsed.error)) {
747
+ return {
748
+ kind: "command_failure",
749
+ exitCode: input.exitCode,
750
+ summary: `npm audit command failed: ${npmAuditFailureReason(parsed, input.stderr)}`
751
+ };
752
+ }
753
+ const audit = summarizeNpmAuditReport(parsed);
754
+ if (!audit) {
755
+ return {
756
+ kind: "command_failure",
757
+ exitCode: input.exitCode,
758
+ summary: "npm audit failed: JSON response missing vulnerability metadata",
759
+ parseError: "missing_metadata"
760
+ };
761
+ }
762
+ if (input.exitCode === 0 && audit.total === 0) {
763
+ return {
764
+ kind: "success",
765
+ exitCode: 0,
766
+ summary: "npm audit: no vulnerabilities reported",
767
+ audit
768
+ };
769
+ }
770
+ return {
771
+ kind: "audit_findings",
772
+ exitCode: input.exitCode,
773
+ summary: formatAuditSummaryLine(audit),
774
+ audit
775
+ };
776
+ }
777
+ function isNpmAuditCommand(command) {
778
+ return NPM_AUDIT_RE.test(command);
779
+ }
780
+ function classifyShellCommandOutcome(input) {
781
+ const stdout = input.stdout ?? "";
782
+ const stderr = input.stderr ?? "";
783
+ const interleaved = input.interleavedOutput ?? "";
784
+ if (isNpmAuditCommand(input.command)) {
785
+ const body = stdout.trim() || interleaved.trim() || stderr.trim();
786
+ return classifyNpmAuditOutcome({
787
+ exitCode: input.exitCode,
788
+ stdout: body,
789
+ stderr
790
+ });
791
+ }
792
+ if (input.exitCode === 0) {
793
+ return {
794
+ kind: "success",
795
+ exitCode: 0,
796
+ summary: `command succeeded (exit 0)`
797
+ };
798
+ }
799
+ const tail = tidy(interleaved || stdout || stderr || `exit ${input.exitCode}`, 180);
800
+ return {
801
+ kind: "command_failure",
802
+ exitCode: input.exitCode,
803
+ summary: `command failed (exit ${input.exitCode}): ${tail}`
804
+ };
805
+ }
806
+
807
+ // src/stream.ts
639
808
  function eventTimestampIso(event) {
640
809
  const tsMs = event.timestamp_ms;
641
810
  return event.timestamp || event.ts || (tsMs ? new Date(tsMs).toISOString() : void 0);
@@ -656,16 +825,43 @@ function recordStreamResult(result, event) {
656
825
  result.error = String(event.result || event.api_error_status || "stream result error");
657
826
  }
658
827
  }
828
+ function shellPayloadFromCursorEvent(event) {
829
+ if (event.type !== "tool_call" || event.subtype !== "completed") return null;
830
+ const toolCall = event.tool_call && typeof event.tool_call === "object" && !Array.isArray(event.tool_call) ? event.tool_call : null;
831
+ const shell = toolCall?.shellToolCall;
832
+ if (!shell || typeof shell !== "object" || Array.isArray(shell)) return null;
833
+ const shellObj = shell;
834
+ const args = shellObj.args;
835
+ const command = args && typeof args === "object" && !Array.isArray(args) && typeof args.command === "string" ? String(args.command) : "";
836
+ const result = shellObj.result;
837
+ if (!result || typeof result !== "object" || Array.isArray(result)) return null;
838
+ const body = result.success ?? result.failure;
839
+ if (!body || typeof body !== "object" || Array.isArray(body)) return null;
840
+ const row = body;
841
+ const exitCode = typeof row.exitCode === "number" ? row.exitCode : 0;
842
+ return {
843
+ command,
844
+ exitCode,
845
+ stdout: typeof row.stdout === "string" ? row.stdout : "",
846
+ stderr: typeof row.stderr === "string" ? row.stderr : "",
847
+ interleaved: typeof row.interleavedOutput === "string" ? row.interleavedOutput : ""
848
+ };
849
+ }
850
+ function applyShellOutcome(parsed, outcome) {
851
+ if (outcome.kind === "success") return;
852
+ parsed.lastShellOutcome = outcome;
853
+ }
659
854
  function parseHarnessStream(file) {
660
855
  const result = {
661
856
  firstEventAt: null,
662
857
  lastEventAt: null,
663
858
  currentTool: null,
664
859
  finalResult: null,
665
- error: null
860
+ error: null,
861
+ lastShellOutcome: null
666
862
  };
667
863
  if (!existsSync6(file)) return result;
668
- const lines = readFileSync4(file, "utf8").split("\n").filter(Boolean);
864
+ const lines = readFileSync5(file, "utf8").split("\n").filter(Boolean);
669
865
  for (const line of lines) {
670
866
  const event = safeJson(line);
671
867
  if (!event) continue;
@@ -690,12 +886,44 @@ function parseHarnessStream(file) {
690
886
  const name = cursorToolNameFromCall(toolCall);
691
887
  if (name) result.currentTool = name;
692
888
  }
889
+ const shell = shellPayloadFromCursorEvent(event);
890
+ if (shell) {
891
+ applyShellOutcome(
892
+ result,
893
+ classifyShellCommandOutcome({
894
+ command: shell.command,
895
+ exitCode: shell.exitCode,
896
+ stdout: shell.stdout,
897
+ stderr: shell.stderr,
898
+ interleavedOutput: shell.interleaved
899
+ })
900
+ );
901
+ }
693
902
  if (event.type === "result") {
694
903
  recordStreamResult(result, event);
695
904
  }
696
905
  }
697
906
  return result;
698
907
  }
908
+ function summarizeShellToolCallEvent(event) {
909
+ const shell = shellPayloadFromCursorEvent(event);
910
+ if (!shell) return void 0;
911
+ const outcome = classifyShellCommandOutcome({
912
+ command: shell.command,
913
+ exitCode: shell.exitCode,
914
+ stdout: shell.stdout,
915
+ stderr: shell.stderr,
916
+ interleavedOutput: shell.interleaved
917
+ });
918
+ const cmd = oneLine(shell.command).slice(0, 120);
919
+ if (outcome.kind === "audit_findings") {
920
+ return `[audit:findings] ${outcome.summary}${cmd ? ` \xB7 ${cmd}` : ""}`;
921
+ }
922
+ if (outcome.kind === "command_failure") {
923
+ return `[command:failed] ${outcome.summary}${cmd ? ` \xB7 ${cmd}` : ""}`;
924
+ }
925
+ return `[command:ok] exit 0${cmd ? ` \xB7 ${cmd}` : ""}`;
926
+ }
699
927
  function summarizeEvent(event) {
700
928
  if (event.type === "system" && event.subtype) {
701
929
  return `[system:${event.subtype}] ${String(event.status || event.cwd || "")}`.trim();
@@ -728,6 +956,8 @@ function summarizeEvent(event) {
728
956
  }
729
957
  if (event.type === "tool_call") {
730
958
  const subtype = String(event.subtype || "");
959
+ const shellSummary = subtype === "completed" ? summarizeShellToolCallEvent(event) : void 0;
960
+ if (shellSummary) return shellSummary;
731
961
  const toolCall = event.tool_call && typeof event.tool_call === "object" && !Array.isArray(event.tool_call) ? event.tool_call : void 0;
732
962
  const name = cursorToolNameFromCall(toolCall) ?? "tool";
733
963
  return `[tool:${subtype}] ${name}`;
@@ -769,7 +999,7 @@ var FAILURE_PATTERNS = [
769
999
  label: "provider authentication failed"
770
1000
  }
771
1001
  ];
772
- function tidy(errorText, max = 240) {
1002
+ function tidy2(errorText, max = 240) {
773
1003
  const oneLine2 = errorText.replace(/\s+/g, " ").trim();
774
1004
  return oneLine2.length > max ? `${oneLine2.slice(0, max - 1)}\u2026` : oneLine2;
775
1005
  }
@@ -778,7 +1008,7 @@ function classifyExitFailure(errorText) {
778
1008
  if (!text) return null;
779
1009
  for (const pattern of FAILURE_PATTERNS) {
780
1010
  if (pattern.test.test(text)) {
781
- return { blocked: true, reason: `${pattern.label}: ${tidy(text)}` };
1011
+ return { blocked: true, reason: `${pattern.label}: ${tidy2(text)}` };
782
1012
  }
783
1013
  }
784
1014
  return null;
@@ -844,6 +1074,53 @@ function assessExitedWorkerSalvage(input) {
844
1074
 
845
1075
  // src/git.ts
846
1076
  import { spawnSync } from "node:child_process";
1077
+
1078
+ // src/worker-env.ts
1079
+ var FORBIDDEN_WORKER_ENV_KEYS = [
1080
+ "ANTHROPIC_API_KEY",
1081
+ "ANALYST_API_KEY",
1082
+ "RECRUITER_API_KEY",
1083
+ "AUTH_SECRET",
1084
+ "NEXTAUTH_SECRET",
1085
+ "DATABASE_URL",
1086
+ "PRODUCTION_DATABASE_URL",
1087
+ "REDIS_URL",
1088
+ "GOOGLE_CLIENT_SECRET",
1089
+ "GITHUB_CLIENT_SECRET",
1090
+ "KYNVER_API_KEY",
1091
+ "KYNVER_SERVICE_SECRET",
1092
+ "KYNVER_RUNTIME_SECRET",
1093
+ "OPENCLAW_CRON_SECRET",
1094
+ "QSTASH_TOKEN",
1095
+ "QSTASH_CURRENT_SIGNING_KEY",
1096
+ "QSTASH_NEXT_SIGNING_KEY",
1097
+ "TOOL_SECRETS_KEK",
1098
+ "TOOL_EXECUTOR_DISPATCH_SECRET",
1099
+ "CLOUDFLARE_API_TOKEN",
1100
+ "STRIPE_SECRET_KEY",
1101
+ "STRIPE_WEBHOOK_SECRET",
1102
+ "STRIPE_IDENTITY_WEBHOOK_SECRET",
1103
+ "VOYAGE_API_KEY",
1104
+ "PERPLEXITY_API_KEY",
1105
+ "FRED_API_KEY",
1106
+ "FMP_API_KEY",
1107
+ "CURSOR_API_KEY"
1108
+ ];
1109
+ var FORBIDDEN_KEY_SET = new Set(FORBIDDEN_WORKER_ENV_KEYS);
1110
+ var FORBIDDEN_SUFFIXES = ["_SECRET", "_API_KEY"];
1111
+ function isForbiddenWorkerEnvKey(key) {
1112
+ if (FORBIDDEN_KEY_SET.has(key)) return true;
1113
+ return FORBIDDEN_SUFFIXES.some((suffix) => key.endsWith(suffix));
1114
+ }
1115
+ function scrubWorkerEnv(env) {
1116
+ const next = { ...env };
1117
+ for (const key of Object.keys(next)) {
1118
+ if (isForbiddenWorkerEnvKey(key)) delete next[key];
1119
+ }
1120
+ return next;
1121
+ }
1122
+
1123
+ // src/git.ts
847
1124
  function git(cwd, args, options = {}) {
848
1125
  const res = spawnSync("git", args, { cwd, encoding: "utf8" });
849
1126
  if (res.status !== 0 && !options.allowFailure) {
@@ -959,11 +1236,6 @@ function unknownAncestry(base, error, head = null) {
959
1236
  error
960
1237
  };
961
1238
  }
962
- function scrubClaudeEnv(env) {
963
- const next = { ...env };
964
- delete next.ANTHROPIC_API_KEY;
965
- return next;
966
- }
967
1239
 
968
1240
  // src/landing-gate.ts
969
1241
  function trimOrNull2(value) {
@@ -1313,15 +1585,7 @@ function computeAutoMaxWorkers(totalMemBytes, opts = {}) {
1313
1585
  return Math.min(raw, AUTO_MAX_WORKERS_CEILING);
1314
1586
  }
1315
1587
  function readAvailableMemBytes() {
1316
- if (process.platform === "linux") {
1317
- try {
1318
- const meminfo = readFileSync5("/proc/meminfo", "utf8");
1319
- const match = meminfo.match(/^MemAvailable:\s+(\d+)\s*kB/m);
1320
- if (match) return Number(match[1]) * 1024;
1321
- } catch {
1322
- }
1323
- }
1324
- return os.freemem();
1588
+ return readMemAvailableBytes();
1325
1589
  }
1326
1590
  function isActiveHarnessWorker(worker) {
1327
1591
  const status = computeWorkerStatus(worker);
@@ -1349,7 +1613,7 @@ function observeRunnerResourceGate(input) {
1349
1613
  input.config,
1350
1614
  input.configuredMaxWorkersOverride
1351
1615
  );
1352
- const totalMemBytes = input.totalMemBytes ?? os.totalmem();
1616
+ const totalMemBytes = input.totalMemBytes ?? os2.totalmem();
1353
1617
  const freeMemBytes = input.freeMemBytes ?? readAvailableMemBytes();
1354
1618
  const activeWorkers = input.activeWorkers ?? countActiveWorkersGlobal();
1355
1619
  const budgetBytes = Math.max(0, Math.floor(totalMemBytes * memUtilization) - memReserveBytes);
@@ -1558,7 +1822,7 @@ var claudeProvider = {
1558
1822
  cwd: opts.worktreePath,
1559
1823
  detached: true,
1560
1824
  stdio,
1561
- env: scrubClaudeEnv(process.env)
1825
+ env: scrubWorkerEnv(process.env)
1562
1826
  })
1563
1827
  );
1564
1828
  closeSync(stdoutFd);
@@ -1945,12 +2209,12 @@ function resolveAgentBin() {
1945
2209
  return "agent";
1946
2210
  }
1947
2211
  function cursorWorkerEnv(agentBin, spawnTarget) {
1948
- return {
2212
+ return scrubWorkerEnv({
1949
2213
  ...process.env,
1950
2214
  CI: "1",
1951
2215
  NO_COLOR: "1",
1952
2216
  ...spawnTarget.bundledVersionDir ? { CURSOR_INVOKED_AS: path9.basename(agentBin) || "agent.cmd" } : {}
1953
- };
2217
+ });
1954
2218
  }
1955
2219
  var cursorProvider = {
1956
2220
  name: "cursor",
@@ -2043,6 +2307,39 @@ function persistCompletionAck(worker, runId, fields) {
2043
2307
  // src/worker-ops.ts
2044
2308
  import path11 from "node:path";
2045
2309
 
2310
+ // src/completion-response.ts
2311
+ function asRecord(value) {
2312
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
2313
+ }
2314
+ function asString(value) {
2315
+ if (typeof value !== "string") return null;
2316
+ const trimmed = value.trim();
2317
+ return trimmed.length ? trimmed : null;
2318
+ }
2319
+ var ADVANCED_OUTCOMES = /* @__PURE__ */ new Set([
2320
+ "review_scheduled",
2321
+ "review_already_scheduled"
2322
+ ]);
2323
+ function summarizeHarnessCompletionResponse(parsed) {
2324
+ const record = asRecord(parsed);
2325
+ if (!record) {
2326
+ return { routeOutcome: null, taskAdvanced: false, detail: null };
2327
+ }
2328
+ const outcome = asString(record.outcome);
2329
+ const detail = asString(record.detail) ?? asString(record.error);
2330
+ const task = asRecord(record.task);
2331
+ const taskStatus = task ? asString(task.status) : null;
2332
+ const taskAdvanced = outcome !== null && ADVANCED_OUTCOMES.has(outcome) || taskStatus === "awaiting_review" || taskStatus === "done";
2333
+ return {
2334
+ routeOutcome: outcome,
2335
+ taskAdvanced,
2336
+ detail
2337
+ };
2338
+ }
2339
+ function completionPostSucceeded(summary) {
2340
+ return summary.taskAdvanced;
2341
+ }
2342
+
2046
2343
  // src/pr-handoff/pr-handoff-assess.ts
2047
2344
  var REVIEW_LANE_RULE = /^(lane:)?(review|deep_review|planning|landing)(:|$)/i;
2048
2345
  function trimOrNull4(value) {
@@ -2103,6 +2400,36 @@ function buildPrHandoffSnapshotFromStatus(status, extras) {
2103
2400
 
2104
2401
  // src/pr-handoff/pr-handoff-gh.ts
2105
2402
  import { spawnSync as spawnSync2 } from "node:child_process";
2403
+
2404
+ // src/github-repo.ts
2405
+ function parseGithubOwnerRepo(remoteUrl) {
2406
+ const trimmed = remoteUrl.trim();
2407
+ if (!trimmed) return null;
2408
+ const ssh = trimmed.match(/^git@github\.com:([^/]+\/[^/\s]+?)(?:\.git)?$/i);
2409
+ if (ssh) return normalizeOwnerRepo(ssh[1]);
2410
+ const scp = trimmed.match(/^ssh:\/\/git@github\.com\/([^/]+\/[^/\s]+?)(?:\.git)?$/i);
2411
+ if (scp) return normalizeOwnerRepo(scp[1]);
2412
+ try {
2413
+ const url = new URL(trimmed.includes("://") ? trimmed : `https://${trimmed}`);
2414
+ if (url.hostname.toLowerCase() !== "github.com") return null;
2415
+ const parts = url.pathname.replace(/^\/+|\/+$/g, "").split("/");
2416
+ if (parts.length < 2) return null;
2417
+ const [owner, repo] = parts;
2418
+ if (!owner || !repo) return null;
2419
+ return `${owner}/${repo.replace(/\.git$/i, "")}`;
2420
+ } catch {
2421
+ return null;
2422
+ }
2423
+ }
2424
+ function normalizeOwnerRepo(value) {
2425
+ const parts = value.split("/").filter(Boolean);
2426
+ if (parts.length < 2) return null;
2427
+ const owner = parts[0];
2428
+ const repo = parts[1].replace(/\.git$/i, "");
2429
+ return owner && repo ? `${owner}/${repo}` : null;
2430
+ }
2431
+
2432
+ // src/pr-handoff/pr-handoff-gh.ts
2106
2433
  function capture(bin, cwd, args) {
2107
2434
  try {
2108
2435
  const res = spawnSync2(bin, args, { cwd, encoding: "utf8" });
@@ -2125,21 +2452,13 @@ var defaultPrHandoffExec = {
2125
2452
  git: (cwd, args) => gitCapture(cwd, args),
2126
2453
  gh: (cwd, args) => capture("gh", cwd, args)
2127
2454
  };
2128
- function parseGithubRepo(remoteUrl) {
2129
- const trimmed = remoteUrl.trim();
2130
- const ssh = trimmed.match(/git@github\.com:([^/]+\/[^/.]+)(?:\.git)?/i);
2131
- if (ssh) return ssh[1];
2132
- const https = trimmed.match(/github\.com[/:]([^/]+\/[^/.]+?)(?:\.git)?/i);
2133
- if (https) return https[1];
2134
- return null;
2135
- }
2136
2455
  function firstLine(text) {
2137
2456
  return text.split("\n").map((l) => l.trim()).find(Boolean) ?? "";
2138
2457
  }
2139
2458
  function resolveGithubRepo(worktreePath, exec) {
2140
2459
  const remote = exec.git(worktreePath, ["remote", "get-url", "origin"]);
2141
2460
  if (remote.status !== 0) return null;
2142
- return parseGithubRepo(remote.stdout);
2461
+ return parseGithubOwnerRepo(remote.stdout);
2143
2462
  }
2144
2463
  function resolveHeadCommit(worktreePath, exec) {
2145
2464
  const head = exec.git(worktreePath, ["rev-parse", "HEAD"]);
@@ -2473,10 +2792,10 @@ function completionErrorText(parsed) {
2473
2792
  }
2474
2793
  return void 0;
2475
2794
  }
2476
- function asRecord(value) {
2795
+ function asRecord2(value) {
2477
2796
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
2478
2797
  }
2479
- function asString(value) {
2798
+ function asString2(value) {
2480
2799
  if (typeof value !== "string") return null;
2481
2800
  const trimmed = value.trim();
2482
2801
  return trimmed.length ? trimmed : null;
@@ -2596,7 +2915,27 @@ async function tryCompleteWorker(args) {
2596
2915
  }
2597
2916
  }
2598
2917
  if (result.ok) {
2918
+ const summary = summarizeHarnessCompletionResponse(result.parsed);
2919
+ if (!completionPostSucceeded(summary)) {
2920
+ const detail2 = summary.detail ?? (summary.routeOutcome ? `harness completion returned ${summary.routeOutcome}` : "harness completion did not advance the linked task");
2921
+ const reason2 = `completion acknowledged but board not advanced: ${detail2}`;
2922
+ persistCompletionBlocker(worker, reason2);
2923
+ const ack2 = {
2924
+ completionReportedAt: (/* @__PURE__ */ new Date()).toISOString(),
2925
+ completionOutcome: "rejected",
2926
+ completionResponse: result.parsed
2927
+ };
2928
+ persistCompletionAck(worker, worker.runId, ack2);
2929
+ return {
2930
+ ok: false,
2931
+ httpStatus: result.status,
2932
+ response: result.parsed,
2933
+ reason: reason2,
2934
+ completionBlocked: true
2935
+ };
2936
+ }
2599
2937
  persistCompletionBlocker(worker, void 0);
2938
+ const routeOutcome = summary.routeOutcome ?? "acknowledged";
2600
2939
  const ack = {
2601
2940
  completionReportedAt: (/* @__PURE__ */ new Date()).toISOString(),
2602
2941
  completionOutcome: "acknowledged",
@@ -2609,6 +2948,7 @@ async function tryCompleteWorker(args) {
2609
2948
  ok: true,
2610
2949
  httpStatus: result.status,
2611
2950
  response: result.parsed,
2951
+ reason: routeOutcome,
2612
2952
  ...prUrl ? { prHandoff: { prUrl } } : {}
2613
2953
  };
2614
2954
  }
@@ -2701,13 +3041,13 @@ function buildRunBoard(runId) {
2701
3041
  const completionBlocker = typeof rawBlocker === "string" && rawBlocker ? rawBlocker : void 0;
2702
3042
  const boardStatus = completionBlocker ? "blocked" : status.status;
2703
3043
  const boardAttention = completionBlocker ? "blocked" : status.attention.state;
2704
- const completionResponse = asRecord(worker.completionResponse);
2705
- const completionTask = asRecord(completionResponse?.task);
2706
- const completionOutcome = asString(completionResponse?.outcome);
2707
- const completionRouteStatus = asString(completionResponse?.status);
3044
+ const completionResponse = asRecord2(worker.completionResponse);
3045
+ const completionTask = asRecord2(completionResponse?.task);
3046
+ const completionOutcome = asString2(completionResponse?.outcome);
3047
+ const completionRouteStatus = asString2(completionResponse?.status);
2708
3048
  const completionWarnings = Array.isArray(completionResponse?.warnings) ? completionResponse.warnings.filter((w) => typeof w === "string" && w.trim().length > 0) : [];
2709
- const prUrl = asString(completionTask?.prUrl) ?? asString(completionResponse?.prUrl);
2710
- const completionReportedAt = asString(worker.completionReportedAt);
3049
+ const prUrl = asString2(completionTask?.prUrl) ?? asString2(completionResponse?.prUrl);
3050
+ const completionReportedAt = asString2(worker.completionReportedAt);
2711
3051
  const lifecycleStage = deriveLifecycleStage({
2712
3052
  finished: isFinishedWorkerStatus(status),
2713
3053
  completionBlocker,
@@ -3898,7 +4238,8 @@ async function dispatchRun(args) {
3898
4238
  harnessBoardSnapshot: buildRunBoard(run.id),
3899
4239
  ...args.lane ? { lane: String(args.lane) } : {},
3900
4240
  executor: args.executor ? String(args.executor) : "harness",
3901
- ...args.diskPath ? { diskPath: String(args.diskPath) } : {}
4241
+ ...args.diskPath ? { diskPath: String(args.diskPath) } : {},
4242
+ ...args.targetTaskId ? { targetTaskId: String(args.targetTaskId) } : {}
3902
4243
  };
3903
4244
  const dispatch = await postJsonWithCredentialRefresh(dispatchUrl, secret, body, { agentOsId, baseUrl: base });
3904
4245
  const responseBody = dispatch.response;
@@ -4191,7 +4532,7 @@ function failExists(message) {
4191
4532
  }
4192
4533
 
4193
4534
  // src/pipeline-tick.ts
4194
- import path29 from "node:path";
4535
+ import path30 from "node:path";
4195
4536
 
4196
4537
  // src/pipeline-dispatch.ts
4197
4538
  var RESERVED_REVIEW_STARTS = 1;
@@ -4897,13 +5238,62 @@ function isPipelineCleanupEnabled() {
4897
5238
  return process.env.KYNVER_PIPELINE_CLEANUP !== "0";
4898
5239
  }
4899
5240
 
5241
+ // src/installed-package-versions.ts
5242
+ import { readFile } from "node:fs/promises";
5243
+ import { homedir as homedir5 } from "node:os";
5244
+ import path29 from "node:path";
5245
+ var MANAGED_PACKAGES = [
5246
+ "@kynver-app/runtime",
5247
+ "@kynver-app/openclaw-agent-os",
5248
+ "@kynver-app/mcp-agent-os"
5249
+ ];
5250
+ function trim(value) {
5251
+ const out = value?.trim();
5252
+ return out ? out : null;
5253
+ }
5254
+ function unique(values) {
5255
+ return [...new Set(values.filter((value) => Boolean(value)))];
5256
+ }
5257
+ function moduleRoots() {
5258
+ const home = homedir5();
5259
+ const openClawPrefix = trim(process.env.KYNVER_OPENCLAW_NPM_ROOT) ?? trim(process.env.OPENCLAW_NPM_ROOT) ?? path29.join(home, ".openclaw", "npm");
5260
+ 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"));
5261
+ return unique([
5262
+ path29.join(openClawPrefix, "lib", "node_modules"),
5263
+ path29.join(openClawPrefix, "node_modules"),
5264
+ npmGlobalRoot.endsWith("node_modules") ? npmGlobalRoot : path29.join(npmGlobalRoot, "lib", "node_modules")
5265
+ ]);
5266
+ }
5267
+ async function readVersion(packageJsonPath) {
5268
+ try {
5269
+ const parsed = JSON.parse(await readFile(packageJsonPath, "utf8"));
5270
+ return typeof parsed.version === "string" && parsed.version.trim() ? parsed.version.trim() : null;
5271
+ } catch {
5272
+ return null;
5273
+ }
5274
+ }
5275
+ async function collectInstalledPackageVersions(observedAt = (/* @__PURE__ */ new Date()).toISOString()) {
5276
+ const roots = moduleRoots();
5277
+ const out = {};
5278
+ for (const packageName of MANAGED_PACKAGES) {
5279
+ for (const root of roots) {
5280
+ const packageJsonPath = path29.join(root, packageName, "package.json");
5281
+ const version = await readVersion(packageJsonPath);
5282
+ if (!version) continue;
5283
+ out[packageName] = { version, observedAt, path: packageJsonPath };
5284
+ break;
5285
+ }
5286
+ }
5287
+ return out;
5288
+ }
5289
+
4900
5290
  // src/pipeline-tick.ts
4901
5291
  async function completeFinishedWorkers(runId, args) {
4902
5292
  const run = loadRun(runId);
4903
5293
  const outcomes = [];
4904
5294
  for (const name of Object.keys(run.workers || {})) {
4905
5295
  const worker = readJson(
4906
- path29.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
5296
+ path30.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
4907
5297
  void 0
4908
5298
  );
4909
5299
  if (!worker?.taskId || worker.localOnly) continue;
@@ -4934,12 +5324,14 @@ async function postOperatorTick(agentOsId, runId, resourceGate, args) {
4934
5324
  const base = resolveBaseUrl(args.baseUrl ? String(args.baseUrl) : void 0);
4935
5325
  const secret = await resolveCallbackSecretWithMint(args.secret ? String(args.secret) : void 0, agentOsId, { baseUrl: base });
4936
5326
  const url = `${base}/api/agent-os/by-id/${encodeURIComponent(agentOsId)}/operator/tick`;
5327
+ const packageVersions = await collectInstalledPackageVersions();
4937
5328
  const res = await postJson(url, secret, {
4938
5329
  agentOsId,
4939
5330
  runId,
4940
5331
  ingestHarness: true,
4941
5332
  harnessBoardSnapshot: buildRunBoard(runId),
4942
- resourceGate
5333
+ resourceGate,
5334
+ packageVersions
4943
5335
  });
4944
5336
  return { ok: res.ok, httpStatus: res.status, response: res.response };
4945
5337
  }
@@ -5042,6 +5434,231 @@ async function runDaemon(args) {
5042
5434
  console.error(JSON.stringify({ event: "daemon_stop", runId, agentOsId }));
5043
5435
  }
5044
5436
 
5437
+ // src/plan-progress.ts
5438
+ import path31 from "node:path";
5439
+
5440
+ // src/bounded-build/constants.ts
5441
+ var DEFAULT_BUILD_MEM_BUDGET_BYTES = 1536 * 1024 * 1024;
5442
+ var DEFAULT_BUILD_MEM_RESERVE_BYTES = 2 * 1024 * 1024 * 1024;
5443
+ var DEFAULT_NODE_OLD_SPACE_SIZE_MB = 1024;
5444
+ var DEFAULT_SYSTEMD_MEMORY_MAX = "1.5G";
5445
+ var DEFAULT_SYSTEMD_MEMORY_SWAP_MAX = "2G";
5446
+
5447
+ // src/bounded-build/node-options.ts
5448
+ var MAX_OLD_SPACE_RE = /--max-old-space-size=(\d+)/;
5449
+ function parsePositiveInt(value, fallback) {
5450
+ const n = Number(value);
5451
+ if (!Number.isFinite(n) || n <= 0) return fallback;
5452
+ return Math.floor(n);
5453
+ }
5454
+ function resolveNodeOldSpaceSizeMb() {
5455
+ return parsePositiveInt(process.env.KYNVER_NODE_OLD_SPACE_SIZE_MB, DEFAULT_NODE_OLD_SPACE_SIZE_MB);
5456
+ }
5457
+ function mergeNodeOptionsForBuildCheck(baseEnv = process.env) {
5458
+ const env = { ...baseEnv };
5459
+ if (process.env.KYNVER_NODE_OLD_SPACE_SIZE_MB === "0") {
5460
+ return env;
5461
+ }
5462
+ const existing = env.NODE_OPTIONS ?? "";
5463
+ if (MAX_OLD_SPACE_RE.test(existing)) {
5464
+ return env;
5465
+ }
5466
+ const mb = resolveNodeOldSpaceSizeMb();
5467
+ const flag = `--max-old-space-size=${mb}`;
5468
+ env.NODE_OPTIONS = existing.trim() ? `${existing.trim()} ${flag}` : flag;
5469
+ return env;
5470
+ }
5471
+ function formatNodeOptionsFlag(mb = resolveNodeOldSpaceSizeMb()) {
5472
+ return `--max-old-space-size=${mb}`;
5473
+ }
5474
+
5475
+ // src/bounded-build/systemd-wrap.ts
5476
+ import { spawnSync as spawnSync3 } from "node:child_process";
5477
+ var systemdAvailableCache;
5478
+ function isSystemdRunAvailable() {
5479
+ if (process.env.KYNVER_BUILD_SKIP_SYSTEMD === "1" || process.env.KYNVER_BUILD_SKIP_SYSTEMD === "true") {
5480
+ return false;
5481
+ }
5482
+ if (systemdAvailableCache !== void 0) return systemdAvailableCache;
5483
+ if (process.platform !== "linux") {
5484
+ systemdAvailableCache = false;
5485
+ return false;
5486
+ }
5487
+ const res = spawnSync3("systemd-run", ["--version"], { encoding: "utf8", stdio: ["ignore", "ignore", "pipe"] });
5488
+ systemdAvailableCache = res.status === 0;
5489
+ return systemdAvailableCache;
5490
+ }
5491
+ function buildSystemdRunArgv(opts) {
5492
+ const memoryMax = opts.memoryMax ?? process.env.KYNVER_BUILD_SYSTEMD_MEMORY_MAX ?? DEFAULT_SYSTEMD_MEMORY_MAX;
5493
+ const memorySwapMax = opts.memorySwapMax ?? process.env.KYNVER_BUILD_SYSTEMD_MEMORY_SWAP_MAX ?? DEFAULT_SYSTEMD_MEMORY_SWAP_MAX;
5494
+ const argv = [
5495
+ "systemd-run",
5496
+ "--scope",
5497
+ "--collect",
5498
+ "-p",
5499
+ `MemoryMax=${memoryMax}`,
5500
+ "-p",
5501
+ `MemorySwapMax=${memorySwapMax}`
5502
+ ];
5503
+ if (opts.cwd) {
5504
+ argv.push("--working-directory", opts.cwd);
5505
+ }
5506
+ argv.push("--", ...opts.command);
5507
+ return argv;
5508
+ }
5509
+
5510
+ // src/bounded-build/admission.ts
5511
+ import { spawnSync as spawnSync4 } from "node:child_process";
5512
+ function positiveInt3(value, fallback) {
5513
+ const n = Number(value);
5514
+ if (!Number.isFinite(n) || n <= 0) return fallback;
5515
+ return Math.floor(n);
5516
+ }
5517
+ function resolveBuildAdmissionConfig(config = loadUserConfig()) {
5518
+ const envBudget = process.env.KYNVER_BUILD_MEM_BUDGET_BYTES ? positiveInt3(process.env.KYNVER_BUILD_MEM_BUDGET_BYTES, DEFAULT_BUILD_MEM_BUDGET_BYTES) : void 0;
5519
+ const envReserve = process.env.KYNVER_BUILD_MEM_RESERVE_BYTES ? positiveInt3(process.env.KYNVER_BUILD_MEM_RESERVE_BYTES, DEFAULT_BUILD_MEM_RESERVE_BYTES) : void 0;
5520
+ return {
5521
+ perBuildBudgetBytes: envBudget ?? positiveInt3(config.perWorkerMemBytes, DEFAULT_BUILD_MEM_BUDGET_BYTES),
5522
+ reserveBytes: envReserve ?? positiveInt3(config.memReserveBytes, DEFAULT_BUILD_MEM_RESERVE_BYTES)
5523
+ };
5524
+ }
5525
+ var activeBuilds = 0;
5526
+ function registerBuildStart() {
5527
+ activeBuilds += 1;
5528
+ }
5529
+ function registerBuildEnd() {
5530
+ activeBuilds = Math.max(0, activeBuilds - 1);
5531
+ }
5532
+ function assessBuildAdmission(opts = {}) {
5533
+ const cfg = { ...resolveBuildAdmissionConfig(), ...opts };
5534
+ const memAvailableBytes = opts.memAvailableBytes ?? readMemAvailableBytes();
5535
+ const requiredBytes = cfg.perBuildBudgetBytes + cfg.reserveBytes;
5536
+ const admitted = memAvailableBytes >= requiredBytes;
5537
+ return {
5538
+ admitted,
5539
+ memAvailableBytes,
5540
+ requiredBytes,
5541
+ activeBuilds,
5542
+ reason: admitted ? null : `insufficient memory: need ${requiredBytes} bytes available (budget ${cfg.perBuildBudgetBytes} + reserve ${cfg.reserveBytes}), have ${memAvailableBytes}`
5543
+ };
5544
+ }
5545
+ function sleepMs2(ms) {
5546
+ if (ms <= 0) return;
5547
+ spawnSync4(process.execPath, ["-e", `const d=Date.now()+${Math.floor(ms)};while(Date.now()<d);`], {
5548
+ stdio: "ignore"
5549
+ });
5550
+ }
5551
+ function waitForBuildAdmission(timeoutMs, pollMs = 2e3, opts = {}) {
5552
+ const deadline = Date.now() + Math.max(0, timeoutMs);
5553
+ let verdict = assessBuildAdmission({
5554
+ ...opts,
5555
+ memAvailableBytes: opts.memAvailableBytes?.()
5556
+ });
5557
+ while (!verdict.admitted && Date.now() < deadline) {
5558
+ sleepMs2(Math.min(pollMs, deadline - Date.now()));
5559
+ verdict = assessBuildAdmission({
5560
+ ...opts,
5561
+ memAvailableBytes: opts.memAvailableBytes?.()
5562
+ });
5563
+ }
5564
+ return verdict;
5565
+ }
5566
+
5567
+ // src/bounded-build/exec.ts
5568
+ import { spawnSync as spawnSync5 } from "node:child_process";
5569
+ function envArgv(env) {
5570
+ const out = [];
5571
+ for (const [key, value] of Object.entries(env)) {
5572
+ if (value === void 0) continue;
5573
+ out.push(`${key}=${value}`);
5574
+ }
5575
+ return out;
5576
+ }
5577
+ function runSpawn(argv, opts) {
5578
+ const res = spawnSync5(argv[0], argv.slice(1), {
5579
+ cwd: opts.cwd,
5580
+ env: opts.env,
5581
+ encoding: "utf8",
5582
+ stdio: ["ignore", "pipe", "pipe"],
5583
+ shell: opts.shell,
5584
+ timeout: opts.timeoutMs
5585
+ });
5586
+ return {
5587
+ exitCode: res.status ?? 1,
5588
+ stdout: (res.stdout ?? "").trim(),
5589
+ stderr: (res.stderr ?? "").trim()
5590
+ };
5591
+ }
5592
+ function runBoundedBuildCheck(input) {
5593
+ const waitMs = input.waitForAdmissionMs ?? 6e5;
5594
+ const admission = waitMs > 0 ? waitForBuildAdmission(waitMs) : assessBuildAdmission();
5595
+ if (!admission.admitted) {
5596
+ return {
5597
+ ok: false,
5598
+ exitCode: 1,
5599
+ stdout: "",
5600
+ stderr: admission.reason ?? "build admission denied",
5601
+ admitted: false,
5602
+ wrappedWithSystemd: false,
5603
+ nodeOptionsFlag: formatNodeOptionsFlag(),
5604
+ admission,
5605
+ command: input.command
5606
+ };
5607
+ }
5608
+ const env = mergeNodeOptionsForBuildCheck({ ...process.env, ...input.env });
5609
+ const nodeOptionsFlag = formatNodeOptionsFlag();
5610
+ const useSystemd = isSystemdRunAvailable();
5611
+ registerBuildStart();
5612
+ try {
5613
+ let result;
5614
+ if (useSystemd) {
5615
+ const argv = buildSystemdRunArgv({
5616
+ cwd: input.cwd,
5617
+ command: ["/usr/bin/env", ...envArgv(env), "/bin/bash", "-lc", input.command]
5618
+ });
5619
+ result = runSpawn(argv, { cwd: input.cwd, env, timeoutMs: input.timeoutMs });
5620
+ } else {
5621
+ result = runSpawn([input.command], {
5622
+ cwd: input.cwd,
5623
+ env,
5624
+ shell: true,
5625
+ timeoutMs: input.timeoutMs
5626
+ });
5627
+ }
5628
+ return {
5629
+ ok: result.exitCode === 0,
5630
+ exitCode: result.exitCode,
5631
+ stdout: result.stdout,
5632
+ stderr: result.stderr,
5633
+ admitted: true,
5634
+ wrappedWithSystemd: useSystemd,
5635
+ nodeOptionsFlag,
5636
+ admission,
5637
+ command: input.command
5638
+ };
5639
+ } finally {
5640
+ registerBuildEnd();
5641
+ }
5642
+ }
5643
+
5644
+ // src/harness-verify.ts
5645
+ var DEFAULT_HARNESS_VERIFY_COMMANDS = ["npm run typecheck", "npm run test"];
5646
+ function runHarnessVerifyCommands(cwd, commands = DEFAULT_HARNESS_VERIFY_COMMANDS, opts = {}) {
5647
+ const steps = [];
5648
+ let passed = true;
5649
+ for (const command of commands) {
5650
+ const result = runBoundedBuildCheck({
5651
+ cwd,
5652
+ command,
5653
+ waitForAdmissionMs: opts.waitForAdmissionMs,
5654
+ timeoutMs: opts.timeoutMs
5655
+ });
5656
+ steps.push({ command, result });
5657
+ if (!result.ok) passed = false;
5658
+ }
5659
+ return { passed, steps };
5660
+ }
5661
+
5045
5662
  // src/plan-progress.ts
5046
5663
  function parseEvidenceArg(raw) {
5047
5664
  const idx = raw.indexOf(":");
@@ -5102,8 +5719,23 @@ async function emitPlanProgress(args) {
5102
5719
  }
5103
5720
  console.log(JSON.stringify(parsed, null, 2));
5104
5721
  }
5722
+ function verifyPlanLocal(args) {
5723
+ const worktree = required(args.worktree ? String(args.worktree) : void 0, "worktree");
5724
+ const cwd = path31.resolve(worktree);
5725
+ const summary = runHarnessVerifyCommands(cwd);
5726
+ const emitJson = args.json === true || args.json === "true";
5727
+ const payload = { passed: summary.passed, worktree: cwd, steps: summary.steps };
5728
+ if (emitJson) console.log(JSON.stringify(payload, null, 2));
5729
+ else console.log(summary.passed ? "local plan verify passed" : "local plan verify failed");
5730
+ if (!summary.passed) process.exit(1);
5731
+ }
5105
5732
  async function verifyPlan(args) {
5106
5733
  const planId = required(args.plan ? String(args.plan) : void 0, "plan");
5734
+ const localOnly = args.local === true || args.local === "true";
5735
+ if (localOnly) {
5736
+ verifyPlanLocal(args);
5737
+ return;
5738
+ }
5107
5739
  const slug = loadUserConfig().agentOsSlug;
5108
5740
  if (!slug) {
5109
5741
  console.error("requires agentOsSlug in ~/.kynver/config.json for verify (session route)");
@@ -5137,6 +5769,52 @@ async function verifyPlan(args) {
5137
5769
  console.log(JSON.stringify(parsed, null, 2));
5138
5770
  }
5139
5771
 
5772
+ // src/harness-verify-cli.ts
5773
+ import path32 from "node:path";
5774
+ function runHarnessVerifyCli(args) {
5775
+ const cwd = path32.resolve(required(args.worktree ? String(args.worktree) : void 0, "worktree"));
5776
+ const emitJson = args.json === true || args.json === "true" || args.emitJson === true || args.emitJson === "true";
5777
+ const commands = [];
5778
+ const rawCmd = args.command;
5779
+ if (Array.isArray(rawCmd)) {
5780
+ for (const c of rawCmd) commands.push(String(c));
5781
+ } else if (typeof rawCmd === "string") {
5782
+ commands.push(rawCmd);
5783
+ }
5784
+ const summary = runHarnessVerifyCommands(
5785
+ cwd,
5786
+ commands.length ? commands : DEFAULT_HARNESS_VERIFY_COMMANDS,
5787
+ {
5788
+ waitForAdmissionMs: args.waitForAdmissionMs ? Number(args.waitForAdmissionMs) : void 0,
5789
+ timeoutMs: args.timeoutMs ? Number(args.timeoutMs) : void 0
5790
+ }
5791
+ );
5792
+ const payload = {
5793
+ passed: summary.passed,
5794
+ worktree: cwd,
5795
+ steps: summary.steps.map((s) => ({
5796
+ command: s.command,
5797
+ ok: s.result.ok,
5798
+ exitCode: s.result.exitCode,
5799
+ admitted: s.result.admitted,
5800
+ wrappedWithSystemd: s.result.wrappedWithSystemd,
5801
+ nodeOptionsFlag: s.result.nodeOptionsFlag,
5802
+ admission: s.result.admission,
5803
+ stderr: s.result.stderr.slice(0, 4e3)
5804
+ }))
5805
+ };
5806
+ if (emitJson) {
5807
+ console.log(JSON.stringify(payload, null, 2));
5808
+ } else {
5809
+ console.log(summary.passed ? "harness verify passed" : "harness verify failed");
5810
+ for (const step of payload.steps) {
5811
+ console.log(` ${step.ok ? "\u2713" : "\u2717"} ${step.command} (exit ${step.exitCode}, systemd=${step.wrappedWithSystemd})`);
5812
+ if (!step.ok && step.stderr) console.log(` ${step.stderr.split("\n")[0]}`);
5813
+ }
5814
+ }
5815
+ process.exit(summary.passed ? 0 : 1);
5816
+ }
5817
+
5140
5818
  // src/plan-persist-cli.ts
5141
5819
  import { readFileSync as readFileSync7 } from "node:fs";
5142
5820
  var OPERATIONS = ["create", "add_version", "update_metadata"];
@@ -5238,7 +5916,7 @@ function runCleanupCli(args) {
5238
5916
  }
5239
5917
 
5240
5918
  // src/monitor/monitor.service.ts
5241
- import path31 from "node:path";
5919
+ import path34 from "node:path";
5242
5920
 
5243
5921
  // src/monitor/monitor.classify.ts
5244
5922
  function expectedLeaseOwner(runId) {
@@ -5295,10 +5973,10 @@ function classifyWorkerHealth(input) {
5295
5973
 
5296
5974
  // src/monitor/monitor.store.ts
5297
5975
  import { existsSync as existsSync17, mkdirSync as mkdirSync6, readdirSync as readdirSync7, unlinkSync as unlinkSync2 } from "node:fs";
5298
- import path30 from "node:path";
5976
+ import path33 from "node:path";
5299
5977
  function monitorsDir() {
5300
5978
  const { harnessRoot } = getHarnessPaths();
5301
- const dir = path30.join(harnessRoot, "monitors");
5979
+ const dir = path33.join(harnessRoot, "monitors");
5302
5980
  mkdirSync6(dir, { recursive: true });
5303
5981
  return dir;
5304
5982
  }
@@ -5306,7 +5984,7 @@ function monitorIdFor(runId, workerName) {
5306
5984
  return workerName ? `${safeSlug(runId)}--${safeSlug(workerName)}` : safeSlug(runId);
5307
5985
  }
5308
5986
  function monitorPath(monitorId) {
5309
- return path30.join(monitorsDir(), `${monitorId}.json`);
5987
+ return path33.join(monitorsDir(), `${monitorId}.json`);
5310
5988
  }
5311
5989
  function loadMonitorSession(monitorId) {
5312
5990
  return readJson(monitorPath(monitorId), void 0);
@@ -5327,7 +6005,7 @@ function listMonitorSessions() {
5327
6005
  for (const name of readdirSync7(dir)) {
5328
6006
  if (!name.endsWith(".json")) continue;
5329
6007
  const session = readJson(
5330
- path30.join(dir, name),
6008
+ path33.join(dir, name),
5331
6009
  void 0
5332
6010
  );
5333
6011
  if (!session?.monitorId) continue;
@@ -5418,7 +6096,7 @@ async function fetchTaskLeasesForWorkers(input) {
5418
6096
  // src/monitor/monitor.service.ts
5419
6097
  function workerRecord2(runId, name) {
5420
6098
  return readJson(
5421
- path31.join(runDirectory(runId), "workers", safeSlug(name), "worker.json"),
6099
+ path34.join(runDirectory(runId), "workers", safeSlug(name), "worker.json"),
5422
6100
  void 0
5423
6101
  );
5424
6102
  }
@@ -5621,17 +6299,17 @@ async function runMonitorLoop(args) {
5621
6299
  // src/monitor/monitor-spawn.ts
5622
6300
  import { spawn as spawn4 } from "node:child_process";
5623
6301
  import { closeSync as closeSync4, existsSync as existsSync18, openSync as openSync4 } from "node:fs";
5624
- import path32 from "node:path";
6302
+ import path35 from "node:path";
5625
6303
  import { fileURLToPath as fileURLToPath2 } from "node:url";
5626
6304
  function resolveDefaultCliPath2() {
5627
- return path32.join(fileURLToPath2(new URL(".", import.meta.url)), "..", "cli.js");
6305
+ return path35.join(fileURLToPath2(new URL(".", import.meta.url)), "..", "cli.js");
5628
6306
  }
5629
6307
  function spawnMonitorSidecar(opts) {
5630
6308
  const cliPath = opts.cliPath ?? resolveDefaultCliPath2();
5631
6309
  if (!existsSync18(cliPath)) return void 0;
5632
6310
  const monitorId = monitorIdFor(opts.runId, opts.workerName);
5633
6311
  const { harnessRoot } = getHarnessPaths();
5634
- const logPath = path32.join(harnessRoot, "monitors", `${monitorId}.log`);
6312
+ const logPath = path35.join(harnessRoot, "monitors", `${monitorId}.log`);
5635
6313
  let logFd;
5636
6314
  try {
5637
6315
  logFd = openSync4(logPath, "a");
@@ -5787,16 +6465,16 @@ function handleCliVersionFlag(argv, moduleUrl = import.meta.url, binName) {
5787
6465
  }
5788
6466
 
5789
6467
  // src/doctor/runtime-takeover.ts
5790
- import path34 from "node:path";
6468
+ import path37 from "node:path";
5791
6469
 
5792
6470
  // src/doctor/runtime-takeover.probes.ts
5793
6471
  import { accessSync, constants, existsSync as existsSync20, readFileSync as readFileSync9 } from "node:fs";
5794
- import { homedir as homedir5 } from "node:os";
5795
- import path33 from "node:path";
5796
- import { spawnSync as spawnSync3 } from "node:child_process";
6472
+ import { homedir as homedir6 } from "node:os";
6473
+ import path36 from "node:path";
6474
+ import { spawnSync as spawnSync6 } from "node:child_process";
5797
6475
  function captureCommand(bin, args) {
5798
6476
  try {
5799
- const res = spawnSync3(bin, args, { encoding: "utf8" });
6477
+ const res = spawnSync6(bin, args, { encoding: "utf8" });
5800
6478
  const stdout = (res.stdout || "").trim();
5801
6479
  const stderr = (res.stderr || "").trim();
5802
6480
  const ok = res.status === 0;
@@ -5834,10 +6512,10 @@ var defaultRuntimeTakeoverProbes = {
5834
6512
  commandOnPath: (bin) => captureCommand(process.platform === "win32" ? "where" : "which", [bin]),
5835
6513
  kynverVersion: (bin) => captureCommand(bin, ["--version"]),
5836
6514
  loadConfig: () => loadUserConfig(),
5837
- configFilePath: () => path33.join(homedir5(), ".kynver", "config.json"),
5838
- credentialsFilePath: () => path33.join(homedir5(), ".kynver", "credentials"),
6515
+ configFilePath: () => path36.join(homedir6(), ".kynver", "config.json"),
6516
+ credentialsFilePath: () => path36.join(homedir6(), ".kynver", "credentials"),
5839
6517
  readCredentials: () => {
5840
- const credPath = path33.join(homedir5(), ".kynver", "credentials");
6518
+ const credPath = path36.join(homedir6(), ".kynver", "credentials");
5841
6519
  if (!existsSync20(credPath)) {
5842
6520
  return { hasApiKey: false };
5843
6521
  }
@@ -5863,7 +6541,7 @@ var defaultRuntimeTakeoverProbes = {
5863
6541
  kynverSchedulerProvider: process.env.KYNVER_SCHEDULER_PROVIDER?.trim() || void 0
5864
6542
  }),
5865
6543
  harnessRoot: () => resolveHarnessRoot(),
5866
- legacyOpenclawHarnessRoot: () => path33.join(homedir5(), ".openclaw", "harness"),
6544
+ legacyOpenclawHarnessRoot: () => path36.join(homedir6(), ".openclaw", "harness"),
5867
6545
  pathExists: (target) => existsSync20(target),
5868
6546
  pathWritable: (target) => isWritable(target),
5869
6547
  vercelVersion: () => captureCommand("vercel", ["--version"]),
@@ -6049,8 +6727,8 @@ function assessVercelCli(probes) {
6049
6727
  }
6050
6728
  function assessHarnessDirs(probes) {
6051
6729
  const harnessRoot = probes.harnessRoot();
6052
- const runsDir = path34.join(harnessRoot, "runs");
6053
- const worktreesDir = path34.join(harnessRoot, "worktrees");
6730
+ const runsDir = path37.join(harnessRoot, "runs");
6731
+ const worktreesDir = path37.join(harnessRoot, "worktrees");
6054
6732
  const displayHarnessRoot = redactHomePath(harnessRoot);
6055
6733
  const displayRunsDir = redactHomePath(runsDir);
6056
6734
  const displayWorktreesDir = redactHomePath(worktreesDir);
@@ -6202,6 +6880,37 @@ function runRuntimeTakeoverDoctorCli() {
6202
6880
  }
6203
6881
  }
6204
6882
 
6883
+ // src/command-center-contract-cli.ts
6884
+ async function runCommandCenterContractCli(args) {
6885
+ const config = loadUserConfig();
6886
+ const agentOsId = (args.agentOsId ? String(args.agentOsId) : config.agentOsId) || "";
6887
+ if (!agentOsId) {
6888
+ console.error("requires --agent-os-id or agentOsId in ~/.kynver/config.json");
6889
+ process.exit(1);
6890
+ }
6891
+ const base = resolveBaseUrl(args.baseUrl ? String(args.baseUrl) : config.apiBaseUrl);
6892
+ const secret = await resolveCallbackSecretWithMint(
6893
+ args.secret ? String(args.secret) : void 0,
6894
+ agentOsId,
6895
+ { baseUrl: base }
6896
+ );
6897
+ const qs = new URLSearchParams();
6898
+ if (typeof args.since === "string" && args.since.trim()) qs.set("since", args.since.trim());
6899
+ if (args.limit != null && String(args.limit).trim()) {
6900
+ const n = Number(args.limit);
6901
+ if (Number.isFinite(n) && n > 0) qs.set("limit", String(Math.floor(n)));
6902
+ }
6903
+ const suffix = qs.toString() ? `?${qs.toString()}` : "";
6904
+ const url = `${base}/api/agent-os/by-id/${encodeURIComponent(agentOsId)}/command-center/dashboard-contract${suffix}`;
6905
+ const res = await getJson(url, secret);
6906
+ if (!res.ok) {
6907
+ console.error(`dashboard-contract GET failed: HTTP ${res.status}`);
6908
+ if (res.response) console.error(JSON.stringify(res.response, null, 2));
6909
+ process.exit(1);
6910
+ }
6911
+ console.log(JSON.stringify(res.response, null, 2));
6912
+ }
6913
+
6205
6914
  // src/cli.ts
6206
6915
  function isHelpFlag(arg) {
6207
6916
  return arg === "help" || arg === "--help" || arg === "-h";
@@ -6223,7 +6932,7 @@ function usage(code = 0) {
6223
6932
  " kynver run create --repo /path/repo [--name name] [--base origin/main]",
6224
6933
  " kynver run list",
6225
6934
  " kynver run status --run RUN_ID",
6226
- " 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 /]",
6935
+ " 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 /]",
6227
6936
  " kynver run sweep --run RUN_ID --agent-os-id AOS_ID [--base-url URL] [--secret SECRET] [--grace-ms MS]",
6228
6937
  ' 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]',
6229
6938
  " kynver worker status --run RUN_ID --name worker",
@@ -6233,7 +6942,8 @@ function usage(code = 0) {
6233
6942
  " 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]",
6234
6943
  " kynver run reconcile",
6235
6944
  " 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]",
6236
- " kynver plan verify --plan PLAN_ID [--worktree PATH] [--task TASK_ID] [--human-override]",
6945
+ " kynver plan verify --plan PLAN_ID [--worktree PATH] [--task TASK_ID] [--human-override] [--local]",
6946
+ " kynver harness verify --worktree PATH [--command CMD] [--json] [--wait-for-admission-ms MS] [--timeout-ms MS]",
6237
6947
  " 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]",
6238
6948
  " kynver plan outbox list",
6239
6949
  " kynver plan outbox drain [--max N] [--id OUTBOX_ID]",
@@ -6245,7 +6955,8 @@ function usage(code = 0) {
6245
6955
  " kynver monitor tick --run RUN_ID [--name worker] [--agent-os-id AOS_ID] [--auto-complete] [--renew-leases]",
6246
6956
  " kynver monitor auto-complete --run RUN_ID --name worker [--agent-os-id AOS_ID] [--base-url URL] [--secret SECRET]",
6247
6957
  " kynver monitor run-loop --run RUN_ID --monitor-id ID [--name worker] [--agent-os-id AOS_ID] [--poll-ms MS] [--auto-complete] [--renew-leases]",
6248
- " kynver doctor runtime-takeover"
6958
+ " kynver doctor runtime-takeover",
6959
+ " kynver board contract [--agent-os-id ID] [--base-url URL] [--since ISO] [--limit N]"
6249
6960
  ].join("\n")
6250
6961
  );
6251
6962
  process.exit(code);
@@ -6256,7 +6967,7 @@ async function main(argv = process.argv.slice(2)) {
6256
6967
  const scope = argv.shift();
6257
6968
  let action;
6258
6969
  let rest;
6259
- if (scope === "run" || scope === "worker" || scope === "plan" || scope === "runner" || scope === "monitor" || scope === "doctor") {
6970
+ if (scope === "run" || scope === "worker" || scope === "plan" || scope === "runner" || scope === "harness" || scope === "monitor" || scope === "doctor" || scope === "board") {
6260
6971
  action = argv.shift();
6261
6972
  rest = argv;
6262
6973
  } else {
@@ -6273,6 +6984,7 @@ async function main(argv = process.argv.slice(2)) {
6273
6984
  if (scope === "daemon") return void await runDaemon(args);
6274
6985
  if (scope === "plan" && action === "progress") return void await emitPlanProgress(args);
6275
6986
  if (scope === "plan" && action === "verify") return void await verifyPlan(args);
6987
+ if (scope === "harness" && action === "verify") return runHarnessVerifyCli(args);
6276
6988
  if (scope === "plan" && action === "persist") return void await runPlanPersist(args);
6277
6989
  if (scope === "plan" && action === "outbox") {
6278
6990
  const outboxAction = rest.shift();
@@ -6282,6 +6994,9 @@ async function main(argv = process.argv.slice(2)) {
6282
6994
  }
6283
6995
  if (scope === "cleanup") return runCleanupCli(args);
6284
6996
  if (scope === "doctor" && action === "runtime-takeover") return runRuntimeTakeoverDoctorCli();
6997
+ if (scope === "board" && action === "contract") {
6998
+ return void await runCommandCenterContractCli(args);
6999
+ }
6285
7000
  if (scope === "run" && action === "create") return createRun(args);
6286
7001
  if (scope === "run" && action === "list") return listRuns();
6287
7002
  if (scope === "run" && action === "status") return runStatus(args);