@alan-ai-hq/agent-manager-darwin-arm64 0.1.157 → 0.1.159

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 (3) hide show
  1. package/alan-agent.cjs +421 -191
  2. package/alan-holder.cjs +377 -188
  3. package/package.json +1 -1
package/alan-agent.cjs CHANGED
@@ -23396,6 +23396,7 @@ If a needed tool is not exposed, use the host's tool-discovery mechanism once wh
23396
23396
  Whatever the intent, check your draft before sending: three or more numbers being compared, several items sharing the same attributes, a sequence, or two or more options means it should be visual. Stay in plain text for one-line facts, yes/no answers, clarifying questions, conversation, and short summaries of code you just changed. Lead with one sentence, show one visual (two at most), then stop; the visual carries the detail, so do not repeat it in prose.
23397
23397
  - Examples of plain questions with visual answers: "Which queue should the importer use, BullMQ or SQS?" \u2192 a one-line recommendation, then \`\`\`openui Tabs with a KeyValue of cost, latency and ops effort per option and a Callout with the pick. "Why did last night's deploy fail?" \u2192 a one-sentence cause, then Steps with the failed step and its detail, then Code with the error. "How's the test suite doing?" \u2192 a row of Stat (passed, failed, flaky) and a line \`\`\`chart of failures per day.
23398
23398
  - \`\`\`mermaid renders in chat, documents, plans and artifacts too; \`\`\`openui renders only in your replies in the Alan chat. In Slack or Teams messages, commit messages, pull request bodies and files, use plain Markdown instead.
23399
+ - When you compose a plan, test report, review or document to save as an Alan artifact, use the \`alan-artifact\` skill for its structure and any HTML or interactive block, and \`alan-diagrams\` for its Mermaid diagrams.
23399
23400
  - \`\`\`chart renders in chat, documents, plans and artifacts, and is **strict JSON, nothing else**:
23400
23401
  \`\`\`chart
23401
23402
  { "type": "bar", "title": "Quarterly Revenue", "data": [{ "name": "Q1", "revenue": 4000 }, { "name": "Q2", "revenue": 3000 }] }
@@ -23442,7 +23443,7 @@ Team
23442
23443
  - When a user asks to create a Skill, default to a team-owned Alan platform Skill through \`alan-skill-authoring\`, whether this session runs locally or in a cloud sandbox. Use a repository or filesystem Skill only when the user explicitly requests that scope. Do not infer repository scope from the current checkout or from a procedure that mentions repository files. If repeated work suggests a reusable Skill, offer the platform Skill and its evidence; do not publish it without the approval required by the authoring workflow.
23443
23444
  - Own mistakes. Wrong ID, jumped too fast \u2014 say so and fix it.
23444
23445
  - When writing code, work like a senior engineer: understand the existing design and conventions, make the smallest coherent change that solves the request, and keep related logic together. Reuse an existing abstraction when it fits; remove duplication that the change would otherwise introduce, but do not refactor unrelated code or add speculative abstractions. Keep names, types, error handling, and tests clear enough for the next engineer to maintain. Review the diff for accidental changes before calling the work done.
23445
- - Write for a human reader. Task, subtask and epic descriptions, documents, artifacts and comments are read by people in the app, not parsed by agents. Lead with the outcome in one sentence, then short sections with headings and bullet lists. Spell out internal shorthand, and keep commit hashes, IDs and migration numbers out of sentences \u2014 put them in a trailing "References" list when they matter.
23446
+ - Write for a human reader. Task, subtask and epic descriptions, documents, artifacts and comments are read by people in the app, not parsed by agents. Lead with the outcome in one sentence, then short sections with headings and bullet lists when there is enough to organise. Size it to what is actually known: a task written from someone's request restates that request and never adds repro steps, causes, verification or acceptance criteria nobody stated. Spell out internal shorthand, and keep commit hashes, IDs and migration numbers out of sentences \u2014 put them in a trailing "References" list when they matter.
23446
23447
  ${ALAN_VISUAL_PROMPT}
23447
23448
  - Images you generate or edit appear in the chat automatically, the way ChatGPT shows them. Do not link, embed, or print the generated file's path afterwards, and do not announce "Generated:" or "Edited image:" \u2014 at most one short sentence about the result. Mention a path only when the user asked for the file to be saved into the project.
23448
23449
 
@@ -25871,7 +25872,9 @@ function prepareConversationTurns(transcript, streaming, previousTurns = []) {
25871
25872
  }
25872
25873
  const tail = turn.working.reduce((latest, node2) => !latest || (node2.event.seq ?? node2.event.line) > (latest.event.seq ?? latest.event.line) ? node2 : latest, void 0);
25873
25874
  turn.working = turn.working.filter((node2) => !isThought(node2));
25874
- const final = turn.activity.state === "idle" && (!turn.activity.stopReason || turn.activity.stopReason === "end_turn" || turn.activity.stopReason === "cancelled") && tail?.event.update.sessionUpdate === "agent_message" && hasAnswerContent(tail) ? tail : void 0;
25875
+ const lastStarted = turn.working.at(-1);
25876
+ const answerTail = [tail, lastStarted].find((node2) => node2?.event.update.sessionUpdate === "agent_message" && hasAnswerContent(node2));
25877
+ const final = turn.activity.state === "idle" && (!turn.activity.stopReason || turn.activity.stopReason === "end_turn" || turn.activity.stopReason === "cancelled") ? answerTail : void 0;
25875
25878
  if (final)
25876
25879
  turn.final = final;
25877
25880
  }
@@ -25964,6 +25967,12 @@ var init_event = __esm({
25964
25967
  });
25965
25968
 
25966
25969
  // ../shared/dist/agent/acp/reduce.js
25970
+ function upsertMcpServers(current, reported) {
25971
+ const byName = new Map((current ?? []).map((server) => [server.name, server]));
25972
+ for (const server of reported)
25973
+ byName.set(server.name, server);
25974
+ return [...byName.values()];
25975
+ }
25967
25976
  function emptyTranscript() {
25968
25977
  return { entries: [], state: "idle", notices: [], unknown: [] };
25969
25978
  }
@@ -26120,6 +26129,12 @@ ${update.description}` : update.title,
26120
26129
  state.thinkingTokens = update.estimated;
26121
26130
  return;
26122
26131
  }
26132
+ case "_alan/mcp_servers": {
26133
+ if (!isUpdate(update, "_alan/mcp_servers"))
26134
+ return;
26135
+ state.mcpServers = upsertMcpServers(state.mcpServers, update.servers);
26136
+ return;
26137
+ }
26123
26138
  // Owned by the tool call that references it, but kept so a terminal-aware
26124
26139
  // renderer can still consume the raw update.
26125
26140
  case "terminal_update":
@@ -26135,10 +26150,34 @@ function noticeKind(severity, meta3) {
26135
26150
  const kind = meta3?.["alan.dev/noticeKind"];
26136
26151
  return typeof kind === "string" ? kind : severity;
26137
26152
  }
26153
+ function isTextBlock(block2) {
26154
+ return block2.type === "text";
26155
+ }
26156
+ function restatesDispatchFailure(state, update) {
26157
+ if (!isUpdate(update, "agent_message"))
26158
+ return false;
26159
+ if (!update.messageId.endsWith(IMPORTED_CONTENT_SUFFIX))
26160
+ return false;
26161
+ const blocks = Array.isArray(update.content) ? update.content : [];
26162
+ if (blocks.length === 0 || !blocks.every(isTextBlock))
26163
+ return false;
26164
+ const text3 = blocks.map((block2) => block2.text).join("").trim();
26165
+ if (!text3)
26166
+ return false;
26167
+ const index = state.notices.findIndex((notice3) => notice3.kind === "application_problem" && notice3.message.trim() === text3);
26168
+ if (index < 0)
26169
+ return false;
26170
+ const notice2 = state.notices[index];
26171
+ if (notice2.level !== "error")
26172
+ state.notices[index] = { ...notice2, level: "error" };
26173
+ return true;
26174
+ }
26138
26175
  function applyContent(state, index, update) {
26139
26176
  const role = ROLE_BY_KIND[update.sessionUpdate];
26140
26177
  if (!role)
26141
26178
  return;
26179
+ if (restatesDispatchFailure(state, update))
26180
+ return;
26142
26181
  const key = `m:${role}:${update.messageId}`;
26143
26182
  let entry = index.get(key);
26144
26183
  if (!entry) {
@@ -26228,7 +26267,7 @@ function applyTool(state, index, update) {
26228
26267
  function messageText2(entry) {
26229
26268
  return entry.content.filter((b) => b.type === "text").map((b) => b.text).join("");
26230
26269
  }
26231
- var ROLE_BY_KIND, entryIndexes, AWAITING_TOOL_CALLS_META, SETTLED;
26270
+ var ROLE_BY_KIND, entryIndexes, AWAITING_TOOL_CALLS_META, IMPORTED_CONTENT_SUFFIX, SETTLED;
26232
26271
  var init_reduce = __esm({
26233
26272
  "../shared/dist/agent/acp/reduce.js"() {
26234
26273
  "use strict";
@@ -26244,6 +26283,7 @@ var init_reduce = __esm({
26244
26283
  };
26245
26284
  entryIndexes = /* @__PURE__ */ new WeakMap();
26246
26285
  AWAITING_TOOL_CALLS_META = "alan.dev/awaitingToolCallIds";
26286
+ IMPORTED_CONTENT_SUFFIX = ":content";
26247
26287
  SETTLED = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
26248
26288
  }
26249
26289
  });
@@ -26735,6 +26775,13 @@ var init_read = __esm({
26735
26775
  }
26736
26776
  });
26737
26777
 
26778
+ // ../shared/dist/agent/acp/session-activity.js
26779
+ var init_session_activity = __esm({
26780
+ "../shared/dist/agent/acp/session-activity.js"() {
26781
+ "use strict";
26782
+ }
26783
+ });
26784
+
26738
26785
  // ../shared/dist/agent/acp/transcript-byte-decoder.js
26739
26786
  var init_transcript_byte_decoder = __esm({
26740
26787
  "../shared/dist/agent/acp/transcript-byte-decoder.js"() {
@@ -26898,6 +26945,8 @@ function mergeTranscriptMessages(messages, cache2) {
26898
26945
  merged.usage = state.usage;
26899
26946
  if (state.title)
26900
26947
  merged.title = state.title;
26948
+ if (state.mcpServers)
26949
+ merged.mcpServers = upsertMcpServers(merged.mcpServers, state.mcpServers);
26901
26950
  updateOffset += state.updateCount ?? 0;
26902
26951
  }
26903
26952
  merged.updateCount = updateOffset;
@@ -26929,6 +26978,7 @@ var init_acp = __esm({
26929
26978
  init_types3();
26930
26979
  init_read();
26931
26980
  init_reduce();
26981
+ init_session_activity();
26932
26982
  init_transcript_byte_decoder();
26933
26983
  init_transcript_fold();
26934
26984
  init_transcript_http();
@@ -27987,7 +28037,7 @@ var init_chunk_ZCTKXKYY = __esm({
27987
28037
  }
27988
28038
  });
27989
28039
 
27990
- // ../agent-core/dist/chunk-ILZBXGVI.js
28040
+ // ../agent-core/dist/chunk-FYZKVT3E.js
27991
28041
  function detectImageMimeType(buffer) {
27992
28042
  if (buffer.length >= 8 && buffer.subarray(0, 8).equals(PNG_SIGNATURE)) return "image/png";
27993
28043
  if (buffer.length >= 3 && buffer[0] === 255 && buffer[1] === 216 && buffer[2] === 255) {
@@ -28084,21 +28134,38 @@ function imageDimensions(buffer, mimeType) {
28084
28134
  if (mimeType === "image/jpeg") return jpegDimensions(buffer);
28085
28135
  return { width: null, height: null };
28086
28136
  }
28087
- function readMediaFiles(candidates2, cwd, mimeByExt, maxBytes) {
28137
+ function readMediaFiles(query) {
28088
28138
  const seen = /* @__PURE__ */ new Set();
28089
28139
  const files = [];
28090
- for (const candidate of candidates2) {
28091
- const path4 = normalizePath(candidate, cwd);
28140
+ for (const candidate of query.candidates) {
28141
+ const path4 = normalizePath(candidate, query.cwd);
28092
28142
  if (!path4 || seen.has(path4) || !(0, import_fs5.existsSync)(path4)) continue;
28093
28143
  seen.add(path4);
28094
- const mimeType = mimeByExt[(0, import_path4.extname)(path4).toLowerCase()];
28144
+ const mimeType = query.mimeByExt[(0, import_path4.extname)(path4).toLowerCase()];
28095
28145
  if (!mimeType) continue;
28096
28146
  const stat22 = (0, import_fs5.statSync)(path4);
28097
- if (!stat22.isFile() || stat22.size <= 0 || stat22.size > maxBytes) continue;
28147
+ if (!stat22.isFile() || stat22.size <= 0 || stat22.size > query.maxBytes) continue;
28148
+ if (stat22.mtimeMs < query.writtenSince && !query.named.has(path4)) continue;
28098
28149
  files.push({ path: path4, mimeType, buffer: (0, import_fs5.readFileSync)(path4) });
28099
28150
  }
28100
28151
  return files;
28101
28152
  }
28153
+ function isCaptureTool(tool) {
28154
+ return isBrowserScreenshotToolName(tool.name) || isBrowserRecordingToolName(tool.name);
28155
+ }
28156
+ function runsCaptureCommand(tool) {
28157
+ return someString(tool.input, (text3) => AGENT_BROWSER_CAPTURE_COMMAND.test(text3));
28158
+ }
28159
+ function capturePaths(tool, content, extensions, cwd) {
28160
+ const values = isCaptureTool(tool) ? contentStrings(content, tool.input) : runsCaptureCommand(tool) ? contentStrings("", tool.input) : [];
28161
+ return pathCandidates(values, extensions).flatMap((candidate) => {
28162
+ const path4 = normalizePath(candidate, cwd);
28163
+ return path4 ? [path4] : [];
28164
+ });
28165
+ }
28166
+ function base64Length(bytes) {
28167
+ return Math.ceil(bytes / 3) * 4;
28168
+ }
28102
28169
  function resultText2(update) {
28103
28170
  const only2 = isJsonRecord(update._meta) ? update._meta[TOOL_RESULT_ONLY_META] : void 0;
28104
28171
  if (typeof only2 === "string") return only2;
@@ -28389,9 +28456,9 @@ function silentStartError(name, timeoutMs) {
28389
28456
  message: `${name} printed nothing for ${seconds}s after it started and was stopped. Send your message again.`
28390
28457
  };
28391
28458
  }
28392
- var import_crypto4, import_fs5, import_path4, PNG_SIGNATURE, IMAGE_MIME_BY_EXT, VIDEO_MIME_BY_EXT, IMAGE_EXTENSIONS, VIDEO_EXTENSIONS, MAX_IMAGE_BYTES, MAX_VIDEO_BYTES, AGENT_BROWSER_MENTION, LocalMediaReader, SessionOpenRefusal, JsonRpcError, ACP_PROTOCOL_VERSION, ACP_ERROR, STDERR_TAIL_LINES, RESULT_EXIT_GRACE_MS, PerTurnSession;
28393
- var init_chunk_ILZBXGVI = __esm({
28394
- "../agent-core/dist/chunk-ILZBXGVI.js"() {
28459
+ var import_crypto4, import_fs5, import_path4, PNG_SIGNATURE, IMAGE_MIME_BY_EXT, VIDEO_MIME_BY_EXT, IMAGE_EXTENSIONS, VIDEO_EXTENSIONS, MAX_IMAGE_BYTES, MAX_VIDEO_BYTES, MAX_TURN_MEDIA_DATA_CHARS, MTIME_SLACK_MS, AGENT_BROWSER_MENTION, AGENT_BROWSER_CAPTURE_COMMAND, LocalMediaReader, SessionOpenRefusal, JsonRpcError, ACP_PROTOCOL_VERSION, ACP_ERROR, STDERR_TAIL_LINES, RESULT_EXIT_GRACE_MS, PerTurnSession;
28460
+ var init_chunk_FYZKVT3E = __esm({
28461
+ "../agent-core/dist/chunk-FYZKVT3E.js"() {
28395
28462
  "use strict";
28396
28463
  init_chunk_OUEMTEUX();
28397
28464
  init_chunk_ZCTKXKYY();
@@ -28419,12 +28486,16 @@ var init_chunk_ILZBXGVI = __esm({
28419
28486
  VIDEO_EXTENSIONS = "mp4|webm|mov";
28420
28487
  MAX_IMAGE_BYTES = 20 * 1024 * 1024;
28421
28488
  MAX_VIDEO_BYTES = 100 * 1024 * 1024;
28489
+ MAX_TURN_MEDIA_DATA_CHARS = 8 * 1024 * 1024;
28490
+ MTIME_SLACK_MS = 2e3;
28422
28491
  AGENT_BROWSER_MENTION = /agent[-_]browser/i;
28492
+ AGENT_BROWSER_CAPTURE_COMMAND = /(?:^|[\s/])agent[-_]browser(?:@[^\s;&|]+)?(?:\s[^\n;&|]*?)?\s(?:screenshot|record)(?=\s|$)/im;
28423
28493
  LocalMediaReader = class {
28424
28494
  #cwd;
28425
28495
  #clock;
28426
28496
  #tools = /* @__PURE__ */ new Map();
28427
28497
  #pathHints = /* @__PURE__ */ new Set();
28498
+ #mediaDataChars = 0;
28428
28499
  constructor(cwd, clock) {
28429
28500
  this.#cwd = cwd;
28430
28501
  this.#clock = clock;
@@ -28449,7 +28520,11 @@ var init_chunk_ILZBXGVI = __esm({
28449
28520
  /** A recording names its output file when it starts; the stop's result may not repeat it. */
28450
28521
  #announce(toolCallId, name, input2) {
28451
28522
  const known = this.#tools.get(toolCallId);
28452
- const tool = { name: name ?? known?.name ?? "", input: input2 ?? known?.input };
28523
+ const tool = {
28524
+ name: name ?? known?.name ?? "",
28525
+ input: input2 ?? known?.input,
28526
+ startedAt: known?.startedAt ?? this.#clock.now()
28527
+ };
28453
28528
  this.#tools.set(toolCallId, tool);
28454
28529
  if (!isAgentBrowserMedia(tool, "", "video")) return;
28455
28530
  const cwd = toolCwd(this.#cwd, tool.input);
@@ -28458,13 +28533,30 @@ var init_chunk_ILZBXGVI = __esm({
28458
28533
  if (path4) this.#pathHints.add(path4);
28459
28534
  }
28460
28535
  }
28461
- #payloadFields(file2, toolId) {
28536
+ /** Media written before the call started is old, unless its capture command named it. */
28537
+ #toolFiles(tool, content, extensions, limits) {
28538
+ const cwd = toolCwd(this.#cwd, tool.input);
28539
+ return readMediaFiles({
28540
+ ...limits,
28541
+ candidates: [
28542
+ ...pathCandidates(contentStrings(content, tool.input), extensions),
28543
+ ...this.#pathHints
28544
+ ],
28545
+ cwd,
28546
+ writtenSince: tool.startedAt - MTIME_SLACK_MS,
28547
+ named: /* @__PURE__ */ new Set([...capturePaths(tool, content, extensions, cwd), ...this.#pathHints])
28548
+ });
28549
+ }
28550
+ #payloadFields(file2, toolId, explicit) {
28551
+ const dataChars = base64Length(file2.buffer.length);
28552
+ const inline = explicit || this.#mediaDataChars + dataChars <= MAX_TURN_MEDIA_DATA_CHARS;
28553
+ if (inline) this.#mediaDataChars += dataChars;
28462
28554
  return {
28463
28555
  id: (0, import_crypto4.randomUUID)(),
28464
28556
  filename: (0, import_path4.basename)(file2.path),
28465
28557
  mimeType: file2.mimeType,
28466
28558
  size: file2.buffer.length,
28467
- data: file2.buffer.toString("base64"),
28559
+ ...inline ? { data: file2.buffer.toString("base64") } : { inlineDataOmitted: true },
28468
28560
  sourcePath: file2.path,
28469
28561
  sourceHash: (0, import_crypto4.createHash)("sha256").update(file2.buffer).digest("hex"),
28470
28562
  toolId,
@@ -28473,15 +28565,14 @@ var init_chunk_ILZBXGVI = __esm({
28473
28565
  }
28474
28566
  #generatedImages(toolId, tool, content) {
28475
28567
  if (!isGeneratedImageToolName(tool.name)) return [];
28476
- const candidates2 = [
28477
- ...pathCandidates(contentStrings(content, tool.input), IMAGE_EXTENSIONS),
28478
- ...this.#pathHints
28479
- ];
28480
- const cwd = toolCwd(this.#cwd, tool.input);
28481
- return readMediaFiles(candidates2, cwd, IMAGE_MIME_BY_EXT, MAX_IMAGE_BYTES).map((file2) => {
28568
+ const files = this.#toolFiles(tool, content, IMAGE_EXTENSIONS, {
28569
+ mimeByExt: IMAGE_MIME_BY_EXT,
28570
+ maxBytes: MAX_IMAGE_BYTES
28571
+ });
28572
+ return files.map((file2) => {
28482
28573
  const image = {
28483
28574
  type: "generated_image",
28484
- ...this.#payloadFields(file2, toolId),
28575
+ ...this.#payloadFields(file2, toolId, true),
28485
28576
  ...imageDimensions(file2.buffer, file2.mimeType)
28486
28577
  };
28487
28578
  return { sessionUpdate: "_alan/generated_image", image };
@@ -28491,25 +28582,19 @@ var init_chunk_ILZBXGVI = __esm({
28491
28582
  const isVideo = isAgentBrowserMedia(tool, content, "video");
28492
28583
  if (!isVideo && !isAgentBrowserMedia(tool, content, "image")) return [];
28493
28584
  const kind = isVideo ? "video" : "image";
28494
- const candidates2 = [
28495
- ...pathCandidates(
28496
- contentStrings(content, tool.input),
28497
- isVideo ? VIDEO_EXTENSIONS : IMAGE_EXTENSIONS
28498
- ),
28499
- ...this.#pathHints
28500
- ];
28501
- const files = readMediaFiles(
28502
- candidates2,
28503
- toolCwd(this.#cwd, tool.input),
28504
- isVideo ? VIDEO_MIME_BY_EXT : IMAGE_MIME_BY_EXT,
28505
- isVideo ? MAX_VIDEO_BYTES : MAX_IMAGE_BYTES
28585
+ const explicit = isCaptureTool(tool) || runsCaptureCommand(tool);
28586
+ const files = this.#toolFiles(
28587
+ tool,
28588
+ content,
28589
+ isVideo ? VIDEO_EXTENSIONS : IMAGE_EXTENSIONS,
28590
+ isVideo ? { mimeByExt: VIDEO_MIME_BY_EXT, maxBytes: MAX_VIDEO_BYTES } : { mimeByExt: IMAGE_MIME_BY_EXT, maxBytes: MAX_IMAGE_BYTES }
28506
28591
  );
28507
28592
  return files.map((file2) => {
28508
28593
  this.#pathHints.delete(file2.path);
28509
28594
  const media = {
28510
28595
  type: "session_media",
28511
28596
  kind,
28512
- ...this.#payloadFields(file2, toolId),
28597
+ ...this.#payloadFields(file2, toolId, explicit),
28513
28598
  ...kind === "image" ? imageDimensions(file2.buffer, file2.mimeType) : {}
28514
28599
  };
28515
28600
  return { sessionUpdate: "_alan/session_media", media };
@@ -28741,128 +28826,6 @@ var init_chunk_ILZBXGVI = __esm({
28741
28826
  }
28742
28827
  });
28743
28828
 
28744
- // ../agent-core/dist/chunk-J2KTV5FP.js
28745
- function selectExternalMcpServers(spec) {
28746
- const isWorkflow = Boolean(spec.workflowId || spec.workflowExecutionId);
28747
- const filter = isWorkflow ? createWorkflowToolsFilter(spec.workflowTools) : null;
28748
- if (filter && !filter.hasFilter) return {};
28749
- const selected = {};
28750
- for (const [name, server] of Object.entries(spec.externalMcpServers ?? {})) {
28751
- if (!isExternalMcpServerName(name)) continue;
28752
- if (filter && !filter.isMcpServerAllowed(name)) continue;
28753
- selected[name] = server;
28754
- }
28755
- return selected;
28756
- }
28757
- function headerEnvName(server, header) {
28758
- const fingerprint = (0, import_crypto5.createHash)("sha256").update(`${server}\0${header}`).digest("hex").slice(0, 12);
28759
- return `ALAN_MCP_HEADER_${fingerprint.toUpperCase()}`;
28760
- }
28761
- function deliverRemote(name, server, env) {
28762
- const headerEnv = {};
28763
- for (const [header, value2] of Object.entries(server.headers ?? {})) {
28764
- if (!isMcpConfigKey(header)) continue;
28765
- const variable = headerEnvName(name, header);
28766
- env[variable] = value2;
28767
- headerEnv[header] = variable;
28768
- }
28769
- return {
28770
- type: server.type === "sse" ? "sse" : "http",
28771
- url: server.url,
28772
- ...Object.keys(headerEnv).length ? { headerEnv } : {}
28773
- };
28774
- }
28775
- function deliverStdio(server, cliEnv, delivery) {
28776
- const envKeys = [];
28777
- for (const [key, value2] of Object.entries(server.env ?? {})) {
28778
- if (!isMcpConfigKey(key)) continue;
28779
- if (key in cliEnv || key in delivery.env && delivery.env[key] !== value2) {
28780
- delivery.skippedEnvKeys.push(key);
28781
- continue;
28782
- }
28783
- delivery.env[key] = value2;
28784
- envKeys.push(key);
28785
- }
28786
- return {
28787
- type: "stdio",
28788
- command: server.command,
28789
- ...server.args?.length ? { args: server.args } : {},
28790
- ...envKeys.length ? { envKeys } : {}
28791
- };
28792
- }
28793
- function planExternalMcpDelivery(spec, cliEnv) {
28794
- const delivery = { servers: {}, env: {}, skippedEnvKeys: [] };
28795
- for (const [name, server] of Object.entries(selectExternalMcpServers(spec))) {
28796
- const { url: url3, command } = server;
28797
- if (url3 && server.type !== "stdio") {
28798
- delivery.servers[name] = deliverRemote(name, { ...server, url: url3 }, delivery.env);
28799
- } else if (command) {
28800
- delivery.servers[name] = deliverStdio({ ...server, command }, cliEnv, delivery);
28801
- }
28802
- }
28803
- return delivery;
28804
- }
28805
- function envReference(name) {
28806
- return `\${${name}}`;
28807
- }
28808
- function managedMcpHeaders(identity) {
28809
- if (identity.scope === "run") {
28810
- return {
28811
- Authorization: envReference(ALAN_MCP_AUTHORIZATION_ENV),
28812
- [MANAGED_MCP_RUN_HEADER]: envReference(ALAN_RUN_ID_ENV)
28813
- };
28814
- }
28815
- return {
28816
- ...identity.authorization === void 0 ? {} : { Authorization: identity.authorization },
28817
- [MANAGED_MCP_CONVERSATION_HEADER]: identity.conversationId
28818
- };
28819
- }
28820
- function credentialDigest(authorization) {
28821
- if (authorization === void 0) return void 0;
28822
- return (0, import_crypto6.createHash)("sha256").update(authorization).digest("hex").slice(0, 16);
28823
- }
28824
- function canonicalizeManagedMcpServerName(serverName) {
28825
- return RUN_SCOPED_SERVER.test(serverName) ? MANAGED_MCP_SERVER_NAME : serverName;
28826
- }
28827
- function canonicalizeManagedMcpToolName(toolName2) {
28828
- const namespaced = NAMESPACED_RUN_TOOL.exec(toolName2);
28829
- if (namespaced) return `mcp__${MANAGED_MCP_SERVER_NAME}__${namespaced[2]}`;
28830
- const flattened = FLATTENED_RUN_TOOL.exec(toolName2);
28831
- return flattened ? `mcp__${MANAGED_MCP_SERVER_NAME}__${flattened[1]}` : toolName2;
28832
- }
28833
- async function writeSecretFile(name, contents) {
28834
- const dir = await (0, import_promises30.mkdtemp)((0, import_path5.join)((0, import_os2.tmpdir)(), "alan-mcp-"));
28835
- const path4 = (0, import_path5.join)(dir, name);
28836
- const remove = async () => {
28837
- await (0, import_promises30.rm)(dir, { recursive: true, force: true });
28838
- };
28839
- try {
28840
- await (0, import_promises30.writeFile)(path4, contents, { mode: 384, flag: "wx" });
28841
- } catch (error62) {
28842
- await remove();
28843
- throw error62;
28844
- }
28845
- return { path: path4, remove, [Symbol.asyncDispose]: remove };
28846
- }
28847
- var import_crypto5, import_crypto6, import_promises30, import_os2, import_path5, MANAGED_MCP_SERVER_NAME, RUN_SCOPED_SERVER, NAMESPACED_RUN_TOOL, FLATTENED_RUN_TOOL;
28848
- var init_chunk_J2KTV5FP = __esm({
28849
- "../agent-core/dist/chunk-J2KTV5FP.js"() {
28850
- "use strict";
28851
- import_crypto5 = require("crypto");
28852
- init_agent2();
28853
- import_crypto6 = require("crypto");
28854
- init_agent2();
28855
- init_runtime_v2();
28856
- import_promises30 = require("fs/promises");
28857
- import_os2 = require("os");
28858
- import_path5 = require("path");
28859
- MANAGED_MCP_SERVER_NAME = "alan";
28860
- RUN_SCOPED_SERVER = /^alan-run-[a-f0-9]{16}$/;
28861
- NAMESPACED_RUN_TOOL = /^mcp__(alan-run-[a-f0-9]{16})__(.+)$/;
28862
- FLATTENED_RUN_TOOL = /^alan-run-[a-f0-9]{16}_(.+)$/;
28863
- }
28864
- });
28865
-
28866
28829
  // ../agent-core/dist/chunk-DLVRNIY5.js
28867
28830
  function repositories(input2, context) {
28868
28831
  const problems = new Map(input2.problems.map((problem) => [problem.path, problem]));
@@ -29673,6 +29636,131 @@ var init_chunk_DLVRNIY5 = __esm({
29673
29636
  }
29674
29637
  });
29675
29638
 
29639
+ // ../agent-core/dist/chunk-OSECDZA5.js
29640
+ function selectExternalMcpServers(spec) {
29641
+ const isWorkflow = Boolean(spec.workflowId || spec.workflowExecutionId);
29642
+ const filter = isWorkflow ? createWorkflowToolsFilter(spec.workflowTools) : null;
29643
+ if (filter && !filter.hasFilter) return {};
29644
+ const selected = {};
29645
+ for (const [name, server] of Object.entries(spec.externalMcpServers ?? {})) {
29646
+ if (!isExternalMcpServerName(name)) continue;
29647
+ if (filter && !filter.isMcpServerAllowed(name)) continue;
29648
+ selected[name] = server;
29649
+ }
29650
+ return selected;
29651
+ }
29652
+ function headerEnvName(server, header) {
29653
+ const fingerprint = (0, import_crypto5.createHash)("sha256").update(`${server}\0${header}`).digest("hex").slice(0, 12);
29654
+ return `ALAN_MCP_HEADER_${fingerprint.toUpperCase()}`;
29655
+ }
29656
+ function deliverRemote(name, server, env) {
29657
+ const headerEnv = {};
29658
+ for (const [header, value2] of Object.entries(server.headers ?? {})) {
29659
+ if (!isMcpConfigKey(header)) continue;
29660
+ const variable = headerEnvName(name, header);
29661
+ env[variable] = value2;
29662
+ headerEnv[header] = variable;
29663
+ }
29664
+ return {
29665
+ type: server.type === "sse" ? "sse" : "http",
29666
+ url: server.url,
29667
+ ...Object.keys(headerEnv).length ? { headerEnv } : {}
29668
+ };
29669
+ }
29670
+ function deliverStdio(server, cliEnv, delivery) {
29671
+ const envKeys = [];
29672
+ for (const [key, value2] of Object.entries(server.env ?? {})) {
29673
+ if (!isMcpConfigKey(key)) continue;
29674
+ if (key in cliEnv || key in delivery.env && delivery.env[key] !== value2) {
29675
+ delivery.skippedEnvKeys.push(key);
29676
+ continue;
29677
+ }
29678
+ delivery.env[key] = value2;
29679
+ envKeys.push(key);
29680
+ }
29681
+ return {
29682
+ type: "stdio",
29683
+ command: server.command,
29684
+ ...server.args?.length ? { args: server.args } : {},
29685
+ ...envKeys.length ? { envKeys } : {}
29686
+ };
29687
+ }
29688
+ function planExternalMcpDelivery(spec, cliEnv) {
29689
+ const delivery = { servers: {}, env: {}, skippedEnvKeys: [] };
29690
+ for (const [name, server] of Object.entries(selectExternalMcpServers(spec))) {
29691
+ const { url: url3, command } = server;
29692
+ if (url3 && server.type !== "stdio") {
29693
+ delivery.servers[name] = deliverRemote(name, { ...server, url: url3 }, delivery.env);
29694
+ } else if (command) {
29695
+ delivery.servers[name] = deliverStdio({ ...server, command }, cliEnv, delivery);
29696
+ }
29697
+ }
29698
+ return delivery;
29699
+ }
29700
+ function envReference(name) {
29701
+ return `\${${name}}`;
29702
+ }
29703
+ function managedMcpHeaders(identity) {
29704
+ if (identity.scope === "run") {
29705
+ return {
29706
+ Authorization: envReference(ALAN_MCP_AUTHORIZATION_ENV),
29707
+ [MANAGED_MCP_RUN_HEADER]: envReference(ALAN_RUN_ID_ENV)
29708
+ };
29709
+ }
29710
+ return {
29711
+ ...identity.authorization === void 0 ? {} : { Authorization: identity.authorization },
29712
+ [MANAGED_MCP_CONVERSATION_HEADER]: identity.conversationId
29713
+ };
29714
+ }
29715
+ function credentialDigest(authorization) {
29716
+ if (authorization === void 0) return void 0;
29717
+ return (0, import_crypto6.createHash)("sha256").update(authorization).digest("hex").slice(0, 16);
29718
+ }
29719
+ function canonicalizeManagedMcpServerName(serverName) {
29720
+ return RUN_SCOPED_SERVER.test(serverName) ? MANAGED_MCP_SERVER_NAME : serverName;
29721
+ }
29722
+ function canonicalizeManagedMcpToolName(toolName2) {
29723
+ const namespaced = NAMESPACED_RUN_TOOL.exec(toolName2);
29724
+ if (namespaced) return `mcp__${MANAGED_MCP_SERVER_NAME}__${namespaced[2]}`;
29725
+ const flattened = FLATTENED_RUN_TOOL.exec(toolName2);
29726
+ return flattened ? `mcp__${MANAGED_MCP_SERVER_NAME}__${flattened[1]}` : toolName2;
29727
+ }
29728
+ async function writeSecretFile(name, contents) {
29729
+ const dir = await (0, import_promises30.mkdtemp)((0, import_path5.join)((0, import_os2.tmpdir)(), "alan-mcp-"));
29730
+ const path4 = (0, import_path5.join)(dir, name);
29731
+ const remove = async () => {
29732
+ await (0, import_promises30.rm)(dir, { recursive: true, force: true });
29733
+ };
29734
+ try {
29735
+ await (0, import_promises30.writeFile)(path4, contents, { mode: 384, flag: "wx" });
29736
+ } catch (error62) {
29737
+ await remove();
29738
+ throw error62;
29739
+ }
29740
+ return { path: path4, remove, [Symbol.asyncDispose]: remove };
29741
+ }
29742
+ var import_crypto5, import_crypto6, import_promises30, import_os2, import_path5, OPENCODE_CODE_MODE_ENV, OPENCODE_CODE_MODE_TOOL, CODE_MODE_CALLS_META, MANAGED_MCP_SERVER_NAME, RUN_SCOPED_SERVER, NAMESPACED_RUN_TOOL, FLATTENED_RUN_TOOL;
29743
+ var init_chunk_OSECDZA5 = __esm({
29744
+ "../agent-core/dist/chunk-OSECDZA5.js"() {
29745
+ "use strict";
29746
+ import_crypto5 = require("crypto");
29747
+ init_agent2();
29748
+ import_crypto6 = require("crypto");
29749
+ init_agent2();
29750
+ init_runtime_v2();
29751
+ import_promises30 = require("fs/promises");
29752
+ import_os2 = require("os");
29753
+ import_path5 = require("path");
29754
+ OPENCODE_CODE_MODE_ENV = "OPENCODE_EXPERIMENTAL_CODE_MODE";
29755
+ OPENCODE_CODE_MODE_TOOL = "execute";
29756
+ CODE_MODE_CALLS_META = "alanToolCalls";
29757
+ MANAGED_MCP_SERVER_NAME = "alan";
29758
+ RUN_SCOPED_SERVER = /^alan-run-[a-f0-9]{16}$/;
29759
+ NAMESPACED_RUN_TOOL = /^mcp__(alan-run-[a-f0-9]{16})__(.+)$/;
29760
+ FLATTENED_RUN_TOOL = /^alan-run-[a-f0-9]{16}_(.+)$/;
29761
+ }
29762
+ });
29763
+
29676
29764
  // ../agent-core/dist/providers/claude.js
29677
29765
  function trimmed(value2) {
29678
29766
  const text22 = value2?.trim();
@@ -29704,16 +29792,16 @@ function externalServerConfig(server) {
29704
29792
  };
29705
29793
  }
29706
29794
  function claudeMcpConfig(mcp) {
29707
- const mcpServers = /* @__PURE__ */ Object.create(null);
29795
+ const mcpServers2 = /* @__PURE__ */ Object.create(null);
29708
29796
  for (const [name, server] of Object.entries(mcp.externalServers ?? {})) {
29709
- mcpServers[name] = externalServerConfig(server);
29797
+ mcpServers2[name] = externalServerConfig(server);
29710
29798
  }
29711
- mcpServers.alan = {
29799
+ mcpServers2.alan = {
29712
29800
  type: "http",
29713
29801
  url: mcp.alanMcpUrl,
29714
29802
  headers: managedMcpHeaders(mcp.identity)
29715
29803
  };
29716
- return { mcpServers };
29804
+ return { mcpServers: mcpServers2 };
29717
29805
  }
29718
29806
  function carriesCredential(mcp) {
29719
29807
  return mcp.identity.scope === "conversation" && mcp.identity.authorization !== void 0;
@@ -29938,11 +30026,27 @@ function parseStreamEvent(event, state) {
29938
30026
  function stringList(value2) {
29939
30027
  return asArray(value2).map((item) => asString(item)).filter(Boolean);
29940
30028
  }
30029
+ function mcpServers(value2) {
30030
+ const servers = [];
30031
+ for (const item of asArray(value2)) {
30032
+ const record2 = asRecord(item);
30033
+ const name = asString(record2?.name);
30034
+ if (!record2 || !name) continue;
30035
+ const source = asString(record2.source);
30036
+ servers.push({
30037
+ name,
30038
+ status: CLAUDE_MCP_STATUS[asString(record2.status)] ?? "unknown",
30039
+ ...source ? { source } : {}
30040
+ });
30041
+ }
30042
+ return servers;
30043
+ }
29941
30044
  function initUpdates(event, state) {
29942
30045
  const model = asString(event.model);
29943
30046
  if (model) state.model = model;
29944
30047
  const tools = stringList(event.tools);
29945
30048
  const slashCommands = stringList(event.slash_commands);
30049
+ const servers = mcpServers(event.mcp_servers);
29946
30050
  return [
29947
30051
  {
29948
30052
  sessionUpdate: "_alan/log",
@@ -29956,7 +30060,8 @@ function initUpdates(event, state) {
29956
30060
  ...tools.length > 0 ? { [TOOLS_META]: tools } : {},
29957
30061
  ...slashCommands.length > 0 ? { [SLASH_COMMANDS_META]: slashCommands } : {}
29958
30062
  }
29959
- }
30063
+ },
30064
+ ...servers.length > 0 ? [{ sessionUpdate: "_alan/mcp_servers", servers }] : []
29960
30065
  ];
29961
30066
  }
29962
30067
  function thinkingTokens(event) {
@@ -30910,17 +31015,17 @@ function claudeTurnClosingUpdates(records, state) {
30910
31015
  function readClaudeTranscriptTurns(chunk, baseOffset, skipped) {
30911
31016
  return readTranscriptTurns(claudeTranscriptFile, chunk, baseOffset, skipped);
30912
31017
  }
30913
- var import_crypto7, import_fs6, import_path6, import_crypto8, import_promises31, EDIT_TOOLS, ThoughtBlocks, UNDERSTOOD_SYSTEM_SUBTYPES, RATE_LIMIT_WARN_AT, CLAUDE_GRAMMAR_NAME, SUBAGENT_TOOL_NAMES, controlResponseSchema, STOPPED_STATUSES, TaskRecords, TERMINAL_BACKGROUND_STATUSES, NON_TERMINAL_BACKGROUND_STATUSES, ASYNC_LAUNCH_ACK, BackgroundTasks, FAILED_STATUSES, STOPPED_BY_USER_TEXT, ClaudeTurn, STDERR_TAIL_LINES2, MAX_EARLY_LINES, UNSUPPORTED_STOP, OUTPUT_CLOSED_REASON, ClaudeSession, DEFAULTS, READ_ONLY_DISALLOWED_TOOLS, DEFAULT_MCP_TIMEOUT_MS, SYNTHETIC_MODEL, INTERRUPT_MARKER, NON_PROMPT_PREFIXES, PRELUDE_TYPES, claudeTranscriptFile;
31018
+ var import_crypto7, import_fs6, import_path6, import_crypto8, import_promises31, EDIT_TOOLS, ThoughtBlocks, UNDERSTOOD_SYSTEM_SUBTYPES, CLAUDE_MCP_STATUS, RATE_LIMIT_WARN_AT, CLAUDE_GRAMMAR_NAME, SUBAGENT_TOOL_NAMES, controlResponseSchema, STOPPED_STATUSES, TaskRecords, TERMINAL_BACKGROUND_STATUSES, NON_TERMINAL_BACKGROUND_STATUSES, ASYNC_LAUNCH_ACK, BackgroundTasks, FAILED_STATUSES, STOPPED_BY_USER_TEXT, ClaudeTurn, STDERR_TAIL_LINES2, MAX_EARLY_LINES, UNSUPPORTED_STOP, OUTPUT_CLOSED_REASON, ClaudeSession, DEFAULTS, READ_ONLY_DISALLOWED_TOOLS, DEFAULT_MCP_TIMEOUT_MS, SYNTHETIC_MODEL, INTERRUPT_MARKER, NON_PROMPT_PREFIXES, PRELUDE_TYPES, claudeTranscriptFile;
30914
31019
  var init_claude = __esm({
30915
31020
  "../agent-core/dist/providers/claude.js"() {
30916
31021
  "use strict";
30917
31022
  init_chunk_D4TIXPWZ();
30918
- init_chunk_ILZBXGVI();
31023
+ init_chunk_FYZKVT3E();
30919
31024
  init_chunk_OUEMTEUX();
30920
31025
  init_chunk_ZCTKXKYY();
30921
- init_chunk_J2KTV5FP();
30922
31026
  init_chunk_6VWVDJ2A();
30923
31027
  init_chunk_DLVRNIY5();
31028
+ init_chunk_OSECDZA5();
30924
31029
  init_chunk_YXWJW7I5();
30925
31030
  init_effort();
30926
31031
  import_crypto7 = require("crypto");
@@ -30979,6 +31084,13 @@ var init_claude = __esm({
30979
31084
  "status",
30980
31085
  "commands_changed"
30981
31086
  ]);
31087
+ CLAUDE_MCP_STATUS = {
31088
+ connected: "connected",
31089
+ pending: "starting",
31090
+ "needs-auth": "needs_auth",
31091
+ failed: "failed",
31092
+ disabled: "disabled"
31093
+ };
30982
31094
  RATE_LIMIT_WARN_AT = 0.8;
30983
31095
  CLAUDE_GRAMMAR_NAME = "claude_cli";
30984
31096
  SUBAGENT_TOOL_NAMES = /* @__PURE__ */ new Set(["agent", "task"]);
@@ -33766,17 +33878,17 @@ function codexTurnInput(run2, context) {
33766
33878
  ...images.length ? { imagePaths: images.map((image) => image.path) } : {}
33767
33879
  };
33768
33880
  }
33769
- var import_fs7, import_path7, import_crypto9, import_crypto10, import_crypto11, import_crypto12, TokenRefresher, MCP_STARTUP_TIMEOUT_SEC, FIELD_TYPES, YES_NO, ACCEPT_DECLINE, MAX_INLINE_GENERATED_IMAGE_BYTES, PNG_SIGNATURE2, JPEG_NON_FRAME_MARKERS, IMAGE_GEN_CALL, PROMPT_LITERAL, RELOCATE_EVERY_MS, CodexImageGenerationFold, CodexRolloutImages, CodexRateLimits, USER_INPUT_METHOD, PERMISSIONS_METHOD, ELICITATION_METHOD, COMMAND_OR_FILE, LEGACY, DECISIONS, COORDINATION_TOOLS, SETTLED_AGENT, STATUS, CHANGE_OPERATIONS, SILENT_ON_START, IGNORED_ITEMS, PLAN_STATUS, WORKER_LIFECYCLE, INFO_KINDS, SILENT, CodexTurn, STDERR_TAIL_LINES3, MAX_BETWEEN_UPDATES, UNSUPPORTED_REQUEST, DECLINED_ELICITATION, IMAGE_CATCH_UP_MS, IMAGE_POLL_MS, CodexSession, CODEX_MIN_VERSION, CODEX_REQUIREMENT, CODEX_TESTED_LINE, DEFAULTS2, CLIENT_INFO, STATUS2, EXITED_WITHOUT_RESPONSE, CodexExecTurn, DEFAULTS22, CodexExecSession, INJECTED_USER_PREFIXES, SHELL_TOOL_NAMES, ANNOUNCING_ITEM_TYPES, OUTPUT_MARKER, OPEN_PAGE_ACTIONS, FIND_IN_PAGE_ACTIONS, FILE_OPERATIONS, UNDERSTOOD_ITEM_TYPES, PRELUDE_TYPES2, PRELUDE_EVENTS, codexRolloutFile;
33881
+ var import_fs7, import_path7, import_crypto9, import_crypto10, import_crypto11, import_crypto12, TokenRefresher, MCP_STARTUP_TIMEOUT_SEC, FIELD_TYPES, YES_NO, ACCEPT_DECLINE, MAX_INLINE_GENERATED_IMAGE_BYTES, PNG_SIGNATURE2, JPEG_NON_FRAME_MARKERS, IMAGE_GEN_CALL, PROMPT_LITERAL, RELOCATE_EVERY_MS, CodexImageGenerationFold, CodexRolloutImages, CodexRateLimits, USER_INPUT_METHOD, PERMISSIONS_METHOD, ELICITATION_METHOD, COMMAND_OR_FILE, LEGACY, DECISIONS, COORDINATION_TOOLS, SETTLED_AGENT, STATUS, CHANGE_OPERATIONS, SILENT_ON_START, IGNORED_ITEMS, PLAN_STATUS, CODEX_MCP_STATUS, WORKER_LIFECYCLE, INFO_KINDS, SILENT, CodexTurn, STDERR_TAIL_LINES3, MAX_BETWEEN_UPDATES, UNSUPPORTED_REQUEST, DECLINED_ELICITATION, IMAGE_CATCH_UP_MS, IMAGE_POLL_MS, CodexSession, CODEX_MIN_VERSION, CODEX_REQUIREMENT, CODEX_TESTED_LINE, DEFAULTS2, CLIENT_INFO, STATUS2, EXITED_WITHOUT_RESPONSE, CodexExecTurn, DEFAULTS22, CodexExecSession, INJECTED_USER_PREFIXES, SHELL_TOOL_NAMES, ANNOUNCING_ITEM_TYPES, OUTPUT_MARKER, OPEN_PAGE_ACTIONS, FIND_IN_PAGE_ACTIONS, FILE_OPERATIONS, UNDERSTOOD_ITEM_TYPES, PRELUDE_TYPES2, PRELUDE_EVENTS, codexRolloutFile;
33770
33882
  var init_codex = __esm({
33771
33883
  "../agent-core/dist/providers/codex.js"() {
33772
33884
  "use strict";
33773
33885
  init_chunk_D4TIXPWZ();
33774
- init_chunk_ILZBXGVI();
33886
+ init_chunk_FYZKVT3E();
33775
33887
  init_chunk_OUEMTEUX();
33776
33888
  init_chunk_ZCTKXKYY();
33777
- init_chunk_J2KTV5FP();
33778
33889
  init_chunk_6VWVDJ2A();
33779
33890
  init_chunk_DLVRNIY5();
33891
+ init_chunk_OSECDZA5();
33780
33892
  init_chunk_YXWJW7I5();
33781
33893
  import_fs7 = require("fs");
33782
33894
  import_path7 = require("path");
@@ -34059,6 +34171,12 @@ var init_codex = __esm({
34059
34171
  ["inProgress", "in_progress"],
34060
34172
  ["completed", "completed"]
34061
34173
  ]);
34174
+ CODEX_MCP_STATUS = {
34175
+ starting: "starting",
34176
+ ready: "connected",
34177
+ failed: "failed",
34178
+ cancelled: "failed"
34179
+ };
34062
34180
  WORKER_LIFECYCLE = /* @__PURE__ */ new Set([
34063
34181
  "turn/started",
34064
34182
  "turn/completed",
@@ -34210,20 +34328,29 @@ var init_codex = __esm({
34210
34328
  )
34211
34329
  ];
34212
34330
  }
34331
+ #mcpStatus(params) {
34332
+ const name = asString(params.name);
34333
+ if (!name) return [];
34334
+ const reported = asString(params.status);
34335
+ const reason = asString(params.error) || asString(params.failureReason);
34336
+ const status = CODEX_MCP_STATUS[reported] ?? "unknown";
34337
+ const listed = {
34338
+ sessionUpdate: "_alan/mcp_servers",
34339
+ servers: [{ name, status, ...status === "failed" && reason ? { error: reason } : {} }]
34340
+ };
34341
+ if (reported !== "failed") return [listed];
34342
+ return [listed, ...this.#mcpFailure(name, reason)];
34343
+ }
34213
34344
  /**
34214
34345
  * Only Alan's own MCP server failing matters in the chat: its tools are gone for the session.
34215
34346
  * The user's other servers (and their logins) belong to their Codex setup, not to Alan.
34216
34347
  */
34217
- #mcpStatus(params) {
34218
- if (asString(params.status) !== "failed") return [];
34219
- const name = asString(params.name);
34348
+ #mcpFailure(name, reason) {
34220
34349
  if (canonicalizeManagedMcpServerName(name) !== MANAGED_MCP_SERVER_NAME) {
34221
- const reason2 = asString(params.error) || asString(params.failureReason);
34222
34350
  return [
34223
- logUpdate("codex/mcp", `MCP server ${name} failed to start${reason2 ? `: ${reason2}` : "."}`)
34351
+ logUpdate("codex/mcp", `MCP server ${name} failed to start${reason ? `: ${reason}` : "."}`)
34224
34352
  ];
34225
34353
  }
34226
- const reason = asString(params.error) || asString(params.failureReason);
34227
34354
  const key = `mcp_server_failed\0${reason}`;
34228
34355
  if (this.#memory.shownWarnings.has(key)) return [];
34229
34356
  this.#memory.shownWarnings.add(key);
@@ -35114,6 +35241,47 @@ const PROVIDER_ID = ${JSON.stringify(ALAN_CODE_ENGINE_PROVIDER_ID)};
35114
35241
  const INCLUDED_RESULTS = 8;
35115
35242
  const MAX_AUTO_RETRIES = 2;
35116
35243
  const MAX_AUTO_RETRY_WAIT_MS = 10_000;
35244
+ const CODE_MODE_TOOL = ${JSON.stringify(OPENCODE_CODE_MODE_TOOL)};
35245
+ const CODE_MODE_CALLS_META = ${JSON.stringify(CODE_MODE_CALLS_META)};
35246
+ const MAX_CHILD_OUTPUT_CHARS = 64 * 1024;
35247
+ const MAX_OPEN_SCRIPTS = 64;
35248
+ const scriptCalls = new Map();
35249
+
35250
+ function mcpResultText(result) {
35251
+ return result.content
35252
+ .flatMap(function (item) {
35253
+ if (item && item.type === "text") return [item.text];
35254
+ if (item && item.type === "resource" && item.resource && item.resource.text) return [item.resource.text];
35255
+ return [];
35256
+ })
35257
+ .join("\\n\\n");
35258
+ }
35259
+
35260
+ function openScript(callID) {
35261
+ if (scriptCalls.size >= MAX_OPEN_SCRIPTS) scriptCalls.delete(scriptCalls.keys().next().value);
35262
+ scriptCalls.set(callID, []);
35263
+ }
35264
+
35265
+ // Code mode names each MCP call "<script callID>/<n>" and hands the hook the raw MCP result.
35266
+ function recordScriptCall(input, result) {
35267
+ const callID = String(input.callID || "");
35268
+ const slash = callID.lastIndexOf("/");
35269
+ const calls = slash > 0 ? scriptCalls.get(callID.slice(0, slash)) : undefined;
35270
+ if (!calls || !result || !Array.isArray(result.content)) return;
35271
+ calls.push({
35272
+ callId: callID,
35273
+ tool: input.tool,
35274
+ input: input.args,
35275
+ output: mcpResultText(result).slice(0, MAX_CHILD_OUTPUT_CHARS),
35276
+ });
35277
+ }
35278
+
35279
+ function closeScript(callID, output) {
35280
+ const calls = scriptCalls.get(callID);
35281
+ scriptCalls.delete(callID);
35282
+ if (!calls || calls.length === 0 || !output || typeof output !== "object") return;
35283
+ output.metadata = Object.assign({}, output.metadata, { [CODE_MODE_CALLS_META]: calls });
35284
+ }
35117
35285
 
35118
35286
  function truncate(text, max) {
35119
35287
  const trimmed = String(text == null ? "" : text).trim();
@@ -35221,6 +35389,13 @@ export const AlanEnginePlugin = async () => ({
35221
35389
  output.headers["x-alan-operation-key"] = Date.now() + "-" + crypto.randomUUID();
35222
35390
  }
35223
35391
  },
35392
+ "tool.execute.before": async (input) => {
35393
+ if (input.tool === CODE_MODE_TOOL) openScript(input.callID);
35394
+ },
35395
+ "tool.execute.after": async (input, output) => {
35396
+ if (input.tool === CODE_MODE_TOOL) closeScript(input.callID, output);
35397
+ else recordScriptCall(input, output);
35398
+ },
35224
35399
  tool: {
35225
35400
  web_search: {
35226
35401
  description: "web_search: Search the public web via Alan's Parallel proxy. Use when you do not already have a URL. Follow up with webfetch on the best result(s).",
@@ -35254,6 +35429,7 @@ function bearerToken(authorization) {
35254
35429
  function alanCodeEngineEnv(input2) {
35255
35430
  return {
35256
35431
  ...alanCodeEngineDirectories(input2.engineRoot),
35432
+ [OPENCODE_CODE_MODE_ENV]: "true",
35257
35433
  [ALAN_CODE_API_KEY_ENV]: input2.apiKey,
35258
35434
  [ALAN_CODE_CONVERSATION_ID_ENV]: input2.conversationId
35259
35435
  };
@@ -35297,6 +35473,7 @@ var import_http9, import_https, import_fs8, import_path8, import_crypto13, impor
35297
35473
  var init_alan_code = __esm({
35298
35474
  "../agent-core/dist/providers/alan-code.js"() {
35299
35475
  "use strict";
35476
+ init_chunk_OSECDZA5();
35300
35477
  init_chunk_YXWJW7I5();
35301
35478
  import_http9 = require("http");
35302
35479
  import_https = require("https");
@@ -35339,10 +35516,15 @@ var init_alan_code = __esm({
35339
35516
  emptyTurn: "Alan Code ended the turn without producing any output. Try again or pick another model."
35340
35517
  };
35341
35518
  WINDOWS_RUNNABLE_EXTENSION = /\.(exe|com|cmd|bat)$/i;
35342
- ALAN_CODE_ENGINE_PLUGIN_VERSION = 2;
35519
+ ALAN_CODE_ENGINE_PLUGIN_VERSION = 3;
35343
35520
  ALAN_CODE_TOOL_NAMING_PROMPT = `## Alan tool names
35344
35521
 
35345
- This engine exposes Alan MCP tools with an \`alan_\` prefix. Where these instructions name an Alan tool, call its prefixed form: \`search_context\` is \`alan_search_context\`, \`search_code_context\` is \`alan_search_code_context\`, and \`find_records\` is \`alan_find_records\`.`;
35522
+ Alan's MCP tools are not separate tools in this engine. Call them inside an \`execute\` script under the \`alan\` namespace: \`search_context\` is \`tools.alan.search_context({ ... })\`, \`search_code_context\` is \`tools.alan.search_code_context({ ... })\`, and \`find_records\` is \`tools.alan.find_records({ ... })\`.
35523
+
35524
+ - Before the first call to a tool whose signature is not shown in the \`execute\` description, read it with \`tools.$codemode.search({ query: "<tool name>" })\` and pass exactly its fields.
35525
+ - Alan tools return JSON as text: \`JSON.parse\` a result before reading its fields or passing it to \`Object.keys\`.
35526
+ - Look up IDs in one script, then make the writes in the next, so a failed lookup never leaves half the writes done.
35527
+ - Pass an \`idempotencyKey\` naming each change (for example \`create-task:<title>\`) on every write that accepts one. If a script fails, check what it already created before running it again, and run only the writes that are missing.`;
35346
35528
  }
35347
35529
  });
35348
35530
 
@@ -45113,7 +45295,7 @@ var require_tar_stream = __commonJS({
45113
45295
  var init_dist = __esm({
45114
45296
  "../agent-core/dist/index.js"() {
45115
45297
  "use strict";
45116
- init_chunk_ILZBXGVI();
45298
+ init_chunk_FYZKVT3E();
45117
45299
  init_chunk_OUEMTEUX();
45118
45300
  init_chunk_ZCTKXKYY();
45119
45301
  init_chunk_6VWVDJ2A();
@@ -45860,12 +46042,12 @@ var import_promises50, import_path10, import_crypto14, import_promises51, CURSOR
45860
46042
  var init_acp3 = __esm({
45861
46043
  "../agent-core/dist/providers/acp.js"() {
45862
46044
  "use strict";
45863
- init_chunk_ILZBXGVI();
46045
+ init_chunk_FYZKVT3E();
45864
46046
  init_chunk_OUEMTEUX();
45865
46047
  init_chunk_ZCTKXKYY();
45866
- init_chunk_J2KTV5FP();
45867
46048
  init_chunk_6VWVDJ2A();
45868
46049
  init_chunk_DLVRNIY5();
46050
+ init_chunk_OSECDZA5();
45869
46051
  init_chunk_YXWJW7I5();
45870
46052
  import_promises50 = require("fs/promises");
45871
46053
  import_path10 = require("path");
@@ -47123,7 +47305,8 @@ var init_persistent = __esm({
47123
47305
  "user_message",
47124
47306
  "user_message_chunk",
47125
47307
  "_alan/log",
47126
- "_alan/thinking_tokens"
47308
+ "_alan/thinking_tokens",
47309
+ "_alan/mcp_servers"
47127
47310
  ]);
47128
47311
  FIRST_OUTPUT_TIMEOUT_MS = 3e5;
47129
47312
  }
@@ -47366,6 +47549,21 @@ function classifyOpenCodeError(error62, fallback) {
47366
47549
  }
47367
47550
  return classifyCliError(message2 || fallback);
47368
47551
  }
47552
+ function readChildCall(value2) {
47553
+ const record2 = asRecord(value2);
47554
+ const callId = asString(record2?.callId);
47555
+ const tool = asString(record2?.tool);
47556
+ if (!record2 || !callId || !tool) return void 0;
47557
+ return { callId, tool, input: record2.input, output: asString(record2.output) };
47558
+ }
47559
+ function readCodeModeChildCalls(metadata) {
47560
+ return asArray(asRecord(metadata)?.[CODE_MODE_CALLS_META]).flatMap(
47561
+ (entry) => {
47562
+ const call = readChildCall(entry);
47563
+ return call ? [call] : [];
47564
+ }
47565
+ );
47566
+ }
47369
47567
  function withParent(updates, parentToolCallId) {
47370
47568
  if (!parentToolCallId) return updates;
47371
47569
  return updates.map(
@@ -47456,6 +47654,24 @@ function toolContent(tool, toolState) {
47456
47654
  const editing = tool.status === "in_progress" && (tool.name === "edit" || tool.name === "write");
47457
47655
  return editing && path4 ? [fileChangeContent({ path: path4, operation: "modify", hunks: [] })] : void 0;
47458
47656
  }
47657
+ function codeModeChildUpdates(tool, metadata) {
47658
+ if (tool.name !== OPENCODE_CODE_MODE_TOOL || tool.status !== "completed") return [];
47659
+ return readCodeModeChildCalls(metadata).map((call) => {
47660
+ const name = canonicalizeManagedMcpToolName(call.tool);
47661
+ const content = outputContent(call.output);
47662
+ return {
47663
+ sessionUpdate: "tool_call_update",
47664
+ toolCallId: call.callId,
47665
+ name,
47666
+ title: name,
47667
+ kind: toolKindFor(name),
47668
+ status: "completed",
47669
+ ...call.input !== void 0 ? { rawInput: call.input } : {},
47670
+ ...content ? { content } : {},
47671
+ ...call.output ? { rawOutput: call.output } : {}
47672
+ };
47673
+ });
47674
+ }
47459
47675
  function createOpenCodeSessionMemory() {
47460
47676
  return { userMessageIds: /* @__PURE__ */ new Set() };
47461
47677
  }
@@ -47794,12 +48010,12 @@ var import_crypto15, import_http10, import_crypto16, import_promises52, import_p
47794
48010
  var init_opencode = __esm({
47795
48011
  "../agent-core/dist/providers/opencode.js"() {
47796
48012
  "use strict";
47797
- init_chunk_ILZBXGVI();
48013
+ init_chunk_FYZKVT3E();
47798
48014
  init_chunk_OUEMTEUX();
47799
48015
  init_chunk_ZCTKXKYY();
47800
- init_chunk_J2KTV5FP();
47801
48016
  init_chunk_6VWVDJ2A();
47802
48017
  init_chunk_DLVRNIY5();
48018
+ init_chunk_OSECDZA5();
47803
48019
  init_chunk_YXWJW7I5();
47804
48020
  import_crypto15 = require("crypto");
47805
48021
  import_http10 = require("http");
@@ -48325,6 +48541,7 @@ var init_opencode = __esm({
48325
48541
  }
48326
48542
  ];
48327
48543
  updates.push(...this.#plan(toolCallId, tool.name, toolState));
48544
+ updates.push(...codeModeChildUpdates(tool, toolState?.metadata));
48328
48545
  if (tool.status === "failed" && (tool.isTask || PERMISSION_DENIED.test(tool.errorMessage))) {
48329
48546
  updates.push(
48330
48547
  noticeUpdate("error", "tool_failed", tool.errorMessage || "OpenCode tool call failed.")
@@ -49844,12 +50061,12 @@ var import_crypto18, import_promises53, FACTORY_API_VERSION, FACTORY_PROTOCOL_VE
49844
50061
  var init_droid = __esm({
49845
50062
  "../agent-core/dist/providers/droid.js"() {
49846
50063
  "use strict";
49847
- init_chunk_ILZBXGVI();
50064
+ init_chunk_FYZKVT3E();
49848
50065
  init_chunk_OUEMTEUX();
49849
50066
  init_chunk_ZCTKXKYY();
49850
- init_chunk_J2KTV5FP();
49851
50067
  init_chunk_6VWVDJ2A();
49852
50068
  init_chunk_DLVRNIY5();
50069
+ init_chunk_OSECDZA5();
49853
50070
  init_chunk_YXWJW7I5();
49854
50071
  init_runtime_v2();
49855
50072
  import_crypto18 = require("crypto");
@@ -50954,7 +51171,7 @@ var init_antigravity = __esm({
50954
51171
  "../agent-core/dist/providers/antigravity.js"() {
50955
51172
  "use strict";
50956
51173
  init_chunk_D4TIXPWZ();
50957
- init_chunk_ILZBXGVI();
51174
+ init_chunk_FYZKVT3E();
50958
51175
  init_chunk_OUEMTEUX();
50959
51176
  init_chunk_ZCTKXKYY();
50960
51177
  init_chunk_6VWVDJ2A();
@@ -51658,12 +51875,12 @@ var import_promises55, import_path16, import_crypto20, COMMAND_CODE_GRAMMAR_NAME
51658
51875
  var init_command_code = __esm({
51659
51876
  "../agent-core/dist/providers/command-code.js"() {
51660
51877
  "use strict";
51661
- init_chunk_ILZBXGVI();
51878
+ init_chunk_FYZKVT3E();
51662
51879
  init_chunk_OUEMTEUX();
51663
51880
  init_chunk_ZCTKXKYY();
51664
- init_chunk_J2KTV5FP();
51665
51881
  init_chunk_6VWVDJ2A();
51666
51882
  init_chunk_DLVRNIY5();
51883
+ init_chunk_OSECDZA5();
51667
51884
  init_chunk_YXWJW7I5();
51668
51885
  import_promises55 = require("fs/promises");
51669
51886
  import_path16 = require("path");
@@ -57061,7 +57278,7 @@ var require_websocket_server = __commonJS({
57061
57278
  // package.json
57062
57279
  var package_default = {
57063
57280
  name: "@alan-ai-hq/agent-manager",
57064
- version: "0.1.157",
57281
+ version: "0.1.159",
57065
57282
  private: true,
57066
57283
  type: "module",
57067
57284
  description: "Alan machine runtime (alan-agent): identity, link, reconciler, session holders, run log, uploader, local API",
@@ -71985,7 +72202,19 @@ async function runHolder({
71985
72202
  ...machine?.platform === void 0 ? {} : { platform: machine.platform }
71986
72203
  });
71987
72204
  const observed = facts.observe(driver);
71988
- const writeStatus = () => writeJsonFileAtomic(launch.statusPath, {
72205
+ let statusWrites = Promise.resolve();
72206
+ const writeStatus = () => {
72207
+ const next = statusWrites.then(() => writeStatusNow());
72208
+ statusWrites = next.catch(
72209
+ (error62) => log.warn("holder.status_write_failed", { error: error62 })
72210
+ );
72211
+ return next;
72212
+ };
72213
+ const queueStatus = () => {
72214
+ writeStatus().catch(() => {
72215
+ });
72216
+ };
72217
+ const writeStatusNow = () => writeJsonFileAtomic(launch.statusPath, {
71989
72218
  protocol: HOLDER_PROTOCOL,
71990
72219
  conversationId: launch.conversationId,
71991
72220
  pid: identity.pid,
@@ -72004,7 +72233,7 @@ async function runHolder({
72004
72233
  holder.state = "idle";
72005
72234
  holder.runId = null;
72006
72235
  holder.turn = null;
72007
- void writeStatus();
72236
+ queueStatus();
72008
72237
  };
72009
72238
  const startTurn = (id, spec, client) => {
72010
72239
  if (holder.runId === spec.runId) {
@@ -72048,7 +72277,7 @@ async function runHolder({
72048
72277
  return;
72049
72278
  }
72050
72279
  writeMessage(client, { type: "ack", id });
72051
- void writeStatus();
72280
+ queueStatus();
72052
72281
  runClaimedTurn(spec, claimed, context, turn.signal).then((outcome2) => broadcast({ type: "turn_ended", runId: spec.runId, outcome: outcome2 })).catch((error62) => log.error("holder.turn_crashed", { runId: spec.runId, error: error62 })).finally(settle2);
72053
72282
  },
72054
72283
  (error62) => {
@@ -72186,6 +72415,7 @@ async function runHolder({
72186
72415
  await driver.suspend?.().catch((error62) => log.warn("holder.driver_suspend_failed", { error: error62 }));
72187
72416
  for (const client of holder.clients) client.end();
72188
72417
  await new Promise((resolve13) => server.close(() => resolve13()));
72418
+ await statusWrites;
72189
72419
  (0, import_node_fs23.rmSync)(launch.statusPath, { force: true });
72190
72420
  log.info("holder.suspended", { conversationId: launch.conversationId });
72191
72421
  } catch (_) {