agent-mcp-hub 0.5.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.
- package/LICENSE +373 -0
- package/README.md +246 -0
- package/dist/adapters/claude.d.ts +2 -0
- package/dist/adapters/claude.js +15 -0
- package/dist/adapters/claude.js.map +1 -0
- package/dist/adapters/codex.d.ts +2 -0
- package/dist/adapters/codex.js +16 -0
- package/dist/adapters/codex.js.map +1 -0
- package/dist/adapters/cursor.d.ts +2 -0
- package/dist/adapters/cursor.js +33 -0
- package/dist/adapters/cursor.js.map +1 -0
- package/dist/adapters/opencode.d.ts +2 -0
- package/dist/adapters/opencode.js +23 -0
- package/dist/adapters/opencode.js.map +1 -0
- package/dist/ansi.d.ts +5 -0
- package/dist/ansi.js +15 -0
- package/dist/ansi.js.map +1 -0
- package/dist/confirm.d.ts +36 -0
- package/dist/confirm.js +65 -0
- package/dist/confirm.js.map +1 -0
- package/dist/exec.d.ts +146 -0
- package/dist/exec.js +494 -0
- package/dist/exec.js.map +1 -0
- package/dist/failure.d.ts +27 -0
- package/dist/failure.js +210 -0
- package/dist/failure.js.map +1 -0
- package/dist/git.d.ts +59 -0
- package/dist/git.js +127 -0
- package/dist/git.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/registry.d.ts +70 -0
- package/dist/registry.js +159 -0
- package/dist/registry.js.map +1 -0
- package/dist/server.d.ts +15 -0
- package/dist/server.js +509 -0
- package/dist/server.js.map +1 -0
- package/dist/types.d.ts +43 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +75 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export const cursorAdapter = {
|
|
2
|
+
name: "cursor",
|
|
3
|
+
summary: "Cursor Agent (cursor-agent) — Cursor's repo-aware autonomous coding agent; implements and edits code from a natural-language task.",
|
|
4
|
+
binary: "cursor-agent",
|
|
5
|
+
loginCommand: "cursor-agent login",
|
|
6
|
+
apiKeyEnv: "CURSOR_API_KEY",
|
|
7
|
+
// `cursor-agent models` requires a valid account, so exit 0 proves authentication
|
|
8
|
+
// — far stronger than `--version`. probeRequiresOutput stays false on purpose: it
|
|
9
|
+
// prints prose ("gpt-5.3-codex-low - Codex 5.3 Low"), not bare ids, so the
|
|
10
|
+
// identifier heuristic would find nothing and condemn a healthy CLI.
|
|
11
|
+
probeArgs: ["models"],
|
|
12
|
+
// Line-anchored on purpose: a loose /retry attempt \d+/i would also match that
|
|
13
|
+
// phrase appearing mid-line in output from a build script the agent runs.
|
|
14
|
+
stallSignatures: [
|
|
15
|
+
/^connection lost, reconnecting to \S+ \(attempt \d+\)\.*$/i,
|
|
16
|
+
/^retry attempt \d+\.*$/i,
|
|
17
|
+
/^retriable\s*error:\s*connection stalled\b/i,
|
|
18
|
+
],
|
|
19
|
+
buildInvocation(prompt, options = {}) {
|
|
20
|
+
// --force: cursor-agent otherwise blocks on an interactive permission prompt
|
|
21
|
+
// ("Workspace Trust Required" / command approval) in any directory it has not
|
|
22
|
+
// seen before, which for a server invoked against arbitrary cwds is most of
|
|
23
|
+
// them. There is no stdin to answer it with in print mode, so the run would
|
|
24
|
+
// hang until the timeout kills it. (`--trust` is NOT a cursor-agent flag —
|
|
25
|
+
// passing it makes the CLI exit 1 with "unknown option '--trust'".)
|
|
26
|
+
const args = ["-p", "--output-format", "text", "--force"];
|
|
27
|
+
if (options.model)
|
|
28
|
+
args.push("--model", options.model);
|
|
29
|
+
// No positional prompt: cursor-agent reads it from piped stdin in print mode.
|
|
30
|
+
return { args, stdin: prompt };
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=cursor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor.js","sourceRoot":"","sources":["../../src/adapters/cursor.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,aAAa,GAAiB;IACzC,IAAI,EAAE,QAAQ;IACd,OAAO,EACL,oIAAoI;IACtI,MAAM,EAAE,cAAc;IACtB,YAAY,EAAE,oBAAoB;IAClC,SAAS,EAAE,gBAAgB;IAC3B,kFAAkF;IAClF,kFAAkF;IAClF,2EAA2E;IAC3E,qEAAqE;IACrE,SAAS,EAAE,CAAC,QAAQ,CAAC;IACrB,+EAA+E;IAC/E,0EAA0E;IAC1E,eAAe,EAAE;QACf,4DAA4D;QAC5D,yBAAyB;QACzB,6CAA6C;KAC9C;IACD,eAAe,CAAC,MAAc,EAAE,UAA2B,EAAE;QAC3D,6EAA6E;QAC7E,8EAA8E;QAC9E,4EAA4E;QAC5E,4EAA4E;QAC5E,2EAA2E;QAC3E,oEAAoE;QACpE,MAAM,IAAI,GAAG,CAAC,IAAI,EAAE,iBAAiB,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;QAC1D,IAAI,OAAO,CAAC,KAAK;YAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QACvD,8EAA8E;QAC9E,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IACjC,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export const opencodeAdapter = {
|
|
2
|
+
name: "opencode",
|
|
3
|
+
summary: "OpenCode — an open-source, provider-agnostic coding agent for agentic code changes; its model defaults to the user's opencode config unless a model is provided. Prompts must not start with '-'.",
|
|
4
|
+
binary: "opencode",
|
|
5
|
+
// `opencode models` prints bare ids ("opencode/big-pickle"), one per line, and
|
|
6
|
+
// exercises config + provider resolution rather than just starting the binary.
|
|
7
|
+
probeArgs: ["models"],
|
|
8
|
+
probeRequiresOutput: true,
|
|
9
|
+
loginCommand: "opencode auth login",
|
|
10
|
+
buildInvocation(prompt, options = {}) {
|
|
11
|
+
if (prompt.startsWith("-")) {
|
|
12
|
+
// opencode documents neither stdin input nor a "--" delimiter, so a
|
|
13
|
+
// dash-leading prompt could be parsed as a flag by its CLI.
|
|
14
|
+
throw new Error("opencode cannot safely run prompts that start with '-' (its CLI may parse them as flags). Rephrase the prompt to start with a word, e.g. \"explain --help ...\".");
|
|
15
|
+
}
|
|
16
|
+
const args = ["run"];
|
|
17
|
+
if (options.model)
|
|
18
|
+
args.push("--model", options.model);
|
|
19
|
+
args.push(prompt);
|
|
20
|
+
return { args };
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=opencode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opencode.js","sourceRoot":"","sources":["../../src/adapters/opencode.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,eAAe,GAAiB;IAC3C,IAAI,EAAE,UAAU;IAChB,OAAO,EACL,mMAAmM;IACrM,MAAM,EAAE,UAAU;IAClB,+EAA+E;IAC/E,+EAA+E;IAC/E,SAAS,EAAE,CAAC,QAAQ,CAAC;IACrB,mBAAmB,EAAE,IAAI;IACzB,YAAY,EAAE,qBAAqB;IACnC,eAAe,CAAC,MAAc,EAAE,UAA2B,EAAE;QAC3D,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC3B,oEAAoE;YACpE,4DAA4D;YAC5D,MAAM,IAAI,KAAK,CACb,kKAAkK,CACnK,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;QACrB,IAAI,OAAO,CAAC,KAAK;YAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QACvD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAClB,OAAO,EAAE,IAAI,EAAE,CAAC;IAClB,CAAC;CACF,CAAC"}
|
package/dist/ansi.d.ts
ADDED
package/dist/ansi.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical zero-dep `ansi-regex` pattern source. Matches 7-bit `ESC[…`, 8-bit
|
|
3
|
+
* CSI (``), OSC (`ESC]…BEL`), private `?`/`#` params, SGR, and cursor
|
|
4
|
+
* moves. Built with the `g` flag so `.replace` clears every occurrence. Kept as
|
|
5
|
+
* a string so the source is auditable against upstream.
|
|
6
|
+
*/
|
|
7
|
+
const ANSI_PATTERN = "[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))";
|
|
8
|
+
/**
|
|
9
|
+
* Remove ANSI escape sequences and collapse carriage-return spinner runs so the
|
|
10
|
+
* text is safe to embed in a plain MCP message. Pure: no I/O.
|
|
11
|
+
*/
|
|
12
|
+
export function stripAnsi(s) {
|
|
13
|
+
return s.replace(new RegExp(ANSI_PATTERN, "g"), "").replace(/\r+/g, "");
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=ansi.js.map
|
package/dist/ansi.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ansi.js","sourceRoot":"","sources":["../src/ansi.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,YAAY,GAChB,uLAAuL,CAAC;AAE1L;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,CAAS;IACjC,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,YAAY,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAC1E,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { ElicitRequestFormParams } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
/**
|
|
3
|
+
* The confirm gate has three modes:
|
|
4
|
+
* - `"off"` — MCP_CONFIRM unset/other → run without a gate (default).
|
|
5
|
+
* - `"on"` — MCP_CONFIRM in {1,true,on,all} → ask; DEGRADE OPEN (run with a
|
|
6
|
+
* warning) if the client cannot show a form.
|
|
7
|
+
* - `"strict"`— MCP_CONFIRM=strict → ask; FAIL CLOSED (refuse to run) if the
|
|
8
|
+
* client cannot show a form. For operators who need "no run without a human".
|
|
9
|
+
*/
|
|
10
|
+
export type ConfirmMode = "off" | "on" | "strict";
|
|
11
|
+
export declare function confirmMode(env?: NodeJS.ProcessEnv): ConfirmMode;
|
|
12
|
+
/** True iff the confirm gate is active in any mode (`on` or `strict`). */
|
|
13
|
+
export declare function confirmEnabled(env?: NodeJS.ProcessEnv): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Truncate `input` so the RESULT length is `<= max`, counting the ellipsis
|
|
16
|
+
* marker (…, U+2026). Inputs already within `max` are returned unchanged.
|
|
17
|
+
*/
|
|
18
|
+
export declare function truncate(input: string, max: number): string;
|
|
19
|
+
/** Short human summary naming the agent, with cwd/model lines only when present. */
|
|
20
|
+
export declare function buildConfirmMessage(agentName: string, opts: {
|
|
21
|
+
prompt: string;
|
|
22
|
+
model?: string;
|
|
23
|
+
cwd?: string;
|
|
24
|
+
}): string;
|
|
25
|
+
/** Summary listing every enabled agent name for a single run_all confirmation. */
|
|
26
|
+
export declare function buildRunAllMessage(agentNames: string[], opts: {
|
|
27
|
+
prompt: string;
|
|
28
|
+
cwd?: string;
|
|
29
|
+
model?: string;
|
|
30
|
+
}): string;
|
|
31
|
+
/** requestedSchema for elicitInput: a single required boolean the client renders.
|
|
32
|
+
* Typed against the SDK so a malformed edit fails typecheck (drift-safe). The
|
|
33
|
+
* import is type-only — erased at runtime, so this module stays pure. */
|
|
34
|
+
export declare const CONFIRM_SCHEMA: ElicitRequestFormParams["requestedSchema"];
|
|
35
|
+
/** Canonical terminal cancel wording shared by both call sites (asserted in tests). */
|
|
36
|
+
export declare const CANCEL_TAIL = "run cancelled by user \u2014 nothing was executed. Do not retry unless the user asks.";
|
package/dist/confirm.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
const ENABLING = new Set(["1", "true", "on", "all"]);
|
|
2
|
+
export function confirmMode(env = process.env) {
|
|
3
|
+
const raw = env.MCP_CONFIRM?.trim().toLowerCase();
|
|
4
|
+
if (raw === undefined)
|
|
5
|
+
return "off";
|
|
6
|
+
if (raw === "strict")
|
|
7
|
+
return "strict";
|
|
8
|
+
return ENABLING.has(raw) ? "on" : "off";
|
|
9
|
+
}
|
|
10
|
+
/** True iff the confirm gate is active in any mode (`on` or `strict`). */
|
|
11
|
+
export function confirmEnabled(env = process.env) {
|
|
12
|
+
return confirmMode(env) !== "off";
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Truncate `input` so the RESULT length is `<= max`, counting the ellipsis
|
|
16
|
+
* marker (…, U+2026). Inputs already within `max` are returned unchanged.
|
|
17
|
+
*/
|
|
18
|
+
export function truncate(input, max) {
|
|
19
|
+
if (max < 1)
|
|
20
|
+
return "";
|
|
21
|
+
if (input.length <= max)
|
|
22
|
+
return input;
|
|
23
|
+
return input.slice(0, max - 1) + "…";
|
|
24
|
+
}
|
|
25
|
+
const PROMPT_MAX = 300;
|
|
26
|
+
/** Short human summary naming the agent, with cwd/model lines only when present. */
|
|
27
|
+
export function buildConfirmMessage(agentName, opts) {
|
|
28
|
+
const lines = [`Run agent "${agentName}"?`, `prompt: ${truncate(opts.prompt, PROMPT_MAX)}`];
|
|
29
|
+
if (opts.cwd !== undefined)
|
|
30
|
+
lines.push(`cwd: ${opts.cwd}`);
|
|
31
|
+
if (opts.model !== undefined)
|
|
32
|
+
lines.push(`model: ${opts.model}`);
|
|
33
|
+
return lines.join("\n");
|
|
34
|
+
}
|
|
35
|
+
/** Summary listing every enabled agent name for a single run_all confirmation. */
|
|
36
|
+
export function buildRunAllMessage(agentNames, opts) {
|
|
37
|
+
const lines = [
|
|
38
|
+
`Run all agents (${agentNames.join(", ")})?`,
|
|
39
|
+
`prompt: ${truncate(opts.prompt, PROMPT_MAX)}`,
|
|
40
|
+
];
|
|
41
|
+
if (opts.cwd !== undefined)
|
|
42
|
+
lines.push(`cwd: ${opts.cwd}`);
|
|
43
|
+
// `model` is shown so a caller sees exactly what is forwarded to each CLI —
|
|
44
|
+
// it is attacker-influenceable and must not be hidden from the human gate.
|
|
45
|
+
if (opts.model !== undefined)
|
|
46
|
+
lines.push(`model: ${opts.model}`);
|
|
47
|
+
return lines.join("\n");
|
|
48
|
+
}
|
|
49
|
+
/** requestedSchema for elicitInput: a single required boolean the client renders.
|
|
50
|
+
* Typed against the SDK so a malformed edit fails typecheck (drift-safe). The
|
|
51
|
+
* import is type-only — erased at runtime, so this module stays pure. */
|
|
52
|
+
export const CONFIRM_SCHEMA = {
|
|
53
|
+
type: "object",
|
|
54
|
+
properties: {
|
|
55
|
+
confirm: {
|
|
56
|
+
type: "boolean",
|
|
57
|
+
title: "Run this agent?",
|
|
58
|
+
description: "Confirm to run; decline to cancel.",
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
required: ["confirm"],
|
|
62
|
+
};
|
|
63
|
+
/** Canonical terminal cancel wording shared by both call sites (asserted in tests). */
|
|
64
|
+
export const CANCEL_TAIL = "run cancelled by user — nothing was executed. Do not retry unless the user asks.";
|
|
65
|
+
//# sourceMappingURL=confirm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confirm.js","sourceRoot":"","sources":["../src/confirm.ts"],"names":[],"mappings":"AAIA,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;AAYrD,MAAM,UAAU,WAAW,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC9D,MAAM,GAAG,GAAG,GAAG,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAClD,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACpC,IAAI,GAAG,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IACtC,OAAO,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;AAC1C,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,cAAc,CAAC,MAAyB,OAAO,CAAC,GAAG;IACjE,OAAO,WAAW,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC;AACpC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,KAAa,EAAE,GAAW;IACjD,IAAI,GAAG,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IACvB,IAAI,KAAK,CAAC,MAAM,IAAI,GAAG;QAAE,OAAO,KAAK,CAAC;IACtC,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,GAAG,GAAG,CAAC;AAEvB,oFAAoF;AACpF,MAAM,UAAU,mBAAmB,CACjC,SAAiB,EACjB,IAAsD;IAEtD,MAAM,KAAK,GAAG,CAAC,cAAc,SAAS,IAAI,EAAE,WAAW,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC,CAAC;IAC5F,IAAI,IAAI,CAAC,GAAG,KAAK,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAC3D,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IACjE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,kBAAkB,CAChC,UAAoB,EACpB,IAAsD;IAEtD,MAAM,KAAK,GAAG;QACZ,mBAAmB,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;QAC5C,WAAW,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE;KAC/C,CAAC;IACF,IAAI,IAAI,CAAC,GAAG,KAAK,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAC3D,4EAA4E;IAC5E,2EAA2E;IAC3E,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IACjE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;0EAE0E;AAC1E,MAAM,CAAC,MAAM,cAAc,GAA+C;IACxE,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE;QACV,OAAO,EAAE;YACP,IAAI,EAAE,SAAS;YACf,KAAK,EAAE,iBAAiB;YACxB,WAAW,EAAE,oCAAoC;SAClD;KACF;IACD,QAAQ,EAAE,CAAC,SAAS,CAAC;CACtB,CAAC;AAEF,uFAAuF;AACvF,MAAM,CAAC,MAAM,WAAW,GACtB,kFAAkF,CAAC"}
|
package/dist/exec.d.ts
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
export interface ExecResult {
|
|
2
|
+
stdout: string;
|
|
3
|
+
stderr: string;
|
|
4
|
+
exitCode: number | null;
|
|
5
|
+
}
|
|
6
|
+
export type Exec = (binary: string, args: string[], opts?: {
|
|
7
|
+
cwd?: string;
|
|
8
|
+
timeoutMs?: number;
|
|
9
|
+
idleTimeoutMs?: number;
|
|
10
|
+
input?: string;
|
|
11
|
+
maxOutputBytes?: number;
|
|
12
|
+
/** Fired synchronously once per ACCEPTED output chunk. Never awaited. */
|
|
13
|
+
onActivity?: () => void;
|
|
14
|
+
/**
|
|
15
|
+
* Line patterns the CLI prints on its DIAGNOSTIC stream (stderr) when it
|
|
16
|
+
* cannot reach its backend. Matched against stderr ONLY: the model's answer
|
|
17
|
+
* arrives on stdout, so a model that quotes one of these phrases can never
|
|
18
|
+
* trip the detector.
|
|
19
|
+
*/
|
|
20
|
+
stallSignatures?: readonly RegExp[];
|
|
21
|
+
/**
|
|
22
|
+
* How many distinct reconnect cycles (each cycle = one "attempt N" line) the
|
|
23
|
+
* child must emit before we treat the stall as permanent. Default 2 — a
|
|
24
|
+
* single legitimate reconnect cycle emits exactly one attempt line.
|
|
25
|
+
*/
|
|
26
|
+
stallAttemptLimit?: number;
|
|
27
|
+
/**
|
|
28
|
+
* Absolute strike cap for signatures that carry no attempt number (e.g. a
|
|
29
|
+
* repeated "RetriableError: …"). Default 4.
|
|
30
|
+
*/
|
|
31
|
+
stallStrikeLimit?: number;
|
|
32
|
+
/**
|
|
33
|
+
* Env-var names to DELETE from the child's environment. Least-privilege
|
|
34
|
+
* denylist that keeps exec generic — it never learns which adapter owns
|
|
35
|
+
* which key. Callers pass the OTHER agents' credential var names (the union
|
|
36
|
+
* of every agent's apiKeyEnv MINUS the one being spawned) so a compromised
|
|
37
|
+
* or prompt-injected child cannot read a sibling agent's key FROM THE ENV.
|
|
38
|
+
* This is env-var isolation, not a full secret boundary: `HOME` is preserved
|
|
39
|
+
* (agents need their config there), so an agent can still read a sibling's
|
|
40
|
+
* on-disk credential file — hardening the env is necessary but not sufficient.
|
|
41
|
+
* Every other var (PATH, HOME, proxy/CA/XDG/locale) is preserved. Undefined or
|
|
42
|
+
* empty leaves behavior identical to inheriting the full parent env.
|
|
43
|
+
*/
|
|
44
|
+
stripEnvKeys?: readonly string[];
|
|
45
|
+
/**
|
|
46
|
+
* Env vars to SET on the child, applied AFTER stripEnvKeys (so an override
|
|
47
|
+
* here always wins). Used to harden a subprocess against its own working
|
|
48
|
+
* tree — e.g. neutralising git's config search path so an untrusted repo's
|
|
49
|
+
* `.git/config` / global / system config cannot execute code during
|
|
50
|
+
* `git diff` / `git status`. Keys set here are never treated as strippable.
|
|
51
|
+
*/
|
|
52
|
+
env?: Readonly<Record<string, string>>;
|
|
53
|
+
}) => Promise<ExecResult>;
|
|
54
|
+
/**
|
|
55
|
+
* TOTAL runtime cap (never reset). Parsed once at module load; override via
|
|
56
|
+
* MCP_AGENT_TIMEOUT_MS. Raised to 30 min so long PRODUCTIVE runs survive — the
|
|
57
|
+
* idle timeout, not this, is the fast hung-agent detector.
|
|
58
|
+
*/
|
|
59
|
+
export declare const DEFAULT_TIMEOUT_MS: number;
|
|
60
|
+
/**
|
|
61
|
+
* IDLE (inactivity) cap: reset on every accepted output chunk. Parsed once at
|
|
62
|
+
* module load; override via MCP_AGENT_IDLE_TIMEOUT_MS. Generous default so a
|
|
63
|
+
* slow-but-streaming CLI is not killed mid-work.
|
|
64
|
+
*/
|
|
65
|
+
export declare const DEFAULT_IDLE_TIMEOUT_MS: number;
|
|
66
|
+
export declare const DEFAULT_MAX_OUTPUT_BYTES: number;
|
|
67
|
+
export declare const DEFAULT_STALL_ATTEMPT_LIMIT = 2;
|
|
68
|
+
export declare const DEFAULT_STALL_STRIKE_LIMIT = 4;
|
|
69
|
+
/**
|
|
70
|
+
* Hard ceiling on any single timer (total or idle). Two jobs:
|
|
71
|
+
* 1. Correctness — `setTimeout` truncates a delay > 2^31-1 ms (~24.8 days) to
|
|
72
|
+
* 1ms and fires it IMMEDIATELY, so an unclamped huge `timeoutMs` would kill
|
|
73
|
+
* the child the instant it starts. 24h is safely under that boundary.
|
|
74
|
+
* 2. Load-shedding — a single run can hold a concurrency slot for at most 24h,
|
|
75
|
+
* so a caller cannot pin all slots for weeks with an enormous `timeoutMs`.
|
|
76
|
+
*/
|
|
77
|
+
export declare const MAX_TIMEOUT_MS: number;
|
|
78
|
+
/** Clamp a caller-supplied timer to [1, MAX_TIMEOUT_MS]; floors non-integers. */
|
|
79
|
+
export declare function clampTimer(ms: number): number;
|
|
80
|
+
/**
|
|
81
|
+
* Cap on children spawned concurrently across the process. Parsed once at module
|
|
82
|
+
* load; override via MCP_MAX_CONCURRENT_AGENTS.
|
|
83
|
+
*/
|
|
84
|
+
export declare const MAX_CONCURRENT_AGENTS: number;
|
|
85
|
+
/**
|
|
86
|
+
* Thrown when every permit is busy AND the wait queue is already full. Overload
|
|
87
|
+
* sheds load here instead of growing latency unbounded — the caller retries
|
|
88
|
+
* later. Surfaces through runCommand → runAdapter → the tool handler's catch as
|
|
89
|
+
* an `isError` result (the 503-equivalent in the stateless per-request model).
|
|
90
|
+
*/
|
|
91
|
+
export declare class ServerBusyError extends Error {
|
|
92
|
+
readonly code = "SERVER_BUSY";
|
|
93
|
+
constructor();
|
|
94
|
+
}
|
|
95
|
+
/** Thrown when the child process fails to spawn (binary missing / not on PATH). */
|
|
96
|
+
export declare class SpawnError extends Error {
|
|
97
|
+
readonly cause?: unknown | undefined;
|
|
98
|
+
readonly code = "spawn";
|
|
99
|
+
constructor(message: string, cause?: unknown | undefined);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Thrown when `cwd` does not exist (or is not a directory). Checked BEFORE spawn
|
|
103
|
+
* because both a missing binary and a missing cwd surface as bare ENOENT from
|
|
104
|
+
* spawn, and collapsing them is actively misleading: a caller passing a repo path
|
|
105
|
+
* the server cannot see was told "codex was not found on PATH" while codex was
|
|
106
|
+
* installed and healthy. Distinguishing them up front makes the real fault legible.
|
|
107
|
+
*/
|
|
108
|
+
export declare class InvalidCwdError extends Error {
|
|
109
|
+
readonly cwd: string;
|
|
110
|
+
readonly code = "invalid_cwd";
|
|
111
|
+
constructor(cwd: string);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Thrown when the child is killed for exceeding a timeout. Carries the bound and
|
|
115
|
+
* WHICH cap fired: `"idle"` (no output for idleTimeoutMs — likely hung/unreachable)
|
|
116
|
+
* or `"total"` (exceeded the total runtime cap). `kind` is additive and defaults
|
|
117
|
+
* to `"total"`, so `new TimeoutError(msg, ms)` call sites are unchanged.
|
|
118
|
+
*/
|
|
119
|
+
export declare class TimeoutError extends Error {
|
|
120
|
+
readonly timeoutMs: number;
|
|
121
|
+
readonly kind: "idle" | "total";
|
|
122
|
+
readonly code = "timeout";
|
|
123
|
+
constructor(message: string, timeoutMs: number, kind?: "idle" | "total");
|
|
124
|
+
}
|
|
125
|
+
/** Thrown when the child is killed for exceeding `maxOutputBytes`. Carries the cap. */
|
|
126
|
+
export declare class OutputLimitError extends Error {
|
|
127
|
+
readonly maxOutputBytes: number;
|
|
128
|
+
readonly code = "output_limit";
|
|
129
|
+
constructor(message: string, maxOutputBytes: number);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Thrown when the child is detected as stalled: it prints diagnostic reconnect
|
|
133
|
+
* phrases on stderr (the adapter's `stallSignatures`) but never produces stdout,
|
|
134
|
+
* and the attempt/strike counters corroborate that it will not recover. The
|
|
135
|
+
* process group is killed; the rejection surfaces on `close` so the semaphore
|
|
136
|
+
* permit is released only after the tree is actually gone.
|
|
137
|
+
*/
|
|
138
|
+
export declare class AgentStalledError extends Error {
|
|
139
|
+
readonly signature: string;
|
|
140
|
+
readonly strikes: number;
|
|
141
|
+
readonly code = "stream_stalled";
|
|
142
|
+
constructor(message: string, signature: string, strikes: number);
|
|
143
|
+
}
|
|
144
|
+
/** Best-effort: kill every still-live child's process group. Never throws. */
|
|
145
|
+
export declare function reapAllChildren(): void;
|
|
146
|
+
export declare const runCommand: Exec;
|