@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.
- package/README.md +15 -0
- package/dist/auto-complete.d.ts +60 -0
- package/dist/bounded-build/admission.d.ts +30 -0
- package/dist/bounded-build/constants.d.ts +10 -0
- package/dist/bounded-build/exec.d.ts +26 -0
- package/dist/bounded-build/index.d.ts +6 -0
- package/dist/bounded-build/meminfo.d.ts +5 -0
- package/dist/bounded-build/node-options.d.ts +9 -0
- package/dist/bounded-build/systemd-wrap.d.ts +17 -0
- package/dist/callback-headers.d.ts +2 -0
- package/dist/callbacks.d.ts +38 -0
- package/dist/cleanup-cli.d.ts +1 -0
- package/dist/cleanup-dir-size.d.ts +4 -0
- package/dist/cleanup-execute.d.ts +4 -0
- package/dist/cleanup-guards.d.ts +18 -0
- package/dist/cleanup-scan.d.ts +14 -0
- package/dist/cleanup-types.d.ts +56 -0
- package/dist/cleanup-worktree-index.d.ts +13 -0
- package/dist/cleanup.d.ts +5 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +840 -77
- package/dist/cli.js.map +4 -4
- package/dist/command-center-contract-cli.d.ts +1 -0
- package/dist/completion-ack.d.ts +10 -0
- package/dist/completion-response.d.ts +15 -0
- package/dist/config.d.ts +61 -0
- package/dist/daemon.d.ts +5 -0
- package/dist/disk-gate.d.ts +9 -0
- package/dist/dispatch.d.ts +16 -0
- package/dist/doctor/doctor.types.d.ts +25 -0
- package/dist/doctor/index.d.ts +4 -0
- package/dist/doctor/runtime-takeover-cli.d.ts +1 -0
- package/dist/doctor/runtime-takeover.d.ts +3 -0
- package/dist/doctor/runtime-takeover.probes.d.ts +37 -0
- package/dist/exit-classify.d.ts +12 -0
- package/dist/exited-salvage.d.ts +22 -0
- package/dist/finalize.d.ts +16 -0
- package/dist/fortress-engagement-gate.d.ts +5 -0
- package/dist/git.d.ts +37 -0
- package/dist/github-repo.d.ts +5 -0
- package/dist/harness-expert-review.d.ts +8 -0
- package/dist/harness-verify-cli.d.ts +1 -0
- package/dist/harness-verify.d.ts +19 -0
- package/dist/heartbeat.d.ts +22 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +880 -81
- package/dist/index.js.map +4 -4
- package/dist/installed-package-versions.d.ts +6 -0
- package/dist/landing-contract-gate.d.ts +24 -0
- package/dist/landing-gate.d.ts +24 -0
- package/dist/lease-renewal.d.ts +15 -0
- package/dist/model-routing-task-enrich.d.ts +8 -0
- package/dist/model-routing.d.ts +29 -0
- package/dist/monitor/index.d.ts +7 -0
- package/dist/monitor/monitor-cli.d.ts +9 -0
- package/dist/monitor/monitor-loop.d.ts +1 -0
- package/dist/monitor/monitor-spawn.d.ts +18 -0
- package/dist/monitor/monitor.classify.d.ts +15 -0
- package/dist/monitor/monitor.service.d.ts +17 -0
- package/dist/monitor/monitor.store.d.ts +6 -0
- package/dist/monitor/monitor.task-lease.d.ts +11 -0
- package/dist/monitor/monitor.terminal.d.ts +11 -0
- package/dist/monitor/monitor.types.d.ts +74 -0
- package/dist/package-version.d.ts +5 -0
- package/dist/path-values.d.ts +5 -0
- package/dist/paths.d.ts +7 -0
- package/dist/pipeline-dispatch.d.ts +7 -0
- package/dist/pipeline-tick.d.ts +45 -0
- package/dist/plan-persist/agentos-api.d.ts +28 -0
- package/dist/plan-persist/body-hash.d.ts +3 -0
- package/dist/plan-persist/drain.d.ts +7 -0
- package/dist/plan-persist/errors.d.ts +9 -0
- package/dist/plan-persist/handoff.d.ts +7 -0
- package/dist/plan-persist/idempotency.d.ts +2 -0
- package/dist/plan-persist/index.d.ts +8 -0
- package/dist/plan-persist/outbox-store.d.ts +18 -0
- package/dist/plan-persist/paths.d.ts +8 -0
- package/dist/plan-persist/persist.d.ts +10 -0
- package/dist/plan-persist/readback.d.ts +17 -0
- package/dist/plan-persist/types.d.ts +91 -0
- package/dist/plan-persist-cli.d.ts +3 -0
- package/dist/plan-progress-daemon-sync.d.ts +7 -0
- package/dist/plan-progress-sync.d.ts +21 -0
- package/dist/plan-progress.d.ts +10 -0
- package/dist/pr-handoff/index.d.ts +4 -0
- package/dist/pr-handoff/pr-handoff-assess.d.ts +33 -0
- package/dist/pr-handoff/pr-handoff-gh.d.ts +44 -0
- package/dist/pr-handoff/pr-handoff.d.ts +8 -0
- package/dist/pr-handoff/pr-handoff.types.d.ts +45 -0
- package/dist/prompt.d.ts +14 -0
- package/dist/providers/claude.d.ts +4 -0
- package/dist/providers/cursor-windows.d.ts +7 -0
- package/dist/providers/cursor.d.ts +11 -0
- package/dist/providers/model-preflight.d.ts +31 -0
- package/dist/providers/registry.d.ts +4 -0
- package/dist/providers/types.d.ts +32 -0
- package/dist/redact.d.ts +1 -0
- package/dist/resource-gate.d.ts +53 -0
- package/dist/retry-limits.d.ts +8 -0
- package/dist/run-store.d.ts +30 -0
- package/dist/shell-command-outcome.d.ts +32 -0
- package/dist/stale-reconcile.d.ts +25 -0
- package/dist/status.d.ts +166 -0
- package/dist/stream.d.ts +20 -0
- package/dist/supervisor.d.ts +29 -0
- package/dist/sweep.d.ts +1 -0
- package/dist/util.d.ts +22 -0
- package/dist/validate.d.ts +5 -0
- package/dist/vercel/index.d.ts +3 -0
- package/dist/vercel/vercel-evidence.d.ts +48 -0
- package/dist/vercel/vercel-github-status.d.ts +19 -0
- package/dist/vercel/vercel-url.d.ts +16 -0
- package/dist/worker-env.d.ts +15 -0
- package/dist/worker-lifecycle.d.ts +28 -0
- package/dist/worker-ops.d.ts +20 -0
- package/dist/workspace-runtime-config.d.ts +8 -0
- package/dist/worktree.d.ts +4 -0
- 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
|
|
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(
|
|
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:
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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}: ${
|
|
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
|
-
|
|
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 ??
|
|
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:
|
|
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
|
|
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
|
|
2885
|
+
function asRecord2(value) {
|
|
2517
2886
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
2518
2887
|
}
|
|
2519
|
-
function
|
|
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 =
|
|
2745
|
-
const completionTask =
|
|
2746
|
-
const completionOutcome =
|
|
2747
|
-
const completionRouteStatus =
|
|
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 =
|
|
2750
|
-
const 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
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
6112
|
+
import path33 from "node:path";
|
|
5370
6113
|
function monitorsDir() {
|
|
5371
6114
|
const { harnessRoot } = getHarnessPaths();
|
|
5372
|
-
const dir =
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
6438
|
+
import path35 from "node:path";
|
|
5696
6439
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
5697
6440
|
function resolveDefaultCliPath2() {
|
|
5698
|
-
return
|
|
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 =
|
|
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
|
|
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
|
|
5830
|
-
import
|
|
5831
|
-
import { spawnSync as
|
|
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 =
|
|
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: () =>
|
|
5873
|
-
credentialsFilePath: () =>
|
|
6615
|
+
configFilePath: () => path36.join(homedir6(), ".kynver", "config.json"),
|
|
6616
|
+
credentialsFilePath: () => path36.join(homedir6(), ".kynver", "credentials"),
|
|
5874
6617
|
readCredentials: () => {
|
|
5875
|
-
const credPath =
|
|
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: () =>
|
|
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 =
|
|
6088
|
-
const worktreesDir =
|
|
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 =
|
|
7226
|
+
let bestScore = Infinity;
|
|
6447
7227
|
for (const row of vercelRows) {
|
|
6448
7228
|
const rowScore = score(normalizeGitHubStatusState(row.state));
|
|
6449
|
-
if (rowScore
|
|
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
|
|
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 =
|
|
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,
|