@kynver-app/runtime 0.1.9 → 0.1.11
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/dist/cli.js +100 -10
- package/dist/cli.js.map +3 -3
- package/dist/index.js +100 -10
- package/dist/index.js.map +3 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -381,12 +381,12 @@ var DEFAULT_CRITICAL_FREE_BYTES = 15 * 1024 * 1024 * 1024;
|
|
|
381
381
|
var DEFAULT_MAX_USED_PERCENT = 80;
|
|
382
382
|
var DEFAULT_HARD_MAX_USED_PERCENT = 90;
|
|
383
383
|
function observeRunnerDiskGate(input = {}) {
|
|
384
|
-
const
|
|
384
|
+
const path14 = input.diskPath?.trim() || "/";
|
|
385
385
|
const warnBelowBytes = input.diskFreeWarnBytes ?? DEFAULT_WARN_FREE_BYTES;
|
|
386
386
|
const criticalBelowBytes = input.diskFreeCriticalBytes ?? DEFAULT_CRITICAL_FREE_BYTES;
|
|
387
387
|
const maxUsedPercent = input.diskMaxUsedPercent ?? DEFAULT_MAX_USED_PERCENT;
|
|
388
388
|
const hardMaxUsedPercent = input.diskHardMaxUsedPercent ?? DEFAULT_HARD_MAX_USED_PERCENT;
|
|
389
|
-
const stats = statfsSync(
|
|
389
|
+
const stats = statfsSync(path14);
|
|
390
390
|
const freeBytes = Number(stats.bavail) * Number(stats.bsize);
|
|
391
391
|
const totalBytes = Number(stats.blocks) * Number(stats.bsize);
|
|
392
392
|
const usedPercent = totalBytes > 0 ? (totalBytes - freeBytes) / totalBytes * 100 : 100;
|
|
@@ -406,7 +406,7 @@ function observeRunnerDiskGate(input = {}) {
|
|
|
406
406
|
}
|
|
407
407
|
return {
|
|
408
408
|
ok,
|
|
409
|
-
path:
|
|
409
|
+
path: path14,
|
|
410
410
|
freeBytes,
|
|
411
411
|
totalBytes,
|
|
412
412
|
usedPercent,
|
|
@@ -594,6 +594,92 @@ function ensureGitRepo(repo) {
|
|
|
594
594
|
function gitStatusShort(worktreePath) {
|
|
595
595
|
return git(worktreePath, ["status", "--short"], { allowFailure: true }).split("\n").map((line) => line.trim()).filter(Boolean);
|
|
596
596
|
}
|
|
597
|
+
function gitCapture(cwd, args) {
|
|
598
|
+
try {
|
|
599
|
+
const res = spawnSync("git", args, { cwd, encoding: "utf8" });
|
|
600
|
+
return {
|
|
601
|
+
status: res.status,
|
|
602
|
+
stdout: res.stdout || "",
|
|
603
|
+
stderr: res.stderr || "",
|
|
604
|
+
error: res.error ? res.error.message : null
|
|
605
|
+
};
|
|
606
|
+
} catch (error) {
|
|
607
|
+
return {
|
|
608
|
+
status: null,
|
|
609
|
+
stdout: "",
|
|
610
|
+
stderr: "",
|
|
611
|
+
error: error.message
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
function gitIsAncestor(cwd, ancestor, descendant) {
|
|
616
|
+
const res = gitCapture(cwd, ["merge-base", "--is-ancestor", ancestor, descendant]);
|
|
617
|
+
if (res.status === 0) return { isAncestor: true, error: null };
|
|
618
|
+
if (res.status === 1) return { isAncestor: false, error: null };
|
|
619
|
+
return { isAncestor: null, error: res.error || res.stderr || res.stdout || `git exited ${res.status}` };
|
|
620
|
+
}
|
|
621
|
+
function computeGitAncestry(worktreePath, base = "origin/main") {
|
|
622
|
+
if (!worktreePath) {
|
|
623
|
+
return unknownAncestry(base, "missing worktree path");
|
|
624
|
+
}
|
|
625
|
+
const head = gitCapture(worktreePath, ["rev-parse", "HEAD"]);
|
|
626
|
+
if (head.status !== 0) return unknownAncestry(base, head.error || head.stderr || head.stdout || "failed to resolve HEAD");
|
|
627
|
+
const baseHead = gitCapture(worktreePath, ["rev-parse", base]);
|
|
628
|
+
if (baseHead.status !== 0) {
|
|
629
|
+
return unknownAncestry(base, baseHead.error || baseHead.stderr || baseHead.stdout || `failed to resolve ${base}`, head.stdout.trim());
|
|
630
|
+
}
|
|
631
|
+
const headSha = head.stdout.trim();
|
|
632
|
+
const baseSha = baseHead.stdout.trim();
|
|
633
|
+
if (headSha === baseSha) {
|
|
634
|
+
return {
|
|
635
|
+
checked: true,
|
|
636
|
+
base,
|
|
637
|
+
head: headSha,
|
|
638
|
+
baseHead: baseSha,
|
|
639
|
+
baseIsAncestorOfHead: true,
|
|
640
|
+
headIsAncestorOfBase: true,
|
|
641
|
+
relation: "synced"
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
const baseIsAncestorOfHead = gitIsAncestor(worktreePath, baseSha, headSha);
|
|
645
|
+
const headIsAncestorOfBase = gitIsAncestor(worktreePath, headSha, baseSha);
|
|
646
|
+
const error = baseIsAncestorOfHead.error || headIsAncestorOfBase.error || void 0;
|
|
647
|
+
if (baseIsAncestorOfHead.isAncestor == null || headIsAncestorOfBase.isAncestor == null) {
|
|
648
|
+
return {
|
|
649
|
+
checked: false,
|
|
650
|
+
base,
|
|
651
|
+
head: headSha,
|
|
652
|
+
baseHead: baseSha,
|
|
653
|
+
baseIsAncestorOfHead: baseIsAncestorOfHead.isAncestor,
|
|
654
|
+
headIsAncestorOfBase: headIsAncestorOfBase.isAncestor,
|
|
655
|
+
relation: "unknown",
|
|
656
|
+
...error ? { error } : {}
|
|
657
|
+
};
|
|
658
|
+
}
|
|
659
|
+
const relation = baseIsAncestorOfHead.isAncestor ? "ahead" : headIsAncestorOfBase.isAncestor ? "merged" : "diverged";
|
|
660
|
+
return {
|
|
661
|
+
checked: true,
|
|
662
|
+
base,
|
|
663
|
+
head: headSha,
|
|
664
|
+
baseHead: baseSha,
|
|
665
|
+
baseIsAncestorOfHead: baseIsAncestorOfHead.isAncestor,
|
|
666
|
+
headIsAncestorOfBase: headIsAncestorOfBase.isAncestor,
|
|
667
|
+
relation,
|
|
668
|
+
...error ? { error } : {}
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
function unknownAncestry(base, error, head = null) {
|
|
672
|
+
return {
|
|
673
|
+
checked: false,
|
|
674
|
+
base,
|
|
675
|
+
head,
|
|
676
|
+
baseHead: null,
|
|
677
|
+
baseIsAncestorOfHead: null,
|
|
678
|
+
headIsAncestorOfBase: null,
|
|
679
|
+
relation: "unknown",
|
|
680
|
+
error
|
|
681
|
+
};
|
|
682
|
+
}
|
|
597
683
|
function scrubClaudeEnv(env) {
|
|
598
684
|
const next = { ...env };
|
|
599
685
|
delete next.ANTHROPIC_API_KEY;
|
|
@@ -620,7 +706,7 @@ function computeAttention(input) {
|
|
|
620
706
|
}
|
|
621
707
|
return { state: "ok", reason: "recent activity" };
|
|
622
708
|
}
|
|
623
|
-
function computeWorkerStatus(worker) {
|
|
709
|
+
function computeWorkerStatus(worker, options = {}) {
|
|
624
710
|
const parsed = parseClaudeStream(worker.stdoutPath);
|
|
625
711
|
const heartbeat = parseHeartbeat(worker.heartbeatPath);
|
|
626
712
|
const alive = isPidAlive(worker.pid);
|
|
@@ -628,6 +714,7 @@ function computeWorkerStatus(worker) {
|
|
|
628
714
|
const stderrBytes = fileSize(worker.stderrPath);
|
|
629
715
|
const heartbeatBytes = fileSize(worker.heartbeatPath);
|
|
630
716
|
const changedFiles = gitStatusShort(worker.worktreePath);
|
|
717
|
+
const gitAncestry = computeGitAncestry(worker.worktreePath, options.base);
|
|
631
718
|
const lastActivityAt = latestIso([
|
|
632
719
|
parsed.lastEventAt,
|
|
633
720
|
heartbeat.lastHeartbeatAt,
|
|
@@ -669,7 +756,8 @@ function computeWorkerStatus(worker) {
|
|
|
669
756
|
heartbeatBlocker: heartbeat.heartbeatBlocker,
|
|
670
757
|
finalResult: parsed.finalResult,
|
|
671
758
|
error: parsed.error || (!alive && !parsed.finalResult ? tailFile(worker.stderrPath, 10).trim() || void 0 : void 0),
|
|
672
|
-
changedFiles
|
|
759
|
+
changedFiles,
|
|
760
|
+
gitAncestry
|
|
673
761
|
};
|
|
674
762
|
}
|
|
675
763
|
function isFinishedWorkerStatus(status) {
|
|
@@ -1458,7 +1546,7 @@ function runStatus(args) {
|
|
|
1458
1546
|
if (!worker) {
|
|
1459
1547
|
return { worker: name, status: "missing", attention: "needs_attention", attentionReason: "worker.json not found" };
|
|
1460
1548
|
}
|
|
1461
|
-
const status = computeWorkerStatus(worker);
|
|
1549
|
+
const status = computeWorkerStatus(worker, { base: run.base });
|
|
1462
1550
|
return {
|
|
1463
1551
|
worker: status.worker,
|
|
1464
1552
|
status: status.status,
|
|
@@ -1472,7 +1560,9 @@ function runStatus(args) {
|
|
|
1472
1560
|
lastHeartbeatSummary: status.lastHeartbeatSummary,
|
|
1473
1561
|
heartbeatBlocker: status.heartbeatBlocker,
|
|
1474
1562
|
changedFileCount: status.changedFiles.length,
|
|
1475
|
-
branch: status.branch
|
|
1563
|
+
branch: status.branch,
|
|
1564
|
+
ancestry: status.gitAncestry.relation,
|
|
1565
|
+
ancestryChecked: status.gitAncestry.checked
|
|
1476
1566
|
};
|
|
1477
1567
|
});
|
|
1478
1568
|
const board = {
|
|
@@ -1517,8 +1607,7 @@ function stopWorker(args) {
|
|
|
1517
1607
|
}
|
|
1518
1608
|
|
|
1519
1609
|
// src/cli.ts
|
|
1520
|
-
import { mkdirSync as mkdirSync5 } from "node:fs";
|
|
1521
|
-
import path14 from "node:path";
|
|
1610
|
+
import { mkdirSync as mkdirSync5, realpathSync } from "node:fs";
|
|
1522
1611
|
import { fileURLToPath } from "node:url";
|
|
1523
1612
|
|
|
1524
1613
|
// src/pipeline-tick.ts
|
|
@@ -1861,6 +1950,7 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
1861
1950
|
} else {
|
|
1862
1951
|
rest = argv;
|
|
1863
1952
|
}
|
|
1953
|
+
if (action && isHelpFlag(action) || rest.some(isHelpFlag)) return usage(0);
|
|
1864
1954
|
const args = parseArgs(rest);
|
|
1865
1955
|
const { runsDir, worktreesDir } = getPaths();
|
|
1866
1956
|
mkdirSync5(runsDir, { recursive: true });
|
|
@@ -1883,7 +1973,7 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
1883
1973
|
if (scope === "worker" && action === "complete") return void await completeWorker(args);
|
|
1884
1974
|
unknownCommand(scope, action);
|
|
1885
1975
|
}
|
|
1886
|
-
var isCliEntry = process.argv[1] &&
|
|
1976
|
+
var isCliEntry = process.argv[1] && realpathSync.native(process.argv[1]) === realpathSync.native(fileURLToPath(import.meta.url));
|
|
1887
1977
|
if (isCliEntry) {
|
|
1888
1978
|
void main().catch((error) => {
|
|
1889
1979
|
console.error(error);
|