@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.
Files changed (2) hide show
  1. package/dist/index.cjs +294 -55
  2. 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: createHash17 } = require("crypto");
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 = createHash17("sha1").update(key + GUID).digest("base64");
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: createHash17 } = require("crypto");
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 = createHash17("sha1").update(key + GUID).digest("base64");
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.91";
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
- { path: `${home}/.cursor/mcp.json`, content: JSON.stringify({ mcpServers }) },
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 import_crypto5 = require("crypto");
38390
+ var import_crypto6 = require("crypto");
38323
38391
  var import_readline2 = require("readline");
38324
38392
  var import_url2 = require("url");
38325
- var import_crypto6 = require("crypto");
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 fingerprint = (0, import_crypto.createHash)("sha256").update(reference).digest("hex").slice(0, 16);
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, env) {
41529
- const entry = env[ALAN_AGENT_ENTRY_ENV]?.trim() || process.argv[1];
41530
- const node2 = env[ALAN_NODE_EXECUTABLE_ENV]?.trim() || process.execPath;
41531
- if (!entry) throw new Error("Cannot resolve the Alan MCP proxy entrypoint");
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
- [ALAN_MCP_URL_ENV]: managedRegistration.url,
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(...buildClaudeManagedMcpArgs(managedRegistration, runContext.env));
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
- "--ignore-user-config",
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.${serverName}.url=${JSON.stringify(registration.url)}`,
42959
+ `mcp_servers.alan.url=${JSON.stringify(registration.url)}`,
42805
42960
  "-c",
42806
- `mcp_servers.${serverName}.env_http_headers.x-alan-run-reference=${JSON.stringify(ALAN_RUN_REFERENCE_ENV)}`,
42961
+ `mcp_servers.alan.env_http_headers.x-alan-run-reference=${JSON.stringify(ALAN_RUN_REFERENCE_ENV)}`,
42807
42962
  "-c",
42808
- `mcp_servers.${serverName}.required=true`,
42963
+ "mcp_servers.alan.required=true",
42809
42964
  "-c",
42810
- `mcp_servers.${serverName}.startup_timeout_sec=${ALAN_MCP_STARTUP_TIMEOUT_SEC}`
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 managedMcpArgs = managedRegistration ? buildCodexManagedMcpArgs(managedRegistration) : [];
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(context);
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
- mcpServers: {
44930
- [managedMcpServerName(registration)]: {
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, import_crypto5.createHash)("sha256").update(runReference).digest("hex").slice(0, 16);
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)) return () => {
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
- console.warn("[base-machine-agent] Failed to sync MCP session headers", error61);
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, import_crypto6.randomUUID)(),
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, import_crypto6.createHash)("sha256").update(buffer).digest("hex"),
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, import_crypto6.randomUUID)(),
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, import_crypto6.createHash)("sha256").update(buffer).digest("hex"),
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 = paths.length > 0 && paths.every((p) => registrationsMatch(readAlanMcpRegistration(p), registration));
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
- return Boolean(normalized.get("x-alan-run-reference") || normalized.get("authorization"));
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.91",
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",