@integrity-labs/agt-cli 0.19.14 → 0.19.15
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/{chunk-HA4IUBVC.js → chunk-3K3RO5NS.js} +2 -1
- package/dist/{chunk-KLNFWXOI.js → chunk-DVWBVANP.js} +379 -141
- package/dist/chunk-DVWBVANP.js.map +1 -0
- package/dist/{claude-pair-runtime-VXN4NVGR.js → claude-pair-runtime-UF4OMFCA.js} +2 -2
- package/dist/lib/manager-worker.js +206 -30
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/{persistent-session-CFDGW7QE.js → persistent-session-M2GVL6Z6.js} +2 -2
- package/mcp/slack-channel.js +111 -0
- package/package.json +1 -1
- package/dist/chunk-KLNFWXOI.js.map +0 -1
- /package/dist/{chunk-HA4IUBVC.js.map → chunk-3K3RO5NS.js.map} +0 -0
- /package/dist/{claude-pair-runtime-VXN4NVGR.js.map → claude-pair-runtime-UF4OMFCA.js.map} +0 -0
- /package/dist/{persistent-session-CFDGW7QE.js.map → persistent-session-M2GVL6Z6.js.map} +0 -0
|
@@ -100,7 +100,7 @@ async function spawnPairSession(session) {
|
|
|
100
100
|
return { ok: true };
|
|
101
101
|
} catch {
|
|
102
102
|
}
|
|
103
|
-
const { resolveClaudeBinary } = await import("./persistent-session-
|
|
103
|
+
const { resolveClaudeBinary } = await import("./persistent-session-M2GVL6Z6.js");
|
|
104
104
|
const claudeBin = resolveClaudeBinary();
|
|
105
105
|
try {
|
|
106
106
|
await execFileAsync("tmux", [
|
|
@@ -357,4 +357,4 @@ export {
|
|
|
357
357
|
startClaudePair,
|
|
358
358
|
submitClaudePairCode
|
|
359
359
|
};
|
|
360
|
-
//# sourceMappingURL=claude-pair-runtime-
|
|
360
|
+
//# sourceMappingURL=claude-pair-runtime-UF4OMFCA.js.map
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
resolveChannels,
|
|
23
23
|
resolveDmTarget,
|
|
24
24
|
wrapScheduledTaskPrompt
|
|
25
|
-
} from "../chunk-
|
|
25
|
+
} from "../chunk-DVWBVANP.js";
|
|
26
26
|
import {
|
|
27
27
|
findTaskByTemplate,
|
|
28
28
|
getProjectDir,
|
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
isAgentIdle,
|
|
40
40
|
isSessionHealthy,
|
|
41
41
|
isStaleForToday,
|
|
42
|
+
parsePsRows,
|
|
42
43
|
peekCurrentSession,
|
|
43
44
|
prepareForRespawn,
|
|
44
45
|
reapOrphanChannelMcps,
|
|
@@ -48,7 +49,7 @@ import {
|
|
|
48
49
|
startPersistentSession,
|
|
49
50
|
stopAllSessionsAndWait,
|
|
50
51
|
stopPersistentSession
|
|
51
|
-
} from "../chunk-
|
|
52
|
+
} from "../chunk-3K3RO5NS.js";
|
|
52
53
|
|
|
53
54
|
// src/lib/manager-worker.ts
|
|
54
55
|
import { createHash } from "crypto";
|
|
@@ -59,6 +60,160 @@ import { join as join4, dirname } from "path";
|
|
|
59
60
|
import { homedir as homedir3 } from "os";
|
|
60
61
|
import { fileURLToPath } from "url";
|
|
61
62
|
|
|
63
|
+
// src/lib/stale-mcp-reaper.ts
|
|
64
|
+
import { execFileSync } from "child_process";
|
|
65
|
+
function parseEnvIntegrationsVars(content) {
|
|
66
|
+
const names = /* @__PURE__ */ new Set();
|
|
67
|
+
for (const raw of content.split(/\r?\n/)) {
|
|
68
|
+
const line = raw.trim();
|
|
69
|
+
if (!line || line.startsWith("#")) continue;
|
|
70
|
+
const eq = line.indexOf("=");
|
|
71
|
+
if (eq <= 0) continue;
|
|
72
|
+
const name = line.slice(0, eq).trim();
|
|
73
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) continue;
|
|
74
|
+
names.add(name);
|
|
75
|
+
}
|
|
76
|
+
return [...names];
|
|
77
|
+
}
|
|
78
|
+
function findMcpServersUsingVars(mcp, changedVars) {
|
|
79
|
+
const changedSet = new Set(changedVars);
|
|
80
|
+
if (!mcp?.mcpServers || changedSet.size === 0) return [];
|
|
81
|
+
const result = [];
|
|
82
|
+
for (const [serverKey, entry] of Object.entries(mcp.mcpServers)) {
|
|
83
|
+
if (!entry || typeof entry !== "object") continue;
|
|
84
|
+
const env = entry.env;
|
|
85
|
+
if (!env || typeof env !== "object") continue;
|
|
86
|
+
let matches = false;
|
|
87
|
+
for (const value of Object.values(env)) {
|
|
88
|
+
if (typeof value !== "string") continue;
|
|
89
|
+
const placeholderMatches = value.match(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g);
|
|
90
|
+
if (placeholderMatches) {
|
|
91
|
+
for (const ph of placeholderMatches) {
|
|
92
|
+
const name = ph.slice(2, -1);
|
|
93
|
+
if (changedSet.has(name)) {
|
|
94
|
+
matches = true;
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (matches) break;
|
|
100
|
+
}
|
|
101
|
+
if (matches) result.push(serverKey);
|
|
102
|
+
}
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
105
|
+
function buildArgvMatchers(serverKeys) {
|
|
106
|
+
const patterns = [];
|
|
107
|
+
for (const key of serverKeys) {
|
|
108
|
+
const safe = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
109
|
+
patterns.push(new RegExp(`\\b${safe}\\b`));
|
|
110
|
+
if (safe.includes("_")) {
|
|
111
|
+
const dashed = safe.replace(/_/g, "-");
|
|
112
|
+
patterns.push(new RegExp(`\\b${dashed}\\b`));
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return patterns;
|
|
116
|
+
}
|
|
117
|
+
function buildClaudeAgentMatcher(codeName) {
|
|
118
|
+
const safe = codeName.replace(/[^A-Za-z0-9_-]/g, "");
|
|
119
|
+
return new RegExp(`\\bclaude\\b.*--name\\s+agt-${safe}(?=\\s|$)`);
|
|
120
|
+
}
|
|
121
|
+
function findMcpChildrenForAgent(args) {
|
|
122
|
+
const { rows, codeName, serverKeys } = args;
|
|
123
|
+
const maxDepth = args.maxDepth ?? 8;
|
|
124
|
+
if (serverKeys.length === 0 || rows.length === 0) return [];
|
|
125
|
+
const claudeMatcher = buildClaudeAgentMatcher(codeName);
|
|
126
|
+
const argvMatchers = buildArgvMatchers(serverKeys);
|
|
127
|
+
const byPid = new Map(rows.map((r) => [r.pid, r]));
|
|
128
|
+
const matched = [];
|
|
129
|
+
for (const row of rows) {
|
|
130
|
+
if (!argvMatchers.some((re) => re.test(row.args))) continue;
|
|
131
|
+
if (/\bclaude\b/.test(row.args) && row.args.includes(`--name agt-${codeName}`)) continue;
|
|
132
|
+
let cur = byPid.get(row.ppid);
|
|
133
|
+
let belongs = false;
|
|
134
|
+
for (let depth = 0; depth < maxDepth && cur; depth++) {
|
|
135
|
+
if (claudeMatcher.test(cur.args)) {
|
|
136
|
+
belongs = true;
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
if (cur.pid === 1) break;
|
|
140
|
+
cur = byPid.get(cur.ppid);
|
|
141
|
+
}
|
|
142
|
+
if (belongs) matched.push(row.pid);
|
|
143
|
+
}
|
|
144
|
+
return matched;
|
|
145
|
+
}
|
|
146
|
+
function reapStaleMcpChildren(args) {
|
|
147
|
+
const { log: log2, codeName, serverKeys, graceMs = 5e3 } = args;
|
|
148
|
+
if (serverKeys.length === 0) return [];
|
|
149
|
+
const runPs = args.runPs ?? (() => execFileSync("ps", ["-eo", "pid,ppid,args"], { encoding: "utf-8", timeout: 5e3 }));
|
|
150
|
+
const killProcess = args.killProcess ?? ((pid, signal) => {
|
|
151
|
+
try {
|
|
152
|
+
process.kill(pid, signal);
|
|
153
|
+
} catch {
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
const isAlive = args.isAlive ?? ((pid) => {
|
|
157
|
+
try {
|
|
158
|
+
process.kill(pid, 0);
|
|
159
|
+
return true;
|
|
160
|
+
} catch {
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
let psOutput;
|
|
165
|
+
try {
|
|
166
|
+
psOutput = runPs();
|
|
167
|
+
} catch (err) {
|
|
168
|
+
log2(`[stale-mcp-reaper] ps invocation failed for '${codeName}': ${err.message} \u2014 skipping reap`);
|
|
169
|
+
return [];
|
|
170
|
+
}
|
|
171
|
+
const rows = parsePsRows(psOutput);
|
|
172
|
+
const targets = findMcpChildrenForAgent({ rows, codeName, serverKeys });
|
|
173
|
+
if (targets.length === 0) return [];
|
|
174
|
+
const byPid = new Map(rows.map((r) => [r.pid, r]));
|
|
175
|
+
const describe = (pid) => {
|
|
176
|
+
const argv = byPid.get(pid)?.args ?? "";
|
|
177
|
+
const pkgMatch = argv.match(/(@[a-z0-9_-]+\/[a-z0-9_-]+|[a-z0-9_-]+-mcp-server|[a-z0-9_-]+-mcp\b)/i);
|
|
178
|
+
return pkgMatch ? `${pkgMatch[1]} (pid ${pid})` : `pid ${pid}`;
|
|
179
|
+
};
|
|
180
|
+
log2(
|
|
181
|
+
`[stale-mcp-reaper] '${codeName}': rotating ${targets.length} stale MCP child(ren) for [${serverKeys.join(", ")}]: ${targets.map(describe).join(", ")}`
|
|
182
|
+
);
|
|
183
|
+
for (const pid of targets) {
|
|
184
|
+
killProcess(pid, "SIGTERM");
|
|
185
|
+
}
|
|
186
|
+
setTimeout(() => {
|
|
187
|
+
try {
|
|
188
|
+
let freshPsOutput;
|
|
189
|
+
try {
|
|
190
|
+
freshPsOutput = runPs();
|
|
191
|
+
} catch (err) {
|
|
192
|
+
log2(`[stale-mcp-reaper] '${codeName}': fresh ps for SIGKILL re-verify failed: ${err.message} \u2014 skipping SIGKILL pass`);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
const stillOwned = new Set(
|
|
196
|
+
findMcpChildrenForAgent({
|
|
197
|
+
rows: parsePsRows(freshPsOutput),
|
|
198
|
+
codeName,
|
|
199
|
+
serverKeys
|
|
200
|
+
})
|
|
201
|
+
);
|
|
202
|
+
const stragglers = targets.filter((pid) => isAlive(pid) && stillOwned.has(pid));
|
|
203
|
+
if (stragglers.length === 0) return;
|
|
204
|
+
log2(
|
|
205
|
+
`[stale-mcp-reaper] '${codeName}': ${stragglers.length} child(ren) survived SIGTERM; sending SIGKILL: ${stragglers.map(describe).join(", ")}`
|
|
206
|
+
);
|
|
207
|
+
for (const pid of stragglers) {
|
|
208
|
+
killProcess(pid, "SIGKILL");
|
|
209
|
+
}
|
|
210
|
+
} catch (err) {
|
|
211
|
+
log2(`[stale-mcp-reaper] '${codeName}': error in SIGKILL pass: ${err.message}`);
|
|
212
|
+
}
|
|
213
|
+
}, graceMs).unref();
|
|
214
|
+
return targets;
|
|
215
|
+
}
|
|
216
|
+
|
|
62
217
|
// src/lib/channel-restart-decision.ts
|
|
63
218
|
function launchableChannelIds(channelConfigs) {
|
|
64
219
|
if (!channelConfigs) return /* @__PURE__ */ new Set();
|
|
@@ -649,7 +804,7 @@ function saveChannelHashCache(source, configDir) {
|
|
|
649
804
|
}
|
|
650
805
|
|
|
651
806
|
// src/lib/channel-sweep.ts
|
|
652
|
-
import { execFileSync } from "child_process";
|
|
807
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
653
808
|
var CHANNEL_BASENAMES = [
|
|
654
809
|
"slack-channel",
|
|
655
810
|
"direct-chat-channel",
|
|
@@ -812,7 +967,7 @@ function resolveLiveAnchorPids(agentCodeNames) {
|
|
|
812
967
|
for (const codeName of agentCodeNames) {
|
|
813
968
|
const pids = /* @__PURE__ */ new Set();
|
|
814
969
|
try {
|
|
815
|
-
const out =
|
|
970
|
+
const out = execFileSync2("tmux", ["list-panes", "-t", `agt-${codeName}`, "-F", "#{pane_pid}"], {
|
|
816
971
|
encoding: "utf-8",
|
|
817
972
|
timeout: 2e3,
|
|
818
973
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -832,7 +987,7 @@ async function sweepChannelProcesses(opts) {
|
|
|
832
987
|
const kill = opts.killFn ?? defaultKill;
|
|
833
988
|
let psOutput = "";
|
|
834
989
|
try {
|
|
835
|
-
psOutput =
|
|
990
|
+
psOutput = execFileSync2("ps", ["eww", "-o", "pid=,ppid=,etime=,command="], {
|
|
836
991
|
encoding: "utf-8",
|
|
837
992
|
timeout: 5e3,
|
|
838
993
|
maxBuffer: 10 * 1024 * 1024
|
|
@@ -869,7 +1024,7 @@ function defaultKillSignal(pid, signal) {
|
|
|
869
1024
|
}
|
|
870
1025
|
}
|
|
871
1026
|
function defaultPs() {
|
|
872
|
-
return
|
|
1027
|
+
return execFileSync2("ps", ["eww", "-o", "pid=,ppid=,etime=,command="], {
|
|
873
1028
|
encoding: "utf-8",
|
|
874
1029
|
timeout: 5e3,
|
|
875
1030
|
maxBuffer: 10 * 1024 * 1024
|
|
@@ -1681,10 +1836,10 @@ function clearAgentCaches(agentId, codeName) {
|
|
|
1681
1836
|
var cachedFrameworkVersion = null;
|
|
1682
1837
|
var lastVersionCheckAt = 0;
|
|
1683
1838
|
var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
|
|
1684
|
-
var agtCliVersion = true ? "0.19.
|
|
1685
|
-
function resolveBrewPath(
|
|
1839
|
+
var agtCliVersion = true ? "0.19.15" : "dev";
|
|
1840
|
+
function resolveBrewPath(execFileSync3) {
|
|
1686
1841
|
try {
|
|
1687
|
-
const out =
|
|
1842
|
+
const out = execFileSync3("which", ["brew"], { timeout: 5e3 }).toString().trim();
|
|
1688
1843
|
if (out) return out;
|
|
1689
1844
|
} catch {
|
|
1690
1845
|
}
|
|
@@ -1726,9 +1881,9 @@ async function ensureToolkitCli(toolkitSlug) {
|
|
|
1726
1881
|
}
|
|
1727
1882
|
const { binary, installer, package: pkg, script } = integration.cli_tool;
|
|
1728
1883
|
const resolvedInstaller = installer ?? "manual";
|
|
1729
|
-
const { execFileSync:
|
|
1884
|
+
const { execFileSync: execFileSync3, execSync } = await import("child_process");
|
|
1730
1885
|
try {
|
|
1731
|
-
|
|
1886
|
+
execFileSync3("which", [binary], { timeout: 5e3, stdio: "pipe" });
|
|
1732
1887
|
toolkitCliEnsured.add(toolkitSlug);
|
|
1733
1888
|
toolkitCliRetryAfter.delete(toolkitSlug);
|
|
1734
1889
|
toolkitCliFailureCount.delete(toolkitSlug);
|
|
@@ -1749,14 +1904,14 @@ async function ensureToolkitCli(toolkitSlug) {
|
|
|
1749
1904
|
return;
|
|
1750
1905
|
}
|
|
1751
1906
|
log(`[toolkit-install] ${toolkitSlug}: installing via npm (${pkg})\u2026`);
|
|
1752
|
-
|
|
1907
|
+
execFileSync3("npm", ["install", "-g", pkg], { timeout: 18e4, stdio: "pipe" });
|
|
1753
1908
|
} else if (resolvedInstaller === "brew") {
|
|
1754
1909
|
if (!pkg) {
|
|
1755
1910
|
log(`[toolkit-install] ${toolkitSlug}: installer=brew but no package declared`);
|
|
1756
1911
|
toolkitCliEnsured.add(toolkitSlug);
|
|
1757
1912
|
return;
|
|
1758
1913
|
}
|
|
1759
|
-
const brewPath = resolveBrewPath(
|
|
1914
|
+
const brewPath = resolveBrewPath(execFileSync3);
|
|
1760
1915
|
if (!brewPath) {
|
|
1761
1916
|
log(`[toolkit-install] ${toolkitSlug}: installer=brew but Homebrew not available \u2014 install manually: brew install ${pkg}`);
|
|
1762
1917
|
toolkitCliEnsured.add(toolkitSlug);
|
|
@@ -1766,9 +1921,9 @@ async function ensureToolkitCli(toolkitSlug) {
|
|
|
1766
1921
|
const isRoot = typeof process.getuid === "function" && process.getuid() === 0;
|
|
1767
1922
|
log(`[toolkit-install] ${toolkitSlug}: installing via brew (${pkg})\u2026`);
|
|
1768
1923
|
if (isRoot) {
|
|
1769
|
-
|
|
1924
|
+
execFileSync3("sudo", ["-u", "ec2-user", "-H", brewPath, "install", pkg], { timeout: 18e4, stdio: "pipe", cwd: "/tmp" });
|
|
1770
1925
|
} else {
|
|
1771
|
-
|
|
1926
|
+
execFileSync3(brewPath, ["install", pkg], { timeout: 18e4, stdio: "pipe" });
|
|
1772
1927
|
}
|
|
1773
1928
|
} else if (resolvedInstaller === "script") {
|
|
1774
1929
|
if (!script) {
|
|
@@ -1788,7 +1943,7 @@ async function ensureToolkitCli(toolkitSlug) {
|
|
|
1788
1943
|
process.env.PATH = `${brewBinDir}:${process.env.PATH ?? ""}`;
|
|
1789
1944
|
}
|
|
1790
1945
|
try {
|
|
1791
|
-
|
|
1946
|
+
execFileSync3("which", [binary], { timeout: 5e3, stdio: "pipe" });
|
|
1792
1947
|
log(`[toolkit-install] ${toolkitSlug}: installed \u2014 ${binary} now on PATH`);
|
|
1793
1948
|
toolkitCliEnsured.add(toolkitSlug);
|
|
1794
1949
|
toolkitCliRetryAfter.delete(toolkitSlug);
|
|
@@ -1841,8 +1996,8 @@ async function ensureFrameworkBinary(frameworkId) {
|
|
|
1841
1996
|
if (frameworkId !== "claude-code") return;
|
|
1842
1997
|
if (frameworkBinaryChecked.has(frameworkId)) return;
|
|
1843
1998
|
frameworkBinaryChecked.add(frameworkId);
|
|
1844
|
-
const { execFileSync:
|
|
1845
|
-
const brewPath = resolveBrewPath(
|
|
1999
|
+
const { execFileSync: execFileSync3 } = await import("child_process");
|
|
2000
|
+
const brewPath = resolveBrewPath(execFileSync3);
|
|
1846
2001
|
if (!brewPath) {
|
|
1847
2002
|
log("Homebrew not found (no `brew` on PATH, no /home/linuxbrew/.linuxbrew/bin/brew). Cannot auto-install Claude Code. Install manually: https://claude.ai/download");
|
|
1848
2003
|
return;
|
|
@@ -1858,7 +2013,7 @@ async function ensureFrameworkBinary(frameworkId) {
|
|
|
1858
2013
|
let claudeExists = existsSync3("/home/linuxbrew/.linuxbrew/bin/claude");
|
|
1859
2014
|
if (!claudeExists) {
|
|
1860
2015
|
try {
|
|
1861
|
-
|
|
2016
|
+
execFileSync3("which", ["claude"], { timeout: 5e3 });
|
|
1862
2017
|
claudeExists = true;
|
|
1863
2018
|
} catch {
|
|
1864
2019
|
}
|
|
@@ -1950,16 +2105,16 @@ async function checkAndUpdateCli() {
|
|
|
1950
2105
|
}
|
|
1951
2106
|
}
|
|
1952
2107
|
async function checkAndUpdateCliViaBrew() {
|
|
1953
|
-
const { execFileSync:
|
|
1954
|
-
const brewPath = resolveBrewPath(
|
|
2108
|
+
const { execFileSync: execFileSync3 } = await import("child_process");
|
|
2109
|
+
const brewPath = resolveBrewPath(execFileSync3);
|
|
1955
2110
|
if (!brewPath) return;
|
|
1956
2111
|
try {
|
|
1957
|
-
|
|
2112
|
+
execFileSync3(brewPath, ["update", "--quiet"], { timeout: 6e4, stdio: "pipe" });
|
|
1958
2113
|
} catch (err) {
|
|
1959
2114
|
log(`[self-update] brew update failed (continuing with stale cache): ${err.message}`);
|
|
1960
2115
|
}
|
|
1961
2116
|
try {
|
|
1962
|
-
const outdated =
|
|
2117
|
+
const outdated = execFileSync3(brewPath, ["outdated", "--json=v2"], {
|
|
1963
2118
|
timeout: 3e4,
|
|
1964
2119
|
encoding: "utf-8"
|
|
1965
2120
|
});
|
|
@@ -1970,7 +2125,7 @@ async function checkAndUpdateCliViaBrew() {
|
|
|
1970
2125
|
const latest = agtOutdated.current_version ?? "unknown";
|
|
1971
2126
|
log(`[self-update] agt CLI update available: ${installed} \u2192 ${latest}. Upgrading via brew...`);
|
|
1972
2127
|
try {
|
|
1973
|
-
|
|
2128
|
+
execFileSync3(brewPath, ["upgrade", "integrity-labs/tap/agt"], {
|
|
1974
2129
|
timeout: 12e4,
|
|
1975
2130
|
stdio: "pipe"
|
|
1976
2131
|
});
|
|
@@ -1989,7 +2144,7 @@ async function checkAndUpdateCliViaBrew() {
|
|
|
1989
2144
|
}
|
|
1990
2145
|
}
|
|
1991
2146
|
async function checkAndUpdateCliViaNpm() {
|
|
1992
|
-
const { execFileSync:
|
|
2147
|
+
const { execFileSync: execFileSync3 } = await import("child_process");
|
|
1993
2148
|
if (agtCliVersion === "dev") return;
|
|
1994
2149
|
let latest;
|
|
1995
2150
|
try {
|
|
@@ -2038,7 +2193,7 @@ async function checkAndUpdateCliViaNpm() {
|
|
|
2038
2193
|
"--registry=https://registry.npmjs.org"
|
|
2039
2194
|
];
|
|
2040
2195
|
try {
|
|
2041
|
-
|
|
2196
|
+
execFileSync3(cmd, args, { timeout: 18e4, stdio: "pipe" });
|
|
2042
2197
|
log(`[self-update] agt CLI upgraded to ${latest}. Scheduling manager restart so the new binary takes effect.`);
|
|
2043
2198
|
restartAfterUpgrade = true;
|
|
2044
2199
|
pendingUpgradeVersion = latest;
|
|
@@ -2585,7 +2740,7 @@ async function pollCycle() {
|
|
|
2585
2740
|
}
|
|
2586
2741
|
try {
|
|
2587
2742
|
const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
|
|
2588
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
2743
|
+
const { collectDiagnostics } = await import("../persistent-session-M2GVL6Z6.js");
|
|
2589
2744
|
const diagCodeNames = [...persistentSessionAgents];
|
|
2590
2745
|
const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
|
|
2591
2746
|
let tailscaleHostname;
|
|
@@ -3333,12 +3488,33 @@ async function processAgent(agent, agentStates) {
|
|
|
3333
3488
|
log(`Integrations provisioned for '${agent.code_name}' (${integrations.length} integration(s))`);
|
|
3334
3489
|
const fw = agentFrameworkCache.get(agent.code_name) ?? "openclaw";
|
|
3335
3490
|
if (fw === "claude-code" && isSessionHealthy(agent.code_name)) {
|
|
3491
|
+
let affectedServerKeys = [];
|
|
3492
|
+
try {
|
|
3493
|
+
const projectDir = join4(homedir3(), ".augmented", agent.code_name, "project");
|
|
3494
|
+
const envIntPath = join4(projectDir, ".env.integrations");
|
|
3495
|
+
const projectMcpPath = join4(projectDir, ".mcp.json");
|
|
3496
|
+
const envContent = readFileSync3(envIntPath, "utf-8");
|
|
3497
|
+
const mcpContent = readFileSync3(projectMcpPath, "utf-8");
|
|
3498
|
+
const changedVars = parseEnvIntegrationsVars(envContent);
|
|
3499
|
+
const mcpJson = JSON.parse(mcpContent);
|
|
3500
|
+
affectedServerKeys = findMcpServersUsingVars(mcpJson, changedVars);
|
|
3501
|
+
} catch (err) {
|
|
3502
|
+
log(`[hot-reload] Failed to compute affected MCP servers for '${agent.code_name}': ${err.message}`);
|
|
3503
|
+
}
|
|
3504
|
+
if (affectedServerKeys.length > 0) {
|
|
3505
|
+
reapStaleMcpChildren({
|
|
3506
|
+
log,
|
|
3507
|
+
codeName: agent.code_name,
|
|
3508
|
+
serverKeys: affectedServerKeys
|
|
3509
|
+
});
|
|
3510
|
+
}
|
|
3336
3511
|
const names = integrations.map((i) => i.display_name || i.definition_id).join(", ");
|
|
3337
|
-
|
|
3512
|
+
const reapNote = affectedServerKeys.length > 0 ? ` The MCP servers that depend on rotating credentials (${affectedServerKeys.join(", ")}) have been signalled to reconnect.` : "";
|
|
3513
|
+
injectMessage(agent.code_name, "system", `Your integrations have been refreshed. You have access to: ${names}.${reapNote}`, {
|
|
3338
3514
|
task_name: "integration-update"
|
|
3339
3515
|
}, log).catch(() => {
|
|
3340
3516
|
});
|
|
3341
|
-
log(`[hot-reload] Notified '${agent.code_name}' about integration update: ${names}`);
|
|
3517
|
+
log(`[hot-reload] Notified '${agent.code_name}' about integration update: ${names} (reaped ${affectedServerKeys.length} stale MCP server(s))`);
|
|
3342
3518
|
}
|
|
3343
3519
|
needsGatewayRestart = true;
|
|
3344
3520
|
}
|
|
@@ -5822,7 +5998,7 @@ async function processClaudePairSessions(agents) {
|
|
|
5822
5998
|
killPairSession,
|
|
5823
5999
|
pairTmuxSession,
|
|
5824
6000
|
finalizeClaudePairOnboarding
|
|
5825
|
-
} = await import("../claude-pair-runtime-
|
|
6001
|
+
} = await import("../claude-pair-runtime-UF4OMFCA.js");
|
|
5826
6002
|
for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
|
|
5827
6003
|
log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
|
|
5828
6004
|
const killed = await killPairSession(pairTmuxSession(pairId));
|