@integrity-labs/agt-cli 0.28.237 → 0.28.239
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/agt.js +4 -4
- package/dist/{chunk-PYVEJMY2.js → chunk-GO4VMK2P.js} +37 -4
- package/dist/chunk-GO4VMK2P.js.map +1 -0
- package/dist/{chunk-DN4HSL6M.js → chunk-O3MVFYYC.js} +298 -9
- package/dist/chunk-O3MVFYYC.js.map +1 -0
- package/dist/{claude-pair-runtime-2ZFH6K4I.js → claude-pair-runtime-422CI7SM.js} +2 -2
- package/dist/lib/manager-worker.js +22 -11
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/mcp/direct-chat-channel.js +63 -21
- package/dist/mcp/origami.js +40510 -0
- package/dist/mcp/slack-channel.js +551 -100
- package/dist/mcp/telegram-channel.js +111 -69
- package/dist/{persistent-session-LVDRHYX7.js → persistent-session-RRCU7CQJ.js} +2 -2
- package/dist/{responsiveness-probe-UW5TXKMS.js → responsiveness-probe-K5HFFW5F.js} +118 -3
- package/dist/responsiveness-probe-K5HFFW5F.js.map +1 -0
- package/package.json +3 -2
- package/dist/chunk-DN4HSL6M.js.map +0 -1
- package/dist/chunk-PYVEJMY2.js.map +0 -1
- package/dist/responsiveness-probe-UW5TXKMS.js.map +0 -1
- /package/dist/{claude-pair-runtime-2ZFH6K4I.js.map → claude-pair-runtime-422CI7SM.js.map} +0 -0
- /package/dist/{persistent-session-LVDRHYX7.js.map → persistent-session-RRCU7CQJ.js.map} +0 -0
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
resolveConnectivityProbe,
|
|
19
19
|
worseConnectivityOutcome,
|
|
20
20
|
wrapScheduledTaskPrompt
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-GO4VMK2P.js";
|
|
22
22
|
import {
|
|
23
23
|
parsePsRows
|
|
24
24
|
} from "./chunk-XWVM4KPK.js";
|
|
@@ -2804,6 +2804,15 @@ function provisionStopHook(codeName) {
|
|
|
2804
2804
|
"# recovery-outbox. OFF (default / unset) \u21D2 exactly today's behavior.",
|
|
2805
2805
|
"BLOCK_TURN_END_ON=0",
|
|
2806
2806
|
'case "${AGT_CHANNEL_BLOCK_TURN_END_ENABLED:-}" in true|1|TRUE|True) BLOCK_TURN_END_ON=1;; esac',
|
|
2807
|
+
"# WS3 (ENG-7397): block-turn-end-all-markers. When ON (and channel-block-turn-end",
|
|
2808
|
+
"# is also ON), the block scan covers EVERY pending marker across all sources, not",
|
|
2809
|
+
"# just the last-tagged conversation, so an agent that owes replies to several",
|
|
2810
|
+
"# threads at once is blocked until it answers all of them (with WS2 it answers",
|
|
2811
|
+
"# each by inbound_id). Registry flag block-turn-end-all-markers; the env var is",
|
|
2812
|
+
"# the operator/canary override the bash reads directly. OFF (default) leaves the",
|
|
2813
|
+
"# single-marker last-tag behavior exactly as-is.",
|
|
2814
|
+
"BLOCK_ALL_MARKERS_ON=0",
|
|
2815
|
+
'case "${AGT_BLOCK_TURN_END_ALL_MARKERS_ENABLED:-}" in true|1|TRUE|True) BLOCK_ALL_MARKERS_ON=1;; esac',
|
|
2807
2816
|
`STOP_ACTIVE=$(echo "$INPUT" | jq -r '.stop_hook_active // false' 2>/dev/null || echo false)`,
|
|
2808
2817
|
'BLOCK_LEDGER_DIR="${AGENT_DIR}/.agt-block-turn-end-ledger"',
|
|
2809
2818
|
"# GC stale ledger entries (>1 day) so the per-marker cap dir cannot grow unbounded.",
|
|
@@ -2852,11 +2861,76 @@ function provisionStopHook(codeName) {
|
|
|
2852
2861
|
` jq -cn --arg r "$reason" '{decision:"block", reason:$r}'`,
|
|
2853
2862
|
" return 0",
|
|
2854
2863
|
"}",
|
|
2864
|
+
"# WS3 (ENG-7397): the multi-marker generalization of emit_block_if_obligated.",
|
|
2865
|
+
"# Enumerates EVERY pending marker across all three source dirs, drops the",
|
|
2866
|
+
"# discretionary/undeliverable ones (same fail-safe defaults) and the ones already",
|
|
2867
|
+
"# answered THIS turn (per-marker replied_this_conv_* on the marker's own coords),",
|
|
2868
|
+
"# and - when 1+ obligated-and-unanswered markers survive and NONE was already",
|
|
2869
|
+
"# blocked once - writes a ledger entry for each and emits ONE block enumerating",
|
|
2870
|
+
"# every owed conversation by inbound_id + source + safe key (never content).",
|
|
2871
|
+
"# Marker-semantics-neutral: arms/clears no markers, only decides WHEN to block.",
|
|
2872
|
+
"# Returns 0 (after printing the block JSON) when it blocked; 1 otherwise.",
|
|
2873
|
+
"emit_block_all_obligated() {",
|
|
2874
|
+
' if [ "$BLOCK_TURN_END_ON" != "1" ] || [ "$BLOCK_ALL_MARKERS_ON" != "1" ]; then return 1; fi',
|
|
2875
|
+
' if [ "$STOP_ACTIVE" = "true" ]; then return 1; fi',
|
|
2876
|
+
" local -a owed_paths=()",
|
|
2877
|
+
' local owed_lines="" owed_count=0 any_capped=0 entry src dir m d u replied ch th cid conv iid key led_name',
|
|
2878
|
+
' for entry in "slack:$SL_MARKER_DIR" "telegram:$TG_MARKER_DIR" "msteams:$MS_MARKER_DIR"; do',
|
|
2879
|
+
' src="${entry%%:*}"; dir="${entry#*:}"',
|
|
2880
|
+
' if [ ! -d "$dir" ]; then continue; fi',
|
|
2881
|
+
" shopt -s nullglob",
|
|
2882
|
+
' for m in "$dir"/*.json; do',
|
|
2883
|
+
' if [ ! -f "$m" ]; then continue; fi',
|
|
2884
|
+
` d=$(jq -r '.discretionary // false' "$m" 2>/dev/null || echo true)`,
|
|
2885
|
+
` u=$(jq -r '.undeliverable // false' "$m" 2>/dev/null || echo true)`,
|
|
2886
|
+
' if [ "$d" = "true" ] || [ "$u" = "true" ]; then continue; fi',
|
|
2887
|
+
' replied=no; ch=""; th=""; cid=""; conv=""',
|
|
2888
|
+
' case "$src" in',
|
|
2889
|
+
` slack) ch=$(jq -r '.channel // ""' "$m" 2>/dev/null || echo ""); th=$(jq -r '.thread_ts // ""' "$m" 2>/dev/null || echo ""); if replied_this_conv_slack "$ch" "$th"; then replied=yes; fi ;;`,
|
|
2890
|
+
` telegram) cid=$(jq -r '.chat_id // ""' "$m" 2>/dev/null || echo ""); if replied_this_conv_telegram "$cid"; then replied=yes; fi ;;`,
|
|
2891
|
+
` msteams) conv=$(jq -r '.conversation_id // ""' "$m" 2>/dev/null || echo ""); if replied_this_conv_teams "$conv"; then replied=yes; fi ;;`,
|
|
2892
|
+
" esac",
|
|
2893
|
+
' if [ "$replied" = "yes" ]; then continue; fi',
|
|
2894
|
+
' led_name="$(basename "$m")"',
|
|
2895
|
+
' if [ -f "${BLOCK_LEDGER_DIR}/${led_name}" ]; then any_capped=1; fi',
|
|
2896
|
+
` iid=$(jq -r '.inbound_id // ""' "$m" 2>/dev/null || echo "")`,
|
|
2897
|
+
' case "$src" in',
|
|
2898
|
+
' slack) key="thread=$(safe_id "$th")" ;;',
|
|
2899
|
+
' telegram) key="chat=$(safe_id "$cid")" ;;',
|
|
2900
|
+
' msteams) key="conv=$(safe_id "$conv")" ;;',
|
|
2901
|
+
' *) key="" ;;',
|
|
2902
|
+
" esac",
|
|
2903
|
+
" owed_count=$((owed_count + 1))",
|
|
2904
|
+
' if [ -n "$iid" ]; then owed_lines="${owed_lines}${owed_count}) source=${src} inbound_id=${iid} ${key}; "; else owed_lines="${owed_lines}${owed_count}) source=${src} ${key}; "; fi',
|
|
2905
|
+
' owed_paths+=("$m")',
|
|
2906
|
+
" done",
|
|
2907
|
+
" done",
|
|
2908
|
+
' if [ "$owed_count" = "0" ]; then return 1; fi',
|
|
2909
|
+
" # Block only when NONE of the owed markers was already blocked once - a capped",
|
|
2910
|
+
" # marker means the model already ignored a block for it, so fall through to the",
|
|
2911
|
+
" # per-source recovery instead of re-blocking.",
|
|
2912
|
+
' if [ "$any_capped" = "1" ]; then echo "agt-ghost-reply-hook: block-turn-end-all degraded (an owed marker already blocked) - falling through to recovery" >&2; return 1; fi',
|
|
2913
|
+
' if ! mkdir -p "$BLOCK_LEDGER_DIR" 2>/dev/null; then echo "agt-ghost-reply-hook: block-turn-end-all degraded (ledger dir create failed) - falling through" >&2; return 1; fi',
|
|
2914
|
+
" local p",
|
|
2915
|
+
' for p in "${owed_paths[@]}"; do',
|
|
2916
|
+
' if ! : > "${BLOCK_LEDGER_DIR}/$(basename "$p")" 2>/dev/null; then echo "agt-ghost-reply-hook: block-turn-end-all degraded (ledger write failed) - falling through" >&2; return 1; fi',
|
|
2917
|
+
" done",
|
|
2918
|
+
' echo "agt-ghost-reply-hook: block-turn-end-all FIRED count=${owed_count}" >&2',
|
|
2919
|
+
' local reason="You have ${owed_count} conversation(s) you did not answer this turn; the people are waiting and will see only silence. Reply to EACH now with its reply tool, passing its inbound_id so your answer lands in the right thread (never answer one conversation in a different thread). Owed: ${owed_lines}Actually send each answer via the tool; do not just summarize what you intended to say."',
|
|
2920
|
+
` jq -cn --arg r "$reason" '{decision:"block", reason:$r}'`,
|
|
2921
|
+
" return 0",
|
|
2922
|
+
"}",
|
|
2855
2923
|
"# Strict correlation: only recover if the last channel tag in the",
|
|
2856
2924
|
"# transcript points at a channel/key that has an exact-match pending",
|
|
2857
2925
|
"# marker. No tag found \u2192 skip; let timeout handle it. Block-turn-end (when",
|
|
2858
2926
|
"# armed) runs FIRST per source; if it blocks we exit before recovery so the",
|
|
2859
2927
|
"# two mechanisms never both fire on one Stop.",
|
|
2928
|
+
"# WS3: when block-turn-end-all-markers is armed, try the multi-marker block",
|
|
2929
|
+
"# FIRST - it covers every owed conversation, not just the last tag. It self-gates",
|
|
2930
|
+
"# on both flags (returns 1 when off), so this call is a no-op unless armed. If it",
|
|
2931
|
+
"# blocks we exit; otherwise fall through to the per-source single-marker path,",
|
|
2932
|
+
"# which still handles the last-tagged conversation.",
|
|
2933
|
+
"if emit_block_all_obligated; then exit 0; fi",
|
|
2860
2934
|
'if [ "$TAG_SOURCE" = "telegram" ]; then',
|
|
2861
2935
|
' CHAT_ID=$(extract_attr "$CHANNEL_TAG" "chat_id")',
|
|
2862
2936
|
' MSG_ID=$(extract_attr "$CHANNEL_TAG" "message_id")',
|
|
@@ -4129,6 +4203,21 @@ function buildMcpJson(input) {
|
|
|
4129
4203
|
}
|
|
4130
4204
|
};
|
|
4131
4205
|
}
|
|
4206
|
+
const origamiIntegration = input.integrations?.find((i) => i.definition_id === "origami");
|
|
4207
|
+
if (origamiIntegration?.stdioMcp === true && origamiIntegration.id) {
|
|
4208
|
+
const localOrigamiMcpPath = join2(getHomeDir(), ".augmented", "_mcp", "origami.js");
|
|
4209
|
+
mcpServers["origami"] = {
|
|
4210
|
+
command: "node",
|
|
4211
|
+
args: [localOrigamiMcpPath],
|
|
4212
|
+
env: {
|
|
4213
|
+
AGT_HOST: "${AGT_HOST}",
|
|
4214
|
+
AGT_TOKEN: "${AGT_TOKEN}",
|
|
4215
|
+
AGT_API_KEY: "${AGT_API_KEY}",
|
|
4216
|
+
AGT_AGENT_ID: input.agent.agent_id,
|
|
4217
|
+
AGT_INTEGRATION_ID: origamiIntegration.id
|
|
4218
|
+
}
|
|
4219
|
+
};
|
|
4220
|
+
}
|
|
4132
4221
|
return { mcpServers };
|
|
4133
4222
|
}
|
|
4134
4223
|
function parseIntervalMinutes(scheduleEvery) {
|
|
@@ -5268,6 +5357,23 @@ ${sections}`
|
|
|
5268
5357
|
}
|
|
5269
5358
|
});
|
|
5270
5359
|
}
|
|
5360
|
+
const origamiStdio = integrations.find((i) => i.definition_id === "origami");
|
|
5361
|
+
const origamiStdioAgentId = resolveBrokerAgentId(codeName) ?? agentId;
|
|
5362
|
+
const origamiStdioExpected = Boolean(origamiStdio?.stdioMcp === true && origamiStdio.id);
|
|
5363
|
+
if (origamiStdioExpected && origamiStdioAgentId) {
|
|
5364
|
+
const localOrigamiMcpPath = join2(getHomeDir(), ".augmented", "_mcp", "origami.js");
|
|
5365
|
+
this.writeMcpServer(codeName, "origami", {
|
|
5366
|
+
command: "node",
|
|
5367
|
+
args: [localOrigamiMcpPath],
|
|
5368
|
+
env: {
|
|
5369
|
+
AGT_HOST: "${AGT_HOST}",
|
|
5370
|
+
AGT_TOKEN: "${AGT_TOKEN}",
|
|
5371
|
+
AGT_API_KEY: "${AGT_API_KEY}",
|
|
5372
|
+
AGT_AGENT_ID: origamiStdioAgentId,
|
|
5373
|
+
AGT_INTEGRATION_ID: origamiStdio.id
|
|
5374
|
+
}
|
|
5375
|
+
});
|
|
5376
|
+
}
|
|
5271
5377
|
if (this.removeMcpServer) {
|
|
5272
5378
|
const nativeMcpKeys = INTEGRATION_REGISTRY.filter((d) => d.nativeMcp !== void 0).map((d) => d.nativeMcp.key ?? d.id);
|
|
5273
5379
|
const integrationDerivedKeys = /* @__PURE__ */ new Set([
|
|
@@ -5277,6 +5383,10 @@ ${sections}`
|
|
|
5277
5383
|
"xero-broker",
|
|
5278
5384
|
"augmented-admin",
|
|
5279
5385
|
"augmented-support",
|
|
5386
|
+
// ENG-7358: the dedicated origami stdio server. In the universe so
|
|
5387
|
+
// that removing the integration OR flipping the catalog stdio_mcp
|
|
5388
|
+
// flag back (rollback) prunes the entry symmetrically.
|
|
5389
|
+
"origami",
|
|
5280
5390
|
...nativeMcpKeys,
|
|
5281
5391
|
...Object.entries(OAUTH_PROVIDERS).filter(([, provider]) => Boolean(provider.mcpUrl)).map(([id]) => id)
|
|
5282
5392
|
]);
|
|
@@ -5293,6 +5403,8 @@ ${sections}`
|
|
|
5293
5403
|
expectedKeys.add("augmented-admin");
|
|
5294
5404
|
if (hasSupport)
|
|
5295
5405
|
expectedKeys.add("augmented-support");
|
|
5406
|
+
if (origamiStdioExpected)
|
|
5407
|
+
expectedKeys.add("origami");
|
|
5296
5408
|
for (const integration of integrations) {
|
|
5297
5409
|
const def = INTEGRATION_REGISTRY.find((d) => d.id === integration.definition_id);
|
|
5298
5410
|
if (def?.nativeMcp) {
|
|
@@ -5720,7 +5832,7 @@ function requireHost() {
|
|
|
5720
5832
|
}
|
|
5721
5833
|
|
|
5722
5834
|
// src/lib/api-client.ts
|
|
5723
|
-
var agtCliVersion = true ? "0.28.
|
|
5835
|
+
var agtCliVersion = true ? "0.28.239" : "dev";
|
|
5724
5836
|
var lastConfigHash = null;
|
|
5725
5837
|
function setConfigHash(hash) {
|
|
5726
5838
|
lastConfigHash = hash && hash.length > 0 ? hash : null;
|
|
@@ -6674,11 +6786,130 @@ function reapMissingMcpSessions(args) {
|
|
|
6674
6786
|
import { join as join5 } from "path";
|
|
6675
6787
|
import { existsSync as existsSync6, readFileSync as readFileSync6 } from "fs";
|
|
6676
6788
|
|
|
6789
|
+
// src/lib/mcp-stdio-probe.ts
|
|
6790
|
+
import { spawn } from "child_process";
|
|
6791
|
+
var DEFAULT_TIMEOUT_MS = 15e3;
|
|
6792
|
+
async function probeMcpStdio(config) {
|
|
6793
|
+
const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
6794
|
+
const child = spawn(config.command, config.args ?? [], {
|
|
6795
|
+
// Faithful reproduction of the real spawn: the child inherits the manager's
|
|
6796
|
+
// process env (PATH/HOME so `node`/`npx` resolve) with the entry's env
|
|
6797
|
+
// overlaid, exactly as Claude Code spawns it.
|
|
6798
|
+
env: { ...process.env, ...config.env ?? {} },
|
|
6799
|
+
cwd: config.cwd,
|
|
6800
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
6801
|
+
});
|
|
6802
|
+
let stdout = "";
|
|
6803
|
+
let stderrTail = "";
|
|
6804
|
+
const pending = /* @__PURE__ */ new Map();
|
|
6805
|
+
return await new Promise((resolve) => {
|
|
6806
|
+
let done = false;
|
|
6807
|
+
const finish = (outcome) => {
|
|
6808
|
+
if (done) return;
|
|
6809
|
+
done = true;
|
|
6810
|
+
clearTimeout(timer);
|
|
6811
|
+
child.stdout.removeAllListeners();
|
|
6812
|
+
try {
|
|
6813
|
+
child.kill("SIGKILL");
|
|
6814
|
+
} catch {
|
|
6815
|
+
}
|
|
6816
|
+
resolve(outcome);
|
|
6817
|
+
};
|
|
6818
|
+
const timer = setTimeout(() => {
|
|
6819
|
+
finish({ status: "transient_error", message: `MCP stdio handshake timed out after ${timeoutMs / 1e3}s` });
|
|
6820
|
+
}, timeoutMs);
|
|
6821
|
+
if (typeof timer.unref === "function") timer.unref();
|
|
6822
|
+
child.on("error", (err) => {
|
|
6823
|
+
finish({ status: "down", message: `MCP server failed to spawn: ${err.message}` });
|
|
6824
|
+
});
|
|
6825
|
+
child.on("exit", (code) => {
|
|
6826
|
+
if (!done) {
|
|
6827
|
+
finish({
|
|
6828
|
+
status: "down",
|
|
6829
|
+
message: `MCP server exited (code ${code ?? "null"})${stderrTail ? `: ${stderrTail.trim().slice(-200)}` : ""}`
|
|
6830
|
+
});
|
|
6831
|
+
}
|
|
6832
|
+
});
|
|
6833
|
+
child.stdin.on("error", () => {
|
|
6834
|
+
});
|
|
6835
|
+
child.stderr.on("data", (d) => {
|
|
6836
|
+
stderrTail = (stderrTail + d.toString()).slice(-500);
|
|
6837
|
+
});
|
|
6838
|
+
child.stdout.on("data", (d) => {
|
|
6839
|
+
stdout += d.toString();
|
|
6840
|
+
let nl;
|
|
6841
|
+
while ((nl = stdout.indexOf("\n")) >= 0) {
|
|
6842
|
+
const line = stdout.slice(0, nl).trim();
|
|
6843
|
+
stdout = stdout.slice(nl + 1);
|
|
6844
|
+
if (!line) continue;
|
|
6845
|
+
let msg = null;
|
|
6846
|
+
try {
|
|
6847
|
+
msg = JSON.parse(line);
|
|
6848
|
+
} catch {
|
|
6849
|
+
continue;
|
|
6850
|
+
}
|
|
6851
|
+
if (msg && typeof msg.id === "number" && pending.has(msg.id)) {
|
|
6852
|
+
const cb = pending.get(msg.id);
|
|
6853
|
+
pending.delete(msg.id);
|
|
6854
|
+
cb(msg);
|
|
6855
|
+
}
|
|
6856
|
+
}
|
|
6857
|
+
});
|
|
6858
|
+
const send = (msg) => child.stdin.write(`${JSON.stringify(msg)}
|
|
6859
|
+
`);
|
|
6860
|
+
const request = (id, method, params) => new Promise((res) => {
|
|
6861
|
+
pending.set(id, res);
|
|
6862
|
+
send({ jsonrpc: "2.0", id, method, ...params ? { params } : {} });
|
|
6863
|
+
});
|
|
6864
|
+
void (async () => {
|
|
6865
|
+
const init = await request(1, "initialize", {
|
|
6866
|
+
protocolVersion: "2025-03-26",
|
|
6867
|
+
capabilities: {},
|
|
6868
|
+
clientInfo: { name: "augmented-connectivity-probe", version: "1.0.0" }
|
|
6869
|
+
});
|
|
6870
|
+
if (done) return;
|
|
6871
|
+
if (init.error) return finish({ status: "down", message: `MCP initialize error: ${init.error.message ?? "unknown"}` });
|
|
6872
|
+
send({ jsonrpc: "2.0", method: "notifications/initialized" });
|
|
6873
|
+
const list = await request(2, "tools/list");
|
|
6874
|
+
if (done) return;
|
|
6875
|
+
if (list.error) return finish({ status: "down", message: `MCP tools/list error: ${list.error.message ?? "unknown"}` });
|
|
6876
|
+
const toolCount = Array.isArray(list.result?.tools) ? list.result.tools.length : void 0;
|
|
6877
|
+
const testTool = config.connectivityTest?.tool;
|
|
6878
|
+
if (testTool) {
|
|
6879
|
+
const rawArgs = config.connectivityTest?.args;
|
|
6880
|
+
if (Array.isArray(rawArgs)) {
|
|
6881
|
+
return finish({
|
|
6882
|
+
status: "down",
|
|
6883
|
+
message: `connectivity_test.args for ${testTool} must be an object (got a string[])`
|
|
6884
|
+
});
|
|
6885
|
+
}
|
|
6886
|
+
const toolArgs = rawArgs ?? {};
|
|
6887
|
+
const call = await request(3, "tools/call", { name: testTool, arguments: toolArgs });
|
|
6888
|
+
if (done) return;
|
|
6889
|
+
if (call.error) return finish({ status: "down", message: `MCP tools/call ${testTool} error: ${call.error.message ?? "unknown"}` });
|
|
6890
|
+
if (call.result?.isError === true) {
|
|
6891
|
+
return finish({ status: "down", message: `MCP tool ${testTool} returned an error result` });
|
|
6892
|
+
}
|
|
6893
|
+
return finish({
|
|
6894
|
+
status: "ok",
|
|
6895
|
+
message: `${testTool} succeeded`,
|
|
6896
|
+
details: { ...toolCount !== void 0 ? { toolCount } : {}, testTool }
|
|
6897
|
+
});
|
|
6898
|
+
}
|
|
6899
|
+
finish({
|
|
6900
|
+
status: "ok",
|
|
6901
|
+
message: toolCount !== void 0 ? `${toolCount} tools` : "reachable",
|
|
6902
|
+
...toolCount !== void 0 ? { details: { toolCount } } : {}
|
|
6903
|
+
});
|
|
6904
|
+
})();
|
|
6905
|
+
});
|
|
6906
|
+
}
|
|
6907
|
+
|
|
6677
6908
|
// src/lib/cli-probe.ts
|
|
6678
6909
|
import { execFile as execFile2 } from "child_process";
|
|
6679
|
-
var
|
|
6910
|
+
var DEFAULT_TIMEOUT_MS2 = 8e3;
|
|
6680
6911
|
function runCliProbe(binary, args, opts = {}) {
|
|
6681
|
-
const timeoutMs = opts.timeoutMs ??
|
|
6912
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
6682
6913
|
return new Promise((resolve) => {
|
|
6683
6914
|
execFile2(
|
|
6684
6915
|
binary,
|
|
@@ -6740,6 +6971,31 @@ function readMcpHttpServerConfig(projectDir, serverKey, env) {
|
|
|
6740
6971
|
return null;
|
|
6741
6972
|
}
|
|
6742
6973
|
}
|
|
6974
|
+
function readMcpStdioServerConfig(projectDir, serverKey, env) {
|
|
6975
|
+
try {
|
|
6976
|
+
const raw = readFileSync6(join5(projectDir, ".mcp.json"), "utf-8");
|
|
6977
|
+
const servers = JSON.parse(raw).mcpServers ?? {};
|
|
6978
|
+
const entry = servers[serverKey];
|
|
6979
|
+
if (!entry || typeof entry.command !== "string") return null;
|
|
6980
|
+
const unresolved = /* @__PURE__ */ new Set();
|
|
6981
|
+
const sub = (value) => {
|
|
6982
|
+
if (!env) return value;
|
|
6983
|
+
const r = expandTemplateVars(value, env);
|
|
6984
|
+
for (const name of r.unresolved) unresolved.add(name);
|
|
6985
|
+
return r.value;
|
|
6986
|
+
};
|
|
6987
|
+
const resolvedEnv = {};
|
|
6988
|
+
for (const [k, v] of Object.entries(entry.env ?? {})) resolvedEnv[k] = sub(v);
|
|
6989
|
+
return {
|
|
6990
|
+
command: entry.command,
|
|
6991
|
+
args: (entry.args ?? []).map(sub),
|
|
6992
|
+
env: resolvedEnv,
|
|
6993
|
+
unresolved: [...unresolved]
|
|
6994
|
+
};
|
|
6995
|
+
} catch {
|
|
6996
|
+
return null;
|
|
6997
|
+
}
|
|
6998
|
+
}
|
|
6743
6999
|
function deriveMcpServerKey(input) {
|
|
6744
7000
|
const kind = resolveConnectivityProbe({
|
|
6745
7001
|
definitionId: input.definitionId,
|
|
@@ -6778,6 +7034,31 @@ function buildConnectivityProbeDeps(projectDir, probeEnv) {
|
|
|
6778
7034
|
}
|
|
6779
7035
|
return probeMcpHttp(cfg);
|
|
6780
7036
|
},
|
|
7037
|
+
// ENG-7405: local-STDIO MCP probe. Spawns the toolkit's bundled server with
|
|
7038
|
+
// the agent's env (the exact command/args/env from `.mcp.json`), handshakes,
|
|
7039
|
+
// and calls the read-only `connectivity_test` tool when the descriptor set
|
|
7040
|
+
// one (threaded via target.toolName). An unresolvable `${VAR}` in the spawn
|
|
7041
|
+
// env → skip as non-escalating, never spawn a doomed server. A missing
|
|
7042
|
+
// server entry is a real `down` — the tools aren't wired.
|
|
7043
|
+
mcpStdioProbe: async (target) => {
|
|
7044
|
+
const cfg = readMcpStdioServerConfig(projectDir, target.serverKey, probeEnv);
|
|
7045
|
+
if (!cfg) {
|
|
7046
|
+
return { status: "down", message: `MCP stdio server '${target.serverKey}' not wired in .mcp.json` };
|
|
7047
|
+
}
|
|
7048
|
+
if (cfg.unresolved.length > 0) {
|
|
7049
|
+
return {
|
|
7050
|
+
status: "transient_error",
|
|
7051
|
+
message: `MCP stdio '${target.serverKey}' env unresolved: ${cfg.unresolved.join(", ")}`
|
|
7052
|
+
};
|
|
7053
|
+
}
|
|
7054
|
+
return probeMcpStdio({
|
|
7055
|
+
command: cfg.command,
|
|
7056
|
+
args: cfg.args,
|
|
7057
|
+
env: cfg.env,
|
|
7058
|
+
cwd: projectDir,
|
|
7059
|
+
connectivityTest: target.toolName ? { tool: target.toolName, args: target.toolArgs ?? null } : null
|
|
7060
|
+
});
|
|
7061
|
+
},
|
|
6781
7062
|
// ENG-6139: connected-account binding check for managed (Composio) toolkits.
|
|
6782
7063
|
// The MCP handshake reads green on a dead/mis-bound account, so the managed
|
|
6783
7064
|
// probe also verifies the account is ACTIVE + bound to the entity the agent
|
|
@@ -7073,12 +7354,12 @@ import chalk3 from "chalk";
|
|
|
7073
7354
|
import { existsSync as existsSync8, realpathSync } from "fs";
|
|
7074
7355
|
import { join as join8 } from "path";
|
|
7075
7356
|
import { homedir as homedir4, userInfo } from "os";
|
|
7076
|
-
import { spawn as
|
|
7357
|
+
import { spawn as spawn3 } from "child_process";
|
|
7077
7358
|
|
|
7078
7359
|
// src/lib/watchdog.ts
|
|
7079
7360
|
import { readFileSync as readFileSync8, writeFileSync as writeFileSync5, unlinkSync as unlinkSync3, existsSync as existsSync7, mkdirSync as mkdirSync5, openSync as openSync2, closeSync as closeSync2, chmodSync as chmodSync4 } from "fs";
|
|
7080
7361
|
import { join as join7 } from "path";
|
|
7081
|
-
import { spawn, execFileSync as execFileSync3 } from "child_process";
|
|
7362
|
+
import { spawn as spawn2, execFileSync as execFileSync3 } from "child_process";
|
|
7082
7363
|
var DEFAULT_CONFIG_DIR = join7(process.env["HOME"] ?? "/tmp", ".augmented");
|
|
7083
7364
|
function getManagerPaths(configDir) {
|
|
7084
7365
|
return {
|
|
@@ -7174,7 +7455,7 @@ function startWatchdog(opts) {
|
|
|
7174
7455
|
} catch {
|
|
7175
7456
|
}
|
|
7176
7457
|
const intervalSec = String(Math.max(Math.floor(opts.intervalMs / 1e3), 5));
|
|
7177
|
-
const child =
|
|
7458
|
+
const child = spawn2(
|
|
7178
7459
|
process.execPath,
|
|
7179
7460
|
[process.argv[1], "manager", "start", "--interval", intervalSec, "--config-dir", configDir, "--supervise"],
|
|
7180
7461
|
{
|
|
@@ -7375,7 +7656,7 @@ function runSupervisorLoop(intervalSec, configDir) {
|
|
|
7375
7656
|
process.on("SIGINT", forwardOrExit("SIGINT"));
|
|
7376
7657
|
const runOne = () => {
|
|
7377
7658
|
respawnTimer = null;
|
|
7378
|
-
currentChild =
|
|
7659
|
+
currentChild = spawn3(
|
|
7379
7660
|
process.execPath,
|
|
7380
7661
|
[process.argv[1], "manager", "start", "--interval", String(intervalSec), "--config-dir", configDir],
|
|
7381
7662
|
{ stdio: "inherit", env: process.env }
|
|
@@ -7736,6 +8017,14 @@ async function executeConnectivityProbe(target, deps = {}) {
|
|
|
7736
8017
|
serverKey: target.mcpServerKey ?? target.definitionId,
|
|
7737
8018
|
definitionId: target.definitionId
|
|
7738
8019
|
});
|
|
8020
|
+
case "mcp_stdio":
|
|
8021
|
+
if (!deps.mcpStdioProbe) return null;
|
|
8022
|
+
return deps.mcpStdioProbe({
|
|
8023
|
+
serverKey: target.mcpServerKey ?? target.definitionId,
|
|
8024
|
+
definitionId: target.definitionId,
|
|
8025
|
+
toolName: descriptor.probeTool ?? null,
|
|
8026
|
+
toolArgs: descriptor.probeArgs ?? null
|
|
8027
|
+
});
|
|
7739
8028
|
case "cli_command":
|
|
7740
8029
|
if (!deps.runCli) return null;
|
|
7741
8030
|
return deps.runCli(target.cliBinary ?? target.definitionId, descriptor.cliArgs ?? ["--version"]);
|
|
@@ -7813,4 +8102,4 @@ export {
|
|
|
7813
8102
|
managerInstallSystemUnitCommand,
|
|
7814
8103
|
managerUninstallSystemUnitCommand
|
|
7815
8104
|
};
|
|
7816
|
-
//# sourceMappingURL=chunk-
|
|
8105
|
+
//# sourceMappingURL=chunk-O3MVFYYC.js.map
|