@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.
- package/dist/bin/agt.js +104 -12
- package/dist/bin/agt.js.map +1 -1
- package/dist/{chunk-57MHPANB.js → chunk-2BRF2FDJ.js} +24 -116
- package/dist/chunk-2BRF2FDJ.js.map +1 -0
- package/dist/{chunk-AL7UJNNI.js → chunk-GBST6UWT.js} +310 -81
- package/dist/chunk-GBST6UWT.js.map +1 -0
- package/dist/{chunk-X5E2Q3W2.js → chunk-SJUD2BWU.js} +3030 -2936
- package/dist/chunk-SJUD2BWU.js.map +1 -0
- package/dist/{claude-pair-runtime-LOL5YGXP.js → claude-pair-runtime-YPTMIWJF.js} +2 -2
- package/dist/lib/manager-worker.js +19 -227
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/mcp/augmented-admin.js +59 -3
- package/dist/{persistent-session-CFELQZI7.js → persistent-session-PNY26VBX.js} +3 -3
- package/dist/{responsiveness-probe-YOT3EKKN.js → responsiveness-probe-4YMZ6LXO.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-57MHPANB.js.map +0 -1
- package/dist/chunk-AL7UJNNI.js.map +0 -1
- package/dist/chunk-X5E2Q3W2.js.map +0 -1
- /package/dist/{claude-pair-runtime-LOL5YGXP.js.map → claude-pair-runtime-YPTMIWJF.js.map} +0 -0
- /package/dist/{persistent-session-CFELQZI7.js.map → persistent-session-PNY26VBX.js.map} +0 -0
- /package/dist/{responsiveness-probe-YOT3EKKN.js.map → responsiveness-probe-4YMZ6LXO.js.map} +0 -0
|
@@ -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-
|
|
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
|
|
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
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
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.
|
|
3415
|
-
|
|
3416
|
-
\`
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
5. If the completion notification reports a failure
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
>
|
|
3426
|
-
>
|
|
3427
|
-
>
|
|
3428
|
-
>
|
|
3429
|
-
>
|
|
3430
|
-
>
|
|
3431
|
-
>
|
|
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
|
|
3436
|
-
>
|
|
3437
|
-
>
|
|
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:
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
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 \`
|
|
3472
|
-
|
|
3473
|
-
|
|
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
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
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:
|
|
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
|
|
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:
|
|
5827
|
+
const { execFile: execFile5 } = await import("child_process");
|
|
5820
5828
|
return new Promise((resolve3) => {
|
|
5821
|
-
|
|
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.
|
|
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
|
|
7668
|
-
import { join as
|
|
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
|
|
7674
|
-
import { join as
|
|
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 =
|
|
7834
|
+
var DEFAULT_CONFIG_DIR = join9(process.env["HOME"] ?? "/tmp", ".augmented");
|
|
7677
7835
|
function getManagerPaths(configDir) {
|
|
7678
7836
|
return {
|
|
7679
|
-
pidFile:
|
|
7680
|
-
stateFile:
|
|
7681
|
-
logFile:
|
|
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 (!
|
|
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 =
|
|
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 =
|
|
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 (
|
|
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 ??
|
|
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 ??
|
|
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 ??
|
|
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 (!
|
|
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 ??
|
|
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) =>
|
|
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" :
|
|
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-
|
|
8558
|
+
//# sourceMappingURL=chunk-GBST6UWT.js.map
|