@integrity-labs/agt-cli 0.14.15 → 0.14.16

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.
@@ -19,7 +19,7 @@ import {
19
19
  resolveChannels,
20
20
  resolveDmTarget,
21
21
  wrapScheduledTaskPrompt
22
- } from "../chunk-LGEQOVFU.js";
22
+ } from "../chunk-NR3CFHSM.js";
23
23
  import {
24
24
  findTaskByTemplate,
25
25
  getProjectDir,
@@ -649,9 +649,43 @@ function parsePsOutput(psOutput) {
649
649
  }
650
650
  return results;
651
651
  }
652
- function pickKillTargets(processes, agentCodeNames) {
652
+ function parseAllPids(psOutput) {
653
+ const map = /* @__PURE__ */ new Map();
654
+ for (const rawLine of psOutput.split("\n")) {
655
+ const line = rawLine.trimStart();
656
+ if (!line) continue;
657
+ const firstSpace = line.search(/\s+/);
658
+ if (firstSpace < 0) continue;
659
+ const pid = parseInt(line.slice(0, firstSpace), 10);
660
+ if (!Number.isFinite(pid)) continue;
661
+ const afterPid = line.slice(firstSpace).trimStart();
662
+ const secondSpace = afterPid.search(/\s+/);
663
+ if (secondSpace < 0) continue;
664
+ const ppid = parseInt(afterPid.slice(0, secondSpace), 10);
665
+ if (!Number.isFinite(ppid)) continue;
666
+ map.set(pid, ppid);
667
+ }
668
+ return map;
669
+ }
670
+ function walkPpidChain(startPid, parentMap) {
671
+ const visited = /* @__PURE__ */ new Set();
672
+ let cur = startPid;
673
+ for (let i = 0; i < 64; i++) {
674
+ if (cur <= 1 || visited.has(cur)) break;
675
+ visited.add(cur);
676
+ const parent = parentMap.get(cur);
677
+ if (parent === void 0) break;
678
+ cur = parent;
679
+ }
680
+ return visited;
681
+ }
682
+ function pickKillTargets(args) {
683
+ const { processes, agentCodeNames, parentMap, livePidsByAgent } = args;
653
684
  const kills = [];
654
- const ambiguousGroups = [];
685
+ const fullParentMap = new Map(parentMap);
686
+ for (const proc of processes) {
687
+ if (!fullParentMap.has(proc.pid)) fullParentMap.set(proc.pid, proc.ppid);
688
+ }
655
689
  const groups = /* @__PURE__ */ new Map();
656
690
  for (const proc of processes) {
657
691
  if (!agentCodeNames.has(proc.codeName)) continue;
@@ -660,25 +694,44 @@ function pickKillTargets(processes, agentCodeNames) {
660
694
  if (bucket) bucket.push(proc);
661
695
  else groups.set(key, [proc]);
662
696
  }
663
- for (const [key, bucket] of groups) {
664
- const orphans = bucket.filter((p) => p.ppid === 1);
665
- const nonOrphans = bucket.filter((p) => p.ppid !== 1);
666
- if (orphans.length === 0 && nonOrphans.length <= 1) continue;
667
- if (nonOrphans.length > 1) {
668
- ambiguousGroups.push(key);
669
- continue;
670
- }
671
- for (const proc of orphans) {
672
- kills.push({
673
- pid: proc.pid,
674
- codeName: proc.codeName,
675
- channelType: proc.channelType,
676
- etimeSeconds: proc.etimeSeconds,
677
- reason: "orphan"
678
- });
697
+ for (const [, bucket] of groups) {
698
+ if (bucket.length === 0) continue;
699
+ const codeName = bucket[0].codeName;
700
+ const liveAnchors = livePidsByAgent.get(codeName);
701
+ const haveAnchors = !!liveAnchors && liveAnchors.size > 0;
702
+ for (const proc of bucket) {
703
+ if (proc.ppid === 1) {
704
+ if (!haveAnchors && bucket.length === 1) continue;
705
+ kills.push({
706
+ pid: proc.pid,
707
+ codeName: proc.codeName,
708
+ channelType: proc.channelType,
709
+ etimeSeconds: proc.etimeSeconds,
710
+ reason: "orphan"
711
+ });
712
+ continue;
713
+ }
714
+ if (!haveAnchors) continue;
715
+ const chain = walkPpidChain(proc.pid, fullParentMap);
716
+ let isLive = false;
717
+ for (const anchor of liveAnchors) {
718
+ if (chain.has(anchor)) {
719
+ isLive = true;
720
+ break;
721
+ }
722
+ }
723
+ if (!isLive) {
724
+ kills.push({
725
+ pid: proc.pid,
726
+ codeName: proc.codeName,
727
+ channelType: proc.channelType,
728
+ etimeSeconds: proc.etimeSeconds,
729
+ reason: "not-in-live-chain"
730
+ });
731
+ }
679
732
  }
680
733
  }
681
- return { kills, ambiguousGroups };
734
+ return { kills, ambiguousGroups: [] };
682
735
  }
683
736
  function defaultKill(pid) {
684
737
  try {
@@ -686,6 +739,26 @@ function defaultKill(pid) {
686
739
  } catch {
687
740
  }
688
741
  }
742
+ function resolveLiveAnchorPids(agentCodeNames) {
743
+ const result = /* @__PURE__ */ new Map();
744
+ for (const codeName of agentCodeNames) {
745
+ const pids = /* @__PURE__ */ new Set();
746
+ try {
747
+ const out = execFileSync("tmux", ["list-panes", "-t", `agt-${codeName}`, "-F", "#{pane_pid}"], {
748
+ encoding: "utf-8",
749
+ timeout: 2e3,
750
+ stdio: ["ignore", "pipe", "ignore"]
751
+ });
752
+ for (const line of out.split("\n")) {
753
+ const pid = parseInt(line.trim(), 10);
754
+ if (Number.isFinite(pid) && pid > 1) pids.add(pid);
755
+ }
756
+ } catch {
757
+ }
758
+ result.set(codeName, pids);
759
+ }
760
+ return result;
761
+ }
689
762
  async function sweepChannelProcesses(opts) {
690
763
  const { agentCodeNames, dryRun, log: log2 } = opts;
691
764
  const kill = opts.killFn ?? defaultKill;
@@ -701,7 +774,9 @@ async function sweepChannelProcesses(opts) {
701
774
  return { kills: [], inspected: 0, scannedAgents: [...agentCodeNames], dryRun };
702
775
  }
703
776
  const processes = parsePsOutput(psOutput);
704
- const { kills, ambiguousGroups } = pickKillTargets(processes, agentCodeNames);
777
+ const parentMap = parseAllPids(psOutput);
778
+ const livePidsByAgent = resolveLiveAnchorPids(agentCodeNames);
779
+ const { kills } = pickKillTargets({ processes, agentCodeNames, parentMap, livePidsByAgent });
705
780
  for (const target of kills) {
706
781
  const ageMin = Math.round(target.etimeSeconds / 60);
707
782
  log2(
@@ -709,11 +784,6 @@ async function sweepChannelProcesses(opts) {
709
784
  );
710
785
  if (!dryRun) kill(target.pid);
711
786
  }
712
- for (const group of ambiguousGroups) {
713
- log2(
714
- `[channel-sweep] ambiguous group ${group} \u2014 >1 non-orphan process, cannot determine which is live. Manual check recommended.`
715
- );
716
- }
717
787
  return {
718
788
  kills,
719
789
  inspected: processes.length,