@kynver-app/runtime 0.1.42 → 0.1.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +789 -74
- 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-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 +829 -78
- 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 +26 -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 +161 -0
- package/dist/stream.d.ts +20 -0
- package/dist/supervisor.d.ts +25 -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);
|
|
@@ -1945,12 +2209,12 @@ function resolveAgentBin() {
|
|
|
1945
2209
|
return "agent";
|
|
1946
2210
|
}
|
|
1947
2211
|
function cursorWorkerEnv(agentBin, spawnTarget) {
|
|
1948
|
-
return {
|
|
2212
|
+
return scrubWorkerEnv({
|
|
1949
2213
|
...process.env,
|
|
1950
2214
|
CI: "1",
|
|
1951
2215
|
NO_COLOR: "1",
|
|
1952
2216
|
...spawnTarget.bundledVersionDir ? { CURSOR_INVOKED_AS: path9.basename(agentBin) || "agent.cmd" } : {}
|
|
1953
|
-
};
|
|
2217
|
+
});
|
|
1954
2218
|
}
|
|
1955
2219
|
var cursorProvider = {
|
|
1956
2220
|
name: "cursor",
|
|
@@ -2043,6 +2307,39 @@ function persistCompletionAck(worker, runId, fields) {
|
|
|
2043
2307
|
// src/worker-ops.ts
|
|
2044
2308
|
import path11 from "node:path";
|
|
2045
2309
|
|
|
2310
|
+
// src/completion-response.ts
|
|
2311
|
+
function asRecord(value) {
|
|
2312
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
2313
|
+
}
|
|
2314
|
+
function asString(value) {
|
|
2315
|
+
if (typeof value !== "string") return null;
|
|
2316
|
+
const trimmed = value.trim();
|
|
2317
|
+
return trimmed.length ? trimmed : null;
|
|
2318
|
+
}
|
|
2319
|
+
var ADVANCED_OUTCOMES = /* @__PURE__ */ new Set([
|
|
2320
|
+
"review_scheduled",
|
|
2321
|
+
"review_already_scheduled"
|
|
2322
|
+
]);
|
|
2323
|
+
function summarizeHarnessCompletionResponse(parsed) {
|
|
2324
|
+
const record = asRecord(parsed);
|
|
2325
|
+
if (!record) {
|
|
2326
|
+
return { routeOutcome: null, taskAdvanced: false, detail: null };
|
|
2327
|
+
}
|
|
2328
|
+
const outcome = asString(record.outcome);
|
|
2329
|
+
const detail = asString(record.detail) ?? asString(record.error);
|
|
2330
|
+
const task = asRecord(record.task);
|
|
2331
|
+
const taskStatus = task ? asString(task.status) : null;
|
|
2332
|
+
const taskAdvanced = outcome !== null && ADVANCED_OUTCOMES.has(outcome) || taskStatus === "awaiting_review" || taskStatus === "done";
|
|
2333
|
+
return {
|
|
2334
|
+
routeOutcome: outcome,
|
|
2335
|
+
taskAdvanced,
|
|
2336
|
+
detail
|
|
2337
|
+
};
|
|
2338
|
+
}
|
|
2339
|
+
function completionPostSucceeded(summary) {
|
|
2340
|
+
return summary.taskAdvanced;
|
|
2341
|
+
}
|
|
2342
|
+
|
|
2046
2343
|
// src/pr-handoff/pr-handoff-assess.ts
|
|
2047
2344
|
var REVIEW_LANE_RULE = /^(lane:)?(review|deep_review|planning|landing)(:|$)/i;
|
|
2048
2345
|
function trimOrNull4(value) {
|
|
@@ -2103,6 +2400,36 @@ function buildPrHandoffSnapshotFromStatus(status, extras) {
|
|
|
2103
2400
|
|
|
2104
2401
|
// src/pr-handoff/pr-handoff-gh.ts
|
|
2105
2402
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
2403
|
+
|
|
2404
|
+
// src/github-repo.ts
|
|
2405
|
+
function parseGithubOwnerRepo(remoteUrl) {
|
|
2406
|
+
const trimmed = remoteUrl.trim();
|
|
2407
|
+
if (!trimmed) return null;
|
|
2408
|
+
const ssh = trimmed.match(/^git@github\.com:([^/]+\/[^/\s]+?)(?:\.git)?$/i);
|
|
2409
|
+
if (ssh) return normalizeOwnerRepo(ssh[1]);
|
|
2410
|
+
const scp = trimmed.match(/^ssh:\/\/git@github\.com\/([^/]+\/[^/\s]+?)(?:\.git)?$/i);
|
|
2411
|
+
if (scp) return normalizeOwnerRepo(scp[1]);
|
|
2412
|
+
try {
|
|
2413
|
+
const url = new URL(trimmed.includes("://") ? trimmed : `https://${trimmed}`);
|
|
2414
|
+
if (url.hostname.toLowerCase() !== "github.com") return null;
|
|
2415
|
+
const parts = url.pathname.replace(/^\/+|\/+$/g, "").split("/");
|
|
2416
|
+
if (parts.length < 2) return null;
|
|
2417
|
+
const [owner, repo] = parts;
|
|
2418
|
+
if (!owner || !repo) return null;
|
|
2419
|
+
return `${owner}/${repo.replace(/\.git$/i, "")}`;
|
|
2420
|
+
} catch {
|
|
2421
|
+
return null;
|
|
2422
|
+
}
|
|
2423
|
+
}
|
|
2424
|
+
function normalizeOwnerRepo(value) {
|
|
2425
|
+
const parts = value.split("/").filter(Boolean);
|
|
2426
|
+
if (parts.length < 2) return null;
|
|
2427
|
+
const owner = parts[0];
|
|
2428
|
+
const repo = parts[1].replace(/\.git$/i, "");
|
|
2429
|
+
return owner && repo ? `${owner}/${repo}` : null;
|
|
2430
|
+
}
|
|
2431
|
+
|
|
2432
|
+
// src/pr-handoff/pr-handoff-gh.ts
|
|
2106
2433
|
function capture(bin, cwd, args) {
|
|
2107
2434
|
try {
|
|
2108
2435
|
const res = spawnSync2(bin, args, { cwd, encoding: "utf8" });
|
|
@@ -2125,21 +2452,13 @@ var defaultPrHandoffExec = {
|
|
|
2125
2452
|
git: (cwd, args) => gitCapture(cwd, args),
|
|
2126
2453
|
gh: (cwd, args) => capture("gh", cwd, args)
|
|
2127
2454
|
};
|
|
2128
|
-
function parseGithubRepo(remoteUrl) {
|
|
2129
|
-
const trimmed = remoteUrl.trim();
|
|
2130
|
-
const ssh = trimmed.match(/git@github\.com:([^/]+\/[^/.]+)(?:\.git)?/i);
|
|
2131
|
-
if (ssh) return ssh[1];
|
|
2132
|
-
const https = trimmed.match(/github\.com[/:]([^/]+\/[^/.]+?)(?:\.git)?/i);
|
|
2133
|
-
if (https) return https[1];
|
|
2134
|
-
return null;
|
|
2135
|
-
}
|
|
2136
2455
|
function firstLine(text) {
|
|
2137
2456
|
return text.split("\n").map((l) => l.trim()).find(Boolean) ?? "";
|
|
2138
2457
|
}
|
|
2139
2458
|
function resolveGithubRepo(worktreePath, exec) {
|
|
2140
2459
|
const remote = exec.git(worktreePath, ["remote", "get-url", "origin"]);
|
|
2141
2460
|
if (remote.status !== 0) return null;
|
|
2142
|
-
return
|
|
2461
|
+
return parseGithubOwnerRepo(remote.stdout);
|
|
2143
2462
|
}
|
|
2144
2463
|
function resolveHeadCommit(worktreePath, exec) {
|
|
2145
2464
|
const head = exec.git(worktreePath, ["rev-parse", "HEAD"]);
|
|
@@ -2473,10 +2792,10 @@ function completionErrorText(parsed) {
|
|
|
2473
2792
|
}
|
|
2474
2793
|
return void 0;
|
|
2475
2794
|
}
|
|
2476
|
-
function
|
|
2795
|
+
function asRecord2(value) {
|
|
2477
2796
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
2478
2797
|
}
|
|
2479
|
-
function
|
|
2798
|
+
function asString2(value) {
|
|
2480
2799
|
if (typeof value !== "string") return null;
|
|
2481
2800
|
const trimmed = value.trim();
|
|
2482
2801
|
return trimmed.length ? trimmed : null;
|
|
@@ -2596,7 +2915,27 @@ async function tryCompleteWorker(args) {
|
|
|
2596
2915
|
}
|
|
2597
2916
|
}
|
|
2598
2917
|
if (result.ok) {
|
|
2918
|
+
const summary = summarizeHarnessCompletionResponse(result.parsed);
|
|
2919
|
+
if (!completionPostSucceeded(summary)) {
|
|
2920
|
+
const detail2 = summary.detail ?? (summary.routeOutcome ? `harness completion returned ${summary.routeOutcome}` : "harness completion did not advance the linked task");
|
|
2921
|
+
const reason2 = `completion acknowledged but board not advanced: ${detail2}`;
|
|
2922
|
+
persistCompletionBlocker(worker, reason2);
|
|
2923
|
+
const ack2 = {
|
|
2924
|
+
completionReportedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2925
|
+
completionOutcome: "rejected",
|
|
2926
|
+
completionResponse: result.parsed
|
|
2927
|
+
};
|
|
2928
|
+
persistCompletionAck(worker, worker.runId, ack2);
|
|
2929
|
+
return {
|
|
2930
|
+
ok: false,
|
|
2931
|
+
httpStatus: result.status,
|
|
2932
|
+
response: result.parsed,
|
|
2933
|
+
reason: reason2,
|
|
2934
|
+
completionBlocked: true
|
|
2935
|
+
};
|
|
2936
|
+
}
|
|
2599
2937
|
persistCompletionBlocker(worker, void 0);
|
|
2938
|
+
const routeOutcome = summary.routeOutcome ?? "acknowledged";
|
|
2600
2939
|
const ack = {
|
|
2601
2940
|
completionReportedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2602
2941
|
completionOutcome: "acknowledged",
|
|
@@ -2609,6 +2948,7 @@ async function tryCompleteWorker(args) {
|
|
|
2609
2948
|
ok: true,
|
|
2610
2949
|
httpStatus: result.status,
|
|
2611
2950
|
response: result.parsed,
|
|
2951
|
+
reason: routeOutcome,
|
|
2612
2952
|
...prUrl ? { prHandoff: { prUrl } } : {}
|
|
2613
2953
|
};
|
|
2614
2954
|
}
|
|
@@ -2701,13 +3041,13 @@ function buildRunBoard(runId) {
|
|
|
2701
3041
|
const completionBlocker = typeof rawBlocker === "string" && rawBlocker ? rawBlocker : void 0;
|
|
2702
3042
|
const boardStatus = completionBlocker ? "blocked" : status.status;
|
|
2703
3043
|
const boardAttention = completionBlocker ? "blocked" : status.attention.state;
|
|
2704
|
-
const completionResponse =
|
|
2705
|
-
const completionTask =
|
|
2706
|
-
const completionOutcome =
|
|
2707
|
-
const completionRouteStatus =
|
|
3044
|
+
const completionResponse = asRecord2(worker.completionResponse);
|
|
3045
|
+
const completionTask = asRecord2(completionResponse?.task);
|
|
3046
|
+
const completionOutcome = asString2(completionResponse?.outcome);
|
|
3047
|
+
const completionRouteStatus = asString2(completionResponse?.status);
|
|
2708
3048
|
const completionWarnings = Array.isArray(completionResponse?.warnings) ? completionResponse.warnings.filter((w) => typeof w === "string" && w.trim().length > 0) : [];
|
|
2709
|
-
const prUrl =
|
|
2710
|
-
const completionReportedAt =
|
|
3049
|
+
const prUrl = asString2(completionTask?.prUrl) ?? asString2(completionResponse?.prUrl);
|
|
3050
|
+
const completionReportedAt = asString2(worker.completionReportedAt);
|
|
2711
3051
|
const lifecycleStage = deriveLifecycleStage({
|
|
2712
3052
|
finished: isFinishedWorkerStatus(status),
|
|
2713
3053
|
completionBlocker,
|
|
@@ -3898,7 +4238,8 @@ async function dispatchRun(args) {
|
|
|
3898
4238
|
harnessBoardSnapshot: buildRunBoard(run.id),
|
|
3899
4239
|
...args.lane ? { lane: String(args.lane) } : {},
|
|
3900
4240
|
executor: args.executor ? String(args.executor) : "harness",
|
|
3901
|
-
...args.diskPath ? { diskPath: String(args.diskPath) } : {}
|
|
4241
|
+
...args.diskPath ? { diskPath: String(args.diskPath) } : {},
|
|
4242
|
+
...args.targetTaskId ? { targetTaskId: String(args.targetTaskId) } : {}
|
|
3902
4243
|
};
|
|
3903
4244
|
const dispatch = await postJsonWithCredentialRefresh(dispatchUrl, secret, body, { agentOsId, baseUrl: base });
|
|
3904
4245
|
const responseBody = dispatch.response;
|
|
@@ -4191,7 +4532,7 @@ function failExists(message) {
|
|
|
4191
4532
|
}
|
|
4192
4533
|
|
|
4193
4534
|
// src/pipeline-tick.ts
|
|
4194
|
-
import
|
|
4535
|
+
import path30 from "node:path";
|
|
4195
4536
|
|
|
4196
4537
|
// src/pipeline-dispatch.ts
|
|
4197
4538
|
var RESERVED_REVIEW_STARTS = 1;
|
|
@@ -4897,13 +5238,62 @@ function isPipelineCleanupEnabled() {
|
|
|
4897
5238
|
return process.env.KYNVER_PIPELINE_CLEANUP !== "0";
|
|
4898
5239
|
}
|
|
4899
5240
|
|
|
5241
|
+
// src/installed-package-versions.ts
|
|
5242
|
+
import { readFile } from "node:fs/promises";
|
|
5243
|
+
import { homedir as homedir5 } from "node:os";
|
|
5244
|
+
import path29 from "node:path";
|
|
5245
|
+
var MANAGED_PACKAGES = [
|
|
5246
|
+
"@kynver-app/runtime",
|
|
5247
|
+
"@kynver-app/openclaw-agent-os",
|
|
5248
|
+
"@kynver-app/mcp-agent-os"
|
|
5249
|
+
];
|
|
5250
|
+
function trim(value) {
|
|
5251
|
+
const out = value?.trim();
|
|
5252
|
+
return out ? out : null;
|
|
5253
|
+
}
|
|
5254
|
+
function unique(values) {
|
|
5255
|
+
return [...new Set(values.filter((value) => Boolean(value)))];
|
|
5256
|
+
}
|
|
5257
|
+
function moduleRoots() {
|
|
5258
|
+
const home = homedir5();
|
|
5259
|
+
const openClawPrefix = trim(process.env.KYNVER_OPENCLAW_NPM_ROOT) ?? trim(process.env.OPENCLAW_NPM_ROOT) ?? path29.join(home, ".openclaw", "npm");
|
|
5260
|
+
const npmGlobalRoot = trim(process.env.KYNVER_NPM_GLOBAL_ROOT) ?? trim(process.env.KYNVER_NPM_GLOBAL_MODULES_ROOT) ?? (trim(process.env.NPM_CONFIG_PREFIX) ? path29.join(trim(process.env.NPM_CONFIG_PREFIX), "lib", "node_modules") : path29.join(home, ".npm-global", "lib", "node_modules"));
|
|
5261
|
+
return unique([
|
|
5262
|
+
path29.join(openClawPrefix, "lib", "node_modules"),
|
|
5263
|
+
path29.join(openClawPrefix, "node_modules"),
|
|
5264
|
+
npmGlobalRoot.endsWith("node_modules") ? npmGlobalRoot : path29.join(npmGlobalRoot, "lib", "node_modules")
|
|
5265
|
+
]);
|
|
5266
|
+
}
|
|
5267
|
+
async function readVersion(packageJsonPath) {
|
|
5268
|
+
try {
|
|
5269
|
+
const parsed = JSON.parse(await readFile(packageJsonPath, "utf8"));
|
|
5270
|
+
return typeof parsed.version === "string" && parsed.version.trim() ? parsed.version.trim() : null;
|
|
5271
|
+
} catch {
|
|
5272
|
+
return null;
|
|
5273
|
+
}
|
|
5274
|
+
}
|
|
5275
|
+
async function collectInstalledPackageVersions(observedAt = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
5276
|
+
const roots = moduleRoots();
|
|
5277
|
+
const out = {};
|
|
5278
|
+
for (const packageName of MANAGED_PACKAGES) {
|
|
5279
|
+
for (const root of roots) {
|
|
5280
|
+
const packageJsonPath = path29.join(root, packageName, "package.json");
|
|
5281
|
+
const version = await readVersion(packageJsonPath);
|
|
5282
|
+
if (!version) continue;
|
|
5283
|
+
out[packageName] = { version, observedAt, path: packageJsonPath };
|
|
5284
|
+
break;
|
|
5285
|
+
}
|
|
5286
|
+
}
|
|
5287
|
+
return out;
|
|
5288
|
+
}
|
|
5289
|
+
|
|
4900
5290
|
// src/pipeline-tick.ts
|
|
4901
5291
|
async function completeFinishedWorkers(runId, args) {
|
|
4902
5292
|
const run = loadRun(runId);
|
|
4903
5293
|
const outcomes = [];
|
|
4904
5294
|
for (const name of Object.keys(run.workers || {})) {
|
|
4905
5295
|
const worker = readJson(
|
|
4906
|
-
|
|
5296
|
+
path30.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
|
|
4907
5297
|
void 0
|
|
4908
5298
|
);
|
|
4909
5299
|
if (!worker?.taskId || worker.localOnly) continue;
|
|
@@ -4934,12 +5324,14 @@ async function postOperatorTick(agentOsId, runId, resourceGate, args) {
|
|
|
4934
5324
|
const base = resolveBaseUrl(args.baseUrl ? String(args.baseUrl) : void 0);
|
|
4935
5325
|
const secret = await resolveCallbackSecretWithMint(args.secret ? String(args.secret) : void 0, agentOsId, { baseUrl: base });
|
|
4936
5326
|
const url = `${base}/api/agent-os/by-id/${encodeURIComponent(agentOsId)}/operator/tick`;
|
|
5327
|
+
const packageVersions = await collectInstalledPackageVersions();
|
|
4937
5328
|
const res = await postJson(url, secret, {
|
|
4938
5329
|
agentOsId,
|
|
4939
5330
|
runId,
|
|
4940
5331
|
ingestHarness: true,
|
|
4941
5332
|
harnessBoardSnapshot: buildRunBoard(runId),
|
|
4942
|
-
resourceGate
|
|
5333
|
+
resourceGate,
|
|
5334
|
+
packageVersions
|
|
4943
5335
|
});
|
|
4944
5336
|
return { ok: res.ok, httpStatus: res.status, response: res.response };
|
|
4945
5337
|
}
|
|
@@ -5042,6 +5434,231 @@ async function runDaemon(args) {
|
|
|
5042
5434
|
console.error(JSON.stringify({ event: "daemon_stop", runId, agentOsId }));
|
|
5043
5435
|
}
|
|
5044
5436
|
|
|
5437
|
+
// src/plan-progress.ts
|
|
5438
|
+
import path31 from "node:path";
|
|
5439
|
+
|
|
5440
|
+
// src/bounded-build/constants.ts
|
|
5441
|
+
var DEFAULT_BUILD_MEM_BUDGET_BYTES = 1536 * 1024 * 1024;
|
|
5442
|
+
var DEFAULT_BUILD_MEM_RESERVE_BYTES = 2 * 1024 * 1024 * 1024;
|
|
5443
|
+
var DEFAULT_NODE_OLD_SPACE_SIZE_MB = 1024;
|
|
5444
|
+
var DEFAULT_SYSTEMD_MEMORY_MAX = "1.5G";
|
|
5445
|
+
var DEFAULT_SYSTEMD_MEMORY_SWAP_MAX = "2G";
|
|
5446
|
+
|
|
5447
|
+
// src/bounded-build/node-options.ts
|
|
5448
|
+
var MAX_OLD_SPACE_RE = /--max-old-space-size=(\d+)/;
|
|
5449
|
+
function parsePositiveInt(value, fallback) {
|
|
5450
|
+
const n = Number(value);
|
|
5451
|
+
if (!Number.isFinite(n) || n <= 0) return fallback;
|
|
5452
|
+
return Math.floor(n);
|
|
5453
|
+
}
|
|
5454
|
+
function resolveNodeOldSpaceSizeMb() {
|
|
5455
|
+
return parsePositiveInt(process.env.KYNVER_NODE_OLD_SPACE_SIZE_MB, DEFAULT_NODE_OLD_SPACE_SIZE_MB);
|
|
5456
|
+
}
|
|
5457
|
+
function mergeNodeOptionsForBuildCheck(baseEnv = process.env) {
|
|
5458
|
+
const env = { ...baseEnv };
|
|
5459
|
+
if (process.env.KYNVER_NODE_OLD_SPACE_SIZE_MB === "0") {
|
|
5460
|
+
return env;
|
|
5461
|
+
}
|
|
5462
|
+
const existing = env.NODE_OPTIONS ?? "";
|
|
5463
|
+
if (MAX_OLD_SPACE_RE.test(existing)) {
|
|
5464
|
+
return env;
|
|
5465
|
+
}
|
|
5466
|
+
const mb = resolveNodeOldSpaceSizeMb();
|
|
5467
|
+
const flag = `--max-old-space-size=${mb}`;
|
|
5468
|
+
env.NODE_OPTIONS = existing.trim() ? `${existing.trim()} ${flag}` : flag;
|
|
5469
|
+
return env;
|
|
5470
|
+
}
|
|
5471
|
+
function formatNodeOptionsFlag(mb = resolveNodeOldSpaceSizeMb()) {
|
|
5472
|
+
return `--max-old-space-size=${mb}`;
|
|
5473
|
+
}
|
|
5474
|
+
|
|
5475
|
+
// src/bounded-build/systemd-wrap.ts
|
|
5476
|
+
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
5477
|
+
var systemdAvailableCache;
|
|
5478
|
+
function isSystemdRunAvailable() {
|
|
5479
|
+
if (process.env.KYNVER_BUILD_SKIP_SYSTEMD === "1" || process.env.KYNVER_BUILD_SKIP_SYSTEMD === "true") {
|
|
5480
|
+
return false;
|
|
5481
|
+
}
|
|
5482
|
+
if (systemdAvailableCache !== void 0) return systemdAvailableCache;
|
|
5483
|
+
if (process.platform !== "linux") {
|
|
5484
|
+
systemdAvailableCache = false;
|
|
5485
|
+
return false;
|
|
5486
|
+
}
|
|
5487
|
+
const res = spawnSync3("systemd-run", ["--version"], { encoding: "utf8", stdio: ["ignore", "ignore", "pipe"] });
|
|
5488
|
+
systemdAvailableCache = res.status === 0;
|
|
5489
|
+
return systemdAvailableCache;
|
|
5490
|
+
}
|
|
5491
|
+
function buildSystemdRunArgv(opts) {
|
|
5492
|
+
const memoryMax = opts.memoryMax ?? process.env.KYNVER_BUILD_SYSTEMD_MEMORY_MAX ?? DEFAULT_SYSTEMD_MEMORY_MAX;
|
|
5493
|
+
const memorySwapMax = opts.memorySwapMax ?? process.env.KYNVER_BUILD_SYSTEMD_MEMORY_SWAP_MAX ?? DEFAULT_SYSTEMD_MEMORY_SWAP_MAX;
|
|
5494
|
+
const argv = [
|
|
5495
|
+
"systemd-run",
|
|
5496
|
+
"--scope",
|
|
5497
|
+
"--collect",
|
|
5498
|
+
"-p",
|
|
5499
|
+
`MemoryMax=${memoryMax}`,
|
|
5500
|
+
"-p",
|
|
5501
|
+
`MemorySwapMax=${memorySwapMax}`
|
|
5502
|
+
];
|
|
5503
|
+
if (opts.cwd) {
|
|
5504
|
+
argv.push("--working-directory", opts.cwd);
|
|
5505
|
+
}
|
|
5506
|
+
argv.push("--", ...opts.command);
|
|
5507
|
+
return argv;
|
|
5508
|
+
}
|
|
5509
|
+
|
|
5510
|
+
// src/bounded-build/admission.ts
|
|
5511
|
+
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
5512
|
+
function positiveInt3(value, fallback) {
|
|
5513
|
+
const n = Number(value);
|
|
5514
|
+
if (!Number.isFinite(n) || n <= 0) return fallback;
|
|
5515
|
+
return Math.floor(n);
|
|
5516
|
+
}
|
|
5517
|
+
function resolveBuildAdmissionConfig(config = loadUserConfig()) {
|
|
5518
|
+
const envBudget = process.env.KYNVER_BUILD_MEM_BUDGET_BYTES ? positiveInt3(process.env.KYNVER_BUILD_MEM_BUDGET_BYTES, DEFAULT_BUILD_MEM_BUDGET_BYTES) : void 0;
|
|
5519
|
+
const envReserve = process.env.KYNVER_BUILD_MEM_RESERVE_BYTES ? positiveInt3(process.env.KYNVER_BUILD_MEM_RESERVE_BYTES, DEFAULT_BUILD_MEM_RESERVE_BYTES) : void 0;
|
|
5520
|
+
return {
|
|
5521
|
+
perBuildBudgetBytes: envBudget ?? positiveInt3(config.perWorkerMemBytes, DEFAULT_BUILD_MEM_BUDGET_BYTES),
|
|
5522
|
+
reserveBytes: envReserve ?? positiveInt3(config.memReserveBytes, DEFAULT_BUILD_MEM_RESERVE_BYTES)
|
|
5523
|
+
};
|
|
5524
|
+
}
|
|
5525
|
+
var activeBuilds = 0;
|
|
5526
|
+
function registerBuildStart() {
|
|
5527
|
+
activeBuilds += 1;
|
|
5528
|
+
}
|
|
5529
|
+
function registerBuildEnd() {
|
|
5530
|
+
activeBuilds = Math.max(0, activeBuilds - 1);
|
|
5531
|
+
}
|
|
5532
|
+
function assessBuildAdmission(opts = {}) {
|
|
5533
|
+
const cfg = { ...resolveBuildAdmissionConfig(), ...opts };
|
|
5534
|
+
const memAvailableBytes = opts.memAvailableBytes ?? readMemAvailableBytes();
|
|
5535
|
+
const requiredBytes = cfg.perBuildBudgetBytes + cfg.reserveBytes;
|
|
5536
|
+
const admitted = memAvailableBytes >= requiredBytes;
|
|
5537
|
+
return {
|
|
5538
|
+
admitted,
|
|
5539
|
+
memAvailableBytes,
|
|
5540
|
+
requiredBytes,
|
|
5541
|
+
activeBuilds,
|
|
5542
|
+
reason: admitted ? null : `insufficient memory: need ${requiredBytes} bytes available (budget ${cfg.perBuildBudgetBytes} + reserve ${cfg.reserveBytes}), have ${memAvailableBytes}`
|
|
5543
|
+
};
|
|
5544
|
+
}
|
|
5545
|
+
function sleepMs2(ms) {
|
|
5546
|
+
if (ms <= 0) return;
|
|
5547
|
+
spawnSync4(process.execPath, ["-e", `const d=Date.now()+${Math.floor(ms)};while(Date.now()<d);`], {
|
|
5548
|
+
stdio: "ignore"
|
|
5549
|
+
});
|
|
5550
|
+
}
|
|
5551
|
+
function waitForBuildAdmission(timeoutMs, pollMs = 2e3, opts = {}) {
|
|
5552
|
+
const deadline = Date.now() + Math.max(0, timeoutMs);
|
|
5553
|
+
let verdict = assessBuildAdmission({
|
|
5554
|
+
...opts,
|
|
5555
|
+
memAvailableBytes: opts.memAvailableBytes?.()
|
|
5556
|
+
});
|
|
5557
|
+
while (!verdict.admitted && Date.now() < deadline) {
|
|
5558
|
+
sleepMs2(Math.min(pollMs, deadline - Date.now()));
|
|
5559
|
+
verdict = assessBuildAdmission({
|
|
5560
|
+
...opts,
|
|
5561
|
+
memAvailableBytes: opts.memAvailableBytes?.()
|
|
5562
|
+
});
|
|
5563
|
+
}
|
|
5564
|
+
return verdict;
|
|
5565
|
+
}
|
|
5566
|
+
|
|
5567
|
+
// src/bounded-build/exec.ts
|
|
5568
|
+
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
5569
|
+
function envArgv(env) {
|
|
5570
|
+
const out = [];
|
|
5571
|
+
for (const [key, value] of Object.entries(env)) {
|
|
5572
|
+
if (value === void 0) continue;
|
|
5573
|
+
out.push(`${key}=${value}`);
|
|
5574
|
+
}
|
|
5575
|
+
return out;
|
|
5576
|
+
}
|
|
5577
|
+
function runSpawn(argv, opts) {
|
|
5578
|
+
const res = spawnSync5(argv[0], argv.slice(1), {
|
|
5579
|
+
cwd: opts.cwd,
|
|
5580
|
+
env: opts.env,
|
|
5581
|
+
encoding: "utf8",
|
|
5582
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
5583
|
+
shell: opts.shell,
|
|
5584
|
+
timeout: opts.timeoutMs
|
|
5585
|
+
});
|
|
5586
|
+
return {
|
|
5587
|
+
exitCode: res.status ?? 1,
|
|
5588
|
+
stdout: (res.stdout ?? "").trim(),
|
|
5589
|
+
stderr: (res.stderr ?? "").trim()
|
|
5590
|
+
};
|
|
5591
|
+
}
|
|
5592
|
+
function runBoundedBuildCheck(input) {
|
|
5593
|
+
const waitMs = input.waitForAdmissionMs ?? 6e5;
|
|
5594
|
+
const admission = waitMs > 0 ? waitForBuildAdmission(waitMs) : assessBuildAdmission();
|
|
5595
|
+
if (!admission.admitted) {
|
|
5596
|
+
return {
|
|
5597
|
+
ok: false,
|
|
5598
|
+
exitCode: 1,
|
|
5599
|
+
stdout: "",
|
|
5600
|
+
stderr: admission.reason ?? "build admission denied",
|
|
5601
|
+
admitted: false,
|
|
5602
|
+
wrappedWithSystemd: false,
|
|
5603
|
+
nodeOptionsFlag: formatNodeOptionsFlag(),
|
|
5604
|
+
admission,
|
|
5605
|
+
command: input.command
|
|
5606
|
+
};
|
|
5607
|
+
}
|
|
5608
|
+
const env = mergeNodeOptionsForBuildCheck({ ...process.env, ...input.env });
|
|
5609
|
+
const nodeOptionsFlag = formatNodeOptionsFlag();
|
|
5610
|
+
const useSystemd = isSystemdRunAvailable();
|
|
5611
|
+
registerBuildStart();
|
|
5612
|
+
try {
|
|
5613
|
+
let result;
|
|
5614
|
+
if (useSystemd) {
|
|
5615
|
+
const argv = buildSystemdRunArgv({
|
|
5616
|
+
cwd: input.cwd,
|
|
5617
|
+
command: ["/usr/bin/env", ...envArgv(env), "/bin/bash", "-lc", input.command]
|
|
5618
|
+
});
|
|
5619
|
+
result = runSpawn(argv, { cwd: input.cwd, env, timeoutMs: input.timeoutMs });
|
|
5620
|
+
} else {
|
|
5621
|
+
result = runSpawn([input.command], {
|
|
5622
|
+
cwd: input.cwd,
|
|
5623
|
+
env,
|
|
5624
|
+
shell: true,
|
|
5625
|
+
timeoutMs: input.timeoutMs
|
|
5626
|
+
});
|
|
5627
|
+
}
|
|
5628
|
+
return {
|
|
5629
|
+
ok: result.exitCode === 0,
|
|
5630
|
+
exitCode: result.exitCode,
|
|
5631
|
+
stdout: result.stdout,
|
|
5632
|
+
stderr: result.stderr,
|
|
5633
|
+
admitted: true,
|
|
5634
|
+
wrappedWithSystemd: useSystemd,
|
|
5635
|
+
nodeOptionsFlag,
|
|
5636
|
+
admission,
|
|
5637
|
+
command: input.command
|
|
5638
|
+
};
|
|
5639
|
+
} finally {
|
|
5640
|
+
registerBuildEnd();
|
|
5641
|
+
}
|
|
5642
|
+
}
|
|
5643
|
+
|
|
5644
|
+
// src/harness-verify.ts
|
|
5645
|
+
var DEFAULT_HARNESS_VERIFY_COMMANDS = ["npm run typecheck", "npm run test"];
|
|
5646
|
+
function runHarnessVerifyCommands(cwd, commands = DEFAULT_HARNESS_VERIFY_COMMANDS, opts = {}) {
|
|
5647
|
+
const steps = [];
|
|
5648
|
+
let passed = true;
|
|
5649
|
+
for (const command of commands) {
|
|
5650
|
+
const result = runBoundedBuildCheck({
|
|
5651
|
+
cwd,
|
|
5652
|
+
command,
|
|
5653
|
+
waitForAdmissionMs: opts.waitForAdmissionMs,
|
|
5654
|
+
timeoutMs: opts.timeoutMs
|
|
5655
|
+
});
|
|
5656
|
+
steps.push({ command, result });
|
|
5657
|
+
if (!result.ok) passed = false;
|
|
5658
|
+
}
|
|
5659
|
+
return { passed, steps };
|
|
5660
|
+
}
|
|
5661
|
+
|
|
5045
5662
|
// src/plan-progress.ts
|
|
5046
5663
|
function parseEvidenceArg(raw) {
|
|
5047
5664
|
const idx = raw.indexOf(":");
|
|
@@ -5102,8 +5719,23 @@ async function emitPlanProgress(args) {
|
|
|
5102
5719
|
}
|
|
5103
5720
|
console.log(JSON.stringify(parsed, null, 2));
|
|
5104
5721
|
}
|
|
5722
|
+
function verifyPlanLocal(args) {
|
|
5723
|
+
const worktree = required(args.worktree ? String(args.worktree) : void 0, "worktree");
|
|
5724
|
+
const cwd = path31.resolve(worktree);
|
|
5725
|
+
const summary = runHarnessVerifyCommands(cwd);
|
|
5726
|
+
const emitJson = args.json === true || args.json === "true";
|
|
5727
|
+
const payload = { passed: summary.passed, worktree: cwd, steps: summary.steps };
|
|
5728
|
+
if (emitJson) console.log(JSON.stringify(payload, null, 2));
|
|
5729
|
+
else console.log(summary.passed ? "local plan verify passed" : "local plan verify failed");
|
|
5730
|
+
if (!summary.passed) process.exit(1);
|
|
5731
|
+
}
|
|
5105
5732
|
async function verifyPlan(args) {
|
|
5106
5733
|
const planId = required(args.plan ? String(args.plan) : void 0, "plan");
|
|
5734
|
+
const localOnly = args.local === true || args.local === "true";
|
|
5735
|
+
if (localOnly) {
|
|
5736
|
+
verifyPlanLocal(args);
|
|
5737
|
+
return;
|
|
5738
|
+
}
|
|
5107
5739
|
const slug = loadUserConfig().agentOsSlug;
|
|
5108
5740
|
if (!slug) {
|
|
5109
5741
|
console.error("requires agentOsSlug in ~/.kynver/config.json for verify (session route)");
|
|
@@ -5137,6 +5769,52 @@ async function verifyPlan(args) {
|
|
|
5137
5769
|
console.log(JSON.stringify(parsed, null, 2));
|
|
5138
5770
|
}
|
|
5139
5771
|
|
|
5772
|
+
// src/harness-verify-cli.ts
|
|
5773
|
+
import path32 from "node:path";
|
|
5774
|
+
function runHarnessVerifyCli(args) {
|
|
5775
|
+
const cwd = path32.resolve(required(args.worktree ? String(args.worktree) : void 0, "worktree"));
|
|
5776
|
+
const emitJson = args.json === true || args.json === "true" || args.emitJson === true || args.emitJson === "true";
|
|
5777
|
+
const commands = [];
|
|
5778
|
+
const rawCmd = args.command;
|
|
5779
|
+
if (Array.isArray(rawCmd)) {
|
|
5780
|
+
for (const c of rawCmd) commands.push(String(c));
|
|
5781
|
+
} else if (typeof rawCmd === "string") {
|
|
5782
|
+
commands.push(rawCmd);
|
|
5783
|
+
}
|
|
5784
|
+
const summary = runHarnessVerifyCommands(
|
|
5785
|
+
cwd,
|
|
5786
|
+
commands.length ? commands : DEFAULT_HARNESS_VERIFY_COMMANDS,
|
|
5787
|
+
{
|
|
5788
|
+
waitForAdmissionMs: args.waitForAdmissionMs ? Number(args.waitForAdmissionMs) : void 0,
|
|
5789
|
+
timeoutMs: args.timeoutMs ? Number(args.timeoutMs) : void 0
|
|
5790
|
+
}
|
|
5791
|
+
);
|
|
5792
|
+
const payload = {
|
|
5793
|
+
passed: summary.passed,
|
|
5794
|
+
worktree: cwd,
|
|
5795
|
+
steps: summary.steps.map((s) => ({
|
|
5796
|
+
command: s.command,
|
|
5797
|
+
ok: s.result.ok,
|
|
5798
|
+
exitCode: s.result.exitCode,
|
|
5799
|
+
admitted: s.result.admitted,
|
|
5800
|
+
wrappedWithSystemd: s.result.wrappedWithSystemd,
|
|
5801
|
+
nodeOptionsFlag: s.result.nodeOptionsFlag,
|
|
5802
|
+
admission: s.result.admission,
|
|
5803
|
+
stderr: s.result.stderr.slice(0, 4e3)
|
|
5804
|
+
}))
|
|
5805
|
+
};
|
|
5806
|
+
if (emitJson) {
|
|
5807
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
5808
|
+
} else {
|
|
5809
|
+
console.log(summary.passed ? "harness verify passed" : "harness verify failed");
|
|
5810
|
+
for (const step of payload.steps) {
|
|
5811
|
+
console.log(` ${step.ok ? "\u2713" : "\u2717"} ${step.command} (exit ${step.exitCode}, systemd=${step.wrappedWithSystemd})`);
|
|
5812
|
+
if (!step.ok && step.stderr) console.log(` ${step.stderr.split("\n")[0]}`);
|
|
5813
|
+
}
|
|
5814
|
+
}
|
|
5815
|
+
process.exit(summary.passed ? 0 : 1);
|
|
5816
|
+
}
|
|
5817
|
+
|
|
5140
5818
|
// src/plan-persist-cli.ts
|
|
5141
5819
|
import { readFileSync as readFileSync7 } from "node:fs";
|
|
5142
5820
|
var OPERATIONS = ["create", "add_version", "update_metadata"];
|
|
@@ -5238,7 +5916,7 @@ function runCleanupCli(args) {
|
|
|
5238
5916
|
}
|
|
5239
5917
|
|
|
5240
5918
|
// src/monitor/monitor.service.ts
|
|
5241
|
-
import
|
|
5919
|
+
import path34 from "node:path";
|
|
5242
5920
|
|
|
5243
5921
|
// src/monitor/monitor.classify.ts
|
|
5244
5922
|
function expectedLeaseOwner(runId) {
|
|
@@ -5295,10 +5973,10 @@ function classifyWorkerHealth(input) {
|
|
|
5295
5973
|
|
|
5296
5974
|
// src/monitor/monitor.store.ts
|
|
5297
5975
|
import { existsSync as existsSync17, mkdirSync as mkdirSync6, readdirSync as readdirSync7, unlinkSync as unlinkSync2 } from "node:fs";
|
|
5298
|
-
import
|
|
5976
|
+
import path33 from "node:path";
|
|
5299
5977
|
function monitorsDir() {
|
|
5300
5978
|
const { harnessRoot } = getHarnessPaths();
|
|
5301
|
-
const dir =
|
|
5979
|
+
const dir = path33.join(harnessRoot, "monitors");
|
|
5302
5980
|
mkdirSync6(dir, { recursive: true });
|
|
5303
5981
|
return dir;
|
|
5304
5982
|
}
|
|
@@ -5306,7 +5984,7 @@ function monitorIdFor(runId, workerName) {
|
|
|
5306
5984
|
return workerName ? `${safeSlug(runId)}--${safeSlug(workerName)}` : safeSlug(runId);
|
|
5307
5985
|
}
|
|
5308
5986
|
function monitorPath(monitorId) {
|
|
5309
|
-
return
|
|
5987
|
+
return path33.join(monitorsDir(), `${monitorId}.json`);
|
|
5310
5988
|
}
|
|
5311
5989
|
function loadMonitorSession(monitorId) {
|
|
5312
5990
|
return readJson(monitorPath(monitorId), void 0);
|
|
@@ -5327,7 +6005,7 @@ function listMonitorSessions() {
|
|
|
5327
6005
|
for (const name of readdirSync7(dir)) {
|
|
5328
6006
|
if (!name.endsWith(".json")) continue;
|
|
5329
6007
|
const session = readJson(
|
|
5330
|
-
|
|
6008
|
+
path33.join(dir, name),
|
|
5331
6009
|
void 0
|
|
5332
6010
|
);
|
|
5333
6011
|
if (!session?.monitorId) continue;
|
|
@@ -5418,7 +6096,7 @@ async function fetchTaskLeasesForWorkers(input) {
|
|
|
5418
6096
|
// src/monitor/monitor.service.ts
|
|
5419
6097
|
function workerRecord2(runId, name) {
|
|
5420
6098
|
return readJson(
|
|
5421
|
-
|
|
6099
|
+
path34.join(runDirectory(runId), "workers", safeSlug(name), "worker.json"),
|
|
5422
6100
|
void 0
|
|
5423
6101
|
);
|
|
5424
6102
|
}
|
|
@@ -5621,17 +6299,17 @@ async function runMonitorLoop(args) {
|
|
|
5621
6299
|
// src/monitor/monitor-spawn.ts
|
|
5622
6300
|
import { spawn as spawn4 } from "node:child_process";
|
|
5623
6301
|
import { closeSync as closeSync4, existsSync as existsSync18, openSync as openSync4 } from "node:fs";
|
|
5624
|
-
import
|
|
6302
|
+
import path35 from "node:path";
|
|
5625
6303
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
5626
6304
|
function resolveDefaultCliPath2() {
|
|
5627
|
-
return
|
|
6305
|
+
return path35.join(fileURLToPath2(new URL(".", import.meta.url)), "..", "cli.js");
|
|
5628
6306
|
}
|
|
5629
6307
|
function spawnMonitorSidecar(opts) {
|
|
5630
6308
|
const cliPath = opts.cliPath ?? resolveDefaultCliPath2();
|
|
5631
6309
|
if (!existsSync18(cliPath)) return void 0;
|
|
5632
6310
|
const monitorId = monitorIdFor(opts.runId, opts.workerName);
|
|
5633
6311
|
const { harnessRoot } = getHarnessPaths();
|
|
5634
|
-
const logPath =
|
|
6312
|
+
const logPath = path35.join(harnessRoot, "monitors", `${monitorId}.log`);
|
|
5635
6313
|
let logFd;
|
|
5636
6314
|
try {
|
|
5637
6315
|
logFd = openSync4(logPath, "a");
|
|
@@ -5787,16 +6465,16 @@ function handleCliVersionFlag(argv, moduleUrl = import.meta.url, binName) {
|
|
|
5787
6465
|
}
|
|
5788
6466
|
|
|
5789
6467
|
// src/doctor/runtime-takeover.ts
|
|
5790
|
-
import
|
|
6468
|
+
import path37 from "node:path";
|
|
5791
6469
|
|
|
5792
6470
|
// src/doctor/runtime-takeover.probes.ts
|
|
5793
6471
|
import { accessSync, constants, existsSync as existsSync20, readFileSync as readFileSync9 } from "node:fs";
|
|
5794
|
-
import { homedir as
|
|
5795
|
-
import
|
|
5796
|
-
import { spawnSync as
|
|
6472
|
+
import { homedir as homedir6 } from "node:os";
|
|
6473
|
+
import path36 from "node:path";
|
|
6474
|
+
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
5797
6475
|
function captureCommand(bin, args) {
|
|
5798
6476
|
try {
|
|
5799
|
-
const res =
|
|
6477
|
+
const res = spawnSync6(bin, args, { encoding: "utf8" });
|
|
5800
6478
|
const stdout = (res.stdout || "").trim();
|
|
5801
6479
|
const stderr = (res.stderr || "").trim();
|
|
5802
6480
|
const ok = res.status === 0;
|
|
@@ -5834,10 +6512,10 @@ var defaultRuntimeTakeoverProbes = {
|
|
|
5834
6512
|
commandOnPath: (bin) => captureCommand(process.platform === "win32" ? "where" : "which", [bin]),
|
|
5835
6513
|
kynverVersion: (bin) => captureCommand(bin, ["--version"]),
|
|
5836
6514
|
loadConfig: () => loadUserConfig(),
|
|
5837
|
-
configFilePath: () =>
|
|
5838
|
-
credentialsFilePath: () =>
|
|
6515
|
+
configFilePath: () => path36.join(homedir6(), ".kynver", "config.json"),
|
|
6516
|
+
credentialsFilePath: () => path36.join(homedir6(), ".kynver", "credentials"),
|
|
5839
6517
|
readCredentials: () => {
|
|
5840
|
-
const credPath =
|
|
6518
|
+
const credPath = path36.join(homedir6(), ".kynver", "credentials");
|
|
5841
6519
|
if (!existsSync20(credPath)) {
|
|
5842
6520
|
return { hasApiKey: false };
|
|
5843
6521
|
}
|
|
@@ -5863,7 +6541,7 @@ var defaultRuntimeTakeoverProbes = {
|
|
|
5863
6541
|
kynverSchedulerProvider: process.env.KYNVER_SCHEDULER_PROVIDER?.trim() || void 0
|
|
5864
6542
|
}),
|
|
5865
6543
|
harnessRoot: () => resolveHarnessRoot(),
|
|
5866
|
-
legacyOpenclawHarnessRoot: () =>
|
|
6544
|
+
legacyOpenclawHarnessRoot: () => path36.join(homedir6(), ".openclaw", "harness"),
|
|
5867
6545
|
pathExists: (target) => existsSync20(target),
|
|
5868
6546
|
pathWritable: (target) => isWritable(target),
|
|
5869
6547
|
vercelVersion: () => captureCommand("vercel", ["--version"]),
|
|
@@ -6049,8 +6727,8 @@ function assessVercelCli(probes) {
|
|
|
6049
6727
|
}
|
|
6050
6728
|
function assessHarnessDirs(probes) {
|
|
6051
6729
|
const harnessRoot = probes.harnessRoot();
|
|
6052
|
-
const runsDir =
|
|
6053
|
-
const worktreesDir =
|
|
6730
|
+
const runsDir = path37.join(harnessRoot, "runs");
|
|
6731
|
+
const worktreesDir = path37.join(harnessRoot, "worktrees");
|
|
6054
6732
|
const displayHarnessRoot = redactHomePath(harnessRoot);
|
|
6055
6733
|
const displayRunsDir = redactHomePath(runsDir);
|
|
6056
6734
|
const displayWorktreesDir = redactHomePath(worktreesDir);
|
|
@@ -6202,6 +6880,37 @@ function runRuntimeTakeoverDoctorCli() {
|
|
|
6202
6880
|
}
|
|
6203
6881
|
}
|
|
6204
6882
|
|
|
6883
|
+
// src/command-center-contract-cli.ts
|
|
6884
|
+
async function runCommandCenterContractCli(args) {
|
|
6885
|
+
const config = loadUserConfig();
|
|
6886
|
+
const agentOsId = (args.agentOsId ? String(args.agentOsId) : config.agentOsId) || "";
|
|
6887
|
+
if (!agentOsId) {
|
|
6888
|
+
console.error("requires --agent-os-id or agentOsId in ~/.kynver/config.json");
|
|
6889
|
+
process.exit(1);
|
|
6890
|
+
}
|
|
6891
|
+
const base = resolveBaseUrl(args.baseUrl ? String(args.baseUrl) : config.apiBaseUrl);
|
|
6892
|
+
const secret = await resolveCallbackSecretWithMint(
|
|
6893
|
+
args.secret ? String(args.secret) : void 0,
|
|
6894
|
+
agentOsId,
|
|
6895
|
+
{ baseUrl: base }
|
|
6896
|
+
);
|
|
6897
|
+
const qs = new URLSearchParams();
|
|
6898
|
+
if (typeof args.since === "string" && args.since.trim()) qs.set("since", args.since.trim());
|
|
6899
|
+
if (args.limit != null && String(args.limit).trim()) {
|
|
6900
|
+
const n = Number(args.limit);
|
|
6901
|
+
if (Number.isFinite(n) && n > 0) qs.set("limit", String(Math.floor(n)));
|
|
6902
|
+
}
|
|
6903
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
6904
|
+
const url = `${base}/api/agent-os/by-id/${encodeURIComponent(agentOsId)}/command-center/dashboard-contract${suffix}`;
|
|
6905
|
+
const res = await getJson(url, secret);
|
|
6906
|
+
if (!res.ok) {
|
|
6907
|
+
console.error(`dashboard-contract GET failed: HTTP ${res.status}`);
|
|
6908
|
+
if (res.response) console.error(JSON.stringify(res.response, null, 2));
|
|
6909
|
+
process.exit(1);
|
|
6910
|
+
}
|
|
6911
|
+
console.log(JSON.stringify(res.response, null, 2));
|
|
6912
|
+
}
|
|
6913
|
+
|
|
6205
6914
|
// src/cli.ts
|
|
6206
6915
|
function isHelpFlag(arg) {
|
|
6207
6916
|
return arg === "help" || arg === "--help" || arg === "-h";
|
|
@@ -6223,7 +6932,7 @@ function usage(code = 0) {
|
|
|
6223
6932
|
" kynver run create --repo /path/repo [--name name] [--base origin/main]",
|
|
6224
6933
|
" kynver run list",
|
|
6225
6934
|
" kynver run status --run RUN_ID",
|
|
6226
|
-
" kynver run dispatch --run RUN_ID --agent-os-id AOS_ID [--base-url URL] [--secret SECRET] [--execute] [--lane any|implementation|review|landing] [--executor harness] [--max-starts 1] [--lease-ms MS] [--owned path[,path]] [--model claude-opus-4-8] [--disk-path /]",
|
|
6935
|
+
" kynver run dispatch --run RUN_ID --agent-os-id AOS_ID [--base-url URL] [--secret SECRET] [--execute] [--lane any|implementation|review|landing] [--target-task-id TASK_ID] [--executor harness] [--max-starts 1] [--lease-ms MS] [--owned path[,path]] [--model claude-opus-4-8] [--disk-path /]",
|
|
6227
6936
|
" kynver run sweep --run RUN_ID --agent-os-id AOS_ID [--base-url URL] [--secret SECRET] [--grace-ms MS]",
|
|
6228
6937
|
' kynver worker start --run RUN_ID --name worker --task "..." [--owned path[,path]] [--model MODEL] [--provider claude|cursor] [--agent-os-id AOS_ID] [--task-id TASK_ID] [--wait]',
|
|
6229
6938
|
" kynver worker status --run RUN_ID --name worker",
|
|
@@ -6233,7 +6942,8 @@ function usage(code = 0) {
|
|
|
6233
6942
|
" kynver worker auto-complete --run RUN_ID --name worker [--agent-os-id AOS_ID] [--poll-ms 5000] [--max-total-ms 21600000] [--complete-attempts 3] [--complete-backoff-ms 5000] [--base-url URL] [--secret SECRET]",
|
|
6234
6943
|
" kynver run reconcile",
|
|
6235
6944
|
" kynver plan progress --plan PLAN_ID --row ROW_KEY --role ROLE --status STATUS [--task TASK_ID] [--note NOTE] [--evidence type:value] [--agent-os-id AOS_ID]",
|
|
6236
|
-
" kynver plan verify --plan PLAN_ID [--worktree PATH] [--task TASK_ID] [--human-override]",
|
|
6945
|
+
" kynver plan verify --plan PLAN_ID [--worktree PATH] [--task TASK_ID] [--human-override] [--local]",
|
|
6946
|
+
" kynver harness verify --worktree PATH [--command CMD] [--json] [--wait-for-admission-ms MS] [--timeout-ms MS]",
|
|
6237
6947
|
" kynver plan persist --operation create|add_version|update_metadata --title TITLE (--body-file PATH | --body TEXT) [--slug SLUG] [--plan PLAN_ID] [--summary TEXT] [--failure-kind approval_guard|auth|network|server|tool_interruption]",
|
|
6238
6948
|
" kynver plan outbox list",
|
|
6239
6949
|
" kynver plan outbox drain [--max N] [--id OUTBOX_ID]",
|
|
@@ -6245,7 +6955,8 @@ function usage(code = 0) {
|
|
|
6245
6955
|
" kynver monitor tick --run RUN_ID [--name worker] [--agent-os-id AOS_ID] [--auto-complete] [--renew-leases]",
|
|
6246
6956
|
" kynver monitor auto-complete --run RUN_ID --name worker [--agent-os-id AOS_ID] [--base-url URL] [--secret SECRET]",
|
|
6247
6957
|
" kynver monitor run-loop --run RUN_ID --monitor-id ID [--name worker] [--agent-os-id AOS_ID] [--poll-ms MS] [--auto-complete] [--renew-leases]",
|
|
6248
|
-
" kynver doctor runtime-takeover"
|
|
6958
|
+
" kynver doctor runtime-takeover",
|
|
6959
|
+
" kynver board contract [--agent-os-id ID] [--base-url URL] [--since ISO] [--limit N]"
|
|
6249
6960
|
].join("\n")
|
|
6250
6961
|
);
|
|
6251
6962
|
process.exit(code);
|
|
@@ -6256,7 +6967,7 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
6256
6967
|
const scope = argv.shift();
|
|
6257
6968
|
let action;
|
|
6258
6969
|
let rest;
|
|
6259
|
-
if (scope === "run" || scope === "worker" || scope === "plan" || scope === "runner" || scope === "monitor" || scope === "doctor") {
|
|
6970
|
+
if (scope === "run" || scope === "worker" || scope === "plan" || scope === "runner" || scope === "harness" || scope === "monitor" || scope === "doctor" || scope === "board") {
|
|
6260
6971
|
action = argv.shift();
|
|
6261
6972
|
rest = argv;
|
|
6262
6973
|
} else {
|
|
@@ -6273,6 +6984,7 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
6273
6984
|
if (scope === "daemon") return void await runDaemon(args);
|
|
6274
6985
|
if (scope === "plan" && action === "progress") return void await emitPlanProgress(args);
|
|
6275
6986
|
if (scope === "plan" && action === "verify") return void await verifyPlan(args);
|
|
6987
|
+
if (scope === "harness" && action === "verify") return runHarnessVerifyCli(args);
|
|
6276
6988
|
if (scope === "plan" && action === "persist") return void await runPlanPersist(args);
|
|
6277
6989
|
if (scope === "plan" && action === "outbox") {
|
|
6278
6990
|
const outboxAction = rest.shift();
|
|
@@ -6282,6 +6994,9 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
6282
6994
|
}
|
|
6283
6995
|
if (scope === "cleanup") return runCleanupCli(args);
|
|
6284
6996
|
if (scope === "doctor" && action === "runtime-takeover") return runRuntimeTakeoverDoctorCli();
|
|
6997
|
+
if (scope === "board" && action === "contract") {
|
|
6998
|
+
return void await runCommandCenterContractCli(args);
|
|
6999
|
+
}
|
|
6285
7000
|
if (scope === "run" && action === "create") return createRun(args);
|
|
6286
7001
|
if (scope === "run" && action === "list") return listRuns();
|
|
6287
7002
|
if (scope === "run" && action === "status") return runStatus(args);
|