@integrity-labs/agt-cli 0.28.207 → 0.28.209
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 +230 -146
- package/dist/bin/agt.js.map +1 -1
- package/dist/{chunk-ELBYWACS.js → chunk-WFCCBTA6.js} +8463 -6842
- package/dist/chunk-WFCCBTA6.js.map +1 -0
- package/dist/{chunk-TPFTAFG3.js → chunk-Z62QHIR3.js} +792 -38
- package/dist/chunk-Z62QHIR3.js.map +1 -0
- package/dist/{claude-pair-runtime-Q4Q2OTTV.js → claude-pair-runtime-UUTPSE2V.js} +2 -2
- package/dist/lib/manager-worker.js +88 -795
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/{persistent-session-6662WBSH.js → persistent-session-Z46SCCQM.js} +2 -3
- package/dist/{responsiveness-probe-TOLTTG6I.js → responsiveness-probe-4MUX7FBH.js} +2 -3
- package/dist/{responsiveness-probe-TOLTTG6I.js.map → responsiveness-probe-4MUX7FBH.js.map} +1 -1
- package/package.json +1 -1
- package/dist/chunk-ELBYWACS.js.map +0 -1
- package/dist/chunk-GWBOA7ZY.js +0 -1634
- package/dist/chunk-GWBOA7ZY.js.map +0 -1
- package/dist/chunk-TPFTAFG3.js.map +0 -1
- /package/dist/{claude-pair-runtime-Q4Q2OTTV.js.map → claude-pair-runtime-UUTPSE2V.js.map} +0 -0
- /package/dist/{persistent-session-6662WBSH.js.map → persistent-session-Z46SCCQM.js.map} +0 -0
|
@@ -9,15 +9,21 @@ import {
|
|
|
9
9
|
atomicWriteFileSync,
|
|
10
10
|
buildConnectivityProbeDeps,
|
|
11
11
|
buildProbeEnv,
|
|
12
|
+
clearPresenceReaperState,
|
|
13
|
+
clearPresenceReaperStateForKeys,
|
|
12
14
|
defaultFlagsCachePath,
|
|
13
15
|
deriveMcpServerKey,
|
|
16
|
+
diffEnvIntegrations,
|
|
14
17
|
estimateActiveTasksTokens,
|
|
15
18
|
exchangeApiKey,
|
|
16
19
|
executeConnectivityProbe,
|
|
17
20
|
extractCommandNotFound,
|
|
21
|
+
findMcpServersUsingVars,
|
|
22
|
+
gatherSessionToolBindProbe,
|
|
18
23
|
getApiKey,
|
|
19
24
|
getCachedClaudeAuthMode,
|
|
20
25
|
getHostId,
|
|
26
|
+
givenUpMcpServerKeys,
|
|
21
27
|
provision,
|
|
22
28
|
provisionAutoKanbanProgressHook,
|
|
23
29
|
provisionChannelProgressHook,
|
|
@@ -25,10 +31,12 @@ import {
|
|
|
25
31
|
provisionOrientHook,
|
|
26
32
|
provisionSessionStateHook,
|
|
27
33
|
provisionStopHook,
|
|
34
|
+
reapMissingMcpSessions,
|
|
35
|
+
reapStaleMcpChildren,
|
|
28
36
|
requireHost,
|
|
29
37
|
safeWriteJsonAtomic,
|
|
30
38
|
setConfigHash
|
|
31
|
-
} from "../chunk-
|
|
39
|
+
} from "../chunk-Z62QHIR3.js";
|
|
32
40
|
import {
|
|
33
41
|
getProjectDir as getProjectDir2,
|
|
34
42
|
getReadyTasks,
|
|
@@ -36,41 +44,6 @@ import {
|
|
|
36
44
|
markTaskFired,
|
|
37
45
|
syncTasksToScheduler
|
|
38
46
|
} from "../chunk-I3YS5WFV.js";
|
|
39
|
-
import {
|
|
40
|
-
buildEgressAllowlist,
|
|
41
|
-
checkChannelInputs,
|
|
42
|
-
creditWatchdogGiveUpCount,
|
|
43
|
-
egressMode,
|
|
44
|
-
getLastFailureContext,
|
|
45
|
-
getProjectDir,
|
|
46
|
-
getSessionState,
|
|
47
|
-
injectMessage,
|
|
48
|
-
injectMessageWithStatus,
|
|
49
|
-
isAgentIdle,
|
|
50
|
-
isAgentPromptReady,
|
|
51
|
-
isSessionHealthy,
|
|
52
|
-
isStaleForToday,
|
|
53
|
-
isolationMode,
|
|
54
|
-
paneLogPath,
|
|
55
|
-
peekCurrentSession,
|
|
56
|
-
prepareForRespawn,
|
|
57
|
-
readPaneLogTail,
|
|
58
|
-
reloadEgressSidecar,
|
|
59
|
-
resetRestartCount,
|
|
60
|
-
resolveClaudeBinary,
|
|
61
|
-
restartEgressSidecar,
|
|
62
|
-
rotateSessionForWedge,
|
|
63
|
-
sendToAgent,
|
|
64
|
-
sessionTranscriptDir,
|
|
65
|
-
startPersistentSession,
|
|
66
|
-
stopAllSessionsAndWait,
|
|
67
|
-
stopPersistentSession,
|
|
68
|
-
subagentActivityAgeSeconds,
|
|
69
|
-
takeWatchdogGiveUpCount,
|
|
70
|
-
takeZombieDetection,
|
|
71
|
-
transcriptActivityAgeSeconds,
|
|
72
|
-
writeEgressAllowlist
|
|
73
|
-
} from "../chunk-GWBOA7ZY.js";
|
|
74
47
|
import {
|
|
75
48
|
CONVERSATION_FAILURE_CATEGORIES,
|
|
76
49
|
DEFAULT_FRAMEWORK,
|
|
@@ -82,17 +55,28 @@ import {
|
|
|
82
55
|
StreamEncoder,
|
|
83
56
|
appendDmFooter,
|
|
84
57
|
attributeTranscriptUsageByRun,
|
|
58
|
+
buildEgressAllowlist,
|
|
85
59
|
buildFailureCategoryPromptLines,
|
|
86
60
|
buildScheduledTaskContextBlocks,
|
|
61
|
+
checkChannelInputs,
|
|
87
62
|
classifyActor,
|
|
88
63
|
classifyOutput,
|
|
89
64
|
coerceOnboardingState,
|
|
65
|
+
creditWatchdogGiveUpCount,
|
|
90
66
|
describeOnboardingChannel,
|
|
67
|
+
egressMode,
|
|
91
68
|
extractFrontmatter,
|
|
92
69
|
formatActorId,
|
|
93
70
|
formatRunMarker,
|
|
94
71
|
getFramework,
|
|
95
72
|
getIntegration,
|
|
73
|
+
getLastFailureContext,
|
|
74
|
+
getProjectDir,
|
|
75
|
+
getSessionState,
|
|
76
|
+
injectMessage,
|
|
77
|
+
injectMessageWithStatus,
|
|
78
|
+
isAgentIdle,
|
|
79
|
+
isAgentPromptReady,
|
|
96
80
|
isBareAck,
|
|
97
81
|
isConversationFailureCategory,
|
|
98
82
|
isEmptyTotals,
|
|
@@ -100,23 +84,44 @@ import {
|
|
|
100
84
|
isParseError,
|
|
101
85
|
isResolveError,
|
|
102
86
|
isSelfCompletion,
|
|
87
|
+
isSessionHealthy,
|
|
88
|
+
isStaleForToday,
|
|
103
89
|
isSystemInjectedContent,
|
|
104
90
|
isUnsetTimezone,
|
|
105
91
|
isVacuousDeliverReason,
|
|
92
|
+
isolationMode,
|
|
106
93
|
laneTagFragment,
|
|
94
|
+
paneLogPath,
|
|
107
95
|
parseDeliverAssertion,
|
|
108
96
|
parseDeliveryTarget,
|
|
109
97
|
parseEnvIntegrations,
|
|
110
98
|
parseTranscriptUsage,
|
|
111
99
|
parseUsageBanner,
|
|
100
|
+
peekCurrentSession,
|
|
101
|
+
prepareForRespawn,
|
|
102
|
+
readPaneLogTail,
|
|
103
|
+
reloadEgressSidecar,
|
|
104
|
+
resetRestartCount,
|
|
112
105
|
resolveAgentTimezone,
|
|
113
106
|
resolveAvatarEnvUrl,
|
|
114
107
|
resolveChannels,
|
|
108
|
+
resolveClaudeBinary,
|
|
115
109
|
resolveDmTarget,
|
|
116
|
-
|
|
117
|
-
|
|
110
|
+
restartEgressSidecar,
|
|
111
|
+
rotateSessionForWedge,
|
|
112
|
+
sendToAgent,
|
|
113
|
+
sessionTranscriptDir,
|
|
114
|
+
startPersistentSession,
|
|
115
|
+
stopAllSessionsAndWait,
|
|
116
|
+
stopPersistentSession,
|
|
117
|
+
subagentActivityAgeSeconds,
|
|
118
|
+
sumTranscriptUsageInWindow,
|
|
119
|
+
takeWatchdogGiveUpCount,
|
|
120
|
+
takeZombieDetection,
|
|
121
|
+
transcriptActivityAgeSeconds,
|
|
122
|
+
writeEgressAllowlist
|
|
123
|
+
} from "../chunk-WFCCBTA6.js";
|
|
118
124
|
import {
|
|
119
|
-
parsePsRows,
|
|
120
125
|
reapOrphanChannelMcps
|
|
121
126
|
} from "../chunk-XWVM4KPK.js";
|
|
122
127
|
|
|
@@ -223,559 +228,9 @@ function computeIntegrationsHash(integrations) {
|
|
|
223
228
|
return createHash2("sha256").update(JSON.stringify(payload)).digest("hex").slice(0, 16);
|
|
224
229
|
}
|
|
225
230
|
|
|
226
|
-
// src/lib/
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
var DEFAULT_ROTATION_GRACE_MS = 15e3;
|
|
230
|
-
function rotationKey(codeName, serverKey) {
|
|
231
|
-
return `${codeName}\0${serverKey}`;
|
|
232
|
-
}
|
|
233
|
-
function recordStaleRotation(codeName, serverKeys, now = Date.now) {
|
|
234
|
-
const ts = now();
|
|
235
|
-
for (const key of serverKeys) {
|
|
236
|
-
rotationTimestamps.set(rotationKey(codeName, key), ts);
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
function wasRecentlyRotated(codeName, serverKey, withinMs, now = Date.now) {
|
|
240
|
-
const k = rotationKey(codeName, serverKey);
|
|
241
|
-
const ts = rotationTimestamps.get(k);
|
|
242
|
-
if (ts === void 0) return false;
|
|
243
|
-
if (now() - ts < withinMs) return true;
|
|
244
|
-
rotationTimestamps.delete(k);
|
|
245
|
-
return false;
|
|
246
|
-
}
|
|
247
|
-
function parseEnvIntegrationsEntries(content) {
|
|
248
|
-
const entries = /* @__PURE__ */ new Map();
|
|
249
|
-
for (const raw of content.split(/\r?\n/)) {
|
|
250
|
-
const line = raw.trim();
|
|
251
|
-
if (!line || line.startsWith("#")) continue;
|
|
252
|
-
const eq = line.indexOf("=");
|
|
253
|
-
if (eq <= 0) continue;
|
|
254
|
-
const name = line.slice(0, eq).trim();
|
|
255
|
-
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) continue;
|
|
256
|
-
const value = line.slice(eq + 1);
|
|
257
|
-
entries.set(name, value);
|
|
258
|
-
}
|
|
259
|
-
return entries;
|
|
260
|
-
}
|
|
261
|
-
function diffEnvIntegrations(oldContent, newContent) {
|
|
262
|
-
const oldEntries = oldContent === void 0 ? /* @__PURE__ */ new Map() : parseEnvIntegrationsEntries(oldContent);
|
|
263
|
-
const newEntries = parseEnvIntegrationsEntries(newContent);
|
|
264
|
-
const changed = /* @__PURE__ */ new Set();
|
|
265
|
-
for (const [name, value] of newEntries) {
|
|
266
|
-
if (oldEntries.get(name) !== value) changed.add(name);
|
|
267
|
-
}
|
|
268
|
-
for (const name of oldEntries.keys()) {
|
|
269
|
-
if (!newEntries.has(name)) changed.add(name);
|
|
270
|
-
}
|
|
271
|
-
return [...changed];
|
|
272
|
-
}
|
|
273
|
-
function findMcpServersUsingVars(mcp, changedVars) {
|
|
274
|
-
const changedSet = new Set(changedVars);
|
|
275
|
-
if (!mcp?.mcpServers || changedSet.size === 0) return [];
|
|
276
|
-
const result = [];
|
|
277
|
-
for (const [serverKey, entry] of Object.entries(mcp.mcpServers)) {
|
|
278
|
-
if (!entry || typeof entry !== "object") continue;
|
|
279
|
-
const env = entry.env;
|
|
280
|
-
if (!env || typeof env !== "object") continue;
|
|
281
|
-
let matches = false;
|
|
282
|
-
for (const value of Object.values(env)) {
|
|
283
|
-
if (typeof value !== "string") continue;
|
|
284
|
-
const placeholderMatches = value.match(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g);
|
|
285
|
-
if (placeholderMatches) {
|
|
286
|
-
for (const ph of placeholderMatches) {
|
|
287
|
-
const name = ph.slice(2, -1);
|
|
288
|
-
if (changedSet.has(name)) {
|
|
289
|
-
matches = true;
|
|
290
|
-
break;
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
if (matches) break;
|
|
295
|
-
}
|
|
296
|
-
if (matches) result.push(serverKey);
|
|
297
|
-
}
|
|
298
|
-
return result;
|
|
299
|
-
}
|
|
300
|
-
function buildArgvMatchersForEntry(key, entry) {
|
|
301
|
-
const escapeRe = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
302
|
-
const patterns = [];
|
|
303
|
-
const args = entry?.args ?? [];
|
|
304
|
-
for (let i = args.length - 1; i >= 0; i--) {
|
|
305
|
-
const arg = args[i];
|
|
306
|
-
if (typeof arg !== "string" || !arg) continue;
|
|
307
|
-
if (arg.startsWith("-")) continue;
|
|
308
|
-
const stripped = arg.replace(
|
|
309
|
-
/@[^/@]*$/,
|
|
310
|
-
(m) => (
|
|
311
|
-
// @latest, @1.2.3, etc. — drop. But @scope at the START of a
|
|
312
|
-
// package spec must NOT be stripped, so we only strip a tail
|
|
313
|
-
// `@...` if it doesn't itself start with a slash inside.
|
|
314
|
-
// The regex above only matches a single trailing `@...`
|
|
315
|
-
// segment after the last `/`, so this is safe for `@scope/pkg`.
|
|
316
|
-
m.includes("/") ? m : ""
|
|
317
|
-
)
|
|
318
|
-
);
|
|
319
|
-
const tail = "(?![A-Za-z0-9_-])";
|
|
320
|
-
if (/^@?[a-z0-9]([a-z0-9._-]*\/)?[a-z0-9._-]+$/i.test(stripped)) {
|
|
321
|
-
patterns.push(new RegExp(`${escapeRe(stripped)}${tail}`));
|
|
322
|
-
const basename = stripped.split("/").pop();
|
|
323
|
-
if (basename && basename !== stripped) {
|
|
324
|
-
patterns.push(new RegExp(`${escapeRe(basename)}${tail}`));
|
|
325
|
-
}
|
|
326
|
-
break;
|
|
327
|
-
}
|
|
328
|
-
if (stripped.includes("/")) {
|
|
329
|
-
const basename = stripped.split("/").pop();
|
|
330
|
-
if (basename) {
|
|
331
|
-
patterns.push(new RegExp(`${escapeRe(basename)}${tail}`));
|
|
332
|
-
break;
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
if (patterns.length === 0) {
|
|
337
|
-
const safe = escapeRe(key);
|
|
338
|
-
patterns.push(new RegExp(`(?<![A-Za-z0-9_])${safe}(?![A-Za-z0-9_])`));
|
|
339
|
-
if (safe.includes("_")) {
|
|
340
|
-
const dashed = safe.replace(/_/g, "-");
|
|
341
|
-
patterns.push(new RegExp(`(?<![A-Za-z0-9_])${dashed}(?![A-Za-z0-9_])`));
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
return patterns;
|
|
345
|
-
}
|
|
346
|
-
function buildClaudeAgentMatcher(codeName) {
|
|
347
|
-
const safe = codeName.replace(/[^A-Za-z0-9_-]/g, "");
|
|
348
|
-
return new RegExp(`\\bclaude\\b.*--name\\s+agt-${safe}(?=\\s|$)`);
|
|
349
|
-
}
|
|
350
|
-
function findMcpChildrenForAgent(args) {
|
|
351
|
-
const { rows, codeName, serverKeys, mcpJson } = args;
|
|
352
|
-
const maxDepth = args.maxDepth ?? 8;
|
|
353
|
-
const inContainer = args.inContainer ?? false;
|
|
354
|
-
if (serverKeys.length === 0 || rows.length === 0) return [];
|
|
355
|
-
const claudeMatcher = inContainer ? /\bclaude\b/ : buildClaudeAgentMatcher(codeName);
|
|
356
|
-
const argvMatchers = [];
|
|
357
|
-
for (const key of serverKeys) {
|
|
358
|
-
const entry = mcpJson?.mcpServers?.[key];
|
|
359
|
-
argvMatchers.push(...buildArgvMatchersForEntry(key, entry));
|
|
360
|
-
}
|
|
361
|
-
const byPid = new Map(rows.map((r) => [r.pid, r]));
|
|
362
|
-
const matched = [];
|
|
363
|
-
for (const row of rows) {
|
|
364
|
-
if (!argvMatchers.some((re) => re.test(row.args))) continue;
|
|
365
|
-
if (/\bclaude\b/.test(row.args) && row.args.includes(`--name agt-${codeName}`)) continue;
|
|
366
|
-
let cur = byPid.get(row.ppid);
|
|
367
|
-
let belongs = false;
|
|
368
|
-
for (let depth = 0; depth < maxDepth && cur; depth++) {
|
|
369
|
-
if (claudeMatcher.test(cur.args)) {
|
|
370
|
-
belongs = true;
|
|
371
|
-
break;
|
|
372
|
-
}
|
|
373
|
-
if (cur.pid === 1) break;
|
|
374
|
-
cur = byPid.get(cur.ppid);
|
|
375
|
-
}
|
|
376
|
-
if (belongs) matched.push(row.pid);
|
|
377
|
-
}
|
|
378
|
-
return matched;
|
|
379
|
-
}
|
|
380
|
-
function reapStaleMcpChildren(args) {
|
|
381
|
-
const { log: log2, codeName, serverKeys, mcpJson, graceMs = 5e3, isolated = false } = args;
|
|
382
|
-
if (serverKeys.length === 0) return [];
|
|
383
|
-
const runPs = args.runPs ?? (isolated ? () => execFileSync("docker", ["exec", `agt-${codeName}`, "ps", "-eo", "pid,ppid,args"], {
|
|
384
|
-
encoding: "utf-8",
|
|
385
|
-
timeout: 8e3
|
|
386
|
-
}) : () => execFileSync("ps", ["-eo", "pid,ppid,args"], { encoding: "utf-8", timeout: 5e3 }));
|
|
387
|
-
const killProcess = args.killProcess ?? (isolated ? (pid, signal) => {
|
|
388
|
-
try {
|
|
389
|
-
execFileSync(
|
|
390
|
-
"docker",
|
|
391
|
-
["exec", `agt-${codeName}`, "kill", signal === "SIGKILL" ? "-KILL" : "-TERM", String(pid)],
|
|
392
|
-
{ timeout: 8e3, stdio: "ignore" }
|
|
393
|
-
);
|
|
394
|
-
} catch {
|
|
395
|
-
}
|
|
396
|
-
} : (pid, signal) => {
|
|
397
|
-
try {
|
|
398
|
-
process.kill(pid, signal);
|
|
399
|
-
} catch {
|
|
400
|
-
}
|
|
401
|
-
});
|
|
402
|
-
const isAlive = args.isAlive ?? (isolated ? (pid) => {
|
|
403
|
-
try {
|
|
404
|
-
execFileSync("docker", ["exec", `agt-${codeName}`, "kill", "-0", String(pid)], {
|
|
405
|
-
timeout: 8e3,
|
|
406
|
-
stdio: "ignore"
|
|
407
|
-
});
|
|
408
|
-
return true;
|
|
409
|
-
} catch {
|
|
410
|
-
return false;
|
|
411
|
-
}
|
|
412
|
-
} : (pid) => {
|
|
413
|
-
try {
|
|
414
|
-
process.kill(pid, 0);
|
|
415
|
-
return true;
|
|
416
|
-
} catch {
|
|
417
|
-
return false;
|
|
418
|
-
}
|
|
419
|
-
});
|
|
420
|
-
let psOutput;
|
|
421
|
-
try {
|
|
422
|
-
psOutput = runPs();
|
|
423
|
-
} catch (err) {
|
|
424
|
-
log2(`[stale-mcp-reaper] ps invocation failed for '${codeName}': ${err.message} \u2014 skipping reap`);
|
|
425
|
-
return [];
|
|
426
|
-
}
|
|
427
|
-
const rows = parsePsRows(psOutput);
|
|
428
|
-
const targets = findMcpChildrenForAgent({ rows, codeName, serverKeys, mcpJson, inContainer: isolated });
|
|
429
|
-
if (targets.length === 0) return [];
|
|
430
|
-
const byPid = new Map(rows.map((r) => [r.pid, r]));
|
|
431
|
-
const describe = (pid) => {
|
|
432
|
-
const argv = byPid.get(pid)?.args ?? "";
|
|
433
|
-
const pkgMatch = argv.match(/(@[a-z0-9_-]+\/[a-z0-9_-]+|[a-z0-9_-]+-mcp-server|[a-z0-9_-]+-mcp\b)/i);
|
|
434
|
-
return pkgMatch ? `${pkgMatch[1]} (pid ${pid})` : `pid ${pid}`;
|
|
435
|
-
};
|
|
436
|
-
log2(
|
|
437
|
-
`[stale-mcp-reaper] '${codeName}': rotating ${targets.length} stale MCP child(ren) for [${serverKeys.join(", ")}]: ${targets.map(describe).join(", ")}`
|
|
438
|
-
);
|
|
439
|
-
for (const pid of targets) {
|
|
440
|
-
killProcess(pid, "SIGTERM");
|
|
441
|
-
}
|
|
442
|
-
const killedKeys = /* @__PURE__ */ new Set();
|
|
443
|
-
for (const pid of targets) {
|
|
444
|
-
const argv = byPid.get(pid)?.args ?? "";
|
|
445
|
-
for (const key of serverKeys) {
|
|
446
|
-
const entry = mcpJson?.mcpServers?.[key];
|
|
447
|
-
const matchers = buildArgvMatchersForEntry(key, entry);
|
|
448
|
-
if (matchers.some((re) => re.test(argv))) killedKeys.add(key);
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
if (killedKeys.size > 0) recordStaleRotation(codeName, killedKeys);
|
|
452
|
-
setTimeout(() => {
|
|
453
|
-
try {
|
|
454
|
-
let freshPsOutput;
|
|
455
|
-
try {
|
|
456
|
-
freshPsOutput = runPs();
|
|
457
|
-
} catch (err) {
|
|
458
|
-
log2(`[stale-mcp-reaper] '${codeName}': fresh ps for SIGKILL re-verify failed: ${err.message} \u2014 skipping SIGKILL pass`);
|
|
459
|
-
return;
|
|
460
|
-
}
|
|
461
|
-
const stillOwned = new Set(
|
|
462
|
-
findMcpChildrenForAgent({
|
|
463
|
-
rows: parsePsRows(freshPsOutput),
|
|
464
|
-
codeName,
|
|
465
|
-
serverKeys,
|
|
466
|
-
mcpJson,
|
|
467
|
-
inContainer: isolated
|
|
468
|
-
})
|
|
469
|
-
);
|
|
470
|
-
const stragglers = targets.filter((pid) => isAlive(pid) && stillOwned.has(pid));
|
|
471
|
-
if (stragglers.length === 0) return;
|
|
472
|
-
log2(
|
|
473
|
-
`[stale-mcp-reaper] '${codeName}': ${stragglers.length} child(ren) survived SIGTERM; sending SIGKILL: ${stragglers.map(describe).join(", ")}`
|
|
474
|
-
);
|
|
475
|
-
for (const pid of stragglers) {
|
|
476
|
-
killProcess(pid, "SIGKILL");
|
|
477
|
-
}
|
|
478
|
-
} catch (err) {
|
|
479
|
-
log2(`[stale-mcp-reaper] '${codeName}': error in SIGKILL pass: ${err.message}`);
|
|
480
|
-
}
|
|
481
|
-
}, graceMs).unref();
|
|
482
|
-
return targets;
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
// src/lib/mcp-presence-reaper.ts
|
|
486
|
-
import { execFileSync as execFileSync2 } from "child_process";
|
|
487
|
-
var DEFAULT_COLD_START_GRACE_MS = 9e4;
|
|
488
|
-
var MAX_PRESENCE_RESTART_ATTEMPTS = 3;
|
|
489
|
-
var BACKOFF_AFTER_RESTARTS = MAX_PRESENCE_RESTART_ATTEMPTS;
|
|
490
|
-
var BACKOFF_BASE_MS = 6e4;
|
|
491
|
-
var BACKOFF_MAX_MS = 30 * 6e4;
|
|
492
|
-
var BACKOFF_WINDOW_MS = 60 * 6e4;
|
|
493
|
-
var BACKOFF_GIVE_UP_RESTARTS = 2 * MAX_PRESENCE_RESTART_ATTEMPTS;
|
|
494
|
-
var BACKOFF_STABLE_RESET_MS = 5 * 6e4;
|
|
495
|
-
var presenceReaperState = /* @__PURE__ */ new Map();
|
|
496
|
-
function stateKey(codeName, serverKey) {
|
|
497
|
-
return `${codeName}\0${serverKey}`;
|
|
498
|
-
}
|
|
499
|
-
function clearPresenceReaperState(codeName) {
|
|
500
|
-
const prefix = `${codeName}\0`;
|
|
501
|
-
for (const key of presenceReaperState.keys()) {
|
|
502
|
-
if (key.startsWith(prefix)) presenceReaperState.delete(key);
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
function clearPresenceReaperStateForKeys(codeName, keys) {
|
|
506
|
-
for (const key of keys) {
|
|
507
|
-
presenceReaperState.delete(stateKey(codeName, key));
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
function givenUpMcpServerKeys(codeName) {
|
|
511
|
-
const prefix = `${codeName}\0`;
|
|
512
|
-
const out = /* @__PURE__ */ new Set();
|
|
513
|
-
for (const [key, st] of presenceReaperState) {
|
|
514
|
-
if (key.startsWith(prefix) && (st.gaveUp || st.attempts >= MAX_PRESENCE_RESTART_ATTEMPTS)) {
|
|
515
|
-
out.add(key.slice(prefix.length));
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
return out;
|
|
519
|
-
}
|
|
520
|
-
function findMissingMcpServers(args) {
|
|
521
|
-
const { rows, codeName, mcpJson, inContainer } = args;
|
|
522
|
-
const servers = mcpJson?.mcpServers ?? {};
|
|
523
|
-
const declared = Object.keys(servers);
|
|
524
|
-
if (declared.length === 0) return [];
|
|
525
|
-
const missing = [];
|
|
526
|
-
for (const key of declared) {
|
|
527
|
-
const entry = servers[key];
|
|
528
|
-
const isStdio = typeof entry?.command === "string";
|
|
529
|
-
if (!isStdio) continue;
|
|
530
|
-
const live = findMcpChildrenForAgent({
|
|
531
|
-
rows,
|
|
532
|
-
codeName,
|
|
533
|
-
serverKeys: [key],
|
|
534
|
-
mcpJson,
|
|
535
|
-
inContainer
|
|
536
|
-
});
|
|
537
|
-
if (live.length === 0) missing.push(key);
|
|
538
|
-
}
|
|
539
|
-
return missing;
|
|
540
|
-
}
|
|
541
|
-
function reapMissingMcpSessions(args) {
|
|
542
|
-
const {
|
|
543
|
-
log: log2,
|
|
544
|
-
codeName,
|
|
545
|
-
mcpJson,
|
|
546
|
-
sessionStartedAt,
|
|
547
|
-
restartPending = false,
|
|
548
|
-
stopSession,
|
|
549
|
-
graceMs = DEFAULT_COLD_START_GRACE_MS,
|
|
550
|
-
rotationGraceMs = DEFAULT_ROTATION_GRACE_MS,
|
|
551
|
-
onGiveUp,
|
|
552
|
-
onRestart,
|
|
553
|
-
// ENG-5932: defaults make quarantine a strict no-op (classify everything
|
|
554
|
-
// essential, mode off) so legacy callers/tests are unaffected.
|
|
555
|
-
classifyKey = () => "essential",
|
|
556
|
-
quarantineDwellMs = 0,
|
|
557
|
-
quarantineMode = "off",
|
|
558
|
-
onQuarantine,
|
|
559
|
-
isolated = false
|
|
560
|
-
} = args;
|
|
561
|
-
const now = args.now ?? Date.now;
|
|
562
|
-
const runPs = args.runPs ?? (isolated ? () => execFileSync2("docker", ["exec", `agt-${codeName}`, "ps", "-eo", "pid,ppid,args"], {
|
|
563
|
-
encoding: "utf-8",
|
|
564
|
-
timeout: 8e3
|
|
565
|
-
}) : () => execFileSync2("ps", ["-eo", "pid,ppid,args"], { encoding: "utf-8", timeout: 5e3 }));
|
|
566
|
-
if (!mcpJson?.mcpServers) {
|
|
567
|
-
return { missing: [], restarted: false, reason: "no-mcp-json" };
|
|
568
|
-
}
|
|
569
|
-
const declaredCount = Object.keys(mcpJson.mcpServers).length;
|
|
570
|
-
if (declaredCount === 0) {
|
|
571
|
-
return { missing: [], restarted: false, reason: "no-declared-servers" };
|
|
572
|
-
}
|
|
573
|
-
if (restartPending) {
|
|
574
|
-
return { missing: [], restarted: false, reason: "restart-pending" };
|
|
575
|
-
}
|
|
576
|
-
if (sessionStartedAt === null) {
|
|
577
|
-
return { missing: [], restarted: false, reason: "session-start-unknown" };
|
|
578
|
-
}
|
|
579
|
-
if (now() - sessionStartedAt < graceMs) {
|
|
580
|
-
return { missing: [], restarted: false, reason: "cold-start" };
|
|
581
|
-
}
|
|
582
|
-
let psOutput;
|
|
583
|
-
try {
|
|
584
|
-
psOutput = runPs();
|
|
585
|
-
} catch (err) {
|
|
586
|
-
log2(`[mcp-presence-reaper] ps invocation failed for '${codeName}': ${err.message} \u2014 skipping`);
|
|
587
|
-
return { missing: [], restarted: false, reason: "healthy" };
|
|
588
|
-
}
|
|
589
|
-
const rows = parsePsRows(psOutput);
|
|
590
|
-
const missingRaw = findMissingMcpServers({ rows, codeName, mcpJson, inContainer: isolated });
|
|
591
|
-
const rotationGraced = [];
|
|
592
|
-
const missing = [];
|
|
593
|
-
for (const key of missingRaw) {
|
|
594
|
-
if (wasRecentlyRotated(codeName, key, rotationGraceMs, now)) {
|
|
595
|
-
rotationGraced.push(key);
|
|
596
|
-
} else {
|
|
597
|
-
missing.push(key);
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
if (rotationGraced.length > 0) {
|
|
601
|
-
log2(
|
|
602
|
-
`[mcp-presence-reaper] '${codeName}': skipping [${rotationGraced.join(", ")}] within rotation grace window (${rotationGraceMs}ms) \u2014 child(ren) just SIGTERM'd by stale-mcp-reaper, awaiting respawn on next tool call (ENG-5344)`
|
|
603
|
-
);
|
|
604
|
-
}
|
|
605
|
-
const declared = mcpJson.mcpServers ?? {};
|
|
606
|
-
const liveKeys = /* @__PURE__ */ new Set();
|
|
607
|
-
for (const key of Object.keys(declared)) {
|
|
608
|
-
const entry = declared[key];
|
|
609
|
-
if (typeof entry?.command !== "string") continue;
|
|
610
|
-
if (!missingRaw.includes(key)) liveKeys.add(key);
|
|
611
|
-
}
|
|
612
|
-
for (const key of liveKeys) {
|
|
613
|
-
const state7 = presenceReaperState.get(stateKey(codeName, key));
|
|
614
|
-
if (state7) {
|
|
615
|
-
state7.attempts = 0;
|
|
616
|
-
state7.lastSeenLiveAt = now();
|
|
617
|
-
state7.lastAttemptedSessionStartedAt = null;
|
|
618
|
-
state7.gaveUpLogged = false;
|
|
619
|
-
state7.firstMissingAt = null;
|
|
620
|
-
state7.quarantineLogged = false;
|
|
621
|
-
state7.gaveUp = false;
|
|
622
|
-
if (state7.stableLiveSince === null) state7.stableLiveSince = now();
|
|
623
|
-
if (now() - state7.stableLiveSince >= BACKOFF_STABLE_RESET_MS) {
|
|
624
|
-
state7.restartHistory = [];
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
if (missing.length === 0) {
|
|
629
|
-
return {
|
|
630
|
-
missing,
|
|
631
|
-
restarted: false,
|
|
632
|
-
reason: "healthy",
|
|
633
|
-
rotationGraced: rotationGraced.length > 0 ? rotationGraced : void 0
|
|
634
|
-
};
|
|
635
|
-
}
|
|
636
|
-
const nowMs = now();
|
|
637
|
-
const givenUp = [];
|
|
638
|
-
const active = [];
|
|
639
|
-
const backingOff = [];
|
|
640
|
-
const newGenerationKeys = /* @__PURE__ */ new Set();
|
|
641
|
-
const quarantined = [];
|
|
642
|
-
const wouldQuarantine = [];
|
|
643
|
-
for (const key of missing) {
|
|
644
|
-
const sk = stateKey(codeName, key);
|
|
645
|
-
const state7 = presenceReaperState.get(sk) ?? {
|
|
646
|
-
attempts: 0,
|
|
647
|
-
lastSeenLiveAt: null,
|
|
648
|
-
lastAttemptedSessionStartedAt: null,
|
|
649
|
-
gaveUpLogged: false,
|
|
650
|
-
firstMissingAt: null,
|
|
651
|
-
quarantineLogged: false,
|
|
652
|
-
restartHistory: [],
|
|
653
|
-
stableLiveSince: null,
|
|
654
|
-
gaveUp: false
|
|
655
|
-
};
|
|
656
|
-
if (state7.firstMissingAt === null) state7.firstMissingAt = nowMs;
|
|
657
|
-
state7.stableLiveSince = null;
|
|
658
|
-
if (state7.lastAttemptedSessionStartedAt !== sessionStartedAt) {
|
|
659
|
-
state7.attempts += 1;
|
|
660
|
-
state7.lastAttemptedSessionStartedAt = sessionStartedAt;
|
|
661
|
-
newGenerationKeys.add(key);
|
|
662
|
-
}
|
|
663
|
-
state7.restartHistory = state7.restartHistory.filter((t) => nowMs - t < BACKOFF_WINDOW_MS);
|
|
664
|
-
const restartsInWindow = state7.restartHistory.length;
|
|
665
|
-
presenceReaperState.set(sk, state7);
|
|
666
|
-
const overAttemptsCap = state7.attempts > MAX_PRESENCE_RESTART_ATTEMPTS;
|
|
667
|
-
const overRateCap = restartsInWindow >= BACKOFF_GIVE_UP_RESTARTS;
|
|
668
|
-
if (overAttemptsCap || overRateCap) {
|
|
669
|
-
givenUp.push(key);
|
|
670
|
-
state7.gaveUp = true;
|
|
671
|
-
if (!state7.gaveUpLogged) {
|
|
672
|
-
const cause = overAttemptsCap ? `${MAX_PRESENCE_RESTART_ATTEMPTS} consecutive failed restarts \u2014 declared but never recovers (likely orphaned config; see ENG-5279)` : `${restartsInWindow} restarts within ${Math.round(BACKOFF_WINDOW_MS / 6e4)}m \u2014 persistently flapping (crash-loop; ENG-6480)`;
|
|
673
|
-
log2(
|
|
674
|
-
`[mcp-presence-reaper] giving up on '${codeName}:${key}' after ${cause}`
|
|
675
|
-
);
|
|
676
|
-
state7.gaveUpLogged = true;
|
|
677
|
-
if (onGiveUp) {
|
|
678
|
-
try {
|
|
679
|
-
onGiveUp(codeName, key);
|
|
680
|
-
} catch (err) {
|
|
681
|
-
log2(
|
|
682
|
-
`[mcp-presence-reaper] onGiveUp callback threw for '${codeName}:${key}' (suppressed; reaper continues): ${err.message}`
|
|
683
|
-
);
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
}
|
|
687
|
-
if (quarantineMode !== "off" && !state7.quarantineLogged && classifyKey(key) === "optional") {
|
|
688
|
-
const dwellElapsed = quarantineDwellMs <= 0 || state7.firstMissingAt !== null && nowMs - state7.firstMissingAt >= quarantineDwellMs;
|
|
689
|
-
if (dwellElapsed) {
|
|
690
|
-
state7.quarantineLogged = true;
|
|
691
|
-
if (quarantineMode === "enforce") {
|
|
692
|
-
quarantined.push(key);
|
|
693
|
-
log2(
|
|
694
|
-
`[mcp-presence-reaper] QUARANTINE '${codeName}:${key}' \u2014 optional channel dead past restart budget + ${quarantineDwellMs}ms dwell; dropping from provisioned set so the dead channel stops restarting the whole session (ENG-5932)`
|
|
695
|
-
);
|
|
696
|
-
if (onQuarantine) {
|
|
697
|
-
try {
|
|
698
|
-
onQuarantine(codeName, key);
|
|
699
|
-
} catch (err) {
|
|
700
|
-
log2(
|
|
701
|
-
`[mcp-presence-reaper] onQuarantine callback threw for '${codeName}:${key}' (suppressed; reaper continues): ${err.message}`
|
|
702
|
-
);
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
} else {
|
|
706
|
-
wouldQuarantine.push(key);
|
|
707
|
-
log2(
|
|
708
|
-
`[mcp-presence-reaper] SHADOW would-quarantine '${codeName}:${key}' \u2014 optional channel dead past restart budget + ${quarantineDwellMs}ms dwell; no action taken (ENG-5932 shadow mode)`
|
|
709
|
-
);
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
|
-
}
|
|
713
|
-
} else {
|
|
714
|
-
const backoffMs = restartsInWindow < BACKOFF_AFTER_RESTARTS ? 0 : Math.min(
|
|
715
|
-
BACKOFF_BASE_MS * 2 ** (restartsInWindow - BACKOFF_AFTER_RESTARTS),
|
|
716
|
-
BACKOFF_MAX_MS
|
|
717
|
-
);
|
|
718
|
-
const lastRestartAt = state7.restartHistory[state7.restartHistory.length - 1] ?? null;
|
|
719
|
-
if (lastRestartAt !== null && nowMs - lastRestartAt < backoffMs) {
|
|
720
|
-
backingOff.push(key);
|
|
721
|
-
} else {
|
|
722
|
-
active.push(key);
|
|
723
|
-
}
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
if (active.length === 0) {
|
|
727
|
-
const reason = backingOff.length > 0 ? "backoff" : "all-keys-over-cap";
|
|
728
|
-
if (backingOff.length > 0) {
|
|
729
|
-
log2(
|
|
730
|
-
`[mcp-presence-reaper] '${codeName}': holding off restart for [${backingOff.join(", ")}] \u2014 escalating backoff interval not yet elapsed (ENG-6480)${givenUp.length > 0 ? ` (given up: [${givenUp.join(", ")}])` : ""}`
|
|
731
|
-
);
|
|
732
|
-
}
|
|
733
|
-
return {
|
|
734
|
-
missing,
|
|
735
|
-
restarted: false,
|
|
736
|
-
reason,
|
|
737
|
-
givenUp,
|
|
738
|
-
backingOff: backingOff.length > 0 ? backingOff : void 0,
|
|
739
|
-
rotationGraced: rotationGraced.length > 0 ? rotationGraced : void 0,
|
|
740
|
-
quarantined: quarantined.length > 0 ? quarantined : void 0,
|
|
741
|
-
wouldQuarantine: wouldQuarantine.length > 0 ? wouldQuarantine : void 0
|
|
742
|
-
};
|
|
743
|
-
}
|
|
744
|
-
const givenUpSuffix = givenUp.length > 0 ? ` (skipping over-cap: [${givenUp.join(", ")}])` : "";
|
|
745
|
-
log2(
|
|
746
|
-
`[mcp-presence-reaper] '${codeName}': declared MCP(s) [${active.join(", ")}] have no live children \u2014 restarting session${givenUpSuffix}`
|
|
747
|
-
);
|
|
748
|
-
if (onRestart) {
|
|
749
|
-
try {
|
|
750
|
-
const maybePromise = onRestart(codeName, { activeKeys: active, givenUpKeys: givenUp });
|
|
751
|
-
if (maybePromise && typeof maybePromise.then === "function") {
|
|
752
|
-
void maybePromise.then(void 0, (err) => {
|
|
753
|
-
log2(
|
|
754
|
-
`[mcp-presence-reaper] onRestart callback rejected for '${codeName}' (suppressed; restart proceeds): ${err.message}`
|
|
755
|
-
);
|
|
756
|
-
});
|
|
757
|
-
}
|
|
758
|
-
} catch (err) {
|
|
759
|
-
log2(
|
|
760
|
-
`[mcp-presence-reaper] onRestart callback threw for '${codeName}' (suppressed; restart proceeds): ${err.message}`
|
|
761
|
-
);
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
stopSession(codeName, { activeKeys: active });
|
|
765
|
-
for (const key of active) {
|
|
766
|
-
if (!newGenerationKeys.has(key)) continue;
|
|
767
|
-
const st = presenceReaperState.get(stateKey(codeName, key));
|
|
768
|
-
if (st) st.restartHistory.push(nowMs);
|
|
769
|
-
}
|
|
770
|
-
return {
|
|
771
|
-
missing,
|
|
772
|
-
restarted: true,
|
|
773
|
-
givenUp: givenUp.length > 0 ? givenUp : void 0,
|
|
774
|
-
backingOff: backingOff.length > 0 ? backingOff : void 0,
|
|
775
|
-
rotationGraced: rotationGraced.length > 0 ? rotationGraced : void 0,
|
|
776
|
-
quarantined: quarantined.length > 0 ? quarantined : void 0,
|
|
777
|
-
wouldQuarantine: wouldQuarantine.length > 0 ? wouldQuarantine : void 0
|
|
778
|
-
};
|
|
231
|
+
// src/lib/host-integration-mapping.ts
|
|
232
|
+
function withResolvedRemoteMcp(integration) {
|
|
233
|
+
return { ...integration, remoteMcp: integration.remote_mcp ?? void 0 };
|
|
779
234
|
}
|
|
780
235
|
|
|
781
236
|
// src/lib/channel-restart-decision.ts
|
|
@@ -1804,116 +1259,6 @@ function isDirectChatMessageExpired(createdAt, nowMs, maxAgeMs) {
|
|
|
1804
1259
|
return nowMs - created > maxAgeMs;
|
|
1805
1260
|
}
|
|
1806
1261
|
|
|
1807
|
-
// src/lib/session-tool-probe.ts
|
|
1808
|
-
function classifyMcpServer(entry) {
|
|
1809
|
-
if (!entry || typeof entry !== "object") return "unknown";
|
|
1810
|
-
const e = entry;
|
|
1811
|
-
if (typeof e.command === "string") return "stdio";
|
|
1812
|
-
if (typeof e.url === "string") return "http";
|
|
1813
|
-
return "unknown";
|
|
1814
|
-
}
|
|
1815
|
-
function splitServerKeysByKind(mcpJson, serverKeys) {
|
|
1816
|
-
const servers = mcpJson?.mcpServers ?? {};
|
|
1817
|
-
const stdio = [];
|
|
1818
|
-
const http = [];
|
|
1819
|
-
for (const key of serverKeys) {
|
|
1820
|
-
const kind = classifyMcpServer(servers[key]);
|
|
1821
|
-
if (kind === "stdio") stdio.push(key);
|
|
1822
|
-
else if (kind === "http") http.push(key);
|
|
1823
|
-
}
|
|
1824
|
-
return { stdio, http };
|
|
1825
|
-
}
|
|
1826
|
-
function computeSessionToolBindStatus(input) {
|
|
1827
|
-
const { stdioServerKeys, httpServerKeys, missingStdioKeys, httpReachable, httpSessionLoaded } = input;
|
|
1828
|
-
if (stdioServerKeys.length === 0 && httpServerKeys.length === 0) return "unknown";
|
|
1829
|
-
if (stdioServerKeys.some((k) => missingStdioKeys.has(k))) return "missing";
|
|
1830
|
-
let anyHttpUnconfirmed = false;
|
|
1831
|
-
for (const k of httpServerKeys) {
|
|
1832
|
-
const reachable = httpReachable.get(k);
|
|
1833
|
-
if (reachable === false) return "unreachable";
|
|
1834
|
-
if (reachable === void 0) {
|
|
1835
|
-
anyHttpUnconfirmed = true;
|
|
1836
|
-
} else if (!httpSessionLoaded) {
|
|
1837
|
-
anyHttpUnconfirmed = true;
|
|
1838
|
-
}
|
|
1839
|
-
}
|
|
1840
|
-
if (anyHttpUnconfirmed && stdioServerKeys.length === 0) return "unknown";
|
|
1841
|
-
return "bound";
|
|
1842
|
-
}
|
|
1843
|
-
|
|
1844
|
-
// src/lib/session-tool-bind-runner.ts
|
|
1845
|
-
var DEFAULT_INTERVAL_MS2 = 60 * 60 * 1e3;
|
|
1846
|
-
var DEFAULT_MAX_PER_RUN2 = 25;
|
|
1847
|
-
function sanitizeServerKey(definitionId) {
|
|
1848
|
-
return definitionId.replace(/[^a-z0-9]/gi, "_").toLowerCase();
|
|
1849
|
-
}
|
|
1850
|
-
function resolveIntegrationServerKeys(definitionId, declaredKeys, hint) {
|
|
1851
|
-
const declared = new Set(declaredKeys);
|
|
1852
|
-
const candidates = [hint, definitionId, sanitizeServerKey(definitionId)].filter(
|
|
1853
|
-
(k) => typeof k === "string" && k.length > 0
|
|
1854
|
-
);
|
|
1855
|
-
const out = /* @__PURE__ */ new Set();
|
|
1856
|
-
for (const c of candidates) if (declared.has(c)) out.add(c);
|
|
1857
|
-
return [...out];
|
|
1858
|
-
}
|
|
1859
|
-
function isDue2(last, now, intervalMs) {
|
|
1860
|
-
if (!last) return true;
|
|
1861
|
-
const t = Date.parse(last);
|
|
1862
|
-
if (Number.isNaN(t)) return true;
|
|
1863
|
-
return now - t >= intervalMs;
|
|
1864
|
-
}
|
|
1865
|
-
async function runSessionToolBindProbes(integrations, options) {
|
|
1866
|
-
const now = (options.now?.() ?? /* @__PURE__ */ new Date()).getTime();
|
|
1867
|
-
const intervalMs = options.intervalMs ?? DEFAULT_INTERVAL_MS2;
|
|
1868
|
-
const maxPerRun = options.maxPerRun ?? DEFAULT_MAX_PER_RUN2;
|
|
1869
|
-
const due = integrations.filter((i) => isDue2(i.last_session_tool_bind_at, now, intervalMs)).sort((a, b) => {
|
|
1870
|
-
const ta = a.last_session_tool_bind_at ? Date.parse(a.last_session_tool_bind_at) : 0;
|
|
1871
|
-
const tb = b.last_session_tool_bind_at ? Date.parse(b.last_session_tool_bind_at) : 0;
|
|
1872
|
-
return ta - tb;
|
|
1873
|
-
});
|
|
1874
|
-
const batch = due.slice(0, maxPerRun);
|
|
1875
|
-
const declaredKeys = Object.keys(options.mcpJson?.mcpServers ?? {});
|
|
1876
|
-
const reports = [];
|
|
1877
|
-
let skipped = 0;
|
|
1878
|
-
let probed = 0;
|
|
1879
|
-
for (const integ of batch) {
|
|
1880
|
-
const keys = resolveIntegrationServerKeys(
|
|
1881
|
-
integ.definition_id,
|
|
1882
|
-
declaredKeys,
|
|
1883
|
-
integ.mcp_server_key
|
|
1884
|
-
);
|
|
1885
|
-
if (keys.length === 0) {
|
|
1886
|
-
skipped += 1;
|
|
1887
|
-
continue;
|
|
1888
|
-
}
|
|
1889
|
-
probed += 1;
|
|
1890
|
-
const { stdio, http } = splitServerKeysByKind(options.mcpJson, keys);
|
|
1891
|
-
const httpReachable = /* @__PURE__ */ new Map();
|
|
1892
|
-
for (const key of http) {
|
|
1893
|
-
let reachable;
|
|
1894
|
-
try {
|
|
1895
|
-
reachable = await options.probeHttp(key);
|
|
1896
|
-
} catch {
|
|
1897
|
-
reachable = void 0;
|
|
1898
|
-
}
|
|
1899
|
-
if (reachable !== void 0) httpReachable.set(key, reachable);
|
|
1900
|
-
}
|
|
1901
|
-
const status = computeSessionToolBindStatus({
|
|
1902
|
-
stdioServerKeys: stdio,
|
|
1903
|
-
httpServerKeys: http,
|
|
1904
|
-
missingStdioKeys: options.missingStdioKeys,
|
|
1905
|
-
httpReachable,
|
|
1906
|
-
httpSessionLoaded: options.httpSessionLoaded ?? false
|
|
1907
|
-
});
|
|
1908
|
-
if (status === "unknown") {
|
|
1909
|
-
skipped += 1;
|
|
1910
|
-
continue;
|
|
1911
|
-
}
|
|
1912
|
-
reports.push({ integration_id: integ.id, scope: integ.scope, status });
|
|
1913
|
-
}
|
|
1914
|
-
return { reports, due: due.length, probed, skipped };
|
|
1915
|
-
}
|
|
1916
|
-
|
|
1917
1262
|
// ../../packages/core/dist/host-config/capture.js
|
|
1918
1263
|
import { createHash as createHash3 } from "crypto";
|
|
1919
1264
|
var NON_SECRET_ENV_GATES = [
|
|
@@ -3430,7 +2775,7 @@ function saveChannelHashCache(source, configDir) {
|
|
|
3430
2775
|
}
|
|
3431
2776
|
|
|
3432
2777
|
// src/lib/channel-sweep.ts
|
|
3433
|
-
import { execFileSync
|
|
2778
|
+
import { execFileSync } from "child_process";
|
|
3434
2779
|
var CHANNEL_BASENAMES = [
|
|
3435
2780
|
"slack-channel",
|
|
3436
2781
|
"direct-chat-channel",
|
|
@@ -3593,7 +2938,7 @@ function resolveLiveAnchorPids(agentCodeNames) {
|
|
|
3593
2938
|
for (const codeName of agentCodeNames) {
|
|
3594
2939
|
const pids = /* @__PURE__ */ new Set();
|
|
3595
2940
|
try {
|
|
3596
|
-
const out =
|
|
2941
|
+
const out = execFileSync("tmux", ["list-panes", "-t", `agt-${codeName}`, "-F", "#{pane_pid}"], {
|
|
3597
2942
|
encoding: "utf-8",
|
|
3598
2943
|
timeout: 2e3,
|
|
3599
2944
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -3613,7 +2958,7 @@ async function sweepChannelProcesses(opts) {
|
|
|
3613
2958
|
const kill = opts.killFn ?? defaultKill;
|
|
3614
2959
|
let psOutput = "";
|
|
3615
2960
|
try {
|
|
3616
|
-
psOutput =
|
|
2961
|
+
psOutput = execFileSync("ps", ["eww", "-o", "pid=,ppid=,etime=,command="], {
|
|
3617
2962
|
encoding: "utf-8",
|
|
3618
2963
|
timeout: 5e3,
|
|
3619
2964
|
maxBuffer: 10 * 1024 * 1024
|
|
@@ -3650,7 +2995,7 @@ function defaultKillSignal(pid, signal) {
|
|
|
3650
2995
|
}
|
|
3651
2996
|
}
|
|
3652
2997
|
function defaultPs() {
|
|
3653
|
-
return
|
|
2998
|
+
return execFileSync("ps", ["eww", "-o", "pid=,ppid=,etime=,command="], {
|
|
3654
2999
|
encoding: "utf-8",
|
|
3655
3000
|
timeout: 5e3,
|
|
3656
3001
|
maxBuffer: 10 * 1024 * 1024
|
|
@@ -6616,65 +5961,13 @@ async function runAgentConnectivityProbes(agent, integrations, projectDir) {
|
|
|
6616
5961
|
}
|
|
6617
5962
|
async function runAgentSessionToolBindProbes(agent, integrations, projectDir) {
|
|
6618
5963
|
if (integrations.length === 0) return;
|
|
6619
|
-
let mcpJson = null;
|
|
6620
|
-
try {
|
|
6621
|
-
mcpJson = JSON.parse(readFileSync14(join16(projectDir, ".mcp.json"), "utf-8"));
|
|
6622
|
-
} catch {
|
|
6623
|
-
return;
|
|
6624
|
-
}
|
|
6625
|
-
if (!mcpJson?.mcpServers || Object.keys(mcpJson.mcpServers).length === 0) return;
|
|
6626
|
-
const isolated = isolationMode(agent.code_name) === "docker";
|
|
6627
|
-
let missingStdioKeys = /* @__PURE__ */ new Set();
|
|
6628
|
-
try {
|
|
6629
|
-
const psOutput = isolated ? syncExecFile("docker", ["exec", `agt-${agent.code_name}`, "ps", "-eo", "pid,ppid,args"], {
|
|
6630
|
-
encoding: "utf-8",
|
|
6631
|
-
timeout: 8e3
|
|
6632
|
-
}) : syncExecFile("ps", ["-eo", "pid,ppid,args"], { encoding: "utf-8", timeout: 5e3 });
|
|
6633
|
-
missingStdioKeys = new Set(
|
|
6634
|
-
findMissingMcpServers({
|
|
6635
|
-
rows: parsePsRows(psOutput),
|
|
6636
|
-
codeName: agent.code_name,
|
|
6637
|
-
mcpJson,
|
|
6638
|
-
inContainer: isolated
|
|
6639
|
-
})
|
|
6640
|
-
);
|
|
6641
|
-
} catch {
|
|
6642
|
-
}
|
|
6643
|
-
const probeEnv = buildProbeEnv(projectDir);
|
|
6644
|
-
const probeDeps = buildConnectivityProbeDeps(projectDir, probeEnv);
|
|
6645
|
-
const probeHttp = async (serverKey) => {
|
|
6646
|
-
if (!probeDeps.mcpProbe) return void 0;
|
|
6647
|
-
const outcome = await probeDeps.mcpProbe({ serverKey, definitionId: serverKey });
|
|
6648
|
-
if (outcome.status === "ok") return true;
|
|
6649
|
-
if (outcome.status === "down") return false;
|
|
6650
|
-
return void 0;
|
|
6651
|
-
};
|
|
6652
|
-
let httpSessionLoaded = false;
|
|
6653
|
-
try {
|
|
6654
|
-
const sessionStartedMs = getSessionState(agent.code_name)?.startedAt ?? null;
|
|
6655
|
-
const mcpMtimeMs = statSync4(join16(projectDir, ".mcp.json")).mtimeMs;
|
|
6656
|
-
httpSessionLoaded = sessionStartedMs != null && sessionStartedMs >= mcpMtimeMs;
|
|
6657
|
-
} catch {
|
|
6658
|
-
}
|
|
6659
5964
|
const intervalSec = Number(process.env.AGT_CONNECTIVITY_PROBE_INTERVAL_SECONDS) || 3600;
|
|
6660
|
-
const
|
|
6661
|
-
|
|
6662
|
-
|
|
6663
|
-
|
|
6664
|
-
|
|
6665
|
-
|
|
6666
|
-
// Server-key hint for managed/remote-MCP kinds; the runner also tries the
|
|
6667
|
-
// raw + sanitised definition_id against the real `.mcp.json` keys.
|
|
6668
|
-
mcp_server_key: deriveMcpServerKey({
|
|
6669
|
-
definitionId: i.definition_id,
|
|
6670
|
-
sourceType: i.source_type ?? null,
|
|
6671
|
-
authType: i.auth_type,
|
|
6672
|
-
connectivityTest: i.connectivity_test ?? null
|
|
6673
|
-
})
|
|
6674
|
-
})),
|
|
6675
|
-
{ mcpJson, missingStdioKeys, probeHttp, httpSessionLoaded, intervalMs: intervalSec * 1e3 }
|
|
6676
|
-
);
|
|
6677
|
-
if (result.reports.length > 0) {
|
|
5965
|
+
const sessionStartedMs = getSessionState(agent.code_name)?.startedAt ?? null;
|
|
5966
|
+
const result = await gatherSessionToolBindProbe(agent, integrations, projectDir, {
|
|
5967
|
+
sessionStartedMs,
|
|
5968
|
+
intervalMs: intervalSec * 1e3
|
|
5969
|
+
});
|
|
5970
|
+
if (result && result.reports.length > 0) {
|
|
6678
5971
|
await api.post("/host/session-tool-bind", {
|
|
6679
5972
|
agent_id: agent.agent_id,
|
|
6680
5973
|
results: result.reports
|
|
@@ -6866,10 +6159,10 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
|
|
|
6866
6159
|
var lastVersionCheckAt = 0;
|
|
6867
6160
|
var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
|
|
6868
6161
|
var lastResponsivenessProbeAt = 0;
|
|
6869
|
-
var agtCliVersion = true ? "0.28.
|
|
6870
|
-
function resolveBrewPath(
|
|
6162
|
+
var agtCliVersion = true ? "0.28.209" : "dev";
|
|
6163
|
+
function resolveBrewPath(execFileSync2) {
|
|
6871
6164
|
try {
|
|
6872
|
-
const out =
|
|
6165
|
+
const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
|
|
6873
6166
|
if (out) return out;
|
|
6874
6167
|
} catch {
|
|
6875
6168
|
}
|
|
@@ -6883,7 +6176,7 @@ function resolveBrewPath(execFileSync4) {
|
|
|
6883
6176
|
}
|
|
6884
6177
|
return null;
|
|
6885
6178
|
}
|
|
6886
|
-
function claudeBinaryInstalled(
|
|
6179
|
+
function claudeBinaryInstalled(execFileSync2) {
|
|
6887
6180
|
const canonical = [
|
|
6888
6181
|
"/home/linuxbrew/.linuxbrew/bin/claude",
|
|
6889
6182
|
"/opt/homebrew/bin/claude",
|
|
@@ -6891,7 +6184,7 @@ function claudeBinaryInstalled(execFileSync4) {
|
|
|
6891
6184
|
];
|
|
6892
6185
|
if (canonical.some((path) => existsSync8(path))) return true;
|
|
6893
6186
|
try {
|
|
6894
|
-
|
|
6187
|
+
execFileSync2("which", ["claude"], { timeout: 5e3 });
|
|
6895
6188
|
return true;
|
|
6896
6189
|
} catch {
|
|
6897
6190
|
return false;
|
|
@@ -6925,9 +6218,9 @@ async function ensureToolkitCli(toolkitSlug) {
|
|
|
6925
6218
|
}
|
|
6926
6219
|
const { binary, installer, package: pkg, script } = integration.cli_tool;
|
|
6927
6220
|
const resolvedInstaller = installer ?? "manual";
|
|
6928
|
-
const { execFileSync:
|
|
6221
|
+
const { execFileSync: execFileSync2, execSync } = await import("child_process");
|
|
6929
6222
|
try {
|
|
6930
|
-
|
|
6223
|
+
execFileSync2("which", [binary], { timeout: 5e3, stdio: "pipe" });
|
|
6931
6224
|
toolkitCliEnsured.add(toolkitSlug);
|
|
6932
6225
|
toolkitCliRetryAfter.delete(toolkitSlug);
|
|
6933
6226
|
toolkitCliFailureCount.delete(toolkitSlug);
|
|
@@ -6948,14 +6241,14 @@ async function ensureToolkitCli(toolkitSlug) {
|
|
|
6948
6241
|
return;
|
|
6949
6242
|
}
|
|
6950
6243
|
log(`[toolkit-install] ${toolkitSlug}: installing via npm (${pkg})\u2026`);
|
|
6951
|
-
|
|
6244
|
+
execFileSync2("npm", ["install", "-g", pkg], { timeout: 18e4, stdio: "pipe" });
|
|
6952
6245
|
} else if (resolvedInstaller === "brew") {
|
|
6953
6246
|
if (!pkg) {
|
|
6954
6247
|
log(`[toolkit-install] ${toolkitSlug}: installer=brew but no package declared`);
|
|
6955
6248
|
toolkitCliEnsured.add(toolkitSlug);
|
|
6956
6249
|
return;
|
|
6957
6250
|
}
|
|
6958
|
-
const brewPath = resolveBrewPath(
|
|
6251
|
+
const brewPath = resolveBrewPath(execFileSync2);
|
|
6959
6252
|
if (!brewPath) {
|
|
6960
6253
|
log(`[toolkit-install] ${toolkitSlug}: installer=brew but Homebrew not available \u2014 install manually: brew install ${pkg}`);
|
|
6961
6254
|
toolkitCliEnsured.add(toolkitSlug);
|
|
@@ -6965,9 +6258,9 @@ async function ensureToolkitCli(toolkitSlug) {
|
|
|
6965
6258
|
const isRoot = typeof process.getuid === "function" && process.getuid() === 0;
|
|
6966
6259
|
log(`[toolkit-install] ${toolkitSlug}: installing via brew (${pkg})\u2026`);
|
|
6967
6260
|
if (isRoot) {
|
|
6968
|
-
|
|
6261
|
+
execFileSync2("sudo", ["-u", "ec2-user", "-H", brewPath, "install", pkg], { timeout: 18e4, stdio: "pipe", cwd: "/tmp" });
|
|
6969
6262
|
} else {
|
|
6970
|
-
|
|
6263
|
+
execFileSync2(brewPath, ["install", pkg], { timeout: 18e4, stdio: "pipe" });
|
|
6971
6264
|
}
|
|
6972
6265
|
} else if (resolvedInstaller === "script") {
|
|
6973
6266
|
if (!script) {
|
|
@@ -6987,7 +6280,7 @@ async function ensureToolkitCli(toolkitSlug) {
|
|
|
6987
6280
|
process.env.PATH = `${brewBinDir}:${process.env.PATH ?? ""}`;
|
|
6988
6281
|
}
|
|
6989
6282
|
try {
|
|
6990
|
-
|
|
6283
|
+
execFileSync2("which", [binary], { timeout: 5e3, stdio: "pipe" });
|
|
6991
6284
|
log(`[toolkit-install] ${toolkitSlug}: installed \u2014 ${binary} now on PATH`);
|
|
6992
6285
|
toolkitCliEnsured.add(toolkitSlug);
|
|
6993
6286
|
toolkitCliRetryAfter.delete(toolkitSlug);
|
|
@@ -7074,8 +6367,8 @@ async function ensureFrameworkBinary(frameworkId) {
|
|
|
7074
6367
|
if (frameworkBinaryChecked.has(frameworkId)) return;
|
|
7075
6368
|
frameworkBinaryChecked.add(frameworkId);
|
|
7076
6369
|
lastManagedSettingsStatus = ensureClaudeManagedSettings();
|
|
7077
|
-
const { execFileSync:
|
|
7078
|
-
const brewPath = resolveBrewPath(
|
|
6370
|
+
const { execFileSync: execFileSync2 } = await import("child_process");
|
|
6371
|
+
const brewPath = resolveBrewPath(execFileSync2);
|
|
7079
6372
|
if (!brewPath) {
|
|
7080
6373
|
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");
|
|
7081
6374
|
return;
|
|
@@ -7088,7 +6381,7 @@ async function ensureFrameworkBinary(frameworkId) {
|
|
|
7088
6381
|
}
|
|
7089
6382
|
return runAsync(brewPath, args, opts);
|
|
7090
6383
|
};
|
|
7091
|
-
const claudeExists = claudeBinaryInstalled(
|
|
6384
|
+
const claudeExists = claudeBinaryInstalled(execFileSync2);
|
|
7092
6385
|
if (!claudeExists) {
|
|
7093
6386
|
log(`Claude Code binary not found \u2014 installing via Homebrew${isRoot ? " (as ec2-user via sudo)" : ""}...`);
|
|
7094
6387
|
try {
|
|
@@ -7123,13 +6416,13 @@ async function maybeUpgradeClaudeCode() {
|
|
|
7123
6416
|
}
|
|
7124
6417
|
claudeCodeUpgradeInFlight = true;
|
|
7125
6418
|
stampClaudeCodeUpgradeMarker();
|
|
7126
|
-
const { execFileSync:
|
|
7127
|
-
const brewPath = resolveBrewPath(
|
|
6419
|
+
const { execFileSync: execFileSync2 } = await import("child_process");
|
|
6420
|
+
const brewPath = resolveBrewPath(execFileSync2);
|
|
7128
6421
|
if (!brewPath) {
|
|
7129
6422
|
claudeCodeUpgradeInFlight = false;
|
|
7130
6423
|
return;
|
|
7131
6424
|
}
|
|
7132
|
-
if (!claudeBinaryInstalled(
|
|
6425
|
+
if (!claudeBinaryInstalled(execFileSync2)) {
|
|
7133
6426
|
claudeCodeUpgradeInFlight = false;
|
|
7134
6427
|
return;
|
|
7135
6428
|
}
|
|
@@ -7208,18 +6501,18 @@ async function checkAndUpdateCli(opts) {
|
|
|
7208
6501
|
}
|
|
7209
6502
|
}
|
|
7210
6503
|
async function checkAndUpdateCliViaBrew(force = false) {
|
|
7211
|
-
const { execFileSync:
|
|
7212
|
-
const brewPath = resolveBrewPath(
|
|
6504
|
+
const { execFileSync: execFileSync2 } = await import("child_process");
|
|
6505
|
+
const brewPath = resolveBrewPath(execFileSync2);
|
|
7213
6506
|
if (!brewPath) return "noop";
|
|
7214
6507
|
let metadataFresh = true;
|
|
7215
6508
|
try {
|
|
7216
|
-
|
|
6509
|
+
execFileSync2(brewPath, ["update", "--quiet"], { timeout: 6e4, stdio: "pipe" });
|
|
7217
6510
|
} catch (err) {
|
|
7218
6511
|
metadataFresh = false;
|
|
7219
6512
|
log(`[self-update] brew update failed (continuing with stale cache): ${err.message}`);
|
|
7220
6513
|
}
|
|
7221
6514
|
try {
|
|
7222
|
-
const outdated =
|
|
6515
|
+
const outdated = execFileSync2(brewPath, ["outdated", "--json=v2"], {
|
|
7223
6516
|
timeout: 3e4,
|
|
7224
6517
|
encoding: "utf-8"
|
|
7225
6518
|
});
|
|
@@ -7252,7 +6545,7 @@ async function checkAndUpdateCliViaBrew(force = false) {
|
|
|
7252
6545
|
}
|
|
7253
6546
|
log(`[self-update] agt CLI update available: ${installed} \u2192 ${latest}. Upgrading via brew${force ? " (forced \u2014 Update CLI now)" : ""}...`);
|
|
7254
6547
|
try {
|
|
7255
|
-
|
|
6548
|
+
execFileSync2(brewPath, ["upgrade", "integrity-labs/tap/agt"], {
|
|
7256
6549
|
timeout: 12e4,
|
|
7257
6550
|
stdio: "pipe"
|
|
7258
6551
|
});
|
|
@@ -7371,7 +6664,7 @@ async function fetchUrgentDistTagVersion() {
|
|
|
7371
6664
|
}
|
|
7372
6665
|
}
|
|
7373
6666
|
async function installAgtCliViaNpm(version, reasonLabel) {
|
|
7374
|
-
const { execFileSync:
|
|
6667
|
+
const { execFileSync: execFileSync2 } = await import("child_process");
|
|
7375
6668
|
const isRoot = typeof process.getuid === "function" && process.getuid() === 0;
|
|
7376
6669
|
const cmd = isRoot ? "npm" : "sudo";
|
|
7377
6670
|
const installArgs = [
|
|
@@ -7382,14 +6675,14 @@ async function installAgtCliViaNpm(version, reasonLabel) {
|
|
|
7382
6675
|
];
|
|
7383
6676
|
const args = isRoot ? installArgs : ["-n", "npm", ...installArgs];
|
|
7384
6677
|
try {
|
|
7385
|
-
|
|
6678
|
+
execFileSync2(cmd, args, { timeout: 18e4, stdio: "pipe" });
|
|
7386
6679
|
} catch (err) {
|
|
7387
6680
|
log(`[self-update] npm upgrade failed: ${err.message}`);
|
|
7388
6681
|
return "failed";
|
|
7389
6682
|
}
|
|
7390
6683
|
let smokeOk = false;
|
|
7391
6684
|
try {
|
|
7392
|
-
const out =
|
|
6685
|
+
const out = execFileSync2("agt", ["--version"], { timeout: 15e3, stdio: "pipe" }).toString();
|
|
7393
6686
|
smokeOk = isAgtVersionSmokeOk(out, version);
|
|
7394
6687
|
if (!smokeOk) {
|
|
7395
6688
|
log(
|
|
@@ -7775,7 +7068,7 @@ async function pollCycle() {
|
|
|
7775
7068
|
}
|
|
7776
7069
|
try {
|
|
7777
7070
|
const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
|
|
7778
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
7071
|
+
const { collectDiagnostics } = await import("../persistent-session-Z46SCCQM.js");
|
|
7779
7072
|
const diagCodeNames = [...agentState.persistentSessionAgents];
|
|
7780
7073
|
const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
|
|
7781
7074
|
let tailscaleHostname;
|
|
@@ -7923,7 +7216,7 @@ async function pollCycle() {
|
|
|
7923
7216
|
const {
|
|
7924
7217
|
collectResponsivenessProbes,
|
|
7925
7218
|
getResponsivenessIntervalMs
|
|
7926
|
-
} = await import("../responsiveness-probe-
|
|
7219
|
+
} = await import("../responsiveness-probe-4MUX7FBH.js");
|
|
7927
7220
|
const probeIntervalMs = getResponsivenessIntervalMs();
|
|
7928
7221
|
if (now - lastResponsivenessProbeAt > probeIntervalMs) {
|
|
7929
7222
|
const probeCodeNames = [...agentState.persistentSessionAgents];
|
|
@@ -7955,7 +7248,7 @@ async function pollCycle() {
|
|
|
7955
7248
|
collectResponsivenessProbes,
|
|
7956
7249
|
livePendingInboundOldestAgeSeconds,
|
|
7957
7250
|
parkPendingInbound
|
|
7958
|
-
} = await import("../responsiveness-probe-
|
|
7251
|
+
} = await import("../responsiveness-probe-4MUX7FBH.js");
|
|
7959
7252
|
const { getProjectDir: wedgeProjectDir } = await import("../claude-scheduler-FATCLHDM.js");
|
|
7960
7253
|
const wedgeNow = /* @__PURE__ */ new Date();
|
|
7961
7254
|
const liveAgents = agentState.persistentSessionAgents;
|
|
@@ -9283,7 +8576,7 @@ async function processAgent(agent, agentStates) {
|
|
|
9283
8576
|
}
|
|
9284
8577
|
try {
|
|
9285
8578
|
const integrationsData = await api.post("/host/agent-integrations", { agent_id: agent.agent_id });
|
|
9286
|
-
const integrations = integrationsData.integrations ?? [];
|
|
8579
|
+
const integrations = (integrationsData.integrations ?? []).map(withResolvedRemoteMcp);
|
|
9287
8580
|
for (const integration of integrations) {
|
|
9288
8581
|
if (integration.auth_type !== "oauth2") continue;
|
|
9289
8582
|
const expiresAt = integration.credentials?.token_expires_at;
|
|
@@ -10982,7 +10275,7 @@ async function processClaudePairSessions(agents) {
|
|
|
10982
10275
|
killPairSession,
|
|
10983
10276
|
pairTmuxSession,
|
|
10984
10277
|
finalizeClaudePairOnboarding
|
|
10985
|
-
} = await import("../claude-pair-runtime-
|
|
10278
|
+
} = await import("../claude-pair-runtime-UUTPSE2V.js");
|
|
10986
10279
|
for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
|
|
10987
10280
|
log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
|
|
10988
10281
|
const killed = await killPairSession(pairTmuxSession(pairId));
|