@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/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
|
|
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(
|
|
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:
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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}: ${
|
|
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
|
-
|
|
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 ??
|
|
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:
|
|
1825
|
+
env: scrubWorkerEnv(process.env)
|
|
1562
1826
|
})
|
|
1563
1827
|
);
|
|
1564
1828
|
closeSync(stdoutFd);
|
|
@@ -1835,6 +2099,7 @@ function buildPrompt(input) {
|
|
|
1835
2099
|
"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.",
|
|
1836
2100
|
"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.",
|
|
1837
2101
|
"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.",
|
|
2102
|
+
"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.",
|
|
1838
2103
|
"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.",
|
|
1839
2104
|
"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.",
|
|
1840
2105
|
"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.",
|
|
@@ -1945,12 +2210,12 @@ function resolveAgentBin() {
|
|
|
1945
2210
|
return "agent";
|
|
1946
2211
|
}
|
|
1947
2212
|
function cursorWorkerEnv(agentBin, spawnTarget) {
|
|
1948
|
-
return {
|
|
2213
|
+
return scrubWorkerEnv({
|
|
1949
2214
|
...process.env,
|
|
1950
2215
|
CI: "1",
|
|
1951
2216
|
NO_COLOR: "1",
|
|
1952
2217
|
...spawnTarget.bundledVersionDir ? { CURSOR_INVOKED_AS: path9.basename(agentBin) || "agent.cmd" } : {}
|
|
1953
|
-
};
|
|
2218
|
+
});
|
|
1954
2219
|
}
|
|
1955
2220
|
var cursorProvider = {
|
|
1956
2221
|
name: "cursor",
|
|
@@ -2043,6 +2308,65 @@ function persistCompletionAck(worker, runId, fields) {
|
|
|
2043
2308
|
// src/worker-ops.ts
|
|
2044
2309
|
import path11 from "node:path";
|
|
2045
2310
|
|
|
2311
|
+
// src/completion-response.ts
|
|
2312
|
+
function asRecord(value) {
|
|
2313
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
2314
|
+
}
|
|
2315
|
+
function asString(value) {
|
|
2316
|
+
if (typeof value !== "string") return null;
|
|
2317
|
+
const trimmed = value.trim();
|
|
2318
|
+
return trimmed.length ? trimmed : null;
|
|
2319
|
+
}
|
|
2320
|
+
var ADVANCED_OUTCOMES = /* @__PURE__ */ new Set([
|
|
2321
|
+
"review_scheduled",
|
|
2322
|
+
"review_already_scheduled"
|
|
2323
|
+
]);
|
|
2324
|
+
function summarizeHarnessCompletionResponse(parsed) {
|
|
2325
|
+
const record = asRecord(parsed);
|
|
2326
|
+
if (!record) {
|
|
2327
|
+
return { routeOutcome: null, taskAdvanced: false, detail: null };
|
|
2328
|
+
}
|
|
2329
|
+
const outcome = asString(record.outcome);
|
|
2330
|
+
const detail = asString(record.detail) ?? asString(record.error);
|
|
2331
|
+
const task = asRecord(record.task);
|
|
2332
|
+
const taskStatus = task ? asString(task.status) : null;
|
|
2333
|
+
const taskAdvanced = outcome !== null && ADVANCED_OUTCOMES.has(outcome) || taskStatus === "awaiting_review" || taskStatus === "done";
|
|
2334
|
+
return {
|
|
2335
|
+
routeOutcome: outcome,
|
|
2336
|
+
taskAdvanced,
|
|
2337
|
+
detail
|
|
2338
|
+
};
|
|
2339
|
+
}
|
|
2340
|
+
function completionPostSucceeded(summary) {
|
|
2341
|
+
return summary.taskAdvanced;
|
|
2342
|
+
}
|
|
2343
|
+
|
|
2344
|
+
// src/harness-expert-review.ts
|
|
2345
|
+
var EXPERT_LANE_REVIEW_REF = "expert-lane-pr-review:";
|
|
2346
|
+
var PLAN_REVIEW_EXECUTOR_REF = "plan-review-task";
|
|
2347
|
+
var SCHEDULED_JOB_EXECUTOR_REF = "scheduledjob:";
|
|
2348
|
+
function normalizePersonaSlug(value) {
|
|
2349
|
+
if (!value) return null;
|
|
2350
|
+
const t = value.trim().toLowerCase();
|
|
2351
|
+
return t.length ? t : null;
|
|
2352
|
+
}
|
|
2353
|
+
function isHarnessExpertReviewWorker(worker) {
|
|
2354
|
+
const ref = (worker.executorRef ?? "").toLowerCase();
|
|
2355
|
+
if (ref.startsWith(EXPERT_LANE_REVIEW_REF)) return true;
|
|
2356
|
+
if (ref === PLAN_REVIEW_EXECUTOR_REF || ref.startsWith("daemon-review:")) return true;
|
|
2357
|
+
if (ref.startsWith(SCHEDULED_JOB_EXECUTOR_REF) && worker.parentTaskId) {
|
|
2358
|
+
const persona = normalizePersonaSlug(worker.personaSlug);
|
|
2359
|
+
if (persona === "lorentz" || persona === "dalton") return true;
|
|
2360
|
+
}
|
|
2361
|
+
const title = (worker.title ?? "").toLowerCase();
|
|
2362
|
+
if (title.includes("expert pr review")) return true;
|
|
2363
|
+
if (worker.parentTaskId && (title.startsWith("review:") || title.includes("review required") || title.includes("runtime review"))) {
|
|
2364
|
+
const persona = normalizePersonaSlug(worker.personaSlug);
|
|
2365
|
+
if (persona === "lorentz" || persona === "dalton") return true;
|
|
2366
|
+
}
|
|
2367
|
+
return false;
|
|
2368
|
+
}
|
|
2369
|
+
|
|
2046
2370
|
// src/pr-handoff/pr-handoff-assess.ts
|
|
2047
2371
|
var REVIEW_LANE_RULE = /^(lane:)?(review|deep_review|planning|landing)(:|$)/i;
|
|
2048
2372
|
function trimOrNull4(value) {
|
|
@@ -2073,6 +2397,14 @@ function assessPrHandoffRequirement(input) {
|
|
|
2073
2397
|
if (!input.dispatched) {
|
|
2074
2398
|
return { required: false, reason: "not_dispatched" };
|
|
2075
2399
|
}
|
|
2400
|
+
if (isHarnessExpertReviewWorker({
|
|
2401
|
+
title: input.taskTitle ?? void 0,
|
|
2402
|
+
personaSlug: input.personaSlug,
|
|
2403
|
+
parentTaskId: input.parentTaskId,
|
|
2404
|
+
executorRef: input.executorRef
|
|
2405
|
+
})) {
|
|
2406
|
+
return { required: false, reason: "expert_review_task" };
|
|
2407
|
+
}
|
|
2076
2408
|
const rule = trimOrNull4(input.routingRule) ?? "";
|
|
2077
2409
|
if (rule && REVIEW_LANE_RULE.test(rule)) {
|
|
2078
2410
|
return { required: false, reason: "review_lane" };
|
|
@@ -2080,7 +2412,7 @@ function assessPrHandoffRequirement(input) {
|
|
|
2080
2412
|
if (trimOrNull4(input.patchPath) || trimOrNull4(input.artifactBundlePath)) {
|
|
2081
2413
|
return { required: false, reason: "patch_or_bundle" };
|
|
2082
2414
|
}
|
|
2083
|
-
const prUrl = trimOrNull4(input.prUrl) ?? trimOrNull4(input.snapshot.prUrl);
|
|
2415
|
+
const prUrl = trimOrNull4(input.prUrl) ?? trimOrNull4(input.taskPrUrl) ?? trimOrNull4(input.snapshot.prUrl);
|
|
2084
2416
|
if (prUrl) {
|
|
2085
2417
|
return { required: false, reason: "already_has_pr" };
|
|
2086
2418
|
}
|
|
@@ -2103,6 +2435,36 @@ function buildPrHandoffSnapshotFromStatus(status, extras) {
|
|
|
2103
2435
|
|
|
2104
2436
|
// src/pr-handoff/pr-handoff-gh.ts
|
|
2105
2437
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
2438
|
+
|
|
2439
|
+
// src/github-repo.ts
|
|
2440
|
+
function parseGithubOwnerRepo(remoteUrl) {
|
|
2441
|
+
const trimmed = remoteUrl.trim();
|
|
2442
|
+
if (!trimmed) return null;
|
|
2443
|
+
const ssh = trimmed.match(/^git@github\.com:([^/]+\/[^/\s]+?)(?:\.git)?$/i);
|
|
2444
|
+
if (ssh) return normalizeOwnerRepo(ssh[1]);
|
|
2445
|
+
const scp = trimmed.match(/^ssh:\/\/git@github\.com\/([^/]+\/[^/\s]+?)(?:\.git)?$/i);
|
|
2446
|
+
if (scp) return normalizeOwnerRepo(scp[1]);
|
|
2447
|
+
try {
|
|
2448
|
+
const url = new URL(trimmed.includes("://") ? trimmed : `https://${trimmed}`);
|
|
2449
|
+
if (url.hostname.toLowerCase() !== "github.com") return null;
|
|
2450
|
+
const parts = url.pathname.replace(/^\/+|\/+$/g, "").split("/");
|
|
2451
|
+
if (parts.length < 2) return null;
|
|
2452
|
+
const [owner, repo] = parts;
|
|
2453
|
+
if (!owner || !repo) return null;
|
|
2454
|
+
return `${owner}/${repo.replace(/\.git$/i, "")}`;
|
|
2455
|
+
} catch {
|
|
2456
|
+
return null;
|
|
2457
|
+
}
|
|
2458
|
+
}
|
|
2459
|
+
function normalizeOwnerRepo(value) {
|
|
2460
|
+
const parts = value.split("/").filter(Boolean);
|
|
2461
|
+
if (parts.length < 2) return null;
|
|
2462
|
+
const owner = parts[0];
|
|
2463
|
+
const repo = parts[1].replace(/\.git$/i, "");
|
|
2464
|
+
return owner && repo ? `${owner}/${repo}` : null;
|
|
2465
|
+
}
|
|
2466
|
+
|
|
2467
|
+
// src/pr-handoff/pr-handoff-gh.ts
|
|
2106
2468
|
function capture(bin, cwd, args) {
|
|
2107
2469
|
try {
|
|
2108
2470
|
const res = spawnSync2(bin, args, { cwd, encoding: "utf8" });
|
|
@@ -2125,21 +2487,13 @@ var defaultPrHandoffExec = {
|
|
|
2125
2487
|
git: (cwd, args) => gitCapture(cwd, args),
|
|
2126
2488
|
gh: (cwd, args) => capture("gh", cwd, args)
|
|
2127
2489
|
};
|
|
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
2490
|
function firstLine(text) {
|
|
2137
2491
|
return text.split("\n").map((l) => l.trim()).find(Boolean) ?? "";
|
|
2138
2492
|
}
|
|
2139
2493
|
function resolveGithubRepo(worktreePath, exec) {
|
|
2140
2494
|
const remote = exec.git(worktreePath, ["remote", "get-url", "origin"]);
|
|
2141
2495
|
if (remote.status !== 0) return null;
|
|
2142
|
-
return
|
|
2496
|
+
return parseGithubOwnerRepo(remote.stdout);
|
|
2143
2497
|
}
|
|
2144
2498
|
function resolveHeadCommit(worktreePath, exec) {
|
|
2145
2499
|
const head = exec.git(worktreePath, ["rev-parse", "HEAD"]);
|
|
@@ -2275,6 +2629,11 @@ function ensurePrReadyHandoff(input, exec = defaultPrHandoffExec) {
|
|
|
2275
2629
|
dispatched: input.worker.dispatched,
|
|
2276
2630
|
routingRule: input.worker.routingRule,
|
|
2277
2631
|
prUrl: prUrlHint,
|
|
2632
|
+
taskTitle: input.worker.taskTitle,
|
|
2633
|
+
executorRef: input.worker.executorRef,
|
|
2634
|
+
parentTaskId: input.worker.parentTaskId,
|
|
2635
|
+
personaSlug: input.worker.personaSlug,
|
|
2636
|
+
taskPrUrl: input.worker.taskPrUrl,
|
|
2278
2637
|
snapshot
|
|
2279
2638
|
});
|
|
2280
2639
|
if (!requirement.required) {
|
|
@@ -2473,10 +2832,10 @@ function completionErrorText(parsed) {
|
|
|
2473
2832
|
}
|
|
2474
2833
|
return void 0;
|
|
2475
2834
|
}
|
|
2476
|
-
function
|
|
2835
|
+
function asRecord2(value) {
|
|
2477
2836
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
2478
2837
|
}
|
|
2479
|
-
function
|
|
2838
|
+
function asString2(value) {
|
|
2480
2839
|
if (typeof value !== "string") return null;
|
|
2481
2840
|
const trimmed = value.trim();
|
|
2482
2841
|
return trimmed.length ? trimmed : null;
|
|
@@ -2596,7 +2955,27 @@ async function tryCompleteWorker(args) {
|
|
|
2596
2955
|
}
|
|
2597
2956
|
}
|
|
2598
2957
|
if (result.ok) {
|
|
2958
|
+
const summary = summarizeHarnessCompletionResponse(result.parsed);
|
|
2959
|
+
if (!completionPostSucceeded(summary)) {
|
|
2960
|
+
const detail2 = summary.detail ?? (summary.routeOutcome ? `harness completion returned ${summary.routeOutcome}` : "harness completion did not advance the linked task");
|
|
2961
|
+
const reason2 = `completion acknowledged but board not advanced: ${detail2}`;
|
|
2962
|
+
persistCompletionBlocker(worker, reason2);
|
|
2963
|
+
const ack2 = {
|
|
2964
|
+
completionReportedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2965
|
+
completionOutcome: "rejected",
|
|
2966
|
+
completionResponse: result.parsed
|
|
2967
|
+
};
|
|
2968
|
+
persistCompletionAck(worker, worker.runId, ack2);
|
|
2969
|
+
return {
|
|
2970
|
+
ok: false,
|
|
2971
|
+
httpStatus: result.status,
|
|
2972
|
+
response: result.parsed,
|
|
2973
|
+
reason: reason2,
|
|
2974
|
+
completionBlocked: true
|
|
2975
|
+
};
|
|
2976
|
+
}
|
|
2599
2977
|
persistCompletionBlocker(worker, void 0);
|
|
2978
|
+
const routeOutcome = summary.routeOutcome ?? "acknowledged";
|
|
2600
2979
|
const ack = {
|
|
2601
2980
|
completionReportedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2602
2981
|
completionOutcome: "acknowledged",
|
|
@@ -2609,6 +2988,7 @@ async function tryCompleteWorker(args) {
|
|
|
2609
2988
|
ok: true,
|
|
2610
2989
|
httpStatus: result.status,
|
|
2611
2990
|
response: result.parsed,
|
|
2991
|
+
reason: routeOutcome,
|
|
2612
2992
|
...prUrl ? { prHandoff: { prUrl } } : {}
|
|
2613
2993
|
};
|
|
2614
2994
|
}
|
|
@@ -2701,13 +3081,13 @@ function buildRunBoard(runId) {
|
|
|
2701
3081
|
const completionBlocker = typeof rawBlocker === "string" && rawBlocker ? rawBlocker : void 0;
|
|
2702
3082
|
const boardStatus = completionBlocker ? "blocked" : status.status;
|
|
2703
3083
|
const boardAttention = completionBlocker ? "blocked" : status.attention.state;
|
|
2704
|
-
const completionResponse =
|
|
2705
|
-
const completionTask =
|
|
2706
|
-
const completionOutcome =
|
|
2707
|
-
const completionRouteStatus =
|
|
3084
|
+
const completionResponse = asRecord2(worker.completionResponse);
|
|
3085
|
+
const completionTask = asRecord2(completionResponse?.task);
|
|
3086
|
+
const completionOutcome = asString2(completionResponse?.outcome);
|
|
3087
|
+
const completionRouteStatus = asString2(completionResponse?.status);
|
|
2708
3088
|
const completionWarnings = Array.isArray(completionResponse?.warnings) ? completionResponse.warnings.filter((w) => typeof w === "string" && w.trim().length > 0) : [];
|
|
2709
|
-
const prUrl =
|
|
2710
|
-
const completionReportedAt =
|
|
3089
|
+
const prUrl = asString2(completionTask?.prUrl) ?? asString2(completionResponse?.prUrl);
|
|
3090
|
+
const completionReportedAt = asString2(worker.completionReportedAt);
|
|
2711
3091
|
const lifecycleStage = deriveLifecycleStage({
|
|
2712
3092
|
finished: isFinishedWorkerStatus(status),
|
|
2713
3093
|
completionBlocker,
|
|
@@ -3133,6 +3513,10 @@ function spawnWorkerProcess(run, opts) {
|
|
|
3133
3513
|
...!opts.agentOsId || !opts.taskId ? { localOnly: true } : {},
|
|
3134
3514
|
routingRule: routing.rule,
|
|
3135
3515
|
...routing.requestedModel ? { requestedModel: routing.requestedModel } : {},
|
|
3516
|
+
...opts.executorRef ? { executorRef: String(opts.executorRef) } : {},
|
|
3517
|
+
...opts.parentTaskId ? { parentTaskId: String(opts.parentTaskId) } : {},
|
|
3518
|
+
...opts.taskTitle ? { taskTitle: String(opts.taskTitle) } : {},
|
|
3519
|
+
...opts.taskPrUrl ? { taskPrUrl: String(opts.taskPrUrl) } : {},
|
|
3136
3520
|
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3137
3521
|
};
|
|
3138
3522
|
saveWorker(run.id, worker);
|
|
@@ -3827,7 +4211,7 @@ function readHarnessWorkerContext(decision) {
|
|
|
3827
4211
|
personaInjectionReady
|
|
3828
4212
|
};
|
|
3829
4213
|
}
|
|
3830
|
-
function
|
|
4214
|
+
function normalizePersonaSlug2(value) {
|
|
3831
4215
|
if (typeof value !== "string") return null;
|
|
3832
4216
|
const trimmed = value.trim().toLowerCase();
|
|
3833
4217
|
return trimmed.length ? trimmed : null;
|
|
@@ -3898,7 +4282,8 @@ async function dispatchRun(args) {
|
|
|
3898
4282
|
harnessBoardSnapshot: buildRunBoard(run.id),
|
|
3899
4283
|
...args.lane ? { lane: String(args.lane) } : {},
|
|
3900
4284
|
executor: args.executor ? String(args.executor) : "harness",
|
|
3901
|
-
...args.diskPath ? { diskPath: String(args.diskPath) } : {}
|
|
4285
|
+
...args.diskPath ? { diskPath: String(args.diskPath) } : {},
|
|
4286
|
+
...args.targetTaskId ? { targetTaskId: String(args.targetTaskId) } : {}
|
|
3902
4287
|
};
|
|
3903
4288
|
const dispatch = await postJsonWithCredentialRefresh(dispatchUrl, secret, body, { agentOsId, baseUrl: base });
|
|
3904
4289
|
const responseBody = dispatch.response;
|
|
@@ -3957,7 +4342,7 @@ async function dispatchRun(args) {
|
|
|
3957
4342
|
const task = decision.task;
|
|
3958
4343
|
const harnessContext = readHarnessWorkerContext(decision);
|
|
3959
4344
|
const taskId = String(task.id);
|
|
3960
|
-
const expectedPersona =
|
|
4345
|
+
const expectedPersona = normalizePersonaSlug2(task.personaSlug);
|
|
3961
4346
|
if (expectedPersona && (!harnessContext?.personaInjectionReady || !harnessContext.personaMarkdown)) {
|
|
3962
4347
|
outcomes.push({
|
|
3963
4348
|
taskId,
|
|
@@ -4001,6 +4386,10 @@ async function dispatchRun(args) {
|
|
|
4001
4386
|
agentOsId,
|
|
4002
4387
|
taskId: String(task.id),
|
|
4003
4388
|
planId,
|
|
4389
|
+
executorRef: task.executorRef ? String(task.executorRef) : void 0,
|
|
4390
|
+
parentTaskId: task.parentTaskId ? String(task.parentTaskId) : void 0,
|
|
4391
|
+
taskTitle: task.title ? String(task.title) : void 0,
|
|
4392
|
+
taskPrUrl: task.prUrl ? String(task.prUrl) : void 0,
|
|
4004
4393
|
instructionPolicyMarkdown: harnessContext?.instructionPolicyMarkdown ?? null,
|
|
4005
4394
|
instructionPolicyFingerprint: harnessContext?.instructionPolicyFingerprint ?? null,
|
|
4006
4395
|
instructionPolicyEvidence: harnessContext?.instructionPolicyEvidence ?? null,
|
|
@@ -4191,7 +4580,7 @@ function failExists(message) {
|
|
|
4191
4580
|
}
|
|
4192
4581
|
|
|
4193
4582
|
// src/pipeline-tick.ts
|
|
4194
|
-
import
|
|
4583
|
+
import path30 from "node:path";
|
|
4195
4584
|
|
|
4196
4585
|
// src/pipeline-dispatch.ts
|
|
4197
4586
|
var RESERVED_REVIEW_STARTS = 1;
|
|
@@ -4897,13 +5286,62 @@ function isPipelineCleanupEnabled() {
|
|
|
4897
5286
|
return process.env.KYNVER_PIPELINE_CLEANUP !== "0";
|
|
4898
5287
|
}
|
|
4899
5288
|
|
|
5289
|
+
// src/installed-package-versions.ts
|
|
5290
|
+
import { readFile } from "node:fs/promises";
|
|
5291
|
+
import { homedir as homedir5 } from "node:os";
|
|
5292
|
+
import path29 from "node:path";
|
|
5293
|
+
var MANAGED_PACKAGES = [
|
|
5294
|
+
"@kynver-app/runtime",
|
|
5295
|
+
"@kynver-app/openclaw-agent-os",
|
|
5296
|
+
"@kynver-app/mcp-agent-os"
|
|
5297
|
+
];
|
|
5298
|
+
function trim(value) {
|
|
5299
|
+
const out = value?.trim();
|
|
5300
|
+
return out ? out : null;
|
|
5301
|
+
}
|
|
5302
|
+
function unique(values) {
|
|
5303
|
+
return [...new Set(values.filter((value) => Boolean(value)))];
|
|
5304
|
+
}
|
|
5305
|
+
function moduleRoots() {
|
|
5306
|
+
const home = homedir5();
|
|
5307
|
+
const openClawPrefix = trim(process.env.KYNVER_OPENCLAW_NPM_ROOT) ?? trim(process.env.OPENCLAW_NPM_ROOT) ?? path29.join(home, ".openclaw", "npm");
|
|
5308
|
+
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"));
|
|
5309
|
+
return unique([
|
|
5310
|
+
path29.join(openClawPrefix, "lib", "node_modules"),
|
|
5311
|
+
path29.join(openClawPrefix, "node_modules"),
|
|
5312
|
+
npmGlobalRoot.endsWith("node_modules") ? npmGlobalRoot : path29.join(npmGlobalRoot, "lib", "node_modules")
|
|
5313
|
+
]);
|
|
5314
|
+
}
|
|
5315
|
+
async function readVersion(packageJsonPath) {
|
|
5316
|
+
try {
|
|
5317
|
+
const parsed = JSON.parse(await readFile(packageJsonPath, "utf8"));
|
|
5318
|
+
return typeof parsed.version === "string" && parsed.version.trim() ? parsed.version.trim() : null;
|
|
5319
|
+
} catch {
|
|
5320
|
+
return null;
|
|
5321
|
+
}
|
|
5322
|
+
}
|
|
5323
|
+
async function collectInstalledPackageVersions(observedAt = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
5324
|
+
const roots = moduleRoots();
|
|
5325
|
+
const out = {};
|
|
5326
|
+
for (const packageName of MANAGED_PACKAGES) {
|
|
5327
|
+
for (const root of roots) {
|
|
5328
|
+
const packageJsonPath = path29.join(root, packageName, "package.json");
|
|
5329
|
+
const version = await readVersion(packageJsonPath);
|
|
5330
|
+
if (!version) continue;
|
|
5331
|
+
out[packageName] = { version, observedAt, path: packageJsonPath };
|
|
5332
|
+
break;
|
|
5333
|
+
}
|
|
5334
|
+
}
|
|
5335
|
+
return out;
|
|
5336
|
+
}
|
|
5337
|
+
|
|
4900
5338
|
// src/pipeline-tick.ts
|
|
4901
5339
|
async function completeFinishedWorkers(runId, args) {
|
|
4902
5340
|
const run = loadRun(runId);
|
|
4903
5341
|
const outcomes = [];
|
|
4904
5342
|
for (const name of Object.keys(run.workers || {})) {
|
|
4905
5343
|
const worker = readJson(
|
|
4906
|
-
|
|
5344
|
+
path30.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
|
|
4907
5345
|
void 0
|
|
4908
5346
|
);
|
|
4909
5347
|
if (!worker?.taskId || worker.localOnly) continue;
|
|
@@ -4934,12 +5372,14 @@ async function postOperatorTick(agentOsId, runId, resourceGate, args) {
|
|
|
4934
5372
|
const base = resolveBaseUrl(args.baseUrl ? String(args.baseUrl) : void 0);
|
|
4935
5373
|
const secret = await resolveCallbackSecretWithMint(args.secret ? String(args.secret) : void 0, agentOsId, { baseUrl: base });
|
|
4936
5374
|
const url = `${base}/api/agent-os/by-id/${encodeURIComponent(agentOsId)}/operator/tick`;
|
|
5375
|
+
const packageVersions = await collectInstalledPackageVersions();
|
|
4937
5376
|
const res = await postJson(url, secret, {
|
|
4938
5377
|
agentOsId,
|
|
4939
5378
|
runId,
|
|
4940
5379
|
ingestHarness: true,
|
|
4941
5380
|
harnessBoardSnapshot: buildRunBoard(runId),
|
|
4942
|
-
resourceGate
|
|
5381
|
+
resourceGate,
|
|
5382
|
+
packageVersions
|
|
4943
5383
|
});
|
|
4944
5384
|
return { ok: res.ok, httpStatus: res.status, response: res.response };
|
|
4945
5385
|
}
|
|
@@ -5042,6 +5482,231 @@ async function runDaemon(args) {
|
|
|
5042
5482
|
console.error(JSON.stringify({ event: "daemon_stop", runId, agentOsId }));
|
|
5043
5483
|
}
|
|
5044
5484
|
|
|
5485
|
+
// src/plan-progress.ts
|
|
5486
|
+
import path31 from "node:path";
|
|
5487
|
+
|
|
5488
|
+
// src/bounded-build/constants.ts
|
|
5489
|
+
var DEFAULT_BUILD_MEM_BUDGET_BYTES = 1536 * 1024 * 1024;
|
|
5490
|
+
var DEFAULT_BUILD_MEM_RESERVE_BYTES = 2 * 1024 * 1024 * 1024;
|
|
5491
|
+
var DEFAULT_NODE_OLD_SPACE_SIZE_MB = 1024;
|
|
5492
|
+
var DEFAULT_SYSTEMD_MEMORY_MAX = "1.5G";
|
|
5493
|
+
var DEFAULT_SYSTEMD_MEMORY_SWAP_MAX = "2G";
|
|
5494
|
+
|
|
5495
|
+
// src/bounded-build/node-options.ts
|
|
5496
|
+
var MAX_OLD_SPACE_RE = /--max-old-space-size=(\d+)/;
|
|
5497
|
+
function parsePositiveInt(value, fallback) {
|
|
5498
|
+
const n = Number(value);
|
|
5499
|
+
if (!Number.isFinite(n) || n <= 0) return fallback;
|
|
5500
|
+
return Math.floor(n);
|
|
5501
|
+
}
|
|
5502
|
+
function resolveNodeOldSpaceSizeMb() {
|
|
5503
|
+
return parsePositiveInt(process.env.KYNVER_NODE_OLD_SPACE_SIZE_MB, DEFAULT_NODE_OLD_SPACE_SIZE_MB);
|
|
5504
|
+
}
|
|
5505
|
+
function mergeNodeOptionsForBuildCheck(baseEnv = process.env) {
|
|
5506
|
+
const env = { ...baseEnv };
|
|
5507
|
+
if (process.env.KYNVER_NODE_OLD_SPACE_SIZE_MB === "0") {
|
|
5508
|
+
return env;
|
|
5509
|
+
}
|
|
5510
|
+
const existing = env.NODE_OPTIONS ?? "";
|
|
5511
|
+
if (MAX_OLD_SPACE_RE.test(existing)) {
|
|
5512
|
+
return env;
|
|
5513
|
+
}
|
|
5514
|
+
const mb = resolveNodeOldSpaceSizeMb();
|
|
5515
|
+
const flag = `--max-old-space-size=${mb}`;
|
|
5516
|
+
env.NODE_OPTIONS = existing.trim() ? `${existing.trim()} ${flag}` : flag;
|
|
5517
|
+
return env;
|
|
5518
|
+
}
|
|
5519
|
+
function formatNodeOptionsFlag(mb = resolveNodeOldSpaceSizeMb()) {
|
|
5520
|
+
return `--max-old-space-size=${mb}`;
|
|
5521
|
+
}
|
|
5522
|
+
|
|
5523
|
+
// src/bounded-build/systemd-wrap.ts
|
|
5524
|
+
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
5525
|
+
var systemdAvailableCache;
|
|
5526
|
+
function isSystemdRunAvailable() {
|
|
5527
|
+
if (process.env.KYNVER_BUILD_SKIP_SYSTEMD === "1" || process.env.KYNVER_BUILD_SKIP_SYSTEMD === "true") {
|
|
5528
|
+
return false;
|
|
5529
|
+
}
|
|
5530
|
+
if (systemdAvailableCache !== void 0) return systemdAvailableCache;
|
|
5531
|
+
if (process.platform !== "linux") {
|
|
5532
|
+
systemdAvailableCache = false;
|
|
5533
|
+
return false;
|
|
5534
|
+
}
|
|
5535
|
+
const res = spawnSync3("systemd-run", ["--version"], { encoding: "utf8", stdio: ["ignore", "ignore", "pipe"] });
|
|
5536
|
+
systemdAvailableCache = res.status === 0;
|
|
5537
|
+
return systemdAvailableCache;
|
|
5538
|
+
}
|
|
5539
|
+
function buildSystemdRunArgv(opts) {
|
|
5540
|
+
const memoryMax = opts.memoryMax ?? process.env.KYNVER_BUILD_SYSTEMD_MEMORY_MAX ?? DEFAULT_SYSTEMD_MEMORY_MAX;
|
|
5541
|
+
const memorySwapMax = opts.memorySwapMax ?? process.env.KYNVER_BUILD_SYSTEMD_MEMORY_SWAP_MAX ?? DEFAULT_SYSTEMD_MEMORY_SWAP_MAX;
|
|
5542
|
+
const argv = [
|
|
5543
|
+
"systemd-run",
|
|
5544
|
+
"--scope",
|
|
5545
|
+
"--collect",
|
|
5546
|
+
"-p",
|
|
5547
|
+
`MemoryMax=${memoryMax}`,
|
|
5548
|
+
"-p",
|
|
5549
|
+
`MemorySwapMax=${memorySwapMax}`
|
|
5550
|
+
];
|
|
5551
|
+
if (opts.cwd) {
|
|
5552
|
+
argv.push("--working-directory", opts.cwd);
|
|
5553
|
+
}
|
|
5554
|
+
argv.push("--", ...opts.command);
|
|
5555
|
+
return argv;
|
|
5556
|
+
}
|
|
5557
|
+
|
|
5558
|
+
// src/bounded-build/admission.ts
|
|
5559
|
+
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
5560
|
+
function positiveInt3(value, fallback) {
|
|
5561
|
+
const n = Number(value);
|
|
5562
|
+
if (!Number.isFinite(n) || n <= 0) return fallback;
|
|
5563
|
+
return Math.floor(n);
|
|
5564
|
+
}
|
|
5565
|
+
function resolveBuildAdmissionConfig(config = loadUserConfig()) {
|
|
5566
|
+
const envBudget = process.env.KYNVER_BUILD_MEM_BUDGET_BYTES ? positiveInt3(process.env.KYNVER_BUILD_MEM_BUDGET_BYTES, DEFAULT_BUILD_MEM_BUDGET_BYTES) : void 0;
|
|
5567
|
+
const envReserve = process.env.KYNVER_BUILD_MEM_RESERVE_BYTES ? positiveInt3(process.env.KYNVER_BUILD_MEM_RESERVE_BYTES, DEFAULT_BUILD_MEM_RESERVE_BYTES) : void 0;
|
|
5568
|
+
return {
|
|
5569
|
+
perBuildBudgetBytes: envBudget ?? positiveInt3(config.perWorkerMemBytes, DEFAULT_BUILD_MEM_BUDGET_BYTES),
|
|
5570
|
+
reserveBytes: envReserve ?? positiveInt3(config.memReserveBytes, DEFAULT_BUILD_MEM_RESERVE_BYTES)
|
|
5571
|
+
};
|
|
5572
|
+
}
|
|
5573
|
+
var activeBuilds = 0;
|
|
5574
|
+
function registerBuildStart() {
|
|
5575
|
+
activeBuilds += 1;
|
|
5576
|
+
}
|
|
5577
|
+
function registerBuildEnd() {
|
|
5578
|
+
activeBuilds = Math.max(0, activeBuilds - 1);
|
|
5579
|
+
}
|
|
5580
|
+
function assessBuildAdmission(opts = {}) {
|
|
5581
|
+
const cfg = { ...resolveBuildAdmissionConfig(), ...opts };
|
|
5582
|
+
const memAvailableBytes = opts.memAvailableBytes ?? readMemAvailableBytes();
|
|
5583
|
+
const requiredBytes = cfg.perBuildBudgetBytes + cfg.reserveBytes;
|
|
5584
|
+
const admitted = memAvailableBytes >= requiredBytes;
|
|
5585
|
+
return {
|
|
5586
|
+
admitted,
|
|
5587
|
+
memAvailableBytes,
|
|
5588
|
+
requiredBytes,
|
|
5589
|
+
activeBuilds,
|
|
5590
|
+
reason: admitted ? null : `insufficient memory: need ${requiredBytes} bytes available (budget ${cfg.perBuildBudgetBytes} + reserve ${cfg.reserveBytes}), have ${memAvailableBytes}`
|
|
5591
|
+
};
|
|
5592
|
+
}
|
|
5593
|
+
function sleepMs2(ms) {
|
|
5594
|
+
if (ms <= 0) return;
|
|
5595
|
+
spawnSync4(process.execPath, ["-e", `const d=Date.now()+${Math.floor(ms)};while(Date.now()<d);`], {
|
|
5596
|
+
stdio: "ignore"
|
|
5597
|
+
});
|
|
5598
|
+
}
|
|
5599
|
+
function waitForBuildAdmission(timeoutMs, pollMs = 2e3, opts = {}) {
|
|
5600
|
+
const deadline = Date.now() + Math.max(0, timeoutMs);
|
|
5601
|
+
let verdict = assessBuildAdmission({
|
|
5602
|
+
...opts,
|
|
5603
|
+
memAvailableBytes: opts.memAvailableBytes?.()
|
|
5604
|
+
});
|
|
5605
|
+
while (!verdict.admitted && Date.now() < deadline) {
|
|
5606
|
+
sleepMs2(Math.min(pollMs, deadline - Date.now()));
|
|
5607
|
+
verdict = assessBuildAdmission({
|
|
5608
|
+
...opts,
|
|
5609
|
+
memAvailableBytes: opts.memAvailableBytes?.()
|
|
5610
|
+
});
|
|
5611
|
+
}
|
|
5612
|
+
return verdict;
|
|
5613
|
+
}
|
|
5614
|
+
|
|
5615
|
+
// src/bounded-build/exec.ts
|
|
5616
|
+
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
5617
|
+
function envArgv(env) {
|
|
5618
|
+
const out = [];
|
|
5619
|
+
for (const [key, value] of Object.entries(env)) {
|
|
5620
|
+
if (value === void 0) continue;
|
|
5621
|
+
out.push(`${key}=${value}`);
|
|
5622
|
+
}
|
|
5623
|
+
return out;
|
|
5624
|
+
}
|
|
5625
|
+
function runSpawn(argv, opts) {
|
|
5626
|
+
const res = spawnSync5(argv[0], argv.slice(1), {
|
|
5627
|
+
cwd: opts.cwd,
|
|
5628
|
+
env: opts.env,
|
|
5629
|
+
encoding: "utf8",
|
|
5630
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
5631
|
+
shell: opts.shell,
|
|
5632
|
+
timeout: opts.timeoutMs
|
|
5633
|
+
});
|
|
5634
|
+
return {
|
|
5635
|
+
exitCode: res.status ?? 1,
|
|
5636
|
+
stdout: (res.stdout ?? "").trim(),
|
|
5637
|
+
stderr: (res.stderr ?? "").trim()
|
|
5638
|
+
};
|
|
5639
|
+
}
|
|
5640
|
+
function runBoundedBuildCheck(input) {
|
|
5641
|
+
const waitMs = input.waitForAdmissionMs ?? 6e5;
|
|
5642
|
+
const admission = waitMs > 0 ? waitForBuildAdmission(waitMs) : assessBuildAdmission();
|
|
5643
|
+
if (!admission.admitted) {
|
|
5644
|
+
return {
|
|
5645
|
+
ok: false,
|
|
5646
|
+
exitCode: 1,
|
|
5647
|
+
stdout: "",
|
|
5648
|
+
stderr: admission.reason ?? "build admission denied",
|
|
5649
|
+
admitted: false,
|
|
5650
|
+
wrappedWithSystemd: false,
|
|
5651
|
+
nodeOptionsFlag: formatNodeOptionsFlag(),
|
|
5652
|
+
admission,
|
|
5653
|
+
command: input.command
|
|
5654
|
+
};
|
|
5655
|
+
}
|
|
5656
|
+
const env = mergeNodeOptionsForBuildCheck({ ...process.env, ...input.env });
|
|
5657
|
+
const nodeOptionsFlag = formatNodeOptionsFlag();
|
|
5658
|
+
const useSystemd = isSystemdRunAvailable();
|
|
5659
|
+
registerBuildStart();
|
|
5660
|
+
try {
|
|
5661
|
+
let result;
|
|
5662
|
+
if (useSystemd) {
|
|
5663
|
+
const argv = buildSystemdRunArgv({
|
|
5664
|
+
cwd: input.cwd,
|
|
5665
|
+
command: ["/usr/bin/env", ...envArgv(env), "/bin/bash", "-lc", input.command]
|
|
5666
|
+
});
|
|
5667
|
+
result = runSpawn(argv, { cwd: input.cwd, env, timeoutMs: input.timeoutMs });
|
|
5668
|
+
} else {
|
|
5669
|
+
result = runSpawn([input.command], {
|
|
5670
|
+
cwd: input.cwd,
|
|
5671
|
+
env,
|
|
5672
|
+
shell: true,
|
|
5673
|
+
timeoutMs: input.timeoutMs
|
|
5674
|
+
});
|
|
5675
|
+
}
|
|
5676
|
+
return {
|
|
5677
|
+
ok: result.exitCode === 0,
|
|
5678
|
+
exitCode: result.exitCode,
|
|
5679
|
+
stdout: result.stdout,
|
|
5680
|
+
stderr: result.stderr,
|
|
5681
|
+
admitted: true,
|
|
5682
|
+
wrappedWithSystemd: useSystemd,
|
|
5683
|
+
nodeOptionsFlag,
|
|
5684
|
+
admission,
|
|
5685
|
+
command: input.command
|
|
5686
|
+
};
|
|
5687
|
+
} finally {
|
|
5688
|
+
registerBuildEnd();
|
|
5689
|
+
}
|
|
5690
|
+
}
|
|
5691
|
+
|
|
5692
|
+
// src/harness-verify.ts
|
|
5693
|
+
var DEFAULT_HARNESS_VERIFY_COMMANDS = ["npm run typecheck", "npm run test"];
|
|
5694
|
+
function runHarnessVerifyCommands(cwd, commands = DEFAULT_HARNESS_VERIFY_COMMANDS, opts = {}) {
|
|
5695
|
+
const steps = [];
|
|
5696
|
+
let passed = true;
|
|
5697
|
+
for (const command of commands) {
|
|
5698
|
+
const result = runBoundedBuildCheck({
|
|
5699
|
+
cwd,
|
|
5700
|
+
command,
|
|
5701
|
+
waitForAdmissionMs: opts.waitForAdmissionMs,
|
|
5702
|
+
timeoutMs: opts.timeoutMs
|
|
5703
|
+
});
|
|
5704
|
+
steps.push({ command, result });
|
|
5705
|
+
if (!result.ok) passed = false;
|
|
5706
|
+
}
|
|
5707
|
+
return { passed, steps };
|
|
5708
|
+
}
|
|
5709
|
+
|
|
5045
5710
|
// src/plan-progress.ts
|
|
5046
5711
|
function parseEvidenceArg(raw) {
|
|
5047
5712
|
const idx = raw.indexOf(":");
|
|
@@ -5102,8 +5767,23 @@ async function emitPlanProgress(args) {
|
|
|
5102
5767
|
}
|
|
5103
5768
|
console.log(JSON.stringify(parsed, null, 2));
|
|
5104
5769
|
}
|
|
5770
|
+
function verifyPlanLocal(args) {
|
|
5771
|
+
const worktree = required(args.worktree ? String(args.worktree) : void 0, "worktree");
|
|
5772
|
+
const cwd = path31.resolve(worktree);
|
|
5773
|
+
const summary = runHarnessVerifyCommands(cwd);
|
|
5774
|
+
const emitJson = args.json === true || args.json === "true";
|
|
5775
|
+
const payload = { passed: summary.passed, worktree: cwd, steps: summary.steps };
|
|
5776
|
+
if (emitJson) console.log(JSON.stringify(payload, null, 2));
|
|
5777
|
+
else console.log(summary.passed ? "local plan verify passed" : "local plan verify failed");
|
|
5778
|
+
if (!summary.passed) process.exit(1);
|
|
5779
|
+
}
|
|
5105
5780
|
async function verifyPlan(args) {
|
|
5106
5781
|
const planId = required(args.plan ? String(args.plan) : void 0, "plan");
|
|
5782
|
+
const localOnly = args.local === true || args.local === "true";
|
|
5783
|
+
if (localOnly) {
|
|
5784
|
+
verifyPlanLocal(args);
|
|
5785
|
+
return;
|
|
5786
|
+
}
|
|
5107
5787
|
const slug = loadUserConfig().agentOsSlug;
|
|
5108
5788
|
if (!slug) {
|
|
5109
5789
|
console.error("requires agentOsSlug in ~/.kynver/config.json for verify (session route)");
|
|
@@ -5137,6 +5817,52 @@ async function verifyPlan(args) {
|
|
|
5137
5817
|
console.log(JSON.stringify(parsed, null, 2));
|
|
5138
5818
|
}
|
|
5139
5819
|
|
|
5820
|
+
// src/harness-verify-cli.ts
|
|
5821
|
+
import path32 from "node:path";
|
|
5822
|
+
function runHarnessVerifyCli(args) {
|
|
5823
|
+
const cwd = path32.resolve(required(args.worktree ? String(args.worktree) : void 0, "worktree"));
|
|
5824
|
+
const emitJson = args.json === true || args.json === "true" || args.emitJson === true || args.emitJson === "true";
|
|
5825
|
+
const commands = [];
|
|
5826
|
+
const rawCmd = args.command;
|
|
5827
|
+
if (Array.isArray(rawCmd)) {
|
|
5828
|
+
for (const c of rawCmd) commands.push(String(c));
|
|
5829
|
+
} else if (typeof rawCmd === "string") {
|
|
5830
|
+
commands.push(rawCmd);
|
|
5831
|
+
}
|
|
5832
|
+
const summary = runHarnessVerifyCommands(
|
|
5833
|
+
cwd,
|
|
5834
|
+
commands.length ? commands : DEFAULT_HARNESS_VERIFY_COMMANDS,
|
|
5835
|
+
{
|
|
5836
|
+
waitForAdmissionMs: args.waitForAdmissionMs ? Number(args.waitForAdmissionMs) : void 0,
|
|
5837
|
+
timeoutMs: args.timeoutMs ? Number(args.timeoutMs) : void 0
|
|
5838
|
+
}
|
|
5839
|
+
);
|
|
5840
|
+
const payload = {
|
|
5841
|
+
passed: summary.passed,
|
|
5842
|
+
worktree: cwd,
|
|
5843
|
+
steps: summary.steps.map((s) => ({
|
|
5844
|
+
command: s.command,
|
|
5845
|
+
ok: s.result.ok,
|
|
5846
|
+
exitCode: s.result.exitCode,
|
|
5847
|
+
admitted: s.result.admitted,
|
|
5848
|
+
wrappedWithSystemd: s.result.wrappedWithSystemd,
|
|
5849
|
+
nodeOptionsFlag: s.result.nodeOptionsFlag,
|
|
5850
|
+
admission: s.result.admission,
|
|
5851
|
+
stderr: s.result.stderr.slice(0, 4e3)
|
|
5852
|
+
}))
|
|
5853
|
+
};
|
|
5854
|
+
if (emitJson) {
|
|
5855
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
5856
|
+
} else {
|
|
5857
|
+
console.log(summary.passed ? "harness verify passed" : "harness verify failed");
|
|
5858
|
+
for (const step of payload.steps) {
|
|
5859
|
+
console.log(` ${step.ok ? "\u2713" : "\u2717"} ${step.command} (exit ${step.exitCode}, systemd=${step.wrappedWithSystemd})`);
|
|
5860
|
+
if (!step.ok && step.stderr) console.log(` ${step.stderr.split("\n")[0]}`);
|
|
5861
|
+
}
|
|
5862
|
+
}
|
|
5863
|
+
process.exit(summary.passed ? 0 : 1);
|
|
5864
|
+
}
|
|
5865
|
+
|
|
5140
5866
|
// src/plan-persist-cli.ts
|
|
5141
5867
|
import { readFileSync as readFileSync7 } from "node:fs";
|
|
5142
5868
|
var OPERATIONS = ["create", "add_version", "update_metadata"];
|
|
@@ -5238,7 +5964,7 @@ function runCleanupCli(args) {
|
|
|
5238
5964
|
}
|
|
5239
5965
|
|
|
5240
5966
|
// src/monitor/monitor.service.ts
|
|
5241
|
-
import
|
|
5967
|
+
import path34 from "node:path";
|
|
5242
5968
|
|
|
5243
5969
|
// src/monitor/monitor.classify.ts
|
|
5244
5970
|
function expectedLeaseOwner(runId) {
|
|
@@ -5295,10 +6021,10 @@ function classifyWorkerHealth(input) {
|
|
|
5295
6021
|
|
|
5296
6022
|
// src/monitor/monitor.store.ts
|
|
5297
6023
|
import { existsSync as existsSync17, mkdirSync as mkdirSync6, readdirSync as readdirSync7, unlinkSync as unlinkSync2 } from "node:fs";
|
|
5298
|
-
import
|
|
6024
|
+
import path33 from "node:path";
|
|
5299
6025
|
function monitorsDir() {
|
|
5300
6026
|
const { harnessRoot } = getHarnessPaths();
|
|
5301
|
-
const dir =
|
|
6027
|
+
const dir = path33.join(harnessRoot, "monitors");
|
|
5302
6028
|
mkdirSync6(dir, { recursive: true });
|
|
5303
6029
|
return dir;
|
|
5304
6030
|
}
|
|
@@ -5306,7 +6032,7 @@ function monitorIdFor(runId, workerName) {
|
|
|
5306
6032
|
return workerName ? `${safeSlug(runId)}--${safeSlug(workerName)}` : safeSlug(runId);
|
|
5307
6033
|
}
|
|
5308
6034
|
function monitorPath(monitorId) {
|
|
5309
|
-
return
|
|
6035
|
+
return path33.join(monitorsDir(), `${monitorId}.json`);
|
|
5310
6036
|
}
|
|
5311
6037
|
function loadMonitorSession(monitorId) {
|
|
5312
6038
|
return readJson(monitorPath(monitorId), void 0);
|
|
@@ -5327,7 +6053,7 @@ function listMonitorSessions() {
|
|
|
5327
6053
|
for (const name of readdirSync7(dir)) {
|
|
5328
6054
|
if (!name.endsWith(".json")) continue;
|
|
5329
6055
|
const session = readJson(
|
|
5330
|
-
|
|
6056
|
+
path33.join(dir, name),
|
|
5331
6057
|
void 0
|
|
5332
6058
|
);
|
|
5333
6059
|
if (!session?.monitorId) continue;
|
|
@@ -5418,7 +6144,7 @@ async function fetchTaskLeasesForWorkers(input) {
|
|
|
5418
6144
|
// src/monitor/monitor.service.ts
|
|
5419
6145
|
function workerRecord2(runId, name) {
|
|
5420
6146
|
return readJson(
|
|
5421
|
-
|
|
6147
|
+
path34.join(runDirectory(runId), "workers", safeSlug(name), "worker.json"),
|
|
5422
6148
|
void 0
|
|
5423
6149
|
);
|
|
5424
6150
|
}
|
|
@@ -5621,17 +6347,17 @@ async function runMonitorLoop(args) {
|
|
|
5621
6347
|
// src/monitor/monitor-spawn.ts
|
|
5622
6348
|
import { spawn as spawn4 } from "node:child_process";
|
|
5623
6349
|
import { closeSync as closeSync4, existsSync as existsSync18, openSync as openSync4 } from "node:fs";
|
|
5624
|
-
import
|
|
6350
|
+
import path35 from "node:path";
|
|
5625
6351
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
5626
6352
|
function resolveDefaultCliPath2() {
|
|
5627
|
-
return
|
|
6353
|
+
return path35.join(fileURLToPath2(new URL(".", import.meta.url)), "..", "cli.js");
|
|
5628
6354
|
}
|
|
5629
6355
|
function spawnMonitorSidecar(opts) {
|
|
5630
6356
|
const cliPath = opts.cliPath ?? resolveDefaultCliPath2();
|
|
5631
6357
|
if (!existsSync18(cliPath)) return void 0;
|
|
5632
6358
|
const monitorId = monitorIdFor(opts.runId, opts.workerName);
|
|
5633
6359
|
const { harnessRoot } = getHarnessPaths();
|
|
5634
|
-
const logPath =
|
|
6360
|
+
const logPath = path35.join(harnessRoot, "monitors", `${monitorId}.log`);
|
|
5635
6361
|
let logFd;
|
|
5636
6362
|
try {
|
|
5637
6363
|
logFd = openSync4(logPath, "a");
|
|
@@ -5787,16 +6513,16 @@ function handleCliVersionFlag(argv, moduleUrl = import.meta.url, binName) {
|
|
|
5787
6513
|
}
|
|
5788
6514
|
|
|
5789
6515
|
// src/doctor/runtime-takeover.ts
|
|
5790
|
-
import
|
|
6516
|
+
import path37 from "node:path";
|
|
5791
6517
|
|
|
5792
6518
|
// src/doctor/runtime-takeover.probes.ts
|
|
5793
6519
|
import { accessSync, constants, existsSync as existsSync20, readFileSync as readFileSync9 } from "node:fs";
|
|
5794
|
-
import { homedir as
|
|
5795
|
-
import
|
|
5796
|
-
import { spawnSync as
|
|
6520
|
+
import { homedir as homedir6 } from "node:os";
|
|
6521
|
+
import path36 from "node:path";
|
|
6522
|
+
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
5797
6523
|
function captureCommand(bin, args) {
|
|
5798
6524
|
try {
|
|
5799
|
-
const res =
|
|
6525
|
+
const res = spawnSync6(bin, args, { encoding: "utf8" });
|
|
5800
6526
|
const stdout = (res.stdout || "").trim();
|
|
5801
6527
|
const stderr = (res.stderr || "").trim();
|
|
5802
6528
|
const ok = res.status === 0;
|
|
@@ -5834,10 +6560,10 @@ var defaultRuntimeTakeoverProbes = {
|
|
|
5834
6560
|
commandOnPath: (bin) => captureCommand(process.platform === "win32" ? "where" : "which", [bin]),
|
|
5835
6561
|
kynverVersion: (bin) => captureCommand(bin, ["--version"]),
|
|
5836
6562
|
loadConfig: () => loadUserConfig(),
|
|
5837
|
-
configFilePath: () =>
|
|
5838
|
-
credentialsFilePath: () =>
|
|
6563
|
+
configFilePath: () => path36.join(homedir6(), ".kynver", "config.json"),
|
|
6564
|
+
credentialsFilePath: () => path36.join(homedir6(), ".kynver", "credentials"),
|
|
5839
6565
|
readCredentials: () => {
|
|
5840
|
-
const credPath =
|
|
6566
|
+
const credPath = path36.join(homedir6(), ".kynver", "credentials");
|
|
5841
6567
|
if (!existsSync20(credPath)) {
|
|
5842
6568
|
return { hasApiKey: false };
|
|
5843
6569
|
}
|
|
@@ -5863,7 +6589,7 @@ var defaultRuntimeTakeoverProbes = {
|
|
|
5863
6589
|
kynverSchedulerProvider: process.env.KYNVER_SCHEDULER_PROVIDER?.trim() || void 0
|
|
5864
6590
|
}),
|
|
5865
6591
|
harnessRoot: () => resolveHarnessRoot(),
|
|
5866
|
-
legacyOpenclawHarnessRoot: () =>
|
|
6592
|
+
legacyOpenclawHarnessRoot: () => path36.join(homedir6(), ".openclaw", "harness"),
|
|
5867
6593
|
pathExists: (target) => existsSync20(target),
|
|
5868
6594
|
pathWritable: (target) => isWritable(target),
|
|
5869
6595
|
vercelVersion: () => captureCommand("vercel", ["--version"]),
|
|
@@ -6049,8 +6775,8 @@ function assessVercelCli(probes) {
|
|
|
6049
6775
|
}
|
|
6050
6776
|
function assessHarnessDirs(probes) {
|
|
6051
6777
|
const harnessRoot = probes.harnessRoot();
|
|
6052
|
-
const runsDir =
|
|
6053
|
-
const worktreesDir =
|
|
6778
|
+
const runsDir = path37.join(harnessRoot, "runs");
|
|
6779
|
+
const worktreesDir = path37.join(harnessRoot, "worktrees");
|
|
6054
6780
|
const displayHarnessRoot = redactHomePath(harnessRoot);
|
|
6055
6781
|
const displayRunsDir = redactHomePath(runsDir);
|
|
6056
6782
|
const displayWorktreesDir = redactHomePath(worktreesDir);
|
|
@@ -6202,6 +6928,37 @@ function runRuntimeTakeoverDoctorCli() {
|
|
|
6202
6928
|
}
|
|
6203
6929
|
}
|
|
6204
6930
|
|
|
6931
|
+
// src/command-center-contract-cli.ts
|
|
6932
|
+
async function runCommandCenterContractCli(args) {
|
|
6933
|
+
const config = loadUserConfig();
|
|
6934
|
+
const agentOsId = (args.agentOsId ? String(args.agentOsId) : config.agentOsId) || "";
|
|
6935
|
+
if (!agentOsId) {
|
|
6936
|
+
console.error("requires --agent-os-id or agentOsId in ~/.kynver/config.json");
|
|
6937
|
+
process.exit(1);
|
|
6938
|
+
}
|
|
6939
|
+
const base = resolveBaseUrl(args.baseUrl ? String(args.baseUrl) : config.apiBaseUrl);
|
|
6940
|
+
const secret = await resolveCallbackSecretWithMint(
|
|
6941
|
+
args.secret ? String(args.secret) : void 0,
|
|
6942
|
+
agentOsId,
|
|
6943
|
+
{ baseUrl: base }
|
|
6944
|
+
);
|
|
6945
|
+
const qs = new URLSearchParams();
|
|
6946
|
+
if (typeof args.since === "string" && args.since.trim()) qs.set("since", args.since.trim());
|
|
6947
|
+
if (args.limit != null && String(args.limit).trim()) {
|
|
6948
|
+
const n = Number(args.limit);
|
|
6949
|
+
if (Number.isFinite(n) && n > 0) qs.set("limit", String(Math.floor(n)));
|
|
6950
|
+
}
|
|
6951
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
6952
|
+
const url = `${base}/api/agent-os/by-id/${encodeURIComponent(agentOsId)}/command-center/dashboard-contract${suffix}`;
|
|
6953
|
+
const res = await getJson(url, secret);
|
|
6954
|
+
if (!res.ok) {
|
|
6955
|
+
console.error(`dashboard-contract GET failed: HTTP ${res.status}`);
|
|
6956
|
+
if (res.response) console.error(JSON.stringify(res.response, null, 2));
|
|
6957
|
+
process.exit(1);
|
|
6958
|
+
}
|
|
6959
|
+
console.log(JSON.stringify(res.response, null, 2));
|
|
6960
|
+
}
|
|
6961
|
+
|
|
6205
6962
|
// src/cli.ts
|
|
6206
6963
|
function isHelpFlag(arg) {
|
|
6207
6964
|
return arg === "help" || arg === "--help" || arg === "-h";
|
|
@@ -6223,7 +6980,7 @@ function usage(code = 0) {
|
|
|
6223
6980
|
" kynver run create --repo /path/repo [--name name] [--base origin/main]",
|
|
6224
6981
|
" kynver run list",
|
|
6225
6982
|
" 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 /]",
|
|
6983
|
+
" 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
6984
|
" kynver run sweep --run RUN_ID --agent-os-id AOS_ID [--base-url URL] [--secret SECRET] [--grace-ms MS]",
|
|
6228
6985
|
' 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
6986
|
" kynver worker status --run RUN_ID --name worker",
|
|
@@ -6233,7 +6990,8 @@ function usage(code = 0) {
|
|
|
6233
6990
|
" 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
6991
|
" kynver run reconcile",
|
|
6235
6992
|
" 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]",
|
|
6993
|
+
" kynver plan verify --plan PLAN_ID [--worktree PATH] [--task TASK_ID] [--human-override] [--local]",
|
|
6994
|
+
" kynver harness verify --worktree PATH [--command CMD] [--json] [--wait-for-admission-ms MS] [--timeout-ms MS]",
|
|
6237
6995
|
" 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
6996
|
" kynver plan outbox list",
|
|
6239
6997
|
" kynver plan outbox drain [--max N] [--id OUTBOX_ID]",
|
|
@@ -6245,7 +7003,8 @@ function usage(code = 0) {
|
|
|
6245
7003
|
" kynver monitor tick --run RUN_ID [--name worker] [--agent-os-id AOS_ID] [--auto-complete] [--renew-leases]",
|
|
6246
7004
|
" kynver monitor auto-complete --run RUN_ID --name worker [--agent-os-id AOS_ID] [--base-url URL] [--secret SECRET]",
|
|
6247
7005
|
" 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"
|
|
7006
|
+
" kynver doctor runtime-takeover",
|
|
7007
|
+
" kynver board contract [--agent-os-id ID] [--base-url URL] [--since ISO] [--limit N]"
|
|
6249
7008
|
].join("\n")
|
|
6250
7009
|
);
|
|
6251
7010
|
process.exit(code);
|
|
@@ -6256,7 +7015,7 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
6256
7015
|
const scope = argv.shift();
|
|
6257
7016
|
let action;
|
|
6258
7017
|
let rest;
|
|
6259
|
-
if (scope === "run" || scope === "worker" || scope === "plan" || scope === "runner" || scope === "monitor" || scope === "doctor") {
|
|
7018
|
+
if (scope === "run" || scope === "worker" || scope === "plan" || scope === "runner" || scope === "harness" || scope === "monitor" || scope === "doctor" || scope === "board") {
|
|
6260
7019
|
action = argv.shift();
|
|
6261
7020
|
rest = argv;
|
|
6262
7021
|
} else {
|
|
@@ -6273,6 +7032,7 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
6273
7032
|
if (scope === "daemon") return void await runDaemon(args);
|
|
6274
7033
|
if (scope === "plan" && action === "progress") return void await emitPlanProgress(args);
|
|
6275
7034
|
if (scope === "plan" && action === "verify") return void await verifyPlan(args);
|
|
7035
|
+
if (scope === "harness" && action === "verify") return runHarnessVerifyCli(args);
|
|
6276
7036
|
if (scope === "plan" && action === "persist") return void await runPlanPersist(args);
|
|
6277
7037
|
if (scope === "plan" && action === "outbox") {
|
|
6278
7038
|
const outboxAction = rest.shift();
|
|
@@ -6282,6 +7042,9 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
6282
7042
|
}
|
|
6283
7043
|
if (scope === "cleanup") return runCleanupCli(args);
|
|
6284
7044
|
if (scope === "doctor" && action === "runtime-takeover") return runRuntimeTakeoverDoctorCli();
|
|
7045
|
+
if (scope === "board" && action === "contract") {
|
|
7046
|
+
return void await runCommandCenterContractCli(args);
|
|
7047
|
+
}
|
|
6285
7048
|
if (scope === "run" && action === "create") return createRun(args);
|
|
6286
7049
|
if (scope === "run" && action === "list") return listRuns();
|
|
6287
7050
|
if (scope === "run" && action === "status") return runStatus(args);
|