@integrity-labs/agt-cli 0.14.15 → 0.15.0
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/bin/agt.js +3 -3
- package/dist/bin/agt.js.map +1 -1
- package/dist/{chunk-LGEQOVFU.js → chunk-WB3T6XIV.js} +1 -1
- package/dist/chunk-WB3T6XIV.js.map +1 -0
- package/dist/lib/manager-worker.js +96 -26
- package/dist/lib/manager-worker.js.map +1 -1
- package/mcp/index.js +164 -0
- package/package.json +1 -1
- package/dist/chunk-LGEQOVFU.js.map +0 -1
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
resolveChannels,
|
|
20
20
|
resolveDmTarget,
|
|
21
21
|
wrapScheduledTaskPrompt
|
|
22
|
-
} from "../chunk-
|
|
22
|
+
} from "../chunk-WB3T6XIV.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
|
|
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
|
|
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 [
|
|
664
|
-
|
|
665
|
-
const
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
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
|
|
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,
|