@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/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 path15 = input.diskPath?.trim() || "/";
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(path15);
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: path15,
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] && path14.resolve(process.argv[1]) === path14.resolve(fileURLToPath(import.meta.url));
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);