@alan-ai-hq/agent-manager 0.1.91 → 0.1.93
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/index.cjs +294 -55
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -3404,7 +3404,7 @@ var require_websocket = __commonJS({
|
|
|
3404
3404
|
var http2 = require("http");
|
|
3405
3405
|
var net = require("net");
|
|
3406
3406
|
var tls = require("tls");
|
|
3407
|
-
var { randomBytes: randomBytes13, createHash:
|
|
3407
|
+
var { randomBytes: randomBytes13, createHash: createHash18 } = require("crypto");
|
|
3408
3408
|
var { Duplex, Readable: Readable2 } = require("stream");
|
|
3409
3409
|
var { URL: URL2 } = require("url");
|
|
3410
3410
|
var PerMessageDeflate = require_permessage_deflate();
|
|
@@ -4061,7 +4061,7 @@ var require_websocket = __commonJS({
|
|
|
4061
4061
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
4062
4062
|
return;
|
|
4063
4063
|
}
|
|
4064
|
-
const digest =
|
|
4064
|
+
const digest = createHash18("sha1").update(key + GUID).digest("base64");
|
|
4065
4065
|
if (res.headers["sec-websocket-accept"] !== digest) {
|
|
4066
4066
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
4067
4067
|
return;
|
|
@@ -4428,7 +4428,7 @@ var require_websocket_server = __commonJS({
|
|
|
4428
4428
|
var EventEmitter = require("events");
|
|
4429
4429
|
var http2 = require("http");
|
|
4430
4430
|
var { Duplex } = require("stream");
|
|
4431
|
-
var { createHash:
|
|
4431
|
+
var { createHash: createHash18 } = require("crypto");
|
|
4432
4432
|
var extension = require_extension();
|
|
4433
4433
|
var PerMessageDeflate = require_permessage_deflate();
|
|
4434
4434
|
var subprotocol = require_subprotocol();
|
|
@@ -4725,7 +4725,7 @@ var require_websocket_server = __commonJS({
|
|
|
4725
4725
|
);
|
|
4726
4726
|
}
|
|
4727
4727
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
4728
|
-
const digest =
|
|
4728
|
+
const digest = createHash18("sha1").update(key + GUID).digest("base64");
|
|
4729
4729
|
const headers = [
|
|
4730
4730
|
"HTTP/1.1 101 Switching Protocols",
|
|
4731
4731
|
"Upgrade: websocket",
|
|
@@ -15451,7 +15451,7 @@ function describeError(error61) {
|
|
|
15451
15451
|
}
|
|
15452
15452
|
|
|
15453
15453
|
// src/version.ts
|
|
15454
|
-
var AGENT_VERSION = "0.1.
|
|
15454
|
+
var AGENT_VERSION = "0.1.93";
|
|
15455
15455
|
|
|
15456
15456
|
// src/daemon-worktree.ts
|
|
15457
15457
|
var import_node_child_process3 = require("child_process");
|
|
@@ -36003,6 +36003,42 @@ var import_fs = require("fs");
|
|
|
36003
36003
|
var import_os = require("os");
|
|
36004
36004
|
var import_path = require("path");
|
|
36005
36005
|
|
|
36006
|
+
// ../shared/dist/utils/workflow-tools-filter.js
|
|
36007
|
+
var WORKFLOW_ALWAYS_ALLOWED_BUILTIN_TOOLS = [
|
|
36008
|
+
"search_context",
|
|
36009
|
+
"create_test_report",
|
|
36010
|
+
"create_plan",
|
|
36011
|
+
"create_document_artifact",
|
|
36012
|
+
"upsert_prototype_version",
|
|
36013
|
+
"list_artifacts",
|
|
36014
|
+
"get_artifact",
|
|
36015
|
+
"list_prototypes",
|
|
36016
|
+
"get_prototype"
|
|
36017
|
+
];
|
|
36018
|
+
function createWorkflowToolsFilter(workflowTools) {
|
|
36019
|
+
const hasFilter = !!workflowTools && workflowTools.length > 0;
|
|
36020
|
+
if (!hasFilter) {
|
|
36021
|
+
return {
|
|
36022
|
+
hasFilter: false,
|
|
36023
|
+
isMcpServerAllowed: () => true,
|
|
36024
|
+
resolveAllowedBuiltinTools: () => null
|
|
36025
|
+
};
|
|
36026
|
+
}
|
|
36027
|
+
const tools = workflowTools;
|
|
36028
|
+
const mcpServerIds = new Set(tools.filter((t) => t.type === "mcp").map((t) => t.id));
|
|
36029
|
+
const builtinToolIds = tools.filter((t) => t.type === "builtin" || t.type === "integration").map((t) => t.id);
|
|
36030
|
+
return {
|
|
36031
|
+
hasFilter: true,
|
|
36032
|
+
isMcpServerAllowed: (serverName) => mcpServerIds.has(serverName),
|
|
36033
|
+
resolveAllowedBuiltinTools: () => {
|
|
36034
|
+
const merged = new Set(builtinToolIds);
|
|
36035
|
+
for (const id of WORKFLOW_ALWAYS_ALLOWED_BUILTIN_TOOLS)
|
|
36036
|
+
merged.add(id);
|
|
36037
|
+
return [...merged];
|
|
36038
|
+
}
|
|
36039
|
+
};
|
|
36040
|
+
}
|
|
36041
|
+
|
|
36006
36042
|
// ../shared/dist/agent/agent-definitions.js
|
|
36007
36043
|
var COORDINATOR_PROMPT = `## You are the Orchestrator
|
|
36008
36044
|
|
|
@@ -36490,6 +36526,34 @@ function buildAlanMcpServers(registration) {
|
|
|
36490
36526
|
}
|
|
36491
36527
|
};
|
|
36492
36528
|
}
|
|
36529
|
+
var ALAN_RUN_REFERENCE_ENV = "ALAN_RUN_REFERENCE";
|
|
36530
|
+
var MCP_CONFIG_KEY = /^[A-Za-z0-9_-]+$/;
|
|
36531
|
+
function isExternalMcpServerName(name) {
|
|
36532
|
+
return MCP_CONFIG_KEY.test(name) && name !== "alan";
|
|
36533
|
+
}
|
|
36534
|
+
function isMcpConfigKey(name) {
|
|
36535
|
+
return MCP_CONFIG_KEY.test(name);
|
|
36536
|
+
}
|
|
36537
|
+
var CURSOR_RUN_REFERENCE_HEADER_VALUE = `\${env:${ALAN_RUN_REFERENCE_ENV}}`;
|
|
36538
|
+
function toCursorMcpServers(src) {
|
|
36539
|
+
const out = {};
|
|
36540
|
+
for (const [name, raw] of Object.entries(src)) {
|
|
36541
|
+
if (!raw || typeof raw !== "object")
|
|
36542
|
+
continue;
|
|
36543
|
+
const s = raw;
|
|
36544
|
+
const isHttp = typeof s.type === "string" && s.type === "http" || typeof s.url === "string";
|
|
36545
|
+
if (!isHttp) {
|
|
36546
|
+
out[name] = s;
|
|
36547
|
+
continue;
|
|
36548
|
+
}
|
|
36549
|
+
const headers = Object.fromEntries(Object.entries(s.headers ?? {}).filter(([key]) => key.toLowerCase() !== "x-alan-run-reference"));
|
|
36550
|
+
out[name] = {
|
|
36551
|
+
...s,
|
|
36552
|
+
headers: { ...headers, "x-alan-run-reference": CURSOR_RUN_REFERENCE_HEADER_VALUE }
|
|
36553
|
+
};
|
|
36554
|
+
}
|
|
36555
|
+
return out;
|
|
36556
|
+
}
|
|
36493
36557
|
function toFactoryMcpServers(src) {
|
|
36494
36558
|
const out = {};
|
|
36495
36559
|
for (const [name, raw] of Object.entries(src)) {
|
|
@@ -36634,7 +36698,10 @@ function renderAlanMcpConfigFiles(mcpServers, home) {
|
|
|
36634
36698
|
mergeJsonKey: "mcpServers"
|
|
36635
36699
|
},
|
|
36636
36700
|
{ path: `${home}/.codex/config.toml`, content: toCodexMcpToml(mcpServers) },
|
|
36637
|
-
{
|
|
36701
|
+
{
|
|
36702
|
+
path: `${home}/.cursor/mcp.json`,
|
|
36703
|
+
content: JSON.stringify({ mcpServers: toCursorMcpServers(mcpServers) })
|
|
36704
|
+
},
|
|
36638
36705
|
{
|
|
36639
36706
|
path: `${home}/.factory/mcp.json`,
|
|
36640
36707
|
content: JSON.stringify({ mcpServers: toFactoryMcpServers(mcpServers) })
|
|
@@ -38302,6 +38369,7 @@ var import_os4 = require("os");
|
|
|
38302
38369
|
var import_path5 = require("path");
|
|
38303
38370
|
var import_url = require("url");
|
|
38304
38371
|
var import_crypto4 = require("crypto");
|
|
38372
|
+
var import_crypto5 = require("crypto");
|
|
38305
38373
|
var import_fs6 = require("fs");
|
|
38306
38374
|
var import_os5 = require("os");
|
|
38307
38375
|
var import_path6 = require("path");
|
|
@@ -38319,14 +38387,16 @@ var import_path9 = require("path");
|
|
|
38319
38387
|
var import_fs10 = require("fs");
|
|
38320
38388
|
var import_os9 = require("os");
|
|
38321
38389
|
var import_path10 = require("path");
|
|
38322
|
-
var
|
|
38390
|
+
var import_crypto6 = require("crypto");
|
|
38323
38391
|
var import_readline2 = require("readline");
|
|
38324
38392
|
var import_url2 = require("url");
|
|
38325
|
-
var
|
|
38393
|
+
var import_crypto7 = require("crypto");
|
|
38326
38394
|
var import_fs11 = require("fs");
|
|
38327
38395
|
var import_path11 = require("path");
|
|
38328
|
-
var ALAN_RUN_REFERENCE_ENV = "ALAN_RUN_REFERENCE";
|
|
38329
38396
|
var ALAN_MCP_URL_ENV = "ALAN_MCP_URL";
|
|
38397
|
+
function deliversRunReferenceViaEnv(backendKind) {
|
|
38398
|
+
return backendKind === "cursor_agent_cli";
|
|
38399
|
+
}
|
|
38330
38400
|
var ALAN_AGENT_ENTRY_ENV = "ALAN_AGENT_ENTRY";
|
|
38331
38401
|
var ALAN_NODE_EXECUTABLE_ENV = "ALAN_NODE_EXECUTABLE";
|
|
38332
38402
|
function usesProcessLocalManagedMcp(backendKind) {
|
|
@@ -38340,9 +38410,10 @@ function requireManagedRunReference(registration) {
|
|
|
38340
38410
|
if (!reference) throw new Error("Alan MCP run reference is missing");
|
|
38341
38411
|
return reference;
|
|
38342
38412
|
}
|
|
38343
|
-
function managedMcpServerName(registration) {
|
|
38413
|
+
function managedMcpServerName(registration, namespaceScope) {
|
|
38344
38414
|
const reference = requireManagedRunReference(registration);
|
|
38345
|
-
const
|
|
38415
|
+
const fingerprintSource = namespaceScope?.trim() || reference;
|
|
38416
|
+
const fingerprint = (0, import_crypto.createHash)("sha256").update(fingerprintSource).digest("hex").slice(0, 16);
|
|
38346
38417
|
return `alan-run-${fingerprint}`;
|
|
38347
38418
|
}
|
|
38348
38419
|
var MANAGED_MCP_SERVER_PATTERN = /^alan-run-[a-f0-9]{16}$/;
|
|
@@ -41091,6 +41162,65 @@ function createAntigravityCliBackend(command = "agy", defaultArgs = []) {
|
|
|
41091
41162
|
}
|
|
41092
41163
|
};
|
|
41093
41164
|
}
|
|
41165
|
+
function isWorkflowRun(config2) {
|
|
41166
|
+
return Boolean(config2.workflowId || config2.workflowExecutionId);
|
|
41167
|
+
}
|
|
41168
|
+
function selectExternalMcpServers(config2) {
|
|
41169
|
+
const selected = {};
|
|
41170
|
+
const filter = isWorkflowRun(config2) ? createWorkflowToolsFilter(config2.workflowTools) : null;
|
|
41171
|
+
if (filter && !filter.hasFilter) return selected;
|
|
41172
|
+
for (const [name, server] of Object.entries(config2.externalMcpServers ?? {})) {
|
|
41173
|
+
if (!isExternalMcpServerName(name)) continue;
|
|
41174
|
+
if (filter && !filter.isMcpServerAllowed(name)) continue;
|
|
41175
|
+
selected[name] = server;
|
|
41176
|
+
}
|
|
41177
|
+
return selected;
|
|
41178
|
+
}
|
|
41179
|
+
function headerEnvName(server, header) {
|
|
41180
|
+
const fingerprint = (0, import_crypto5.createHash)("sha256").update(`${server}\0${header}`).digest("hex").slice(0, 12).toUpperCase();
|
|
41181
|
+
return `ALAN_MCP_HEADER_${fingerprint}`;
|
|
41182
|
+
}
|
|
41183
|
+
function planExternalMcpDelivery(config2, processEnv) {
|
|
41184
|
+
const verbatim = selectExternalMcpServers(config2);
|
|
41185
|
+
const servers = {};
|
|
41186
|
+
const env = {};
|
|
41187
|
+
for (const [name, server] of Object.entries(verbatim)) {
|
|
41188
|
+
if (server.url && server.type !== "stdio") {
|
|
41189
|
+
const headerEnv = {};
|
|
41190
|
+
for (const [header, value2] of Object.entries(server.headers ?? {})) {
|
|
41191
|
+
if (!isMcpConfigKey(header)) continue;
|
|
41192
|
+
const variable = headerEnvName(name, header);
|
|
41193
|
+
env[variable] = value2;
|
|
41194
|
+
headerEnv[header] = variable;
|
|
41195
|
+
}
|
|
41196
|
+
servers[name] = {
|
|
41197
|
+
type: server.type === "sse" ? "sse" : "http",
|
|
41198
|
+
url: server.url,
|
|
41199
|
+
...Object.keys(headerEnv).length ? { headerEnv } : {}
|
|
41200
|
+
};
|
|
41201
|
+
} else if (server.command) {
|
|
41202
|
+
const envKeys = [];
|
|
41203
|
+
for (const [key, value2] of Object.entries(server.env ?? {})) {
|
|
41204
|
+
if (!isMcpConfigKey(key)) continue;
|
|
41205
|
+
if (key in processEnv || key in env && env[key] !== value2) {
|
|
41206
|
+
console.warn(
|
|
41207
|
+
`[external-mcp] Not forwarding env ${key} for MCP server ${name}: it is already set for this run`
|
|
41208
|
+
);
|
|
41209
|
+
continue;
|
|
41210
|
+
}
|
|
41211
|
+
env[key] = value2;
|
|
41212
|
+
envKeys.push(key);
|
|
41213
|
+
}
|
|
41214
|
+
servers[name] = {
|
|
41215
|
+
type: "stdio",
|
|
41216
|
+
command: server.command,
|
|
41217
|
+
...server.args?.length ? { args: server.args } : {},
|
|
41218
|
+
...envKeys.length ? { envKeys } : {}
|
|
41219
|
+
};
|
|
41220
|
+
}
|
|
41221
|
+
}
|
|
41222
|
+
return { servers, env, verbatim };
|
|
41223
|
+
}
|
|
41094
41224
|
function resolveClaudeHome(env, variant = "claude") {
|
|
41095
41225
|
if (variant === "supatest") {
|
|
41096
41226
|
return (0, import_path6.join)((0, import_os5.homedir)(), ".supatest", "claude-internal");
|
|
@@ -41525,22 +41655,40 @@ function buildClaudeModelArg(baseModel, selectedContextWindow) {
|
|
|
41525
41655
|
if (selectedContextWindow === "1m") return `${baseModel}[1m]`;
|
|
41526
41656
|
return baseModel;
|
|
41527
41657
|
}
|
|
41528
|
-
function buildClaudeManagedMcpArgs(registration,
|
|
41529
|
-
const
|
|
41530
|
-
const
|
|
41531
|
-
|
|
41658
|
+
function buildClaudeManagedMcpArgs(registration, options = {}) {
|
|
41659
|
+
const mcpServers = {};
|
|
41660
|
+
for (const [name, server] of Object.entries(options.externalServers ?? {})) {
|
|
41661
|
+
if (server.type === "stdio") {
|
|
41662
|
+
mcpServers[name] = {
|
|
41663
|
+
type: "stdio",
|
|
41664
|
+
command: server.command,
|
|
41665
|
+
...server.args?.length ? { args: server.args } : {},
|
|
41666
|
+
...server.envKeys?.length ? { env: Object.fromEntries(server.envKeys.map((key) => [key, `\${${key}}`])) } : {}
|
|
41667
|
+
};
|
|
41668
|
+
} else {
|
|
41669
|
+
mcpServers[name] = {
|
|
41670
|
+
type: server.type,
|
|
41671
|
+
url: server.url,
|
|
41672
|
+
...server.headerEnv ? {
|
|
41673
|
+
headers: Object.fromEntries(
|
|
41674
|
+
Object.entries(server.headerEnv).map(([header, variable]) => [
|
|
41675
|
+
header,
|
|
41676
|
+
`\${${variable}}`
|
|
41677
|
+
])
|
|
41678
|
+
)
|
|
41679
|
+
} : {}
|
|
41680
|
+
};
|
|
41681
|
+
}
|
|
41682
|
+
}
|
|
41683
|
+
mcpServers.alan = {
|
|
41684
|
+
type: "http",
|
|
41685
|
+
url: registration.url,
|
|
41686
|
+
headers: { "x-alan-run-reference": `\${${ALAN_RUN_REFERENCE_ENV}}` }
|
|
41687
|
+
};
|
|
41532
41688
|
return [
|
|
41533
|
-
"--strict-mcp-config",
|
|
41689
|
+
...options.strict ? ["--strict-mcp-config"] : [],
|
|
41534
41690
|
"--mcp-config",
|
|
41535
|
-
JSON.stringify({
|
|
41536
|
-
mcpServers: {
|
|
41537
|
-
[managedMcpServerName(registration)]: {
|
|
41538
|
-
type: "stdio",
|
|
41539
|
-
command: node2,
|
|
41540
|
-
args: [entry, "mcp-proxy"]
|
|
41541
|
-
}
|
|
41542
|
-
}
|
|
41543
|
-
})
|
|
41691
|
+
JSON.stringify({ mcpServers })
|
|
41544
41692
|
];
|
|
41545
41693
|
}
|
|
41546
41694
|
function createClaudeCliBackend(command = "claude", defaultArgs = []) {
|
|
@@ -41549,11 +41697,12 @@ function createClaudeCliBackend(command = "claude", defaultArgs = []) {
|
|
|
41549
41697
|
supportTier: "structured",
|
|
41550
41698
|
async run(context) {
|
|
41551
41699
|
const managedRegistration = context.config.alanMcp;
|
|
41700
|
+
const externalMcp = managedRegistration ? planExternalMcpDelivery(context.config, context.env) : void 0;
|
|
41552
41701
|
const runContext = managedRegistration ? {
|
|
41553
41702
|
...context,
|
|
41554
41703
|
env: {
|
|
41555
41704
|
...context.env,
|
|
41556
|
-
|
|
41705
|
+
...externalMcp?.env,
|
|
41557
41706
|
[ALAN_RUN_REFERENCE_ENV]: requireManagedRunReference(managedRegistration)
|
|
41558
41707
|
}
|
|
41559
41708
|
} : context;
|
|
@@ -41567,7 +41716,12 @@ function createClaudeCliBackend(command = "claude", defaultArgs = []) {
|
|
|
41567
41716
|
getClaudePermissionMode(context.config)
|
|
41568
41717
|
];
|
|
41569
41718
|
if (managedRegistration) {
|
|
41570
|
-
args.push(
|
|
41719
|
+
args.push(
|
|
41720
|
+
...buildClaudeManagedMcpArgs(managedRegistration, {
|
|
41721
|
+
strict: isWorkflowRun(context.config),
|
|
41722
|
+
externalServers: externalMcp?.servers
|
|
41723
|
+
})
|
|
41724
|
+
);
|
|
41571
41725
|
}
|
|
41572
41726
|
const disallowedTools = getClaudeDisallowedTools(context.config);
|
|
41573
41727
|
if (disallowedTools.length > 0) {
|
|
@@ -42796,31 +42950,59 @@ function buildCodexEffortArgs(selectedEffortLevel, options) {
|
|
|
42796
42950
|
}
|
|
42797
42951
|
var CODEX_STARTUP_TIMEOUT_MS = 3e5;
|
|
42798
42952
|
var ALAN_MCP_STARTUP_TIMEOUT_SEC = 30;
|
|
42799
|
-
function buildCodexManagedMcpArgs(registration) {
|
|
42800
|
-
const serverName = managedMcpServerName(registration);
|
|
42953
|
+
function buildCodexManagedMcpArgs(registration, options = {}) {
|
|
42801
42954
|
return [
|
|
42802
|
-
|
|
42955
|
+
// Workflow runs keep the exclusive config: their tool set is a policy,
|
|
42956
|
+
// not the user's own server list.
|
|
42957
|
+
...options.strict ? ["--ignore-user-config"] : [],
|
|
42803
42958
|
"-c",
|
|
42804
|
-
`mcp_servers
|
|
42959
|
+
`mcp_servers.alan.url=${JSON.stringify(registration.url)}`,
|
|
42805
42960
|
"-c",
|
|
42806
|
-
`mcp_servers
|
|
42961
|
+
`mcp_servers.alan.env_http_headers.x-alan-run-reference=${JSON.stringify(ALAN_RUN_REFERENCE_ENV)}`,
|
|
42807
42962
|
"-c",
|
|
42808
|
-
|
|
42963
|
+
"mcp_servers.alan.required=true",
|
|
42809
42964
|
"-c",
|
|
42810
|
-
`mcp_servers
|
|
42965
|
+
`mcp_servers.alan.startup_timeout_sec=${ALAN_MCP_STARTUP_TIMEOUT_SEC}`
|
|
42811
42966
|
];
|
|
42812
42967
|
}
|
|
42968
|
+
function buildCodexExternalMcpArgs(servers) {
|
|
42969
|
+
const args = [];
|
|
42970
|
+
for (const [name, server] of Object.entries(servers ?? {})) {
|
|
42971
|
+
const key = `mcp_servers.${name}`;
|
|
42972
|
+
if (server.type === "stdio") {
|
|
42973
|
+
args.push("-c", `${key}.command=${JSON.stringify(server.command)}`);
|
|
42974
|
+
if (server.args?.length) args.push("-c", `${key}.args=${JSON.stringify(server.args)}`);
|
|
42975
|
+
if (server.envKeys?.length) {
|
|
42976
|
+
args.push("-c", `${key}.env_vars=${JSON.stringify(server.envKeys)}`);
|
|
42977
|
+
}
|
|
42978
|
+
} else {
|
|
42979
|
+
if (server.type === "sse") continue;
|
|
42980
|
+
args.push("-c", `${key}.url=${JSON.stringify(server.url)}`);
|
|
42981
|
+
for (const [header, variable] of Object.entries(server.headerEnv ?? {})) {
|
|
42982
|
+
args.push("-c", `${key}.env_http_headers.${header}=${JSON.stringify(variable)}`);
|
|
42983
|
+
}
|
|
42984
|
+
}
|
|
42985
|
+
}
|
|
42986
|
+
return args;
|
|
42987
|
+
}
|
|
42813
42988
|
function createCodexRuntimeBackend(command = "codex", defaultArgs = []) {
|
|
42814
42989
|
return {
|
|
42815
42990
|
kind: "codex_app_server",
|
|
42816
42991
|
supportTier: "structured",
|
|
42817
42992
|
async run(context) {
|
|
42818
42993
|
const managedRegistration = context.config.alanMcp;
|
|
42819
|
-
const
|
|
42994
|
+
const externalMcp = managedRegistration ? planExternalMcpDelivery(context.config, context.env) : void 0;
|
|
42995
|
+
const managedMcpArgs = managedRegistration ? [
|
|
42996
|
+
...buildCodexManagedMcpArgs(managedRegistration, {
|
|
42997
|
+
strict: isWorkflowRun(context.config)
|
|
42998
|
+
}),
|
|
42999
|
+
...buildCodexExternalMcpArgs(externalMcp?.servers)
|
|
43000
|
+
] : [];
|
|
42820
43001
|
const runContext = managedRegistration ? {
|
|
42821
43002
|
...context,
|
|
42822
43003
|
env: {
|
|
42823
43004
|
...context.env,
|
|
43005
|
+
...externalMcp?.env,
|
|
42824
43006
|
[ALAN_RUN_REFERENCE_ENV]: requireManagedRunReference(managedRegistration)
|
|
42825
43007
|
}
|
|
42826
43008
|
} : context;
|
|
@@ -43781,6 +43963,13 @@ function createCursorAgentCliBackend(command = "cursor-agent", defaultArgs = [])
|
|
|
43781
43963
|
context.cwd
|
|
43782
43964
|
);
|
|
43783
43965
|
const approveMcps = context.config.alanMcp ? await cliSupportsFlag(command, "--approve-mcps", context.env) : false;
|
|
43966
|
+
const runContext = context.config.alanMcp ? {
|
|
43967
|
+
...context,
|
|
43968
|
+
env: {
|
|
43969
|
+
...context.env,
|
|
43970
|
+
[ALAN_RUN_REFERENCE_ENV]: requireManagedRunReference(context.config.alanMcp)
|
|
43971
|
+
}
|
|
43972
|
+
} : context;
|
|
43784
43973
|
try {
|
|
43785
43974
|
return await createGenericCliBackend({
|
|
43786
43975
|
kind: "cursor_agent_cli",
|
|
@@ -43858,7 +44047,7 @@ function createCursorAgentCliBackend(command = "cursor-agent", defaultArgs = [])
|
|
|
43858
44047
|
return appendImagePathReferences(prompt, imageFiles);
|
|
43859
44048
|
},
|
|
43860
44049
|
parseStructuredLine: parseCursorStructuredLine
|
|
43861
|
-
}).run(
|
|
44050
|
+
}).run(runContext);
|
|
43862
44051
|
} finally {
|
|
43863
44052
|
cleanup();
|
|
43864
44053
|
}
|
|
@@ -44914,6 +45103,28 @@ function resolveKimiCliModelArg(model) {
|
|
|
44914
45103
|
if (trimmed.startsWith("claude-")) return void 0;
|
|
44915
45104
|
return trimmed;
|
|
44916
45105
|
}
|
|
45106
|
+
function buildKimiMcpConfig(registration, externalServers = {}) {
|
|
45107
|
+
const mcpServers = {};
|
|
45108
|
+
for (const [name, server] of Object.entries(externalServers)) {
|
|
45109
|
+
if (server.url && server.type !== "stdio") {
|
|
45110
|
+
mcpServers[name] = {
|
|
45111
|
+
url: server.url,
|
|
45112
|
+
...server.headers ? { headers: server.headers } : {}
|
|
45113
|
+
};
|
|
45114
|
+
} else if (server.command) {
|
|
45115
|
+
mcpServers[name] = {
|
|
45116
|
+
command: server.command,
|
|
45117
|
+
...server.args?.length ? { args: server.args } : {},
|
|
45118
|
+
...server.env ? { env: server.env } : {}
|
|
45119
|
+
};
|
|
45120
|
+
}
|
|
45121
|
+
}
|
|
45122
|
+
mcpServers[managedMcpServerName(registration)] = {
|
|
45123
|
+
url: registration.url,
|
|
45124
|
+
headers: { "x-alan-run-reference": requireManagedRunReference(registration) }
|
|
45125
|
+
};
|
|
45126
|
+
return { mcpServers };
|
|
45127
|
+
}
|
|
44917
45128
|
function createKimiCliBackend(command = "kimi-cli", defaultArgs = []) {
|
|
44918
45129
|
return {
|
|
44919
45130
|
kind: "kimi_cli",
|
|
@@ -44925,14 +45136,9 @@ function createKimiCliBackend(command = "kimi-cli", defaultArgs = []) {
|
|
|
44925
45136
|
if (registration && mcpConfigPath) {
|
|
44926
45137
|
(0, import_fs9.writeFileSync)(
|
|
44927
45138
|
mcpConfigPath,
|
|
44928
|
-
JSON.stringify(
|
|
44929
|
-
|
|
44930
|
-
|
|
44931
|
-
url: registration.url,
|
|
44932
|
-
headers: { "x-alan-run-reference": requireManagedRunReference(registration) }
|
|
44933
|
-
}
|
|
44934
|
-
}
|
|
44935
|
-
}),
|
|
45139
|
+
JSON.stringify(
|
|
45140
|
+
buildKimiMcpConfig(registration, selectExternalMcpServers(context.config))
|
|
45141
|
+
),
|
|
44936
45142
|
{ mode: 384 }
|
|
44937
45143
|
);
|
|
44938
45144
|
}
|
|
@@ -45459,7 +45665,7 @@ function leaseKeyFor(context) {
|
|
|
45459
45665
|
if (!conversationId) return null;
|
|
45460
45666
|
const runReference = context.config.alanMcp?.headers?.["x-alan-run-reference"];
|
|
45461
45667
|
if (!runReference) return `conv:${conversationId}`;
|
|
45462
|
-
const fingerprint = (0,
|
|
45668
|
+
const fingerprint = (0, import_crypto6.createHash)("sha256").update(runReference).digest("hex").slice(0, 16);
|
|
45463
45669
|
return `conv:${conversationId}|mcp:${fingerprint}`;
|
|
45464
45670
|
}
|
|
45465
45671
|
function isLeaseUsable(lease) {
|
|
@@ -46484,8 +46690,10 @@ var BaseMachineAgent = class _BaseMachineAgent {
|
|
|
46484
46690
|
*/
|
|
46485
46691
|
async beginMcpConfigCriticalSection(backend, context) {
|
|
46486
46692
|
const runHeaders = context.config.alanMcp?.headers;
|
|
46487
|
-
if (!runHeaders || usesProcessLocalManagedMcp(backend.kind)
|
|
46488
|
-
|
|
46693
|
+
if (!runHeaders || usesProcessLocalManagedMcp(backend.kind) || deliversRunReferenceViaEnv(backend.kind)) {
|
|
46694
|
+
return () => {
|
|
46695
|
+
};
|
|
46696
|
+
}
|
|
46489
46697
|
const releaseGate = await acquireMcpConfigWriteGate();
|
|
46490
46698
|
try {
|
|
46491
46699
|
const writtenClis = await syncAlanMcpSessionHeaders({
|
|
@@ -46498,7 +46706,11 @@ var BaseMachineAgent = class _BaseMachineAgent {
|
|
|
46498
46706
|
void this.presenter.onLog(`Synced Alan MCP session headers to ${writtenClis.join(", ")}`);
|
|
46499
46707
|
}
|
|
46500
46708
|
} catch (error61) {
|
|
46501
|
-
|
|
46709
|
+
releaseGate();
|
|
46710
|
+
throw new Error(
|
|
46711
|
+
`Alan could not write this run's MCP credential for ${backend.kind}, so the provider was not started: ${error61 instanceof Error ? error61.message : String(error61)}`,
|
|
46712
|
+
{ cause: error61 }
|
|
46713
|
+
);
|
|
46502
46714
|
}
|
|
46503
46715
|
return releaseGate;
|
|
46504
46716
|
}
|
|
@@ -46993,7 +47205,7 @@ function extractGeneratedImagesFromToolResult(toolId, content, cwd, toolName, op
|
|
|
46993
47205
|
const { width, height } = readImageDimensions2(buffer, mimeType);
|
|
46994
47206
|
images.push({
|
|
46995
47207
|
type: "generated_image",
|
|
46996
|
-
id: (0,
|
|
47208
|
+
id: (0, import_crypto7.randomUUID)(),
|
|
46997
47209
|
filename: (0, import_path11.basename)(path2),
|
|
46998
47210
|
mimeType,
|
|
46999
47211
|
size: buffer.length,
|
|
@@ -47001,7 +47213,7 @@ function extractGeneratedImagesFromToolResult(toolId, content, cwd, toolName, op
|
|
|
47001
47213
|
height,
|
|
47002
47214
|
data: buffer.toString("base64"),
|
|
47003
47215
|
sourcePath: path2,
|
|
47004
|
-
sourceHash: (0,
|
|
47216
|
+
sourceHash: (0, import_crypto7.createHash)("sha256").update(buffer).digest("hex"),
|
|
47005
47217
|
toolId,
|
|
47006
47218
|
ts: Date.now()
|
|
47007
47219
|
});
|
|
@@ -47033,7 +47245,7 @@ function extractSessionMediaFromToolResult(toolId, content, cwd, toolName, optio
|
|
|
47033
47245
|
media.push({
|
|
47034
47246
|
type: "session_media",
|
|
47035
47247
|
kind,
|
|
47036
|
-
id: (0,
|
|
47248
|
+
id: (0, import_crypto7.randomUUID)(),
|
|
47037
47249
|
filename: (0, import_path11.basename)(path2),
|
|
47038
47250
|
mimeType,
|
|
47039
47251
|
size: buffer.length,
|
|
@@ -47041,7 +47253,7 @@ function extractSessionMediaFromToolResult(toolId, content, cwd, toolName, optio
|
|
|
47041
47253
|
height: dimensions?.height,
|
|
47042
47254
|
data: buffer.toString("base64"),
|
|
47043
47255
|
sourcePath: path2,
|
|
47044
|
-
sourceHash: (0,
|
|
47256
|
+
sourceHash: (0, import_crypto7.createHash)("sha256").update(buffer).digest("hex"),
|
|
47045
47257
|
toolId,
|
|
47046
47258
|
ts: Date.now()
|
|
47047
47259
|
});
|
|
@@ -56805,7 +57017,12 @@ async function ensureAlanMcpRegistered(backendKind, registration, home = (0, imp
|
|
|
56805
57017
|
releaseLock();
|
|
56806
57018
|
}
|
|
56807
57019
|
}
|
|
56808
|
-
const fileOk =
|
|
57020
|
+
const fileOk = files.length > 0 && files.every(
|
|
57021
|
+
(file2) => registrationsMatch(
|
|
57022
|
+
readAlanMcpRegistration(file2.path),
|
|
57023
|
+
parseAlanMcpRegistration(file2.path, file2.content) ?? registration
|
|
57024
|
+
)
|
|
57025
|
+
);
|
|
56809
57026
|
if (!fileOk) {
|
|
56810
57027
|
const issue2 = {
|
|
56811
57028
|
code: "mcp_config_repair_required",
|
|
@@ -56979,7 +57196,8 @@ function hasUsableRegistrationCredential(headers) {
|
|
|
56979
57196
|
const normalized = new Map(
|
|
56980
57197
|
Object.entries(headers).map(([name, value2]) => [name.toLowerCase(), value2.trim()])
|
|
56981
57198
|
);
|
|
56982
|
-
|
|
57199
|
+
const reference = normalized.get("x-alan-run-reference") ?? "";
|
|
57200
|
+
return Boolean(reference && !reference.startsWith("${") || normalized.get("authorization"));
|
|
56983
57201
|
}
|
|
56984
57202
|
function readAlanMcpRegistration(path2) {
|
|
56985
57203
|
return parseAlanMcpRegistration(path2, (0, import_node_fs16.readFileSync)(path2, "utf8"));
|
|
@@ -75271,10 +75489,13 @@ async function handleAgentExecute(ctx, payload) {
|
|
|
75271
75489
|
prMeta: payload.prMeta,
|
|
75272
75490
|
conversationId: payload.conversationId,
|
|
75273
75491
|
alanMcp: payload.alanMcp,
|
|
75492
|
+
externalMcpServers: payload.externalMcpServers,
|
|
75274
75493
|
taskId: payload.taskId ?? payload.taskMeta?.id,
|
|
75275
75494
|
teamId: payload.teamId,
|
|
75276
75495
|
currentUser: payload.currentUser,
|
|
75277
75496
|
workflowTools: payload.workflowTools,
|
|
75497
|
+
workflowId: payload.workflowId,
|
|
75498
|
+
workflowExecutionId: payload.workflowExecutionId,
|
|
75278
75499
|
images: payload.images,
|
|
75279
75500
|
files: payload.files,
|
|
75280
75501
|
parsedAttachments: payload.parsedAttachments
|
|
@@ -96809,6 +97030,7 @@ var WSClient = class {
|
|
|
96809
97030
|
providerSessionId: data.providerSessionId,
|
|
96810
97031
|
resumeFallbackContext: data.resumeFallbackContext,
|
|
96811
97032
|
backendKind: data.backendKind,
|
|
97033
|
+
providerApiKey: data.providerApiKey,
|
|
96812
97034
|
agentId: data.agentId,
|
|
96813
97035
|
agentPrompt: data.agentPrompt,
|
|
96814
97036
|
selectedModel: data.selectedModel,
|
|
@@ -96826,7 +97048,10 @@ var WSClient = class {
|
|
|
96826
97048
|
cloudEnvironmentId: data.cloudEnvironmentId,
|
|
96827
97049
|
conversationId: data.conversationId,
|
|
96828
97050
|
teamId: data.teamId,
|
|
96829
|
-
currentUser: data.currentUser
|
|
97051
|
+
currentUser: data.currentUser,
|
|
97052
|
+
terminalContextRefs: data.terminalContextRefs,
|
|
97053
|
+
terminalSnapshots: data.terminalSnapshots,
|
|
97054
|
+
externalMcpServers: data.externalMcpServers
|
|
96830
97055
|
};
|
|
96831
97056
|
const acceptDelivery = () => {
|
|
96832
97057
|
if (data.messageId) this.rememberAcceptedMessageId(data.messageId);
|
|
@@ -96850,6 +97075,9 @@ var WSClient = class {
|
|
|
96850
97075
|
this.socket.on("stop", () => {
|
|
96851
97076
|
callbacks.onStop();
|
|
96852
97077
|
});
|
|
97078
|
+
this.socket.on("agent.abort", (data) => {
|
|
97079
|
+
callbacks.onAbort?.({ runId: data?.runId, reason: data?.reason });
|
|
97080
|
+
});
|
|
96853
97081
|
this.socket.on("tool_response", (data) => {
|
|
96854
97082
|
if (data?.toolId && typeof data.response === "string") {
|
|
96855
97083
|
callbacks.onToolResponse?.(data.toolId, data.response);
|
|
@@ -96907,6 +97135,7 @@ async function runSandbox(config2) {
|
|
|
96907
97135
|
let currentTaskMeta;
|
|
96908
97136
|
let currentPrMeta;
|
|
96909
97137
|
let currentWorkflowTools;
|
|
97138
|
+
let currentExternalMcpServers;
|
|
96910
97139
|
let currentMaxIterations = config2.maxIterations ?? 50;
|
|
96911
97140
|
let currentTaskId = config2.taskId;
|
|
96912
97141
|
let currentConversationId = config2.sessionId;
|
|
@@ -97001,6 +97230,14 @@ async function runSandbox(config2) {
|
|
|
97001
97230
|
lifecycle.info("sandbox_agent_stop_received");
|
|
97002
97231
|
stopActiveAgent();
|
|
97003
97232
|
},
|
|
97233
|
+
onAbort: ({ runId, reason }) => {
|
|
97234
|
+
if (runId && currentRunId && runId !== currentRunId) {
|
|
97235
|
+
lifecycle.info("sandbox_agent_abort_ignored_stale_run", { runId, currentRunId });
|
|
97236
|
+
return;
|
|
97237
|
+
}
|
|
97238
|
+
lifecycle.info("sandbox_agent_abort_received", { runId, reason });
|
|
97239
|
+
stopActiveAgent(reason === "watchdog_timeout" ? "watchdog_timeout" : "user");
|
|
97240
|
+
},
|
|
97004
97241
|
onToolResponse: (toolId, response) => {
|
|
97005
97242
|
if (currentAgent) {
|
|
97006
97243
|
const sent = currentAgent.sendToolResponse(toolId, response);
|
|
@@ -97197,6 +97434,7 @@ async function runSandbox(config2) {
|
|
|
97197
97434
|
resumeFallbackContext,
|
|
97198
97435
|
taskMeta: currentTaskMeta,
|
|
97199
97436
|
prMeta: currentPrMeta,
|
|
97437
|
+
externalMcpServers: currentExternalMcpServers,
|
|
97200
97438
|
taskId: currentTaskId,
|
|
97201
97439
|
conversationId: currentConversationId,
|
|
97202
97440
|
alanMcp: currentAlanMcp,
|
|
@@ -97314,6 +97552,7 @@ async function runSandbox(config2) {
|
|
|
97314
97552
|
activeMode = nextPayload.mode;
|
|
97315
97553
|
}
|
|
97316
97554
|
currentAlanMcp = nextPayload.alanMcp;
|
|
97555
|
+
currentExternalMcpServers = nextPayload.externalMcpServers;
|
|
97317
97556
|
if (nextPayload.taskMeta !== void 0) {
|
|
97318
97557
|
currentTaskMeta = nextPayload.taskMeta;
|
|
97319
97558
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alan-ai-hq/agent-manager",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.93",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Alan agent runtime — cloud sandbox and local daemon (alan-agent CLI)",
|
|
6
6
|
"bin": {
|
|
@@ -26,9 +26,9 @@
|
|
|
26
26
|
"tsup": "^8.5.1",
|
|
27
27
|
"tsx": "^4.19.0",
|
|
28
28
|
"typescript": "~5.9.3",
|
|
29
|
-
"@alan-ai/agent-core": "0.1.0",
|
|
30
29
|
"@alan-ai/sandbox-runtime-spec": "0.1.0",
|
|
31
|
-
"@alan-ai/shared": "0.1.0"
|
|
30
|
+
"@alan-ai/shared": "0.1.0",
|
|
31
|
+
"@alan-ai/agent-core": "0.1.0"
|
|
32
32
|
},
|
|
33
33
|
"scripts": {
|
|
34
34
|
"build": "tsup",
|