@integrity-labs/agt-cli 0.25.1 → 0.25.2

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.
@@ -100,7 +100,7 @@ async function spawnPairSession(session) {
100
100
  return { ok: true };
101
101
  } catch {
102
102
  }
103
- const { resolveClaudeBinary } = await import("./persistent-session-3FQVLVJM.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-MUJA45LT.js");
104
104
  const claudeBin = resolveClaudeBinary();
105
105
  const pairEnv = {
106
106
  ...process.env,
@@ -373,4 +373,4 @@ export {
373
373
  startClaudePair,
374
374
  submitClaudePairCode
375
375
  };
376
- //# sourceMappingURL=claude-pair-runtime-ZWE5572F.js.map
376
+ //# sourceMappingURL=claude-pair-runtime-Q5CZLM2R.js.map
@@ -13,7 +13,7 @@ import {
13
13
  provisionOrientHook,
14
14
  provisionStopHook,
15
15
  requireHost
16
- } from "../chunk-AAK2IU2Z.js";
16
+ } from "../chunk-U4DAVDAZ.js";
17
17
  import {
18
18
  findTaskByTemplate,
19
19
  getProjectDir as getProjectDir2,
@@ -50,7 +50,7 @@ import {
50
50
  stopAllSessionsAndWait,
51
51
  stopPersistentSession,
52
52
  takeZombieDetection
53
- } from "../chunk-4FSQVXWB.js";
53
+ } from "../chunk-M2RBM3M5.js";
54
54
  import {
55
55
  KANBAN_CHECK_COMMAND,
56
56
  appendDmFooter,
@@ -68,10 +68,12 @@ import {
68
68
  parseDeliveryTarget,
69
69
  parseTranscriptUsage,
70
70
  parseUsageBanner,
71
+ probeHttpProvider,
71
72
  resolveChannels,
73
+ resolveConnectivityProbe,
72
74
  resolveDmTarget,
73
75
  wrapScheduledTaskPrompt
74
- } from "../chunk-4K3ERUGE.js";
76
+ } from "../chunk-VWOXS4YP.js";
75
77
 
76
78
  // src/lib/manager-worker.ts
77
79
  import { createHash as createHash3 } from "crypto";
@@ -691,6 +693,223 @@ function shouldRespawnForModelChange(input) {
691
693
  return previousModel !== primaryModel;
692
694
  }
693
695
 
696
+ // src/lib/connectivity-probe-executor.ts
697
+ async function executeConnectivityProbe(target, deps = {}) {
698
+ const descriptor = resolveConnectivityProbe({
699
+ definitionId: target.definitionId,
700
+ sourceType: target.sourceType,
701
+ authType: target.authType
702
+ });
703
+ if (!descriptor.readOnly) {
704
+ throw new Error(`Refusing non-read-only probe for ${target.definitionId}`);
705
+ }
706
+ switch (descriptor.kind) {
707
+ case "http_provider":
708
+ return probeHttpProvider(target.definitionId, target.credentials, deps.fetchImpl ?? fetch);
709
+ case "composio_account":
710
+ if (!deps.composioProbe) return null;
711
+ return deps.composioProbe(target.definitionId, target.credentials);
712
+ case "mcp_tools_list":
713
+ if (!deps.mcpProbe) return null;
714
+ return deps.mcpProbe({
715
+ serverKey: target.mcpServerKey ?? target.definitionId,
716
+ definitionId: target.definitionId
717
+ });
718
+ case "cli_command":
719
+ if (!deps.runCli) return null;
720
+ return deps.runCli(target.cliBinary ?? target.definitionId, descriptor.cliArgs ?? ["--version"]);
721
+ case "builtin":
722
+ return { status: "ok", message: `${target.definitionId}: built-in` };
723
+ case "unsupported":
724
+ default:
725
+ return null;
726
+ }
727
+ }
728
+
729
+ // src/lib/connectivity-probe-runner.ts
730
+ var DEFAULT_INTERVAL_MS = 60 * 60 * 1e3;
731
+ var DEFAULT_MAX_PER_RUN = 25;
732
+ function isDue(lastCheck, now, intervalMs) {
733
+ if (!lastCheck) return true;
734
+ const t = Date.parse(lastCheck);
735
+ if (Number.isNaN(t)) return true;
736
+ return now - t >= intervalMs;
737
+ }
738
+ async function runConnectivityProbes(integrations, options = {}) {
739
+ const now = (options.now?.() ?? /* @__PURE__ */ new Date()).getTime();
740
+ const intervalMs = options.intervalMs ?? DEFAULT_INTERVAL_MS;
741
+ const maxPerRun = options.maxPerRun ?? DEFAULT_MAX_PER_RUN;
742
+ const probeDeps = options.probeDeps ?? {};
743
+ const execute = options.executeProbe ?? executeConnectivityProbe;
744
+ const due = integrations.filter((i) => isDue(i.last_connectivity_check_at, now, intervalMs)).sort((a, b) => {
745
+ const ta = a.last_connectivity_check_at ? Date.parse(a.last_connectivity_check_at) : 0;
746
+ const tb = b.last_connectivity_check_at ? Date.parse(b.last_connectivity_check_at) : 0;
747
+ return ta - tb;
748
+ });
749
+ const batch = due.slice(0, maxPerRun);
750
+ const reports = [];
751
+ let skipped = 0;
752
+ for (const integ of batch) {
753
+ const target = {
754
+ definitionId: integ.definition_id,
755
+ sourceType: integ.source_type ?? null,
756
+ authType: integ.auth_type ?? null,
757
+ credentials: integ.credentials ?? {},
758
+ cliBinary: integ.cli_binary,
759
+ mcpServerKey: integ.mcp_server_key
760
+ };
761
+ let outcome;
762
+ try {
763
+ outcome = await execute(target, probeDeps);
764
+ } catch (err) {
765
+ console.warn(`[connectivity-probe] ${integ.definition_id} threw: ${err.message}`);
766
+ outcome = null;
767
+ }
768
+ if (!outcome) {
769
+ skipped += 1;
770
+ continue;
771
+ }
772
+ reports.push({
773
+ integration_id: integ.id,
774
+ scope: integ.scope,
775
+ status: outcome.status,
776
+ ...outcome.message ? { message: outcome.message } : {}
777
+ });
778
+ }
779
+ return { reports, due: due.length, probed: batch.length, skipped };
780
+ }
781
+
782
+ // src/lib/mcp-probe-client.ts
783
+ var MCP_ACCEPT = "application/json, text/event-stream";
784
+ var DEFAULT_TIMEOUT_MS = 1e4;
785
+ async function parseRpc(res, expectedId) {
786
+ const ct = res.headers.get("content-type") ?? "";
787
+ if (ct.includes("text/event-stream")) {
788
+ const text = await res.text();
789
+ let dataLines = [];
790
+ for (const rawLine of text.split(/\r?\n/)) {
791
+ if (rawLine.startsWith("data:")) {
792
+ dataLines.push(rawLine.slice(5).trimStart());
793
+ continue;
794
+ }
795
+ if (rawLine === "" && dataLines.length > 0) {
796
+ try {
797
+ const msg2 = JSON.parse(dataLines.join("\n"));
798
+ if (("result" in msg2 || "error" in msg2) && msg2["id"] === expectedId) return msg2;
799
+ } catch {
800
+ }
801
+ dataLines = [];
802
+ }
803
+ }
804
+ return null;
805
+ }
806
+ const msg = await res.json().catch(() => null);
807
+ if (msg && ("result" in msg || "error" in msg) && msg["id"] === expectedId) return msg;
808
+ return msg;
809
+ }
810
+ function httpStatusOutcome(status, step) {
811
+ if (status === 401 || status === 403) {
812
+ return { status: "down", message: `MCP ${step} unauthorized (${status}) \u2014 reconnect required` };
813
+ }
814
+ if (status >= 500) {
815
+ return { status: "transient_error", message: `MCP ${step} returned ${status}` };
816
+ }
817
+ return { status: "down", message: `MCP ${step} returned ${status}` };
818
+ }
819
+ async function probeMcpHttp(config2, fetchImpl = fetch) {
820
+ const timeoutMs = config2.timeoutMs ?? DEFAULT_TIMEOUT_MS;
821
+ const baseHeaders = {
822
+ ...config2.headers ?? {},
823
+ "Content-Type": "application/json",
824
+ Accept: MCP_ACCEPT
825
+ };
826
+ try {
827
+ const initRes = await fetchImpl(config2.url, {
828
+ method: "POST",
829
+ headers: baseHeaders,
830
+ body: JSON.stringify({
831
+ jsonrpc: "2.0",
832
+ id: 1,
833
+ method: "initialize",
834
+ params: {
835
+ protocolVersion: "2025-03-26",
836
+ capabilities: {},
837
+ clientInfo: { name: "augmented-connectivity-probe", version: "1.0.0" }
838
+ }
839
+ }),
840
+ signal: AbortSignal.timeout(timeoutMs)
841
+ });
842
+ if (!initRes.ok) return httpStatusOutcome(initRes.status, "initialize");
843
+ const sessionId = initRes.headers.get("mcp-session-id");
844
+ await parseRpc(initRes, 1);
845
+ const sessionHeaders = { ...baseHeaders, ...sessionId ? { "Mcp-Session-Id": sessionId } : {} };
846
+ const initializedRes = await fetchImpl(config2.url, {
847
+ method: "POST",
848
+ headers: sessionHeaders,
849
+ body: JSON.stringify({ jsonrpc: "2.0", method: "notifications/initialized" }),
850
+ signal: AbortSignal.timeout(5e3)
851
+ });
852
+ if (!initializedRes.ok) return httpStatusOutcome(initializedRes.status, "initialized");
853
+ await initializedRes.text().catch(() => "");
854
+ const listRes = await fetchImpl(config2.url, {
855
+ method: "POST",
856
+ headers: sessionHeaders,
857
+ body: JSON.stringify({ jsonrpc: "2.0", id: 2, method: "tools/list" }),
858
+ signal: AbortSignal.timeout(timeoutMs)
859
+ });
860
+ if (!listRes.ok) return httpStatusOutcome(listRes.status, "tools/list");
861
+ const rpc = await parseRpc(listRes, 2);
862
+ if (rpc && "error" in rpc) {
863
+ const err = rpc["error"];
864
+ return { status: "down", message: `MCP tools/list error: ${err?.message ?? "unknown"}` };
865
+ }
866
+ const result = rpc?.["result"];
867
+ const toolCount = Array.isArray(result?.tools) ? result.tools.length : void 0;
868
+ return {
869
+ status: "ok",
870
+ message: toolCount !== void 0 ? `${toolCount} tools` : "reachable",
871
+ ...toolCount !== void 0 ? { details: { toolCount } } : {}
872
+ };
873
+ } catch (err) {
874
+ const isAbort = err?.name === "TimeoutError" || err?.name === "AbortError";
875
+ return {
876
+ status: "transient_error",
877
+ message: isAbort ? `MCP handshake timed out after ${timeoutMs / 1e3}s` : `MCP handshake failed: ${err.message}`
878
+ };
879
+ }
880
+ }
881
+
882
+ // src/lib/cli-probe.ts
883
+ import { execFile } from "child_process";
884
+ var DEFAULT_TIMEOUT_MS2 = 8e3;
885
+ function runCliProbe(binary, args, opts = {}) {
886
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
887
+ return new Promise((resolve) => {
888
+ execFile(
889
+ binary,
890
+ args,
891
+ { timeout: timeoutMs, env: opts.env ?? process.env, windowsHide: true },
892
+ (err, stdout) => {
893
+ if (!err) {
894
+ const firstLine = String(stdout).split(/\r?\n/, 1)[0]?.trim();
895
+ resolve({ status: "ok", message: firstLine ? `${binary}: ${firstLine}` : `${binary}: ok` });
896
+ return;
897
+ }
898
+ const e = err;
899
+ if (e.code === "ENOENT") {
900
+ resolve({ status: "down", message: `${binary} not found on PATH (not installed)` });
901
+ return;
902
+ }
903
+ if (e.killed || e.signal === "SIGTERM") {
904
+ resolve({ status: "transient_error", message: `${binary} probe timed out after ${timeoutMs / 1e3}s` });
905
+ return;
906
+ }
907
+ resolve({ status: "down", message: `${binary} exited non-zero: ${e.message}` });
908
+ }
909
+ );
910
+ });
911
+ }
912
+
694
913
  // src/lib/usage-banner-monitor.ts
695
914
  var MIN_CHECK_INTERVAL_MS = 6e4;
696
915
  var PANE_TAIL_LINES_FOR_BANNER = 200;
@@ -1377,9 +1596,9 @@ var GatewayClientPool = class extends EventEmitter {
1377
1596
  import { readFile, readdir } from "fs/promises";
1378
1597
  import { homedir as homedir2, platform } from "os";
1379
1598
  import { join as join3 } from "path";
1380
- import { execFile } from "child_process";
1599
+ import { execFile as execFile2 } from "child_process";
1381
1600
  import { promisify } from "util";
1382
- var execFileAsync = promisify(execFile);
1601
+ var execFileAsync = promisify(execFile2);
1383
1602
  var EXPIRING_SOON_MS = 48 * 60 * 60 * 1e3;
1384
1603
  async function detectClaudeAuth() {
1385
1604
  if (process.env["ANTHROPIC_API_KEY"] || process.env["ANTHROPIC_AUTH_TOKEN"]) {
@@ -2712,6 +2931,55 @@ function projectMcpKeys(_codeName, projectDir) {
2712
2931
  return null;
2713
2932
  }
2714
2933
  }
2934
+ function readMcpHttpServerConfig(projectDir, serverKey) {
2935
+ try {
2936
+ const raw = readFileSync5(join6(projectDir, ".mcp.json"), "utf-8");
2937
+ const servers = JSON.parse(raw).mcpServers ?? {};
2938
+ const entry = servers[serverKey];
2939
+ if (entry && typeof entry.url === "string" && (entry.type === "http" || entry.type === void 0)) {
2940
+ return { url: entry.url, ...entry.headers ? { headers: entry.headers } : {} };
2941
+ }
2942
+ return null;
2943
+ } catch {
2944
+ return null;
2945
+ }
2946
+ }
2947
+ async function runAgentConnectivityProbes(agent, integrations, projectDir) {
2948
+ if (integrations.length === 0) return;
2949
+ const probeDeps = {
2950
+ fetchImpl: fetch,
2951
+ runCli: (binary, args) => runCliProbe(binary, args),
2952
+ mcpProbe: async (target) => {
2953
+ const cfg = readMcpHttpServerConfig(projectDir, target.serverKey);
2954
+ if (!cfg) {
2955
+ return { status: "transient_error", message: `MCP server '${target.serverKey}' not resolvable from .mcp.json` };
2956
+ }
2957
+ return probeMcpHttp(cfg);
2958
+ }
2959
+ };
2960
+ const intervalSec = Number(process.env.AGT_CONNECTIVITY_PROBE_INTERVAL_SECONDS) || 3600;
2961
+ const result = await runConnectivityProbes(
2962
+ integrations.map((i) => ({
2963
+ id: i.id,
2964
+ definition_id: i.definition_id,
2965
+ scope: i.scope,
2966
+ auth_type: i.auth_type,
2967
+ source_type: i.source_type ?? null,
2968
+ credentials: i.credentials,
2969
+ last_connectivity_check_at: i.last_connectivity_check_at ?? null
2970
+ })),
2971
+ { probeDeps, intervalMs: intervalSec * 1e3 }
2972
+ );
2973
+ if (result.reports.length > 0) {
2974
+ await api.post("/host/integration-connectivity", {
2975
+ agent_id: agent.agent_id,
2976
+ results: result.reports
2977
+ });
2978
+ log(
2979
+ `Connectivity probe for '${agent.code_name}': probed=${result.probed} reported=${result.reports.length} due=${result.due}`
2980
+ );
2981
+ }
2982
+ }
2715
2983
  function stopPersistentSessionAndForgetMcpBaseline(codeName, breakerReason) {
2716
2984
  cancelPendingSessionRestart(codeName);
2717
2985
  stopPersistentSession(codeName, log);
@@ -2862,7 +3130,7 @@ var cachedFrameworkVersion = null;
2862
3130
  var lastVersionCheckAt = 0;
2863
3131
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
2864
3132
  var lastResponsivenessProbeAt = 0;
2865
- var agtCliVersion = true ? "0.25.1" : "dev";
3133
+ var agtCliVersion = true ? "0.25.2" : "dev";
2866
3134
  function resolveBrewPath(execFileSync4) {
2867
3135
  try {
2868
3136
  const out = execFileSync4("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -3821,7 +4089,7 @@ async function pollCycle() {
3821
4089
  }
3822
4090
  try {
3823
4091
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
3824
- const { collectDiagnostics } = await import("../persistent-session-3FQVLVJM.js");
4092
+ const { collectDiagnostics } = await import("../persistent-session-MUJA45LT.js");
3825
4093
  const diagCodeNames = [...persistentSessionAgents];
3826
4094
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
3827
4095
  let tailscaleHostname;
@@ -3879,7 +4147,7 @@ async function pollCycle() {
3879
4147
  const {
3880
4148
  collectResponsivenessProbes,
3881
4149
  getResponsivenessIntervalMs
3882
- } = await import("../responsiveness-probe-M7PUFD5V.js");
4150
+ } = await import("../responsiveness-probe-2TBRHC5T.js");
3883
4151
  const probeIntervalMs = getResponsivenessIntervalMs();
3884
4152
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
3885
4153
  const probeCodeNames = [...persistentSessionAgents];
@@ -4789,6 +5057,14 @@ async function processAgent(agent, agentStates) {
4789
5057
  log(`OAuth token refresh failed for '${agent.code_name}/${integration.definition_id}': ${err.message}`);
4790
5058
  }
4791
5059
  }
5060
+ if (process.env.AGT_CONNECTIVITY_PROBE_ENABLED === "true") {
5061
+ try {
5062
+ const probeProjectDir = join6(homedir4(), ".augmented", agent.code_name, "project");
5063
+ await runAgentConnectivityProbes(agent, integrations, probeProjectDir);
5064
+ } catch (err) {
5065
+ log(`Connectivity probe failed for '${agent.code_name}': ${err.message}`);
5066
+ }
5067
+ }
4792
5068
  if (integrations.length > 0) {
4793
5069
  const intHash = computeIntegrationsHash(integrations);
4794
5070
  const prevIntHash = knownIntegrationHashes.get(agent.agent_id);
@@ -7875,7 +8151,7 @@ async function processClaudePairSessions(agents) {
7875
8151
  killPairSession,
7876
8152
  pairTmuxSession,
7877
8153
  finalizeClaudePairOnboarding
7878
- } = await import("../claude-pair-runtime-ZWE5572F.js");
8154
+ } = await import("../claude-pair-runtime-Q5CZLM2R.js");
7879
8155
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
7880
8156
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
7881
8157
  const killed = await killPairSession(pairTmuxSession(pairId));