@integrity-labs/agt-cli 0.28.204 → 0.28.206

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.
@@ -28,7 +28,7 @@ import {
28
28
  requireHost,
29
29
  safeWriteJsonAtomic,
30
30
  setConfigHash
31
- } from "../chunk-DKVV2REL.js";
31
+ } from "../chunk-WALP3HBE.js";
32
32
  import {
33
33
  getProjectDir as getProjectDir2,
34
34
  getReadyTasks,
@@ -70,7 +70,7 @@ import {
70
70
  takeZombieDetection,
71
71
  transcriptActivityAgeSeconds,
72
72
  writeEgressAllowlist
73
- } from "../chunk-2A2EV3B3.js";
73
+ } from "../chunk-GWBOA7ZY.js";
74
74
  import {
75
75
  CONVERSATION_FAILURE_CATEGORIES,
76
76
  DEFAULT_FRAMEWORK,
@@ -114,7 +114,7 @@ import {
114
114
  resolveChannels,
115
115
  resolveDmTarget,
116
116
  sumTranscriptUsageInWindow
117
- } from "../chunk-2AWUVRIX.js";
117
+ } from "../chunk-ELBYWACS.js";
118
118
  import {
119
119
  parsePsRows,
120
120
  reapOrphanChannelMcps
@@ -1804,6 +1804,116 @@ function isDirectChatMessageExpired(createdAt, nowMs, maxAgeMs) {
1804
1804
  return nowMs - created > maxAgeMs;
1805
1805
  }
1806
1806
 
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
+
1807
1917
  // ../../packages/core/dist/host-config/capture.js
1808
1918
  import { createHash as createHash3 } from "crypto";
1809
1919
  var NON_SECRET_ENV_GATES = [
@@ -6504,6 +6614,76 @@ async function runAgentConnectivityProbes(agent, integrations, projectDir) {
6504
6614
  );
6505
6615
  }
6506
6616
  }
6617
+ async function runAgentSessionToolBindProbes(agent, integrations, projectDir) {
6618
+ 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
+ const intervalSec = Number(process.env.AGT_CONNECTIVITY_PROBE_INTERVAL_SECONDS) || 3600;
6660
+ const result = await runSessionToolBindProbes(
6661
+ integrations.map((i) => ({
6662
+ id: i.id,
6663
+ definition_id: i.definition_id,
6664
+ scope: i.scope,
6665
+ last_session_tool_bind_at: i.last_session_tool_bind_at ?? null,
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) {
6678
+ await api.post("/host/session-tool-bind", {
6679
+ agent_id: agent.agent_id,
6680
+ results: result.reports
6681
+ });
6682
+ log(
6683
+ `Session-tool-bind probe for '${agent.code_name}': probed=${result.probed} reported=${result.reports.length} due=${result.due}`
6684
+ );
6685
+ }
6686
+ }
6507
6687
  function stopPersistentSessionAndForgetMcpBaseline(codeName, breakerReason, gateReason = breakerReason) {
6508
6688
  const gate = restartGateFor(codeName, gateReason);
6509
6689
  if (gate !== "bypass" && gate !== "proceed") {
@@ -6686,7 +6866,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
6686
6866
  var lastVersionCheckAt = 0;
6687
6867
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
6688
6868
  var lastResponsivenessProbeAt = 0;
6689
- var agtCliVersion = true ? "0.28.204" : "dev";
6869
+ var agtCliVersion = true ? "0.28.206" : "dev";
6690
6870
  function resolveBrewPath(execFileSync4) {
6691
6871
  try {
6692
6872
  const out = execFileSync4("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -7595,7 +7775,7 @@ async function pollCycle() {
7595
7775
  }
7596
7776
  try {
7597
7777
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
7598
- const { collectDiagnostics } = await import("../persistent-session-OXQGFIXK.js");
7778
+ const { collectDiagnostics } = await import("../persistent-session-6662WBSH.js");
7599
7779
  const diagCodeNames = [...agentState.persistentSessionAgents];
7600
7780
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
7601
7781
  let tailscaleHostname;
@@ -7743,7 +7923,7 @@ async function pollCycle() {
7743
7923
  const {
7744
7924
  collectResponsivenessProbes,
7745
7925
  getResponsivenessIntervalMs
7746
- } = await import("../responsiveness-probe-T5Z5KPVX.js");
7926
+ } = await import("../responsiveness-probe-TOLTTG6I.js");
7747
7927
  const probeIntervalMs = getResponsivenessIntervalMs();
7748
7928
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
7749
7929
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -7775,7 +7955,7 @@ async function pollCycle() {
7775
7955
  collectResponsivenessProbes,
7776
7956
  livePendingInboundOldestAgeSeconds,
7777
7957
  parkPendingInbound
7778
- } = await import("../responsiveness-probe-T5Z5KPVX.js");
7958
+ } = await import("../responsiveness-probe-TOLTTG6I.js");
7779
7959
  const { getProjectDir: wedgeProjectDir } = await import("../claude-scheduler-FATCLHDM.js");
7780
7960
  const wedgeNow = /* @__PURE__ */ new Date();
7781
7961
  const liveAgents = agentState.persistentSessionAgents;
@@ -9135,7 +9315,7 @@ async function processAgent(agent, agentStates) {
9135
9315
  log(`OAuth token refresh failed for '${agent.code_name}/${integration.definition_id}': ${err.message}`);
9136
9316
  }
9137
9317
  }
9138
- if (process.env.AGT_CONNECTIVITY_PROBE_ENABLED === "true") {
9318
+ if (hostFlagStore().getBoolean("connectivity-probe")) {
9139
9319
  try {
9140
9320
  const probeProjectDir = join16(homedir9(), ".augmented", agent.code_name, "project");
9141
9321
  await runAgentConnectivityProbes(agent, integrations, probeProjectDir);
@@ -9143,6 +9323,14 @@ async function processAgent(agent, agentStates) {
9143
9323
  log(`Connectivity probe failed for '${agent.code_name}': ${err.message}`);
9144
9324
  }
9145
9325
  }
9326
+ if (hostFlagStore().getBoolean("session-tool-probe")) {
9327
+ try {
9328
+ const probeProjectDir = join16(homedir9(), ".augmented", agent.code_name, "project");
9329
+ await runAgentSessionToolBindProbes(agent, integrations, probeProjectDir);
9330
+ } catch (err) {
9331
+ log(`Session-tool-bind probe failed for '${agent.code_name}': ${err.message}`);
9332
+ }
9333
+ }
9146
9334
  if (integrations.length > 0) {
9147
9335
  const intHash = computeIntegrationsHash(integrations);
9148
9336
  const prevIntHash = agentState.knownIntegrationHashes.get(agent.agent_id);
@@ -10794,7 +10982,7 @@ async function processClaudePairSessions(agents) {
10794
10982
  killPairSession,
10795
10983
  pairTmuxSession,
10796
10984
  finalizeClaudePairOnboarding
10797
- } = await import("../claude-pair-runtime-H5UNK3LX.js");
10985
+ } = await import("../claude-pair-runtime-Q4Q2OTTV.js");
10798
10986
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
10799
10987
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
10800
10988
  const killed = await killPairSession(pairTmuxSession(pairId));