@integrity-labs/agt-cli 0.28.208 → 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.
@@ -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-3MHPMBN4.js";
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
- sumTranscriptUsageInWindow
117
- } from "../chunk-ELBYWACS.js";
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
 
@@ -228,561 +233,6 @@ function withResolvedRemoteMcp(integration) {
228
233
  return { ...integration, remoteMcp: integration.remote_mcp ?? void 0 };
229
234
  }
230
235
 
231
- // src/lib/stale-mcp-reaper.ts
232
- import { execFileSync } from "child_process";
233
- var rotationTimestamps = /* @__PURE__ */ new Map();
234
- var DEFAULT_ROTATION_GRACE_MS = 15e3;
235
- function rotationKey(codeName, serverKey) {
236
- return `${codeName}\0${serverKey}`;
237
- }
238
- function recordStaleRotation(codeName, serverKeys, now = Date.now) {
239
- const ts = now();
240
- for (const key of serverKeys) {
241
- rotationTimestamps.set(rotationKey(codeName, key), ts);
242
- }
243
- }
244
- function wasRecentlyRotated(codeName, serverKey, withinMs, now = Date.now) {
245
- const k = rotationKey(codeName, serverKey);
246
- const ts = rotationTimestamps.get(k);
247
- if (ts === void 0) return false;
248
- if (now() - ts < withinMs) return true;
249
- rotationTimestamps.delete(k);
250
- return false;
251
- }
252
- function parseEnvIntegrationsEntries(content) {
253
- const entries = /* @__PURE__ */ new Map();
254
- for (const raw of content.split(/\r?\n/)) {
255
- const line = raw.trim();
256
- if (!line || line.startsWith("#")) continue;
257
- const eq = line.indexOf("=");
258
- if (eq <= 0) continue;
259
- const name = line.slice(0, eq).trim();
260
- if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) continue;
261
- const value = line.slice(eq + 1);
262
- entries.set(name, value);
263
- }
264
- return entries;
265
- }
266
- function diffEnvIntegrations(oldContent, newContent) {
267
- const oldEntries = oldContent === void 0 ? /* @__PURE__ */ new Map() : parseEnvIntegrationsEntries(oldContent);
268
- const newEntries = parseEnvIntegrationsEntries(newContent);
269
- const changed = /* @__PURE__ */ new Set();
270
- for (const [name, value] of newEntries) {
271
- if (oldEntries.get(name) !== value) changed.add(name);
272
- }
273
- for (const name of oldEntries.keys()) {
274
- if (!newEntries.has(name)) changed.add(name);
275
- }
276
- return [...changed];
277
- }
278
- function findMcpServersUsingVars(mcp, changedVars) {
279
- const changedSet = new Set(changedVars);
280
- if (!mcp?.mcpServers || changedSet.size === 0) return [];
281
- const result = [];
282
- for (const [serverKey, entry] of Object.entries(mcp.mcpServers)) {
283
- if (!entry || typeof entry !== "object") continue;
284
- const env = entry.env;
285
- if (!env || typeof env !== "object") continue;
286
- let matches = false;
287
- for (const value of Object.values(env)) {
288
- if (typeof value !== "string") continue;
289
- const placeholderMatches = value.match(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g);
290
- if (placeholderMatches) {
291
- for (const ph of placeholderMatches) {
292
- const name = ph.slice(2, -1);
293
- if (changedSet.has(name)) {
294
- matches = true;
295
- break;
296
- }
297
- }
298
- }
299
- if (matches) break;
300
- }
301
- if (matches) result.push(serverKey);
302
- }
303
- return result;
304
- }
305
- function buildArgvMatchersForEntry(key, entry) {
306
- const escapeRe = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
307
- const patterns = [];
308
- const args = entry?.args ?? [];
309
- for (let i = args.length - 1; i >= 0; i--) {
310
- const arg = args[i];
311
- if (typeof arg !== "string" || !arg) continue;
312
- if (arg.startsWith("-")) continue;
313
- const stripped = arg.replace(
314
- /@[^/@]*$/,
315
- (m) => (
316
- // @latest, @1.2.3, etc. — drop. But @scope at the START of a
317
- // package spec must NOT be stripped, so we only strip a tail
318
- // `@...` if it doesn't itself start with a slash inside.
319
- // The regex above only matches a single trailing `@...`
320
- // segment after the last `/`, so this is safe for `@scope/pkg`.
321
- m.includes("/") ? m : ""
322
- )
323
- );
324
- const tail = "(?![A-Za-z0-9_-])";
325
- if (/^@?[a-z0-9]([a-z0-9._-]*\/)?[a-z0-9._-]+$/i.test(stripped)) {
326
- patterns.push(new RegExp(`${escapeRe(stripped)}${tail}`));
327
- const basename = stripped.split("/").pop();
328
- if (basename && basename !== stripped) {
329
- patterns.push(new RegExp(`${escapeRe(basename)}${tail}`));
330
- }
331
- break;
332
- }
333
- if (stripped.includes("/")) {
334
- const basename = stripped.split("/").pop();
335
- if (basename) {
336
- patterns.push(new RegExp(`${escapeRe(basename)}${tail}`));
337
- break;
338
- }
339
- }
340
- }
341
- if (patterns.length === 0) {
342
- const safe = escapeRe(key);
343
- patterns.push(new RegExp(`(?<![A-Za-z0-9_])${safe}(?![A-Za-z0-9_])`));
344
- if (safe.includes("_")) {
345
- const dashed = safe.replace(/_/g, "-");
346
- patterns.push(new RegExp(`(?<![A-Za-z0-9_])${dashed}(?![A-Za-z0-9_])`));
347
- }
348
- }
349
- return patterns;
350
- }
351
- function buildClaudeAgentMatcher(codeName) {
352
- const safe = codeName.replace(/[^A-Za-z0-9_-]/g, "");
353
- return new RegExp(`\\bclaude\\b.*--name\\s+agt-${safe}(?=\\s|$)`);
354
- }
355
- function findMcpChildrenForAgent(args) {
356
- const { rows, codeName, serverKeys, mcpJson } = args;
357
- const maxDepth = args.maxDepth ?? 8;
358
- const inContainer = args.inContainer ?? false;
359
- if (serverKeys.length === 0 || rows.length === 0) return [];
360
- const claudeMatcher = inContainer ? /\bclaude\b/ : buildClaudeAgentMatcher(codeName);
361
- const argvMatchers = [];
362
- for (const key of serverKeys) {
363
- const entry = mcpJson?.mcpServers?.[key];
364
- argvMatchers.push(...buildArgvMatchersForEntry(key, entry));
365
- }
366
- const byPid = new Map(rows.map((r) => [r.pid, r]));
367
- const matched = [];
368
- for (const row of rows) {
369
- if (!argvMatchers.some((re) => re.test(row.args))) continue;
370
- if (/\bclaude\b/.test(row.args) && row.args.includes(`--name agt-${codeName}`)) continue;
371
- let cur = byPid.get(row.ppid);
372
- let belongs = false;
373
- for (let depth = 0; depth < maxDepth && cur; depth++) {
374
- if (claudeMatcher.test(cur.args)) {
375
- belongs = true;
376
- break;
377
- }
378
- if (cur.pid === 1) break;
379
- cur = byPid.get(cur.ppid);
380
- }
381
- if (belongs) matched.push(row.pid);
382
- }
383
- return matched;
384
- }
385
- function reapStaleMcpChildren(args) {
386
- const { log: log2, codeName, serverKeys, mcpJson, graceMs = 5e3, isolated = false } = args;
387
- if (serverKeys.length === 0) return [];
388
- const runPs = args.runPs ?? (isolated ? () => execFileSync("docker", ["exec", `agt-${codeName}`, "ps", "-eo", "pid,ppid,args"], {
389
- encoding: "utf-8",
390
- timeout: 8e3
391
- }) : () => execFileSync("ps", ["-eo", "pid,ppid,args"], { encoding: "utf-8", timeout: 5e3 }));
392
- const killProcess = args.killProcess ?? (isolated ? (pid, signal) => {
393
- try {
394
- execFileSync(
395
- "docker",
396
- ["exec", `agt-${codeName}`, "kill", signal === "SIGKILL" ? "-KILL" : "-TERM", String(pid)],
397
- { timeout: 8e3, stdio: "ignore" }
398
- );
399
- } catch {
400
- }
401
- } : (pid, signal) => {
402
- try {
403
- process.kill(pid, signal);
404
- } catch {
405
- }
406
- });
407
- const isAlive = args.isAlive ?? (isolated ? (pid) => {
408
- try {
409
- execFileSync("docker", ["exec", `agt-${codeName}`, "kill", "-0", String(pid)], {
410
- timeout: 8e3,
411
- stdio: "ignore"
412
- });
413
- return true;
414
- } catch {
415
- return false;
416
- }
417
- } : (pid) => {
418
- try {
419
- process.kill(pid, 0);
420
- return true;
421
- } catch {
422
- return false;
423
- }
424
- });
425
- let psOutput;
426
- try {
427
- psOutput = runPs();
428
- } catch (err) {
429
- log2(`[stale-mcp-reaper] ps invocation failed for '${codeName}': ${err.message} \u2014 skipping reap`);
430
- return [];
431
- }
432
- const rows = parsePsRows(psOutput);
433
- const targets = findMcpChildrenForAgent({ rows, codeName, serverKeys, mcpJson, inContainer: isolated });
434
- if (targets.length === 0) return [];
435
- const byPid = new Map(rows.map((r) => [r.pid, r]));
436
- const describe = (pid) => {
437
- const argv = byPid.get(pid)?.args ?? "";
438
- const pkgMatch = argv.match(/(@[a-z0-9_-]+\/[a-z0-9_-]+|[a-z0-9_-]+-mcp-server|[a-z0-9_-]+-mcp\b)/i);
439
- return pkgMatch ? `${pkgMatch[1]} (pid ${pid})` : `pid ${pid}`;
440
- };
441
- log2(
442
- `[stale-mcp-reaper] '${codeName}': rotating ${targets.length} stale MCP child(ren) for [${serverKeys.join(", ")}]: ${targets.map(describe).join(", ")}`
443
- );
444
- for (const pid of targets) {
445
- killProcess(pid, "SIGTERM");
446
- }
447
- const killedKeys = /* @__PURE__ */ new Set();
448
- for (const pid of targets) {
449
- const argv = byPid.get(pid)?.args ?? "";
450
- for (const key of serverKeys) {
451
- const entry = mcpJson?.mcpServers?.[key];
452
- const matchers = buildArgvMatchersForEntry(key, entry);
453
- if (matchers.some((re) => re.test(argv))) killedKeys.add(key);
454
- }
455
- }
456
- if (killedKeys.size > 0) recordStaleRotation(codeName, killedKeys);
457
- setTimeout(() => {
458
- try {
459
- let freshPsOutput;
460
- try {
461
- freshPsOutput = runPs();
462
- } catch (err) {
463
- log2(`[stale-mcp-reaper] '${codeName}': fresh ps for SIGKILL re-verify failed: ${err.message} \u2014 skipping SIGKILL pass`);
464
- return;
465
- }
466
- const stillOwned = new Set(
467
- findMcpChildrenForAgent({
468
- rows: parsePsRows(freshPsOutput),
469
- codeName,
470
- serverKeys,
471
- mcpJson,
472
- inContainer: isolated
473
- })
474
- );
475
- const stragglers = targets.filter((pid) => isAlive(pid) && stillOwned.has(pid));
476
- if (stragglers.length === 0) return;
477
- log2(
478
- `[stale-mcp-reaper] '${codeName}': ${stragglers.length} child(ren) survived SIGTERM; sending SIGKILL: ${stragglers.map(describe).join(", ")}`
479
- );
480
- for (const pid of stragglers) {
481
- killProcess(pid, "SIGKILL");
482
- }
483
- } catch (err) {
484
- log2(`[stale-mcp-reaper] '${codeName}': error in SIGKILL pass: ${err.message}`);
485
- }
486
- }, graceMs).unref();
487
- return targets;
488
- }
489
-
490
- // src/lib/mcp-presence-reaper.ts
491
- import { execFileSync as execFileSync2 } from "child_process";
492
- var DEFAULT_COLD_START_GRACE_MS = 9e4;
493
- var MAX_PRESENCE_RESTART_ATTEMPTS = 3;
494
- var BACKOFF_AFTER_RESTARTS = MAX_PRESENCE_RESTART_ATTEMPTS;
495
- var BACKOFF_BASE_MS = 6e4;
496
- var BACKOFF_MAX_MS = 30 * 6e4;
497
- var BACKOFF_WINDOW_MS = 60 * 6e4;
498
- var BACKOFF_GIVE_UP_RESTARTS = 2 * MAX_PRESENCE_RESTART_ATTEMPTS;
499
- var BACKOFF_STABLE_RESET_MS = 5 * 6e4;
500
- var presenceReaperState = /* @__PURE__ */ new Map();
501
- function stateKey(codeName, serverKey) {
502
- return `${codeName}\0${serverKey}`;
503
- }
504
- function clearPresenceReaperState(codeName) {
505
- const prefix = `${codeName}\0`;
506
- for (const key of presenceReaperState.keys()) {
507
- if (key.startsWith(prefix)) presenceReaperState.delete(key);
508
- }
509
- }
510
- function clearPresenceReaperStateForKeys(codeName, keys) {
511
- for (const key of keys) {
512
- presenceReaperState.delete(stateKey(codeName, key));
513
- }
514
- }
515
- function givenUpMcpServerKeys(codeName) {
516
- const prefix = `${codeName}\0`;
517
- const out = /* @__PURE__ */ new Set();
518
- for (const [key, st] of presenceReaperState) {
519
- if (key.startsWith(prefix) && (st.gaveUp || st.attempts >= MAX_PRESENCE_RESTART_ATTEMPTS)) {
520
- out.add(key.slice(prefix.length));
521
- }
522
- }
523
- return out;
524
- }
525
- function findMissingMcpServers(args) {
526
- const { rows, codeName, mcpJson, inContainer } = args;
527
- const servers = mcpJson?.mcpServers ?? {};
528
- const declared = Object.keys(servers);
529
- if (declared.length === 0) return [];
530
- const missing = [];
531
- for (const key of declared) {
532
- const entry = servers[key];
533
- const isStdio = typeof entry?.command === "string";
534
- if (!isStdio) continue;
535
- const live = findMcpChildrenForAgent({
536
- rows,
537
- codeName,
538
- serverKeys: [key],
539
- mcpJson,
540
- inContainer
541
- });
542
- if (live.length === 0) missing.push(key);
543
- }
544
- return missing;
545
- }
546
- function reapMissingMcpSessions(args) {
547
- const {
548
- log: log2,
549
- codeName,
550
- mcpJson,
551
- sessionStartedAt,
552
- restartPending = false,
553
- stopSession,
554
- graceMs = DEFAULT_COLD_START_GRACE_MS,
555
- rotationGraceMs = DEFAULT_ROTATION_GRACE_MS,
556
- onGiveUp,
557
- onRestart,
558
- // ENG-5932: defaults make quarantine a strict no-op (classify everything
559
- // essential, mode off) so legacy callers/tests are unaffected.
560
- classifyKey = () => "essential",
561
- quarantineDwellMs = 0,
562
- quarantineMode = "off",
563
- onQuarantine,
564
- isolated = false
565
- } = args;
566
- const now = args.now ?? Date.now;
567
- const runPs = args.runPs ?? (isolated ? () => execFileSync2("docker", ["exec", `agt-${codeName}`, "ps", "-eo", "pid,ppid,args"], {
568
- encoding: "utf-8",
569
- timeout: 8e3
570
- }) : () => execFileSync2("ps", ["-eo", "pid,ppid,args"], { encoding: "utf-8", timeout: 5e3 }));
571
- if (!mcpJson?.mcpServers) {
572
- return { missing: [], restarted: false, reason: "no-mcp-json" };
573
- }
574
- const declaredCount = Object.keys(mcpJson.mcpServers).length;
575
- if (declaredCount === 0) {
576
- return { missing: [], restarted: false, reason: "no-declared-servers" };
577
- }
578
- if (restartPending) {
579
- return { missing: [], restarted: false, reason: "restart-pending" };
580
- }
581
- if (sessionStartedAt === null) {
582
- return { missing: [], restarted: false, reason: "session-start-unknown" };
583
- }
584
- if (now() - sessionStartedAt < graceMs) {
585
- return { missing: [], restarted: false, reason: "cold-start" };
586
- }
587
- let psOutput;
588
- try {
589
- psOutput = runPs();
590
- } catch (err) {
591
- log2(`[mcp-presence-reaper] ps invocation failed for '${codeName}': ${err.message} \u2014 skipping`);
592
- return { missing: [], restarted: false, reason: "healthy" };
593
- }
594
- const rows = parsePsRows(psOutput);
595
- const missingRaw = findMissingMcpServers({ rows, codeName, mcpJson, inContainer: isolated });
596
- const rotationGraced = [];
597
- const missing = [];
598
- for (const key of missingRaw) {
599
- if (wasRecentlyRotated(codeName, key, rotationGraceMs, now)) {
600
- rotationGraced.push(key);
601
- } else {
602
- missing.push(key);
603
- }
604
- }
605
- if (rotationGraced.length > 0) {
606
- log2(
607
- `[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)`
608
- );
609
- }
610
- const declared = mcpJson.mcpServers ?? {};
611
- const liveKeys = /* @__PURE__ */ new Set();
612
- for (const key of Object.keys(declared)) {
613
- const entry = declared[key];
614
- if (typeof entry?.command !== "string") continue;
615
- if (!missingRaw.includes(key)) liveKeys.add(key);
616
- }
617
- for (const key of liveKeys) {
618
- const state7 = presenceReaperState.get(stateKey(codeName, key));
619
- if (state7) {
620
- state7.attempts = 0;
621
- state7.lastSeenLiveAt = now();
622
- state7.lastAttemptedSessionStartedAt = null;
623
- state7.gaveUpLogged = false;
624
- state7.firstMissingAt = null;
625
- state7.quarantineLogged = false;
626
- state7.gaveUp = false;
627
- if (state7.stableLiveSince === null) state7.stableLiveSince = now();
628
- if (now() - state7.stableLiveSince >= BACKOFF_STABLE_RESET_MS) {
629
- state7.restartHistory = [];
630
- }
631
- }
632
- }
633
- if (missing.length === 0) {
634
- return {
635
- missing,
636
- restarted: false,
637
- reason: "healthy",
638
- rotationGraced: rotationGraced.length > 0 ? rotationGraced : void 0
639
- };
640
- }
641
- const nowMs = now();
642
- const givenUp = [];
643
- const active = [];
644
- const backingOff = [];
645
- const newGenerationKeys = /* @__PURE__ */ new Set();
646
- const quarantined = [];
647
- const wouldQuarantine = [];
648
- for (const key of missing) {
649
- const sk = stateKey(codeName, key);
650
- const state7 = presenceReaperState.get(sk) ?? {
651
- attempts: 0,
652
- lastSeenLiveAt: null,
653
- lastAttemptedSessionStartedAt: null,
654
- gaveUpLogged: false,
655
- firstMissingAt: null,
656
- quarantineLogged: false,
657
- restartHistory: [],
658
- stableLiveSince: null,
659
- gaveUp: false
660
- };
661
- if (state7.firstMissingAt === null) state7.firstMissingAt = nowMs;
662
- state7.stableLiveSince = null;
663
- if (state7.lastAttemptedSessionStartedAt !== sessionStartedAt) {
664
- state7.attempts += 1;
665
- state7.lastAttemptedSessionStartedAt = sessionStartedAt;
666
- newGenerationKeys.add(key);
667
- }
668
- state7.restartHistory = state7.restartHistory.filter((t) => nowMs - t < BACKOFF_WINDOW_MS);
669
- const restartsInWindow = state7.restartHistory.length;
670
- presenceReaperState.set(sk, state7);
671
- const overAttemptsCap = state7.attempts > MAX_PRESENCE_RESTART_ATTEMPTS;
672
- const overRateCap = restartsInWindow >= BACKOFF_GIVE_UP_RESTARTS;
673
- if (overAttemptsCap || overRateCap) {
674
- givenUp.push(key);
675
- state7.gaveUp = true;
676
- if (!state7.gaveUpLogged) {
677
- 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)`;
678
- log2(
679
- `[mcp-presence-reaper] giving up on '${codeName}:${key}' after ${cause}`
680
- );
681
- state7.gaveUpLogged = true;
682
- if (onGiveUp) {
683
- try {
684
- onGiveUp(codeName, key);
685
- } catch (err) {
686
- log2(
687
- `[mcp-presence-reaper] onGiveUp callback threw for '${codeName}:${key}' (suppressed; reaper continues): ${err.message}`
688
- );
689
- }
690
- }
691
- }
692
- if (quarantineMode !== "off" && !state7.quarantineLogged && classifyKey(key) === "optional") {
693
- const dwellElapsed = quarantineDwellMs <= 0 || state7.firstMissingAt !== null && nowMs - state7.firstMissingAt >= quarantineDwellMs;
694
- if (dwellElapsed) {
695
- state7.quarantineLogged = true;
696
- if (quarantineMode === "enforce") {
697
- quarantined.push(key);
698
- log2(
699
- `[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)`
700
- );
701
- if (onQuarantine) {
702
- try {
703
- onQuarantine(codeName, key);
704
- } catch (err) {
705
- log2(
706
- `[mcp-presence-reaper] onQuarantine callback threw for '${codeName}:${key}' (suppressed; reaper continues): ${err.message}`
707
- );
708
- }
709
- }
710
- } else {
711
- wouldQuarantine.push(key);
712
- log2(
713
- `[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)`
714
- );
715
- }
716
- }
717
- }
718
- } else {
719
- const backoffMs = restartsInWindow < BACKOFF_AFTER_RESTARTS ? 0 : Math.min(
720
- BACKOFF_BASE_MS * 2 ** (restartsInWindow - BACKOFF_AFTER_RESTARTS),
721
- BACKOFF_MAX_MS
722
- );
723
- const lastRestartAt = state7.restartHistory[state7.restartHistory.length - 1] ?? null;
724
- if (lastRestartAt !== null && nowMs - lastRestartAt < backoffMs) {
725
- backingOff.push(key);
726
- } else {
727
- active.push(key);
728
- }
729
- }
730
- }
731
- if (active.length === 0) {
732
- const reason = backingOff.length > 0 ? "backoff" : "all-keys-over-cap";
733
- if (backingOff.length > 0) {
734
- log2(
735
- `[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(", ")}])` : ""}`
736
- );
737
- }
738
- return {
739
- missing,
740
- restarted: false,
741
- reason,
742
- givenUp,
743
- backingOff: backingOff.length > 0 ? backingOff : void 0,
744
- rotationGraced: rotationGraced.length > 0 ? rotationGraced : void 0,
745
- quarantined: quarantined.length > 0 ? quarantined : void 0,
746
- wouldQuarantine: wouldQuarantine.length > 0 ? wouldQuarantine : void 0
747
- };
748
- }
749
- const givenUpSuffix = givenUp.length > 0 ? ` (skipping over-cap: [${givenUp.join(", ")}])` : "";
750
- log2(
751
- `[mcp-presence-reaper] '${codeName}': declared MCP(s) [${active.join(", ")}] have no live children \u2014 restarting session${givenUpSuffix}`
752
- );
753
- if (onRestart) {
754
- try {
755
- const maybePromise = onRestart(codeName, { activeKeys: active, givenUpKeys: givenUp });
756
- if (maybePromise && typeof maybePromise.then === "function") {
757
- void maybePromise.then(void 0, (err) => {
758
- log2(
759
- `[mcp-presence-reaper] onRestart callback rejected for '${codeName}' (suppressed; restart proceeds): ${err.message}`
760
- );
761
- });
762
- }
763
- } catch (err) {
764
- log2(
765
- `[mcp-presence-reaper] onRestart callback threw for '${codeName}' (suppressed; restart proceeds): ${err.message}`
766
- );
767
- }
768
- }
769
- stopSession(codeName, { activeKeys: active });
770
- for (const key of active) {
771
- if (!newGenerationKeys.has(key)) continue;
772
- const st = presenceReaperState.get(stateKey(codeName, key));
773
- if (st) st.restartHistory.push(nowMs);
774
- }
775
- return {
776
- missing,
777
- restarted: true,
778
- givenUp: givenUp.length > 0 ? givenUp : void 0,
779
- backingOff: backingOff.length > 0 ? backingOff : void 0,
780
- rotationGraced: rotationGraced.length > 0 ? rotationGraced : void 0,
781
- quarantined: quarantined.length > 0 ? quarantined : void 0,
782
- wouldQuarantine: wouldQuarantine.length > 0 ? wouldQuarantine : void 0
783
- };
784
- }
785
-
786
236
  // src/lib/channel-restart-decision.ts
787
237
  function launchableChannelIds(channelConfigs) {
788
238
  if (!channelConfigs) return /* @__PURE__ */ new Set();
@@ -1809,116 +1259,6 @@ function isDirectChatMessageExpired(createdAt, nowMs, maxAgeMs) {
1809
1259
  return nowMs - created > maxAgeMs;
1810
1260
  }
1811
1261
 
1812
- // src/lib/session-tool-probe.ts
1813
- function classifyMcpServer(entry) {
1814
- if (!entry || typeof entry !== "object") return "unknown";
1815
- const e = entry;
1816
- if (typeof e.command === "string") return "stdio";
1817
- if (typeof e.url === "string") return "http";
1818
- return "unknown";
1819
- }
1820
- function splitServerKeysByKind(mcpJson, serverKeys) {
1821
- const servers = mcpJson?.mcpServers ?? {};
1822
- const stdio = [];
1823
- const http = [];
1824
- for (const key of serverKeys) {
1825
- const kind = classifyMcpServer(servers[key]);
1826
- if (kind === "stdio") stdio.push(key);
1827
- else if (kind === "http") http.push(key);
1828
- }
1829
- return { stdio, http };
1830
- }
1831
- function computeSessionToolBindStatus(input) {
1832
- const { stdioServerKeys, httpServerKeys, missingStdioKeys, httpReachable, httpSessionLoaded } = input;
1833
- if (stdioServerKeys.length === 0 && httpServerKeys.length === 0) return "unknown";
1834
- if (stdioServerKeys.some((k) => missingStdioKeys.has(k))) return "missing";
1835
- let anyHttpUnconfirmed = false;
1836
- for (const k of httpServerKeys) {
1837
- const reachable = httpReachable.get(k);
1838
- if (reachable === false) return "unreachable";
1839
- if (reachable === void 0) {
1840
- anyHttpUnconfirmed = true;
1841
- } else if (!httpSessionLoaded) {
1842
- anyHttpUnconfirmed = true;
1843
- }
1844
- }
1845
- if (anyHttpUnconfirmed && stdioServerKeys.length === 0) return "unknown";
1846
- return "bound";
1847
- }
1848
-
1849
- // src/lib/session-tool-bind-runner.ts
1850
- var DEFAULT_INTERVAL_MS2 = 60 * 60 * 1e3;
1851
- var DEFAULT_MAX_PER_RUN2 = 25;
1852
- function sanitizeServerKey(definitionId) {
1853
- return definitionId.replace(/[^a-z0-9]/gi, "_").toLowerCase();
1854
- }
1855
- function resolveIntegrationServerKeys(definitionId, declaredKeys, hint) {
1856
- const declared = new Set(declaredKeys);
1857
- const candidates = [hint, definitionId, sanitizeServerKey(definitionId)].filter(
1858
- (k) => typeof k === "string" && k.length > 0
1859
- );
1860
- const out = /* @__PURE__ */ new Set();
1861
- for (const c of candidates) if (declared.has(c)) out.add(c);
1862
- return [...out];
1863
- }
1864
- function isDue2(last, now, intervalMs) {
1865
- if (!last) return true;
1866
- const t = Date.parse(last);
1867
- if (Number.isNaN(t)) return true;
1868
- return now - t >= intervalMs;
1869
- }
1870
- async function runSessionToolBindProbes(integrations, options) {
1871
- const now = (options.now?.() ?? /* @__PURE__ */ new Date()).getTime();
1872
- const intervalMs = options.intervalMs ?? DEFAULT_INTERVAL_MS2;
1873
- const maxPerRun = options.maxPerRun ?? DEFAULT_MAX_PER_RUN2;
1874
- const due = integrations.filter((i) => isDue2(i.last_session_tool_bind_at, now, intervalMs)).sort((a, b) => {
1875
- const ta = a.last_session_tool_bind_at ? Date.parse(a.last_session_tool_bind_at) : 0;
1876
- const tb = b.last_session_tool_bind_at ? Date.parse(b.last_session_tool_bind_at) : 0;
1877
- return ta - tb;
1878
- });
1879
- const batch = due.slice(0, maxPerRun);
1880
- const declaredKeys = Object.keys(options.mcpJson?.mcpServers ?? {});
1881
- const reports = [];
1882
- let skipped = 0;
1883
- let probed = 0;
1884
- for (const integ of batch) {
1885
- const keys = resolveIntegrationServerKeys(
1886
- integ.definition_id,
1887
- declaredKeys,
1888
- integ.mcp_server_key
1889
- );
1890
- if (keys.length === 0) {
1891
- skipped += 1;
1892
- continue;
1893
- }
1894
- probed += 1;
1895
- const { stdio, http } = splitServerKeysByKind(options.mcpJson, keys);
1896
- const httpReachable = /* @__PURE__ */ new Map();
1897
- for (const key of http) {
1898
- let reachable;
1899
- try {
1900
- reachable = await options.probeHttp(key);
1901
- } catch {
1902
- reachable = void 0;
1903
- }
1904
- if (reachable !== void 0) httpReachable.set(key, reachable);
1905
- }
1906
- const status = computeSessionToolBindStatus({
1907
- stdioServerKeys: stdio,
1908
- httpServerKeys: http,
1909
- missingStdioKeys: options.missingStdioKeys,
1910
- httpReachable,
1911
- httpSessionLoaded: options.httpSessionLoaded ?? false
1912
- });
1913
- if (status === "unknown") {
1914
- skipped += 1;
1915
- continue;
1916
- }
1917
- reports.push({ integration_id: integ.id, scope: integ.scope, status });
1918
- }
1919
- return { reports, due: due.length, probed, skipped };
1920
- }
1921
-
1922
1262
  // ../../packages/core/dist/host-config/capture.js
1923
1263
  import { createHash as createHash3 } from "crypto";
1924
1264
  var NON_SECRET_ENV_GATES = [
@@ -3435,7 +2775,7 @@ function saveChannelHashCache(source, configDir) {
3435
2775
  }
3436
2776
 
3437
2777
  // src/lib/channel-sweep.ts
3438
- import { execFileSync as execFileSync3 } from "child_process";
2778
+ import { execFileSync } from "child_process";
3439
2779
  var CHANNEL_BASENAMES = [
3440
2780
  "slack-channel",
3441
2781
  "direct-chat-channel",
@@ -3598,7 +2938,7 @@ function resolveLiveAnchorPids(agentCodeNames) {
3598
2938
  for (const codeName of agentCodeNames) {
3599
2939
  const pids = /* @__PURE__ */ new Set();
3600
2940
  try {
3601
- const out = execFileSync3("tmux", ["list-panes", "-t", `agt-${codeName}`, "-F", "#{pane_pid}"], {
2941
+ const out = execFileSync("tmux", ["list-panes", "-t", `agt-${codeName}`, "-F", "#{pane_pid}"], {
3602
2942
  encoding: "utf-8",
3603
2943
  timeout: 2e3,
3604
2944
  stdio: ["ignore", "pipe", "ignore"]
@@ -3618,7 +2958,7 @@ async function sweepChannelProcesses(opts) {
3618
2958
  const kill = opts.killFn ?? defaultKill;
3619
2959
  let psOutput = "";
3620
2960
  try {
3621
- psOutput = execFileSync3("ps", ["eww", "-o", "pid=,ppid=,etime=,command="], {
2961
+ psOutput = execFileSync("ps", ["eww", "-o", "pid=,ppid=,etime=,command="], {
3622
2962
  encoding: "utf-8",
3623
2963
  timeout: 5e3,
3624
2964
  maxBuffer: 10 * 1024 * 1024
@@ -3655,7 +2995,7 @@ function defaultKillSignal(pid, signal) {
3655
2995
  }
3656
2996
  }
3657
2997
  function defaultPs() {
3658
- return execFileSync3("ps", ["eww", "-o", "pid=,ppid=,etime=,command="], {
2998
+ return execFileSync("ps", ["eww", "-o", "pid=,ppid=,etime=,command="], {
3659
2999
  encoding: "utf-8",
3660
3000
  timeout: 5e3,
3661
3001
  maxBuffer: 10 * 1024 * 1024
@@ -6621,65 +5961,13 @@ async function runAgentConnectivityProbes(agent, integrations, projectDir) {
6621
5961
  }
6622
5962
  async function runAgentSessionToolBindProbes(agent, integrations, projectDir) {
6623
5963
  if (integrations.length === 0) return;
6624
- let mcpJson = null;
6625
- try {
6626
- mcpJson = JSON.parse(readFileSync14(join16(projectDir, ".mcp.json"), "utf-8"));
6627
- } catch {
6628
- return;
6629
- }
6630
- if (!mcpJson?.mcpServers || Object.keys(mcpJson.mcpServers).length === 0) return;
6631
- const isolated = isolationMode(agent.code_name) === "docker";
6632
- let missingStdioKeys = /* @__PURE__ */ new Set();
6633
- try {
6634
- const psOutput = isolated ? syncExecFile("docker", ["exec", `agt-${agent.code_name}`, "ps", "-eo", "pid,ppid,args"], {
6635
- encoding: "utf-8",
6636
- timeout: 8e3
6637
- }) : syncExecFile("ps", ["-eo", "pid,ppid,args"], { encoding: "utf-8", timeout: 5e3 });
6638
- missingStdioKeys = new Set(
6639
- findMissingMcpServers({
6640
- rows: parsePsRows(psOutput),
6641
- codeName: agent.code_name,
6642
- mcpJson,
6643
- inContainer: isolated
6644
- })
6645
- );
6646
- } catch {
6647
- }
6648
- const probeEnv = buildProbeEnv(projectDir);
6649
- const probeDeps = buildConnectivityProbeDeps(projectDir, probeEnv);
6650
- const probeHttp = async (serverKey) => {
6651
- if (!probeDeps.mcpProbe) return void 0;
6652
- const outcome = await probeDeps.mcpProbe({ serverKey, definitionId: serverKey });
6653
- if (outcome.status === "ok") return true;
6654
- if (outcome.status === "down") return false;
6655
- return void 0;
6656
- };
6657
- let httpSessionLoaded = false;
6658
- try {
6659
- const sessionStartedMs = getSessionState(agent.code_name)?.startedAt ?? null;
6660
- const mcpMtimeMs = statSync4(join16(projectDir, ".mcp.json")).mtimeMs;
6661
- httpSessionLoaded = sessionStartedMs != null && sessionStartedMs >= mcpMtimeMs;
6662
- } catch {
6663
- }
6664
5964
  const intervalSec = Number(process.env.AGT_CONNECTIVITY_PROBE_INTERVAL_SECONDS) || 3600;
6665
- const result = await runSessionToolBindProbes(
6666
- integrations.map((i) => ({
6667
- id: i.id,
6668
- definition_id: i.definition_id,
6669
- scope: i.scope,
6670
- last_session_tool_bind_at: i.last_session_tool_bind_at ?? null,
6671
- // Server-key hint for managed/remote-MCP kinds; the runner also tries the
6672
- // raw + sanitised definition_id against the real `.mcp.json` keys.
6673
- mcp_server_key: deriveMcpServerKey({
6674
- definitionId: i.definition_id,
6675
- sourceType: i.source_type ?? null,
6676
- authType: i.auth_type,
6677
- connectivityTest: i.connectivity_test ?? null
6678
- })
6679
- })),
6680
- { mcpJson, missingStdioKeys, probeHttp, httpSessionLoaded, intervalMs: intervalSec * 1e3 }
6681
- );
6682
- 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) {
6683
5971
  await api.post("/host/session-tool-bind", {
6684
5972
  agent_id: agent.agent_id,
6685
5973
  results: result.reports
@@ -6871,10 +6159,10 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
6871
6159
  var lastVersionCheckAt = 0;
6872
6160
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
6873
6161
  var lastResponsivenessProbeAt = 0;
6874
- var agtCliVersion = true ? "0.28.208" : "dev";
6875
- function resolveBrewPath(execFileSync4) {
6162
+ var agtCliVersion = true ? "0.28.209" : "dev";
6163
+ function resolveBrewPath(execFileSync2) {
6876
6164
  try {
6877
- const out = execFileSync4("which", ["brew"], { timeout: 5e3 }).toString().trim();
6165
+ const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
6878
6166
  if (out) return out;
6879
6167
  } catch {
6880
6168
  }
@@ -6888,7 +6176,7 @@ function resolveBrewPath(execFileSync4) {
6888
6176
  }
6889
6177
  return null;
6890
6178
  }
6891
- function claudeBinaryInstalled(execFileSync4) {
6179
+ function claudeBinaryInstalled(execFileSync2) {
6892
6180
  const canonical = [
6893
6181
  "/home/linuxbrew/.linuxbrew/bin/claude",
6894
6182
  "/opt/homebrew/bin/claude",
@@ -6896,7 +6184,7 @@ function claudeBinaryInstalled(execFileSync4) {
6896
6184
  ];
6897
6185
  if (canonical.some((path) => existsSync8(path))) return true;
6898
6186
  try {
6899
- execFileSync4("which", ["claude"], { timeout: 5e3 });
6187
+ execFileSync2("which", ["claude"], { timeout: 5e3 });
6900
6188
  return true;
6901
6189
  } catch {
6902
6190
  return false;
@@ -6930,9 +6218,9 @@ async function ensureToolkitCli(toolkitSlug) {
6930
6218
  }
6931
6219
  const { binary, installer, package: pkg, script } = integration.cli_tool;
6932
6220
  const resolvedInstaller = installer ?? "manual";
6933
- const { execFileSync: execFileSync4, execSync } = await import("child_process");
6221
+ const { execFileSync: execFileSync2, execSync } = await import("child_process");
6934
6222
  try {
6935
- execFileSync4("which", [binary], { timeout: 5e3, stdio: "pipe" });
6223
+ execFileSync2("which", [binary], { timeout: 5e3, stdio: "pipe" });
6936
6224
  toolkitCliEnsured.add(toolkitSlug);
6937
6225
  toolkitCliRetryAfter.delete(toolkitSlug);
6938
6226
  toolkitCliFailureCount.delete(toolkitSlug);
@@ -6953,14 +6241,14 @@ async function ensureToolkitCli(toolkitSlug) {
6953
6241
  return;
6954
6242
  }
6955
6243
  log(`[toolkit-install] ${toolkitSlug}: installing via npm (${pkg})\u2026`);
6956
- execFileSync4("npm", ["install", "-g", pkg], { timeout: 18e4, stdio: "pipe" });
6244
+ execFileSync2("npm", ["install", "-g", pkg], { timeout: 18e4, stdio: "pipe" });
6957
6245
  } else if (resolvedInstaller === "brew") {
6958
6246
  if (!pkg) {
6959
6247
  log(`[toolkit-install] ${toolkitSlug}: installer=brew but no package declared`);
6960
6248
  toolkitCliEnsured.add(toolkitSlug);
6961
6249
  return;
6962
6250
  }
6963
- const brewPath = resolveBrewPath(execFileSync4);
6251
+ const brewPath = resolveBrewPath(execFileSync2);
6964
6252
  if (!brewPath) {
6965
6253
  log(`[toolkit-install] ${toolkitSlug}: installer=brew but Homebrew not available \u2014 install manually: brew install ${pkg}`);
6966
6254
  toolkitCliEnsured.add(toolkitSlug);
@@ -6970,9 +6258,9 @@ async function ensureToolkitCli(toolkitSlug) {
6970
6258
  const isRoot = typeof process.getuid === "function" && process.getuid() === 0;
6971
6259
  log(`[toolkit-install] ${toolkitSlug}: installing via brew (${pkg})\u2026`);
6972
6260
  if (isRoot) {
6973
- execFileSync4("sudo", ["-u", "ec2-user", "-H", brewPath, "install", pkg], { timeout: 18e4, stdio: "pipe", cwd: "/tmp" });
6261
+ execFileSync2("sudo", ["-u", "ec2-user", "-H", brewPath, "install", pkg], { timeout: 18e4, stdio: "pipe", cwd: "/tmp" });
6974
6262
  } else {
6975
- execFileSync4(brewPath, ["install", pkg], { timeout: 18e4, stdio: "pipe" });
6263
+ execFileSync2(brewPath, ["install", pkg], { timeout: 18e4, stdio: "pipe" });
6976
6264
  }
6977
6265
  } else if (resolvedInstaller === "script") {
6978
6266
  if (!script) {
@@ -6992,7 +6280,7 @@ async function ensureToolkitCli(toolkitSlug) {
6992
6280
  process.env.PATH = `${brewBinDir}:${process.env.PATH ?? ""}`;
6993
6281
  }
6994
6282
  try {
6995
- execFileSync4("which", [binary], { timeout: 5e3, stdio: "pipe" });
6283
+ execFileSync2("which", [binary], { timeout: 5e3, stdio: "pipe" });
6996
6284
  log(`[toolkit-install] ${toolkitSlug}: installed \u2014 ${binary} now on PATH`);
6997
6285
  toolkitCliEnsured.add(toolkitSlug);
6998
6286
  toolkitCliRetryAfter.delete(toolkitSlug);
@@ -7079,8 +6367,8 @@ async function ensureFrameworkBinary(frameworkId) {
7079
6367
  if (frameworkBinaryChecked.has(frameworkId)) return;
7080
6368
  frameworkBinaryChecked.add(frameworkId);
7081
6369
  lastManagedSettingsStatus = ensureClaudeManagedSettings();
7082
- const { execFileSync: execFileSync4 } = await import("child_process");
7083
- const brewPath = resolveBrewPath(execFileSync4);
6370
+ const { execFileSync: execFileSync2 } = await import("child_process");
6371
+ const brewPath = resolveBrewPath(execFileSync2);
7084
6372
  if (!brewPath) {
7085
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");
7086
6374
  return;
@@ -7093,7 +6381,7 @@ async function ensureFrameworkBinary(frameworkId) {
7093
6381
  }
7094
6382
  return runAsync(brewPath, args, opts);
7095
6383
  };
7096
- const claudeExists = claudeBinaryInstalled(execFileSync4);
6384
+ const claudeExists = claudeBinaryInstalled(execFileSync2);
7097
6385
  if (!claudeExists) {
7098
6386
  log(`Claude Code binary not found \u2014 installing via Homebrew${isRoot ? " (as ec2-user via sudo)" : ""}...`);
7099
6387
  try {
@@ -7128,13 +6416,13 @@ async function maybeUpgradeClaudeCode() {
7128
6416
  }
7129
6417
  claudeCodeUpgradeInFlight = true;
7130
6418
  stampClaudeCodeUpgradeMarker();
7131
- const { execFileSync: execFileSync4 } = await import("child_process");
7132
- const brewPath = resolveBrewPath(execFileSync4);
6419
+ const { execFileSync: execFileSync2 } = await import("child_process");
6420
+ const brewPath = resolveBrewPath(execFileSync2);
7133
6421
  if (!brewPath) {
7134
6422
  claudeCodeUpgradeInFlight = false;
7135
6423
  return;
7136
6424
  }
7137
- if (!claudeBinaryInstalled(execFileSync4)) {
6425
+ if (!claudeBinaryInstalled(execFileSync2)) {
7138
6426
  claudeCodeUpgradeInFlight = false;
7139
6427
  return;
7140
6428
  }
@@ -7213,18 +6501,18 @@ async function checkAndUpdateCli(opts) {
7213
6501
  }
7214
6502
  }
7215
6503
  async function checkAndUpdateCliViaBrew(force = false) {
7216
- const { execFileSync: execFileSync4 } = await import("child_process");
7217
- const brewPath = resolveBrewPath(execFileSync4);
6504
+ const { execFileSync: execFileSync2 } = await import("child_process");
6505
+ const brewPath = resolveBrewPath(execFileSync2);
7218
6506
  if (!brewPath) return "noop";
7219
6507
  let metadataFresh = true;
7220
6508
  try {
7221
- execFileSync4(brewPath, ["update", "--quiet"], { timeout: 6e4, stdio: "pipe" });
6509
+ execFileSync2(brewPath, ["update", "--quiet"], { timeout: 6e4, stdio: "pipe" });
7222
6510
  } catch (err) {
7223
6511
  metadataFresh = false;
7224
6512
  log(`[self-update] brew update failed (continuing with stale cache): ${err.message}`);
7225
6513
  }
7226
6514
  try {
7227
- const outdated = execFileSync4(brewPath, ["outdated", "--json=v2"], {
6515
+ const outdated = execFileSync2(brewPath, ["outdated", "--json=v2"], {
7228
6516
  timeout: 3e4,
7229
6517
  encoding: "utf-8"
7230
6518
  });
@@ -7257,7 +6545,7 @@ async function checkAndUpdateCliViaBrew(force = false) {
7257
6545
  }
7258
6546
  log(`[self-update] agt CLI update available: ${installed} \u2192 ${latest}. Upgrading via brew${force ? " (forced \u2014 Update CLI now)" : ""}...`);
7259
6547
  try {
7260
- execFileSync4(brewPath, ["upgrade", "integrity-labs/tap/agt"], {
6548
+ execFileSync2(brewPath, ["upgrade", "integrity-labs/tap/agt"], {
7261
6549
  timeout: 12e4,
7262
6550
  stdio: "pipe"
7263
6551
  });
@@ -7376,7 +6664,7 @@ async function fetchUrgentDistTagVersion() {
7376
6664
  }
7377
6665
  }
7378
6666
  async function installAgtCliViaNpm(version, reasonLabel) {
7379
- const { execFileSync: execFileSync4 } = await import("child_process");
6667
+ const { execFileSync: execFileSync2 } = await import("child_process");
7380
6668
  const isRoot = typeof process.getuid === "function" && process.getuid() === 0;
7381
6669
  const cmd = isRoot ? "npm" : "sudo";
7382
6670
  const installArgs = [
@@ -7387,14 +6675,14 @@ async function installAgtCliViaNpm(version, reasonLabel) {
7387
6675
  ];
7388
6676
  const args = isRoot ? installArgs : ["-n", "npm", ...installArgs];
7389
6677
  try {
7390
- execFileSync4(cmd, args, { timeout: 18e4, stdio: "pipe" });
6678
+ execFileSync2(cmd, args, { timeout: 18e4, stdio: "pipe" });
7391
6679
  } catch (err) {
7392
6680
  log(`[self-update] npm upgrade failed: ${err.message}`);
7393
6681
  return "failed";
7394
6682
  }
7395
6683
  let smokeOk = false;
7396
6684
  try {
7397
- const out = execFileSync4("agt", ["--version"], { timeout: 15e3, stdio: "pipe" }).toString();
6685
+ const out = execFileSync2("agt", ["--version"], { timeout: 15e3, stdio: "pipe" }).toString();
7398
6686
  smokeOk = isAgtVersionSmokeOk(out, version);
7399
6687
  if (!smokeOk) {
7400
6688
  log(
@@ -7780,7 +7068,7 @@ async function pollCycle() {
7780
7068
  }
7781
7069
  try {
7782
7070
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
7783
- const { collectDiagnostics } = await import("../persistent-session-6662WBSH.js");
7071
+ const { collectDiagnostics } = await import("../persistent-session-Z46SCCQM.js");
7784
7072
  const diagCodeNames = [...agentState.persistentSessionAgents];
7785
7073
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
7786
7074
  let tailscaleHostname;
@@ -7928,7 +7216,7 @@ async function pollCycle() {
7928
7216
  const {
7929
7217
  collectResponsivenessProbes,
7930
7218
  getResponsivenessIntervalMs
7931
- } = await import("../responsiveness-probe-TOLTTG6I.js");
7219
+ } = await import("../responsiveness-probe-4MUX7FBH.js");
7932
7220
  const probeIntervalMs = getResponsivenessIntervalMs();
7933
7221
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
7934
7222
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -7960,7 +7248,7 @@ async function pollCycle() {
7960
7248
  collectResponsivenessProbes,
7961
7249
  livePendingInboundOldestAgeSeconds,
7962
7250
  parkPendingInbound
7963
- } = await import("../responsiveness-probe-TOLTTG6I.js");
7251
+ } = await import("../responsiveness-probe-4MUX7FBH.js");
7964
7252
  const { getProjectDir: wedgeProjectDir } = await import("../claude-scheduler-FATCLHDM.js");
7965
7253
  const wedgeNow = /* @__PURE__ */ new Date();
7966
7254
  const liveAgents = agentState.persistentSessionAgents;
@@ -10987,7 +10275,7 @@ async function processClaudePairSessions(agents) {
10987
10275
  killPairSession,
10988
10276
  pairTmuxSession,
10989
10277
  finalizeClaudePairOnboarding
10990
- } = await import("../claude-pair-runtime-Q4Q2OTTV.js");
10278
+ } = await import("../claude-pair-runtime-UUTPSE2V.js");
10991
10279
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
10992
10280
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
10993
10281
  const killed = await killPairSession(pairTmuxSession(pairId));