@integrity-labs/agt-cli 0.28.39 → 0.28.41

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.
@@ -3,6 +3,7 @@ import {
3
3
  DEFAULT_MODELS,
4
4
  OAUTH_PROVIDERS,
5
5
  coerceEnvValue,
6
+ expandTemplateVars,
6
7
  formatForOpenClawCli,
7
8
  getChannel,
8
9
  getFlagDefinition,
@@ -11,10 +12,17 @@ import {
11
12
  listFlagDefinitions,
12
13
  normalizeFlagValue,
13
14
  parseDeliveryTarget,
15
+ parseEnvIntegrations,
16
+ probeComposioAccount,
17
+ probeComposioMcpToolCall,
18
+ probeHttpProvider,
19
+ probeMcpHttp,
14
20
  registerFramework,
15
21
  resolveAvatarEnvUrl,
22
+ resolveConnectivityProbe,
23
+ worseConnectivityOutcome,
16
24
  wrapScheduledTaskPrompt
17
- } from "./chunk-X5E2Q3W2.js";
25
+ } from "./chunk-SJUD2BWU.js";
18
26
 
19
27
  // ../../packages/core/dist/integrations/registry.js
20
28
  var INTEGRATION_REGISTRY = [
@@ -3390,54 +3398,43 @@ acknowledge before you start.
3390
3398
  - **FAST (< 60s):** handle inline. Reply via the channel tool
3391
3399
  (slack.reply / telegram.reply / directchat.reply) and end your turn.
3392
3400
 
3393
- - **SLOW (\u2265 60s):** acknowledge, dispatch to a background channel worker,
3394
- stay responsive.
3401
+ - **SLOW (\u2265 60s):** acknowledge, dispatch to background, stay responsive.
3395
3402
  1. Send a one-line acknowledgement via the channel tool \u2014 short, warm,
3396
3403
  and tell the user you'll come back. Example shape (don't copy verbatim,
3397
3404
  match your voice): "On it \u2014 this'll take a minute or two, I'll ping
3398
3405
  when it's done."
3399
- 2. Dispatch the work to a background \`channel-message-handler\` sub-agent:
3400
- the Agent tool with \`subagent_type: channel-message-handler\` AND
3401
- \`run_in_background: true\`. Put EVERYTHING the worker needs in the
3402
- dispatch prompt \u2014 the user's full request, relevant thread context,
3403
- which integrations/tools to use \u2014 plus the **channel-specific routing
3404
- keys** its reply tool needs: Slack threads \u2192 \`{ channel_id, thread_ts }\`;
3405
- Slack non-thread DMs \u2192 \`{ channel_id }\`; Telegram \u2192 \`{ chat_id, message_id }\`;
3406
- Direct Chat \u2192 \`{ conversation_id }\`. Pass these verbatim from the
3407
- inbound \`<channel>\` tag \u2014 don't substitute a generic \`message_ts\`,
3408
- since only Slack threads use it. The worker inherits your full MCP tool
3409
- surface but NOT your conversation context.
3406
+ 2. Dispatch the work to a background sub-agent: the Agent tool with
3407
+ \`subagent_type: general-purpose\` AND \`run_in_background: true\`.
3408
+ Put EVERYTHING the worker needs in the dispatch prompt \u2014 the user's
3409
+ full request, relevant thread context, which integrations/tools to
3410
+ use, and the exact shape of result you want back. The worker inherits
3411
+ your full MCP tool surface but NOT your conversation context.
3410
3412
  3. End your turn after dispatching. This is the point: you stay free to
3411
3413
  answer other messages while the worker grinds. Do NOT wait, poll, or
3412
3414
  dispatch the same work synchronously \u2014 a synchronous dispatch blocks
3413
3415
  your turn and defeats the purpose.
3414
- 4. \`channel-message-handler\` posts the substantive reply **itself**, via
3415
- its own channel reply tool (\`slack.reply\` / \`telegram.reply\` /
3416
- \`directchat.reply\`) addressed by the routing keys you passed \u2014 you do
3417
- NOT relay it. Its completion notification lands automatically as a
3418
- system message; read it just to confirm the reply went out.
3419
- 5. If the completion notification reports a failure \u2014 or that the worker
3420
- could not post \u2014 post the reply (or a brief status) yourself to the
3421
- same thread / chat / conversation you acknowledged in step 1, and
3422
- either re-dispatch with a better prompt or handle it inline. Never go
3423
- silent.
3424
-
3425
- > **Why a background \`channel-message-handler\` dispatch:** two findings
3426
- > combine into this shape. (1) ENG-6274 (2026-06-10, Claude Code 2.1.170,
3427
- > \`docs/spikes/ENG-6274-run-in-background-dispatch.md\`): a background
3428
- > dispatch returns immediately, your turn ends, and inbound messages get
3429
- > answered in seconds while the worker runs \u2014 the completion arrives as a
3430
- > notification you handle like any other turn. (2) ENG-6273 (on-host probe
3431
- > at the fleet's pinned 2.1.170,
3432
- > \`docs/spikes/ENG-6273-verify-64909-onhost-probe.md\`): the upstream
3433
- > empty-registry bug
3416
+ 4. When the worker's completion notification arrives (it lands
3417
+ automatically as a system message), read its result and reply via the
3418
+ channel tool (\`slack.reply\` / \`telegram.reply\` / \`directchat.reply\`)
3419
+ to the same thread / chat / conversation you acknowledged in step 1.
3420
+ **You post the substantive reply \u2014 the worker has no channel tools.**
3421
+ 5. If the completion notification reports a failure or an unusable
3422
+ result, tell the user what happened and either re-dispatch with a
3423
+ better prompt or handle it inline \u2014 never go silent.
3424
+
3425
+ > **Why background dispatch (and why \`general-purpose\`):** validated
3426
+ > 2026-06-10 on Claude Code 2.1.170 (ENG-6274 spike,
3427
+ > \`docs/spikes/ENG-6274-run-in-background-dispatch.md\`): background
3428
+ > dispatch returns immediately, your turn ends, inbound messages get
3429
+ > answered in seconds while the worker runs, and the completion arrives
3430
+ > as a notification you handle like any other turn. Use
3431
+ > \`subagent_type: general-purpose\` (inherit-all tools) \u2014 NOT
3432
+ > \`channel-message-handler\` or \`augmented-worker\` \u2014 until ENG-6273
3433
+ > re-verifies on this host that the upstream allowlist bug
3434
3434
  > ([anthropics/claude-code#64909](https://github.com/anthropics/claude-code/issues/64909),
3435
- > 0/6 MCP tools in named sub-agents on 2026-06-03) is **fixed** \u2014 a named
3436
- > sub-agent with an explicit \`tools:\` allowlist binds the full MCP surface
3437
- > again (10/11, zero empty-registry misses). So \`channel-message-handler\`
3438
- > can reach its own channel reply tool: dispatch it in the background and it
3439
- > both does the work AND posts the reply over the audited channel path,
3440
- > while you stay free.
3435
+ > empirically 0/6 MCP tools in named sub-agents on 2026-06-03) is fixed
3436
+ > at the fleet's pinned Claude Code version. \`general-purpose\` escapes
3437
+ > that bug by construction either way.
3441
3438
 
3442
3439
  **Why this triage decision still matters more than any other instruction
3443
3440
  below:** if you skip the acknowledgement and just dive into slow work
@@ -3457,20 +3454,31 @@ consistency.
3457
3454
 
3458
3455
  For background tool work that **isn't** a channel reply \u2014 multi-step data
3459
3456
  pulls, CRM enrichments, research workflows, cross-MCP orchestration \u2014 use
3460
- \`subagent_type: augmented-worker\`. It carries an explicit allowlist of
3461
- every \`mcp__*\` server you have wired \u2014 a tighter, safer tool surface than
3462
- inherit-all \u2014 and binds them reliably now that ENG-6273's on-host probe
3463
- confirmed the upstream allowlist bug (claude-code#64909) is fixed at the
3464
- fleet's pinned Claude Code 2.1.170. For anything expected to take more than
3465
- a minute, add \`run_in_background: true\` so your turn ends and you stay
3466
- responsive; the completion notification brings you the result. Don't
3467
- background-dispatch trivial work \u2014 each dispatch is a fresh context and
3468
- costs real tokens.
3457
+ \`subagent_type: general-purpose\` (Anthropic's built-in). It inherits the
3458
+ full MCP tool surface from this session and reliably binds every
3459
+ \`mcp__*\` server you have available. For anything expected to take more
3460
+ than a minute, add \`run_in_background: true\` so your turn ends and you
3461
+ stay responsive; the completion notification brings you the result.
3462
+ Don't background-dispatch trivial work \u2014 each dispatch is a fresh
3463
+ context and costs real tokens.
3464
+
3465
+ **Why not \`augmented-worker\` for now:** there is an upstream Claude Code
3466
+ bug ([anthropics/claude-code#64909](https://github.com/anthropics/claude-code/issues/64909))
3467
+ where sub-agents with an explicit \`tools:\` allowlist get an empty MCP
3468
+ tool registry \u2014 every \`mcp__*\` call returns "No such tool available."
3469
+ \`general-purpose\` uses \`tools: *\` (inherit-all) and escapes the bug.
3470
+ The fix appears to have shipped upstream (verified locally on Claude Code
3471
+ 2.1.170, 2026-06-10 \u2014 ENG-6269 spike); once ENG-6273 re-verifies it on
3472
+ this host's pinned version, \`augmented-worker\` becomes preferred again
3473
+ (restricted tool surface for safety + working MCP binding) and
3474
+ \`channel-message-handler\` returns as a dispatch target. Until then,
3475
+ \`general-purpose\` only.
3469
3476
 
3470
3477
  For slow **channel** replies, see \xA7 FIRST ACTION above \u2014 those are
3471
- dispatched as background \`channel-message-handler\` workers, the channel-aware
3472
- sibling of \`augmented-worker\`, which post the reply themselves over the
3473
- audited channel path.
3478
+ dispatched as background \`general-purpose\` workers and **you** post the
3479
+ result back to the channel when the completion notification arrives
3480
+ (\`channel-message-handler\` is not yet the dispatch target for the same
3481
+ ENG-6273-pending reason).
3474
3482
 
3475
3483
  ${activeTasksSection}${personalitySection}## Identity
3476
3484
 
@@ -3500,10 +3508,10 @@ ${resolvedChannels?.includes("slack") ? `
3500
3508
 
3501
3509
  You have a Slack MCP server connected. **First, see \xA7 FIRST ACTION on
3502
3510
  every channel message: triage** at the top of this document \u2014 decide
3503
- fast vs slow before anything else. Handle fast requests inline;
3504
- acknowledge slow ones, then dispatch them to a background
3505
- \`channel-message-handler\` worker (which posts the reply itself) and stay
3506
- responsive \u2014 see the FIRST ACTION section for the full rationale.
3511
+ fast vs slow before anything else, then acknowledge inline before
3512
+ diving into slow work (sub-agent dispatch for channel replies is
3513
+ currently disabled due to an upstream Claude Code bug; see the FIRST
3514
+ ACTION section for the full rationale).
3507
3515
 
3508
3516
  For fast requests, respond directly in the conversation. You can also
3509
3517
  proactively use:
@@ -5330,7 +5338,7 @@ If a capability seems missing, **check first** \u2014 run the CLI, list tools (\
5330
5338
  `;
5331
5339
  return `---
5332
5340
  name: augmented-worker
5333
- description: General-purpose background worker for multi-step tool tasks the parent doesn't want to inline (data pulls, multi-API workflows, CRM enrichments, research that needs MCP tools). Has explicit access to every \`mcp__*\` server the parent has wired. Use this \u2014 not \`general-purpose\` and not the read-only researcher/reviewer subagents from other plugins \u2014 whenever the work requires calling MCP tools (e.g. \`mcp__granola__*\`, \`mcp__composio_attio__*\`, \`mcp__slack__*\`, \`mcp__augmented__*\`). Many community subagents declare restrictive \`tools:\` allowlists that exclude MCP tools, so dispatching to them will silently produce "No such tool available." failures and force unsafe fallback paths (reading raw secrets from \`.mcp.json\`, bypassing the Credential Access Control guardrail).
5341
+ description: Background worker for multi-step tool tasks the parent doesn't want to inline (data pulls, multi-API workflows, CRM enrichments, research that needs MCP tools). Carries an explicit \`mcp__*\` wildcard allowlist for every server the parent has wired. **Until [anthropics/claude-code#64909](https://github.com/anthropics/claude-code/issues/64909) ships an upstream fix, prefer \`subagent_type: general-purpose\` for MCP-tool dispatch** \u2014 the bug is in Claude Code's sub-agent dispatch path: sub-agents with an explicit \`tools:\` allowlist get an empty MCP tool registry (every \`mcp__*\` call returns "No such tool available."), while \`general-purpose\` (\`tools: *\` inherit-all) correctly binds the full MCP surface. This subagent's allowlist is correct and will work the moment Anthropic lands the fix; until then it is retained for the eventual structural fix and the rare case where you specifically need a restricted tool surface AND can accept the MCP gap. See [[ENG-5938]] for the workaround tracker.
5334
5342
  background: true
5335
5343
  tools: ${tools}
5336
5344
  ---
@@ -5344,7 +5352,7 @@ Your \`tools:\` allowlist (above) names every MCP server the parent has connecte
5344
5352
  ## Hard rules \u2014 Credential Access Control
5345
5353
 
5346
5354
  1. **Never** read raw secrets out of \`.mcp.json\`, \`~/.augmented/*/provision/.mcp.json\`, \`.env.integrations\`, or any agent config file. Those files contain bot tokens, API keys, and OAuth credentials. The Credential Access Control guardrail (\`block_read: true\` on secrets) treats reads of those values as a violation regardless of intent. As **defence-in-depth (not structural enforcement)**, the plugin's \`settings.json\` also denies \`Bash(cat:*/.mcp.json)\`, \`Bash(cat:*/.env.integrations)\`, and \`Bash(jq:*/.mcp.json)\` (ENG-5901 / ADR-0018) \u2014 these block the obvious copy-paste paths but a determined in-process reader can still reach the values; the durable fix is Phase 2/3 of ADR-0018.
5347
- 2. **Never** post Slack messages via raw \`chat.postMessage\` + a bot token lifted from config. Use the channel MCP's reply tool (\`mcp__slack__slack_reply\`, \`mcp__telegram__telegram_reply\`, \`mcp__direct-chat__direct_chat_reply\`, etc.) so the call goes through the audited path.
5355
+ 2. **Never** post channel messages via raw API calls + bot tokens lifted from config. Use the channel MCP reply tools (\`mcp__slack__slack_reply\`, \`mcp__telegram__telegram_reply\`, \`mcp__direct_chat__direct_chat_reply\`, etc.) so calls go through the audited path.
5348
5356
  3. If an \`mcp__*\` tool you expect to be available returns "No such tool available.", **stop and surface the gap to the parent** in your summary rather than working around it. A missing MCP binding is a platform bug worth fixing \u2014 it's the exact failure shape this sub-agent was added to prevent (see ENG-5897 / ENG-5905).
5349
5357
  4. When verifying a capability is wired, confirm the relevant env var exists **without printing its value** \u2014 use \`[ -n "$POSTIZ_API_KEY" ] && echo present || echo absent\`, never \`echo $POSTIZ_API_KEY\`. The Credential Access Control guardrail covers tool-call output as well as file reads.
5350
5358
 
@@ -5816,9 +5824,9 @@ ${sections}`
5816
5824
  // so ensureGatewayRunning() returns early with running=false
5817
5825
  async getVersion() {
5818
5826
  try {
5819
- const { execFile: execFile4 } = await import("child_process");
5827
+ const { execFile: execFile5 } = await import("child_process");
5820
5828
  return new Promise((resolve3) => {
5821
- execFile4("claude", ["--version"], { timeout: 5e3 }, (err, stdout) => {
5829
+ execFile5("claude", ["--version"], { timeout: 5e3 }, (err, stdout) => {
5822
5830
  if (err) {
5823
5831
  resolve3(null);
5824
5832
  return;
@@ -7266,7 +7274,7 @@ function requireHost() {
7266
7274
  }
7267
7275
 
7268
7276
  // src/lib/api-client.ts
7269
- var agtCliVersion = true ? "0.28.39" : "dev";
7277
+ var agtCliVersion = true ? "0.28.41" : "dev";
7270
7278
  var lastConfigHash = null;
7271
7279
  function setConfigHash(hash) {
7272
7280
  lastConfigHash = hash && hash.length > 0 ? hash : null;
@@ -7662,27 +7670,177 @@ function provision(input, frameworkId = "openclaw") {
7662
7670
  };
7663
7671
  }
7664
7672
 
7673
+ // src/lib/connectivity-probe-context.ts
7674
+ import { join as join8 } from "path";
7675
+ import { existsSync as existsSync8, readFileSync as readFileSync8 } from "fs";
7676
+
7677
+ // src/lib/cli-probe.ts
7678
+ import { execFile as execFile4 } from "child_process";
7679
+ var DEFAULT_TIMEOUT_MS = 8e3;
7680
+ function runCliProbe(binary, args, opts = {}) {
7681
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
7682
+ return new Promise((resolve3) => {
7683
+ execFile4(
7684
+ binary,
7685
+ args,
7686
+ { timeout: timeoutMs, env: opts.env ?? process.env, windowsHide: true },
7687
+ (err, stdout) => {
7688
+ if (!err) {
7689
+ const firstLine = String(stdout).split(/\r?\n/, 1)[0]?.trim();
7690
+ resolve3({ status: "ok", message: firstLine ? `${binary}: ${firstLine}` : `${binary}: ok` });
7691
+ return;
7692
+ }
7693
+ const e = err;
7694
+ if (e.code === "ENOENT") {
7695
+ resolve3({ status: "down", message: `${binary} not found on PATH (not installed)` });
7696
+ return;
7697
+ }
7698
+ if (e.killed || e.signal === "SIGTERM") {
7699
+ resolve3({ status: "transient_error", message: `${binary} probe timed out after ${timeoutMs / 1e3}s` });
7700
+ return;
7701
+ }
7702
+ resolve3({ status: "down", message: `${binary} exited non-zero: ${e.message}` });
7703
+ }
7704
+ );
7705
+ });
7706
+ }
7707
+
7708
+ // src/lib/connectivity-probe-context.ts
7709
+ function readMcpHttpServerConfig(projectDir, serverKey, env) {
7710
+ try {
7711
+ const raw = readFileSync8(join8(projectDir, ".mcp.json"), "utf-8");
7712
+ const servers = JSON.parse(raw).mcpServers ?? {};
7713
+ const entry = servers[serverKey];
7714
+ if (entry && typeof entry.url === "string" && (entry.type === "http" || entry.type === void 0)) {
7715
+ const unresolved = /* @__PURE__ */ new Set();
7716
+ const sub = (value) => {
7717
+ if (!env) return value;
7718
+ const r = expandTemplateVars(value, env);
7719
+ for (const name of r.unresolved) unresolved.add(name);
7720
+ return r.value;
7721
+ };
7722
+ const url = sub(entry.url);
7723
+ let headers;
7724
+ if (entry.headers) {
7725
+ headers = {};
7726
+ for (const [k, v] of Object.entries(entry.headers)) headers[k] = sub(v);
7727
+ }
7728
+ return { url, ...headers ? { headers } : {}, unresolved: [...unresolved] };
7729
+ }
7730
+ return null;
7731
+ } catch {
7732
+ return null;
7733
+ }
7734
+ }
7735
+ function deriveMcpServerKey(input) {
7736
+ const kind = resolveConnectivityProbe({
7737
+ definitionId: input.definitionId,
7738
+ sourceType: input.sourceType,
7739
+ authType: input.authType,
7740
+ connectivityTest: input.connectivityTest ?? null
7741
+ }).kind;
7742
+ if (kind !== "mcp_tools_list" && kind !== "managed_composite") return void 0;
7743
+ return input.definitionId.replace(/[^a-z0-9]/gi, "_").toLowerCase();
7744
+ }
7745
+ function buildProbeEnv(projectDir) {
7746
+ const probeEnv = { ...process.env };
7747
+ try {
7748
+ const envIntPath = join8(projectDir, ".env.integrations");
7749
+ if (existsSync8(envIntPath)) {
7750
+ Object.assign(probeEnv, parseEnvIntegrations(readFileSync8(envIntPath, "utf-8")));
7751
+ }
7752
+ } catch {
7753
+ }
7754
+ return probeEnv;
7755
+ }
7756
+ function buildConnectivityProbeDeps(projectDir, probeEnv) {
7757
+ return {
7758
+ fetchImpl: fetch,
7759
+ runCli: (binary, args) => runCliProbe(binary, args, { env: probeEnv }),
7760
+ mcpProbe: async (target) => {
7761
+ const cfg = readMcpHttpServerConfig(projectDir, target.serverKey, probeEnv);
7762
+ if (!cfg) {
7763
+ return { status: "transient_error", message: `MCP server '${target.serverKey}' not resolvable from .mcp.json` };
7764
+ }
7765
+ if (cfg.unresolved.length > 0) {
7766
+ return {
7767
+ status: "transient_error",
7768
+ message: `MCP '${target.serverKey}' auth unresolved: ${cfg.unresolved.join(", ")}`
7769
+ };
7770
+ }
7771
+ return probeMcpHttp(cfg);
7772
+ },
7773
+ // ENG-6139: connected-account binding check for managed (Composio) toolkits.
7774
+ // The MCP handshake reads green on a dead/mis-bound account, so the managed
7775
+ // probe also verifies the account is ACTIVE + bound to the entity the agent
7776
+ // queries with. Inputs come from the agent's OWN wired MCP server: the
7777
+ // `x-api-key` header and the `user_id` query param (the agent already
7778
+ // authenticates with these), plus the recorded connected_account_id.
7779
+ composioProbe: async (definitionId, credentials) => {
7780
+ const serverKey = definitionId.replace(/[^a-z0-9]/gi, "_").toLowerCase();
7781
+ const cfg = readMcpHttpServerConfig(projectDir, serverKey, probeEnv);
7782
+ if (!cfg) {
7783
+ return { status: "transient_error", message: `MCP server '${serverKey}' not resolvable from .mcp.json` };
7784
+ }
7785
+ if (cfg.unresolved.length > 0) {
7786
+ return {
7787
+ status: "transient_error",
7788
+ message: `MCP '${serverKey}' auth unresolved: ${cfg.unresolved.join(", ")}`
7789
+ };
7790
+ }
7791
+ const apiKey = Object.entries(cfg.headers ?? {}).find(([k]) => k.toLowerCase() === "x-api-key")?.[1] ?? "";
7792
+ let expectedUserId = "";
7793
+ let serverId;
7794
+ try {
7795
+ const u = new URL(cfg.url);
7796
+ expectedUserId = u.searchParams.get("user_id") ?? "";
7797
+ const m = u.pathname.match(/\/v3\/mcp\/([^/]+)\/mcp/);
7798
+ serverId = m?.[1] ? decodeURIComponent(m[1]) : void 0;
7799
+ } catch {
7800
+ expectedUserId = "";
7801
+ }
7802
+ const connectedAccountId = typeof credentials?.["connected_account_id"] === "string" ? credentials["connected_account_id"] : "";
7803
+ return probeComposioAccount({ connectedAccountId, apiKey, expectedUserId, serverId });
7804
+ },
7805
+ // ENG-6157 (Phase 2): the live tool-call leg. Uses the agent's OWN wired MCP
7806
+ // URL + headers (the exact path tool calls take), so a broken auth_config
7807
+ // linkage surfaces as a real `No connected account found` instead of a
7808
+ // green handshake. Skips (`null`) when no safe read-only tool is callable.
7809
+ composioToolCallProbe: async (target) => {
7810
+ const cfg = readMcpHttpServerConfig(projectDir, target.serverKey, probeEnv);
7811
+ if (!cfg) return null;
7812
+ if (cfg.unresolved.length > 0) return null;
7813
+ return probeComposioMcpToolCall({
7814
+ url: cfg.url,
7815
+ headers: cfg.headers,
7816
+ toolName: target.toolName,
7817
+ toolArgs: target.toolArgs
7818
+ });
7819
+ }
7820
+ };
7821
+ }
7822
+
7665
7823
  // src/commands/manager.ts
7666
7824
  import chalk3 from "chalk";
7667
- import { existsSync as existsSync9, realpathSync } from "fs";
7668
- import { join as join9 } from "path";
7825
+ import { existsSync as existsSync10, realpathSync } from "fs";
7826
+ import { join as join10 } from "path";
7669
7827
  import { homedir as homedir6, userInfo } from "os";
7670
7828
  import { spawn as spawn3 } from "child_process";
7671
7829
 
7672
7830
  // src/lib/watchdog.ts
7673
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync7, unlinkSync as unlinkSync4, existsSync as existsSync8, mkdirSync as mkdirSync7, openSync as openSync2, closeSync as closeSync2, chmodSync as chmodSync6 } from "fs";
7674
- import { join as join8 } from "path";
7831
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync7, unlinkSync as unlinkSync4, existsSync as existsSync9, mkdirSync as mkdirSync7, openSync as openSync2, closeSync as closeSync2, chmodSync as chmodSync6 } from "fs";
7832
+ import { join as join9 } from "path";
7675
7833
  import { spawn as spawn2, execFileSync } from "child_process";
7676
- var DEFAULT_CONFIG_DIR = join8(process.env["HOME"] ?? "/tmp", ".augmented");
7834
+ var DEFAULT_CONFIG_DIR = join9(process.env["HOME"] ?? "/tmp", ".augmented");
7677
7835
  function getManagerPaths(configDir) {
7678
7836
  return {
7679
- pidFile: join8(configDir, "manager.pid"),
7680
- stateFile: join8(configDir, "manager-state.json"),
7681
- logFile: join8(configDir, "manager.log")
7837
+ pidFile: join9(configDir, "manager.pid"),
7838
+ stateFile: join9(configDir, "manager-state.json"),
7839
+ logFile: join9(configDir, "manager.log")
7682
7840
  };
7683
7841
  }
7684
7842
  function ensureDir2(configDir) {
7685
- if (!existsSync8(configDir)) {
7843
+ if (!existsSync9(configDir)) {
7686
7844
  mkdirSync7(configDir, { recursive: true });
7687
7845
  }
7688
7846
  }
@@ -7692,7 +7850,7 @@ function writePidFile(configDir, pid) {
7692
7850
  }
7693
7851
  function readPidFile(configDir) {
7694
7852
  try {
7695
- const raw = readFileSync8(getManagerPaths(configDir).pidFile, "utf-8").trim();
7853
+ const raw = readFileSync9(getManagerPaths(configDir).pidFile, "utf-8").trim();
7696
7854
  const pid = parseInt(raw, 10);
7697
7855
  return isNaN(pid) ? null : pid;
7698
7856
  } catch {
@@ -7730,7 +7888,7 @@ function defaultPgrep() {
7730
7888
  }
7731
7889
  function readStateFile(configDir) {
7732
7890
  try {
7733
- const raw = readFileSync8(getManagerPaths(configDir).stateFile, "utf-8");
7891
+ const raw = readFileSync9(getManagerPaths(configDir).stateFile, "utf-8");
7734
7892
  return JSON.parse(raw);
7735
7893
  } catch {
7736
7894
  return null;
@@ -7786,7 +7944,7 @@ function startWatchdog(opts) {
7786
7944
  const deadline = Date.now() + 5e3;
7787
7945
  const sleepBuf = new Int32Array(new SharedArrayBuffer(4));
7788
7946
  while (Date.now() < deadline) {
7789
- if (existsSync8(pidFile)) {
7947
+ if (existsSync9(pidFile)) {
7790
7948
  return { pid: child.pid };
7791
7949
  }
7792
7950
  if (child.exitCode !== null) {
@@ -7914,7 +8072,7 @@ function managerStartCommand(opts) {
7914
8072
  process.exitCode = 1;
7915
8073
  return;
7916
8074
  }
7917
- const configDir = opts.configDir ?? join9(homedir6(), ".augmented");
8075
+ const configDir = opts.configDir ?? join10(homedir6(), ".augmented");
7918
8076
  if (opts.supervise) {
7919
8077
  if (json) {
7920
8078
  jsonOutput({ ok: false, error: "--supervise is not supported with --json" });
@@ -8010,7 +8168,7 @@ function runSupervisorLoop(intervalSec, configDir) {
8010
8168
  }
8011
8169
  async function managerStopCommand(opts = {}) {
8012
8170
  const json = isJsonMode();
8013
- const configDir = opts.configDir ?? join9(homedir6(), ".augmented");
8171
+ const configDir = opts.configDir ?? join10(homedir6(), ".augmented");
8014
8172
  try {
8015
8173
  const result = await stopWatchdog(configDir);
8016
8174
  if (!result.stopped && !result.pid) {
@@ -8038,7 +8196,7 @@ async function managerStopCommand(opts = {}) {
8038
8196
  }
8039
8197
  function managerStatusCommand(opts = {}) {
8040
8198
  const json = isJsonMode();
8041
- const configDir = opts.configDir ?? join9(homedir6(), ".augmented");
8199
+ const configDir = opts.configDir ?? join10(homedir6(), ".augmented");
8042
8200
  const status = getManagerStatus(configDir);
8043
8201
  if (!status) {
8044
8202
  if (json) {
@@ -8110,7 +8268,7 @@ function resolveStableAgtBin(rawPath) {
8110
8268
  if (!prefix || !formula) return rawPath;
8111
8269
  const candidates = [`${prefix}/bin/${formula}`, `${prefix}/bin/agt`];
8112
8270
  for (const candidate of candidates) {
8113
- if (!existsSync9(candidate)) continue;
8271
+ if (!existsSync10(candidate)) continue;
8114
8272
  try {
8115
8273
  realpathSync(candidate);
8116
8274
  return candidate;
@@ -8130,7 +8288,7 @@ async function managerInstallCommand(opts = {}) {
8130
8288
  process.exitCode = 1;
8131
8289
  return;
8132
8290
  }
8133
- const configDir = opts.configDir ?? join9(homedir6(), ".augmented");
8291
+ const configDir = opts.configDir ?? join10(homedir6(), ".augmented");
8134
8292
  const rawAgtBin = process.argv[1];
8135
8293
  if (!rawAgtBin) {
8136
8294
  const msg = "Could not resolve the agt binary path from argv. Re-run via the installed `agt` command.";
@@ -8143,7 +8301,7 @@ async function managerInstallCommand(opts = {}) {
8143
8301
  if (process.platform === "darwin") {
8144
8302
  const home = homedir6();
8145
8303
  const protectedRoots = ["Documents", "Downloads", "Desktop", "Movies", "Music", "Pictures"];
8146
- const offending = protectedRoots.map((r) => join9(home, r)).find((p) => agtBin === p || agtBin.startsWith(`${p}/`));
8304
+ const offending = protectedRoots.map((r) => join10(home, r)).find((p) => agtBin === p || agtBin.startsWith(`${p}/`));
8147
8305
  if (offending) {
8148
8306
  const msg = `agt binary at ${agtBin} sits inside a macOS TCC-protected folder (${offending}). launchd-spawned processes cannot read files there and the manager would EPERM on startup. Either install agt globally (\`npm install -g @integrity-labs/agt-cli\`) or copy the dist outside protected folders before running this command.`;
8149
8307
  if (json) jsonOutput({ ok: false, error: msg });
@@ -8211,7 +8369,7 @@ async function managerInstallSystemUnitCommand(opts = {}) {
8211
8369
  return;
8212
8370
  }
8213
8371
  const user = opts.user ?? "root";
8214
- const configDir = opts.configDir ?? (user === "root" ? "/root/.augmented" : join9("/home", user, ".augmented"));
8372
+ const configDir = opts.configDir ?? (user === "root" ? "/root/.augmented" : join10("/home", user, ".augmented"));
8215
8373
  const rawAgtBin = process.argv[1];
8216
8374
  if (!rawAgtBin) {
8217
8375
  const msg = "Could not resolve the agt binary path from argv. Re-run via the installed `agt` command.";
@@ -8274,6 +8432,73 @@ async function managerUninstallSystemUnitCommand() {
8274
8432
  }
8275
8433
  }
8276
8434
 
8435
+ // src/lib/connectivity-probe-executor.ts
8436
+ async function executeConnectivityProbe(target, deps = {}) {
8437
+ const descriptor = resolveConnectivityProbe({
8438
+ definitionId: target.definitionId,
8439
+ sourceType: target.sourceType,
8440
+ authType: target.authType,
8441
+ // ENG-6242: carry the toolkit's connectivity_test override so a managed
8442
+ // descriptor surfaces `probeTool`/`probeArgs` (the prescribed read-only tool)
8443
+ // — without this the hourly probe auto-picked a different tool than the Test
8444
+ // path, the false-RED that flagged every managed Linear install "unreachable".
8445
+ connectivityTest: target.connectivityTest ?? null
8446
+ });
8447
+ if (!descriptor.readOnly) {
8448
+ throw new Error(`Refusing non-read-only probe for ${target.definitionId}`);
8449
+ }
8450
+ switch (descriptor.kind) {
8451
+ case "http_provider":
8452
+ return probeHttpProvider(target.definitionId, target.credentials, deps.fetchImpl ?? fetch);
8453
+ case "composio_account":
8454
+ if (!deps.composioProbe) return null;
8455
+ return deps.composioProbe(target.definitionId, target.credentials);
8456
+ case "managed_composite": {
8457
+ const outcomes = [];
8458
+ if (deps.mcpProbe) {
8459
+ outcomes.push(
8460
+ await deps.mcpProbe({
8461
+ serverKey: target.mcpServerKey ?? target.definitionId,
8462
+ definitionId: target.definitionId
8463
+ })
8464
+ );
8465
+ }
8466
+ if (deps.composioProbe) {
8467
+ outcomes.push(await deps.composioProbe(target.definitionId, target.credentials));
8468
+ }
8469
+ if (deps.composioToolCallProbe) {
8470
+ const toolCall = await deps.composioToolCallProbe({
8471
+ serverKey: target.mcpServerKey ?? target.definitionId,
8472
+ definitionId: target.definitionId,
8473
+ // ENG-6242: thread the prescribed tool through to the live tool-call
8474
+ // leg. resolveConnectivityProbe only sets these for managed toolkits
8475
+ // with a stored override; the probe re-validates read-only and falls
8476
+ // back to auto-pick on drift, so a missing/invalid override is safe.
8477
+ toolName: descriptor.probeTool ?? null,
8478
+ toolArgs: descriptor.probeArgs ?? null
8479
+ });
8480
+ if (toolCall) outcomes.push(toolCall);
8481
+ }
8482
+ if (outcomes.length === 0) return null;
8483
+ return outcomes.reduce((acc, o) => worseConnectivityOutcome(acc, o));
8484
+ }
8485
+ case "mcp_tools_list":
8486
+ if (!deps.mcpProbe) return null;
8487
+ return deps.mcpProbe({
8488
+ serverKey: target.mcpServerKey ?? target.definitionId,
8489
+ definitionId: target.definitionId
8490
+ });
8491
+ case "cli_command":
8492
+ if (!deps.runCli) return null;
8493
+ return deps.runCli(target.cliBinary ?? target.definitionId, descriptor.cliArgs ?? ["--version"]);
8494
+ case "builtin":
8495
+ return { status: "ok", message: `${target.definitionId}: built-in` };
8496
+ case "unsupported":
8497
+ default:
8498
+ return null;
8499
+ }
8500
+ }
8501
+
8277
8502
  export {
8278
8503
  getIntegration,
8279
8504
  extractCommandNotFound,
@@ -8315,6 +8540,10 @@ export {
8315
8540
  resolveAllFlags,
8316
8541
  HostFlagStore,
8317
8542
  provision,
8543
+ executeConnectivityProbe,
8544
+ deriveMcpServerKey,
8545
+ buildProbeEnv,
8546
+ buildConnectivityProbeDeps,
8318
8547
  getManagerPaths,
8319
8548
  startWatchdog,
8320
8549
  managerStartCommand,
@@ -8326,4 +8555,4 @@ export {
8326
8555
  managerInstallSystemUnitCommand,
8327
8556
  managerUninstallSystemUnitCommand
8328
8557
  };
8329
- //# sourceMappingURL=chunk-AL7UJNNI.js.map
8558
+ //# sourceMappingURL=chunk-GBST6UWT.js.map