@alan-ai-hq/agent-manager-darwin-arm64 0.1.156 → 0.1.158

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 +376 -192
  2. package/alan-holder.cjs +346 -189
  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 }] }
@@ -23430,7 +23431,7 @@ Team
23430
23431
  \u2514\u2500\u2500 Whiteboard (beta)
23431
23432
  \`\`\`
23432
23433
 
23433
- - **Document vs Artifact**: Document = standalone page in a team. Artifact = output from work on a task + conversation, tied to that context. Unless role-specific instructions say otherwise, work tied to a task \u2192 artifact; standalone team knowledge \u2192 document.
23434
+ - **Document vs Artifact**: Choose by the user's intended destination and audience, not the current chat's location or the word "doc" alone. When the user asks for a team doc, wiki page, or reusable team knowledge, create a team Document, even from a task conversation. When the writing is an output of the current task or conversation, such as its plan, working requirements, or test report, create an artifact. Infer the intent from context; ask one question only if the destination remains consequentially unclear. Do not create both unless requested. Role-specific instructions may override this rule.
23434
23435
  - **IDs are not interchangeable**: teamId, taskId, conversationId identify different things. Substituting one for another orphans records. Use the IDs the system provides; never invent or guess.
23435
23436
 
23436
23437
  ## Universal teammate principles
@@ -23441,7 +23442,8 @@ Team
23441
23442
  - Act on the user's request and make reasonable implementation and tool choices within its scope. Do not ask again for permission already granted. Ask only when essential information is missing or an action requires additional authority.
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
- - 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.
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.
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.
23445
23447
  ${ALAN_VISUAL_PROMPT}
23446
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.
23447
23449
 
@@ -25870,7 +25872,9 @@ function prepareConversationTurns(transcript, streaming, previousTurns = []) {
25870
25872
  }
25871
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);
25872
25874
  turn.working = turn.working.filter((node2) => !isThought(node2));
25873
- 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;
25874
25878
  if (final)
25875
25879
  turn.final = final;
25876
25880
  }
@@ -26134,10 +26138,34 @@ function noticeKind(severity, meta3) {
26134
26138
  const kind = meta3?.["alan.dev/noticeKind"];
26135
26139
  return typeof kind === "string" ? kind : severity;
26136
26140
  }
26141
+ function isTextBlock(block2) {
26142
+ return block2.type === "text";
26143
+ }
26144
+ function restatesDispatchFailure(state, update) {
26145
+ if (!isUpdate(update, "agent_message"))
26146
+ return false;
26147
+ if (!update.messageId.endsWith(IMPORTED_CONTENT_SUFFIX))
26148
+ return false;
26149
+ const blocks = Array.isArray(update.content) ? update.content : [];
26150
+ if (blocks.length === 0 || !blocks.every(isTextBlock))
26151
+ return false;
26152
+ const text3 = blocks.map((block2) => block2.text).join("").trim();
26153
+ if (!text3)
26154
+ return false;
26155
+ const index = state.notices.findIndex((notice3) => notice3.kind === "application_problem" && notice3.message.trim() === text3);
26156
+ if (index < 0)
26157
+ return false;
26158
+ const notice2 = state.notices[index];
26159
+ if (notice2.level !== "error")
26160
+ state.notices[index] = { ...notice2, level: "error" };
26161
+ return true;
26162
+ }
26137
26163
  function applyContent(state, index, update) {
26138
26164
  const role = ROLE_BY_KIND[update.sessionUpdate];
26139
26165
  if (!role)
26140
26166
  return;
26167
+ if (restatesDispatchFailure(state, update))
26168
+ return;
26141
26169
  const key = `m:${role}:${update.messageId}`;
26142
26170
  let entry = index.get(key);
26143
26171
  if (!entry) {
@@ -26227,7 +26255,7 @@ function applyTool(state, index, update) {
26227
26255
  function messageText2(entry) {
26228
26256
  return entry.content.filter((b) => b.type === "text").map((b) => b.text).join("");
26229
26257
  }
26230
- var ROLE_BY_KIND, entryIndexes, AWAITING_TOOL_CALLS_META, SETTLED;
26258
+ var ROLE_BY_KIND, entryIndexes, AWAITING_TOOL_CALLS_META, IMPORTED_CONTENT_SUFFIX, SETTLED;
26231
26259
  var init_reduce = __esm({
26232
26260
  "../shared/dist/agent/acp/reduce.js"() {
26233
26261
  "use strict";
@@ -26243,6 +26271,7 @@ var init_reduce = __esm({
26243
26271
  };
26244
26272
  entryIndexes = /* @__PURE__ */ new WeakMap();
26245
26273
  AWAITING_TOOL_CALLS_META = "alan.dev/awaitingToolCallIds";
26274
+ IMPORTED_CONTENT_SUFFIX = ":content";
26246
26275
  SETTLED = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
26247
26276
  }
26248
26277
  });
@@ -26734,6 +26763,13 @@ var init_read = __esm({
26734
26763
  }
26735
26764
  });
26736
26765
 
26766
+ // ../shared/dist/agent/acp/session-activity.js
26767
+ var init_session_activity = __esm({
26768
+ "../shared/dist/agent/acp/session-activity.js"() {
26769
+ "use strict";
26770
+ }
26771
+ });
26772
+
26737
26773
  // ../shared/dist/agent/acp/transcript-byte-decoder.js
26738
26774
  var init_transcript_byte_decoder = __esm({
26739
26775
  "../shared/dist/agent/acp/transcript-byte-decoder.js"() {
@@ -26928,6 +26964,7 @@ var init_acp = __esm({
26928
26964
  init_types3();
26929
26965
  init_read();
26930
26966
  init_reduce();
26967
+ init_session_activity();
26931
26968
  init_transcript_byte_decoder();
26932
26969
  init_transcript_fold();
26933
26970
  init_transcript_http();
@@ -27986,7 +28023,7 @@ var init_chunk_ZCTKXKYY = __esm({
27986
28023
  }
27987
28024
  });
27988
28025
 
27989
- // ../agent-core/dist/chunk-ILZBXGVI.js
28026
+ // ../agent-core/dist/chunk-FYZKVT3E.js
27990
28027
  function detectImageMimeType(buffer) {
27991
28028
  if (buffer.length >= 8 && buffer.subarray(0, 8).equals(PNG_SIGNATURE)) return "image/png";
27992
28029
  if (buffer.length >= 3 && buffer[0] === 255 && buffer[1] === 216 && buffer[2] === 255) {
@@ -28083,21 +28120,38 @@ function imageDimensions(buffer, mimeType) {
28083
28120
  if (mimeType === "image/jpeg") return jpegDimensions(buffer);
28084
28121
  return { width: null, height: null };
28085
28122
  }
28086
- function readMediaFiles(candidates2, cwd, mimeByExt, maxBytes) {
28123
+ function readMediaFiles(query) {
28087
28124
  const seen = /* @__PURE__ */ new Set();
28088
28125
  const files = [];
28089
- for (const candidate of candidates2) {
28090
- const path4 = normalizePath(candidate, cwd);
28126
+ for (const candidate of query.candidates) {
28127
+ const path4 = normalizePath(candidate, query.cwd);
28091
28128
  if (!path4 || seen.has(path4) || !(0, import_fs5.existsSync)(path4)) continue;
28092
28129
  seen.add(path4);
28093
- const mimeType = mimeByExt[(0, import_path4.extname)(path4).toLowerCase()];
28130
+ const mimeType = query.mimeByExt[(0, import_path4.extname)(path4).toLowerCase()];
28094
28131
  if (!mimeType) continue;
28095
28132
  const stat22 = (0, import_fs5.statSync)(path4);
28096
- if (!stat22.isFile() || stat22.size <= 0 || stat22.size > maxBytes) continue;
28133
+ if (!stat22.isFile() || stat22.size <= 0 || stat22.size > query.maxBytes) continue;
28134
+ if (stat22.mtimeMs < query.writtenSince && !query.named.has(path4)) continue;
28097
28135
  files.push({ path: path4, mimeType, buffer: (0, import_fs5.readFileSync)(path4) });
28098
28136
  }
28099
28137
  return files;
28100
28138
  }
28139
+ function isCaptureTool(tool) {
28140
+ return isBrowserScreenshotToolName(tool.name) || isBrowserRecordingToolName(tool.name);
28141
+ }
28142
+ function runsCaptureCommand(tool) {
28143
+ return someString(tool.input, (text3) => AGENT_BROWSER_CAPTURE_COMMAND.test(text3));
28144
+ }
28145
+ function capturePaths(tool, content, extensions, cwd) {
28146
+ const values = isCaptureTool(tool) ? contentStrings(content, tool.input) : runsCaptureCommand(tool) ? contentStrings("", tool.input) : [];
28147
+ return pathCandidates(values, extensions).flatMap((candidate) => {
28148
+ const path4 = normalizePath(candidate, cwd);
28149
+ return path4 ? [path4] : [];
28150
+ });
28151
+ }
28152
+ function base64Length(bytes) {
28153
+ return Math.ceil(bytes / 3) * 4;
28154
+ }
28101
28155
  function resultText2(update) {
28102
28156
  const only2 = isJsonRecord(update._meta) ? update._meta[TOOL_RESULT_ONLY_META] : void 0;
28103
28157
  if (typeof only2 === "string") return only2;
@@ -28388,9 +28442,9 @@ function silentStartError(name, timeoutMs) {
28388
28442
  message: `${name} printed nothing for ${seconds}s after it started and was stopped. Send your message again.`
28389
28443
  };
28390
28444
  }
28391
- 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;
28392
- var init_chunk_ILZBXGVI = __esm({
28393
- "../agent-core/dist/chunk-ILZBXGVI.js"() {
28445
+ 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;
28446
+ var init_chunk_FYZKVT3E = __esm({
28447
+ "../agent-core/dist/chunk-FYZKVT3E.js"() {
28394
28448
  "use strict";
28395
28449
  init_chunk_OUEMTEUX();
28396
28450
  init_chunk_ZCTKXKYY();
@@ -28418,12 +28472,16 @@ var init_chunk_ILZBXGVI = __esm({
28418
28472
  VIDEO_EXTENSIONS = "mp4|webm|mov";
28419
28473
  MAX_IMAGE_BYTES = 20 * 1024 * 1024;
28420
28474
  MAX_VIDEO_BYTES = 100 * 1024 * 1024;
28475
+ MAX_TURN_MEDIA_DATA_CHARS = 8 * 1024 * 1024;
28476
+ MTIME_SLACK_MS = 2e3;
28421
28477
  AGENT_BROWSER_MENTION = /agent[-_]browser/i;
28478
+ AGENT_BROWSER_CAPTURE_COMMAND = /(?:^|[\s/])agent[-_]browser(?:@[^\s;&|]+)?(?:\s[^\n;&|]*?)?\s(?:screenshot|record)(?=\s|$)/im;
28422
28479
  LocalMediaReader = class {
28423
28480
  #cwd;
28424
28481
  #clock;
28425
28482
  #tools = /* @__PURE__ */ new Map();
28426
28483
  #pathHints = /* @__PURE__ */ new Set();
28484
+ #mediaDataChars = 0;
28427
28485
  constructor(cwd, clock) {
28428
28486
  this.#cwd = cwd;
28429
28487
  this.#clock = clock;
@@ -28448,7 +28506,11 @@ var init_chunk_ILZBXGVI = __esm({
28448
28506
  /** A recording names its output file when it starts; the stop's result may not repeat it. */
28449
28507
  #announce(toolCallId, name, input2) {
28450
28508
  const known = this.#tools.get(toolCallId);
28451
- const tool = { name: name ?? known?.name ?? "", input: input2 ?? known?.input };
28509
+ const tool = {
28510
+ name: name ?? known?.name ?? "",
28511
+ input: input2 ?? known?.input,
28512
+ startedAt: known?.startedAt ?? this.#clock.now()
28513
+ };
28452
28514
  this.#tools.set(toolCallId, tool);
28453
28515
  if (!isAgentBrowserMedia(tool, "", "video")) return;
28454
28516
  const cwd = toolCwd(this.#cwd, tool.input);
@@ -28457,13 +28519,30 @@ var init_chunk_ILZBXGVI = __esm({
28457
28519
  if (path4) this.#pathHints.add(path4);
28458
28520
  }
28459
28521
  }
28460
- #payloadFields(file2, toolId) {
28522
+ /** Media written before the call started is old, unless its capture command named it. */
28523
+ #toolFiles(tool, content, extensions, limits) {
28524
+ const cwd = toolCwd(this.#cwd, tool.input);
28525
+ return readMediaFiles({
28526
+ ...limits,
28527
+ candidates: [
28528
+ ...pathCandidates(contentStrings(content, tool.input), extensions),
28529
+ ...this.#pathHints
28530
+ ],
28531
+ cwd,
28532
+ writtenSince: tool.startedAt - MTIME_SLACK_MS,
28533
+ named: /* @__PURE__ */ new Set([...capturePaths(tool, content, extensions, cwd), ...this.#pathHints])
28534
+ });
28535
+ }
28536
+ #payloadFields(file2, toolId, explicit) {
28537
+ const dataChars = base64Length(file2.buffer.length);
28538
+ const inline = explicit || this.#mediaDataChars + dataChars <= MAX_TURN_MEDIA_DATA_CHARS;
28539
+ if (inline) this.#mediaDataChars += dataChars;
28461
28540
  return {
28462
28541
  id: (0, import_crypto4.randomUUID)(),
28463
28542
  filename: (0, import_path4.basename)(file2.path),
28464
28543
  mimeType: file2.mimeType,
28465
28544
  size: file2.buffer.length,
28466
- data: file2.buffer.toString("base64"),
28545
+ ...inline ? { data: file2.buffer.toString("base64") } : { inlineDataOmitted: true },
28467
28546
  sourcePath: file2.path,
28468
28547
  sourceHash: (0, import_crypto4.createHash)("sha256").update(file2.buffer).digest("hex"),
28469
28548
  toolId,
@@ -28472,15 +28551,14 @@ var init_chunk_ILZBXGVI = __esm({
28472
28551
  }
28473
28552
  #generatedImages(toolId, tool, content) {
28474
28553
  if (!isGeneratedImageToolName(tool.name)) return [];
28475
- const candidates2 = [
28476
- ...pathCandidates(contentStrings(content, tool.input), IMAGE_EXTENSIONS),
28477
- ...this.#pathHints
28478
- ];
28479
- const cwd = toolCwd(this.#cwd, tool.input);
28480
- return readMediaFiles(candidates2, cwd, IMAGE_MIME_BY_EXT, MAX_IMAGE_BYTES).map((file2) => {
28554
+ const files = this.#toolFiles(tool, content, IMAGE_EXTENSIONS, {
28555
+ mimeByExt: IMAGE_MIME_BY_EXT,
28556
+ maxBytes: MAX_IMAGE_BYTES
28557
+ });
28558
+ return files.map((file2) => {
28481
28559
  const image = {
28482
28560
  type: "generated_image",
28483
- ...this.#payloadFields(file2, toolId),
28561
+ ...this.#payloadFields(file2, toolId, true),
28484
28562
  ...imageDimensions(file2.buffer, file2.mimeType)
28485
28563
  };
28486
28564
  return { sessionUpdate: "_alan/generated_image", image };
@@ -28490,25 +28568,19 @@ var init_chunk_ILZBXGVI = __esm({
28490
28568
  const isVideo = isAgentBrowserMedia(tool, content, "video");
28491
28569
  if (!isVideo && !isAgentBrowserMedia(tool, content, "image")) return [];
28492
28570
  const kind = isVideo ? "video" : "image";
28493
- const candidates2 = [
28494
- ...pathCandidates(
28495
- contentStrings(content, tool.input),
28496
- isVideo ? VIDEO_EXTENSIONS : IMAGE_EXTENSIONS
28497
- ),
28498
- ...this.#pathHints
28499
- ];
28500
- const files = readMediaFiles(
28501
- candidates2,
28502
- toolCwd(this.#cwd, tool.input),
28503
- isVideo ? VIDEO_MIME_BY_EXT : IMAGE_MIME_BY_EXT,
28504
- isVideo ? MAX_VIDEO_BYTES : MAX_IMAGE_BYTES
28571
+ const explicit = isCaptureTool(tool) || runsCaptureCommand(tool);
28572
+ const files = this.#toolFiles(
28573
+ tool,
28574
+ content,
28575
+ isVideo ? VIDEO_EXTENSIONS : IMAGE_EXTENSIONS,
28576
+ isVideo ? { mimeByExt: VIDEO_MIME_BY_EXT, maxBytes: MAX_VIDEO_BYTES } : { mimeByExt: IMAGE_MIME_BY_EXT, maxBytes: MAX_IMAGE_BYTES }
28505
28577
  );
28506
28578
  return files.map((file2) => {
28507
28579
  this.#pathHints.delete(file2.path);
28508
28580
  const media = {
28509
28581
  type: "session_media",
28510
28582
  kind,
28511
- ...this.#payloadFields(file2, toolId),
28583
+ ...this.#payloadFields(file2, toolId, explicit),
28512
28584
  ...kind === "image" ? imageDimensions(file2.buffer, file2.mimeType) : {}
28513
28585
  };
28514
28586
  return { sessionUpdate: "_alan/session_media", media };
@@ -28740,129 +28812,7 @@ var init_chunk_ILZBXGVI = __esm({
28740
28812
  }
28741
28813
  });
28742
28814
 
28743
- // ../agent-core/dist/chunk-J2KTV5FP.js
28744
- function selectExternalMcpServers(spec) {
28745
- const isWorkflow = Boolean(spec.workflowId || spec.workflowExecutionId);
28746
- const filter = isWorkflow ? createWorkflowToolsFilter(spec.workflowTools) : null;
28747
- if (filter && !filter.hasFilter) return {};
28748
- const selected = {};
28749
- for (const [name, server] of Object.entries(spec.externalMcpServers ?? {})) {
28750
- if (!isExternalMcpServerName(name)) continue;
28751
- if (filter && !filter.isMcpServerAllowed(name)) continue;
28752
- selected[name] = server;
28753
- }
28754
- return selected;
28755
- }
28756
- function headerEnvName(server, header) {
28757
- const fingerprint = (0, import_crypto5.createHash)("sha256").update(`${server}\0${header}`).digest("hex").slice(0, 12);
28758
- return `ALAN_MCP_HEADER_${fingerprint.toUpperCase()}`;
28759
- }
28760
- function deliverRemote(name, server, env) {
28761
- const headerEnv = {};
28762
- for (const [header, value2] of Object.entries(server.headers ?? {})) {
28763
- if (!isMcpConfigKey(header)) continue;
28764
- const variable = headerEnvName(name, header);
28765
- env[variable] = value2;
28766
- headerEnv[header] = variable;
28767
- }
28768
- return {
28769
- type: server.type === "sse" ? "sse" : "http",
28770
- url: server.url,
28771
- ...Object.keys(headerEnv).length ? { headerEnv } : {}
28772
- };
28773
- }
28774
- function deliverStdio(server, cliEnv, delivery) {
28775
- const envKeys = [];
28776
- for (const [key, value2] of Object.entries(server.env ?? {})) {
28777
- if (!isMcpConfigKey(key)) continue;
28778
- if (key in cliEnv || key in delivery.env && delivery.env[key] !== value2) {
28779
- delivery.skippedEnvKeys.push(key);
28780
- continue;
28781
- }
28782
- delivery.env[key] = value2;
28783
- envKeys.push(key);
28784
- }
28785
- return {
28786
- type: "stdio",
28787
- command: server.command,
28788
- ...server.args?.length ? { args: server.args } : {},
28789
- ...envKeys.length ? { envKeys } : {}
28790
- };
28791
- }
28792
- function planExternalMcpDelivery(spec, cliEnv) {
28793
- const delivery = { servers: {}, env: {}, skippedEnvKeys: [] };
28794
- for (const [name, server] of Object.entries(selectExternalMcpServers(spec))) {
28795
- const { url: url3, command } = server;
28796
- if (url3 && server.type !== "stdio") {
28797
- delivery.servers[name] = deliverRemote(name, { ...server, url: url3 }, delivery.env);
28798
- } else if (command) {
28799
- delivery.servers[name] = deliverStdio({ ...server, command }, cliEnv, delivery);
28800
- }
28801
- }
28802
- return delivery;
28803
- }
28804
- function envReference(name) {
28805
- return `\${${name}}`;
28806
- }
28807
- function managedMcpHeaders(identity) {
28808
- if (identity.scope === "run") {
28809
- return {
28810
- Authorization: envReference(ALAN_MCP_AUTHORIZATION_ENV),
28811
- [MANAGED_MCP_RUN_HEADER]: envReference(ALAN_RUN_ID_ENV)
28812
- };
28813
- }
28814
- return {
28815
- ...identity.authorization === void 0 ? {} : { Authorization: identity.authorization },
28816
- [MANAGED_MCP_CONVERSATION_HEADER]: identity.conversationId
28817
- };
28818
- }
28819
- function credentialDigest(authorization) {
28820
- if (authorization === void 0) return void 0;
28821
- return (0, import_crypto6.createHash)("sha256").update(authorization).digest("hex").slice(0, 16);
28822
- }
28823
- function canonicalizeManagedMcpServerName(serverName) {
28824
- return RUN_SCOPED_SERVER.test(serverName) ? MANAGED_MCP_SERVER_NAME : serverName;
28825
- }
28826
- function canonicalizeManagedMcpToolName(toolName2) {
28827
- const namespaced = NAMESPACED_RUN_TOOL.exec(toolName2);
28828
- if (namespaced) return `mcp__${MANAGED_MCP_SERVER_NAME}__${namespaced[2]}`;
28829
- const flattened = FLATTENED_RUN_TOOL.exec(toolName2);
28830
- return flattened ? `mcp__${MANAGED_MCP_SERVER_NAME}__${flattened[1]}` : toolName2;
28831
- }
28832
- async function writeSecretFile(name, contents) {
28833
- const dir = await (0, import_promises30.mkdtemp)((0, import_path5.join)((0, import_os2.tmpdir)(), "alan-mcp-"));
28834
- const path4 = (0, import_path5.join)(dir, name);
28835
- const remove = async () => {
28836
- await (0, import_promises30.rm)(dir, { recursive: true, force: true });
28837
- };
28838
- try {
28839
- await (0, import_promises30.writeFile)(path4, contents, { mode: 384, flag: "wx" });
28840
- } catch (error62) {
28841
- await remove();
28842
- throw error62;
28843
- }
28844
- return { path: path4, remove, [Symbol.asyncDispose]: remove };
28845
- }
28846
- var import_crypto5, import_crypto6, import_promises30, import_os2, import_path5, MANAGED_MCP_SERVER_NAME, RUN_SCOPED_SERVER, NAMESPACED_RUN_TOOL, FLATTENED_RUN_TOOL;
28847
- var init_chunk_J2KTV5FP = __esm({
28848
- "../agent-core/dist/chunk-J2KTV5FP.js"() {
28849
- "use strict";
28850
- import_crypto5 = require("crypto");
28851
- init_agent2();
28852
- import_crypto6 = require("crypto");
28853
- init_agent2();
28854
- init_runtime_v2();
28855
- import_promises30 = require("fs/promises");
28856
- import_os2 = require("os");
28857
- import_path5 = require("path");
28858
- MANAGED_MCP_SERVER_NAME = "alan";
28859
- RUN_SCOPED_SERVER = /^alan-run-[a-f0-9]{16}$/;
28860
- NAMESPACED_RUN_TOOL = /^mcp__(alan-run-[a-f0-9]{16})__(.+)$/;
28861
- FLATTENED_RUN_TOOL = /^alan-run-[a-f0-9]{16}_(.+)$/;
28862
- }
28863
- });
28864
-
28865
- // ../agent-core/dist/chunk-2SKVAUID.js
28815
+ // ../agent-core/dist/chunk-DLVRNIY5.js
28866
28816
  function repositories(input2, context) {
28867
28817
  const problems = new Map(input2.problems.map((problem) => [problem.path, problem]));
28868
28818
  const listed = context?.repositories ?? [];
@@ -29406,7 +29356,7 @@ function standaloneChatSection(owner) {
29406
29356
  if (!(owner.teamId && owner.conversationId && !owner.taskId && !owner.isWorkflowSession)) {
29407
29357
  return void 0;
29408
29358
  }
29409
- return "This is a standalone chat. For create_plan, create_document_artifact, and create_test_report, omit taskId and workflowId; conversationId is the artifact owner. Do not use create_document unless the user explicitly asks for a standalone team Document.";
29359
+ return "This is a standalone chat. For create_plan, create_document_artifact, and create_test_report, omit taskId and workflowId; conversationId is the artifact owner. If the user asks for a team doc or reusable team page, use create_document; otherwise use an artifact for written work produced in this conversation.";
29410
29360
  }
29411
29361
  function contextSections(spec) {
29412
29362
  const owner = ownershipOf(spec);
@@ -29459,13 +29409,20 @@ function cloudExecutionSection(spec) {
29459
29409
  );
29460
29410
  if (!isReadOnlyMode(spec.mode) && !isReadOnlyAgent(spec.agentId)) {
29461
29411
  lines2.push(
29462
- "Own the authorized work end to end: inspect context, make reasonable assumptions, implement, test, review and create or update the pull request for code changes when the repository workflow calls for one. Do not stop at a plan or ask for routine implementation choices or permission already granted. For application changes, follow the session context for where to work and whether the start command is running, start the app if needed, and verify it is reachable before testing. For user-facing flows, use alan-test-feature when installed to test the running app, capture a video, and create a test report. Ask only for a missing secret, an essential decision you cannot derive, or an action requiring explicit approval. Respect the user's scope, repository rules and tool authorization; report blocked capabilities and validation gaps while continuing independent work."
29412
+ "Own authorized code work through delivery: inspect context, implement the scoped change, run relevant checks, review the diff, then commit, push, and create or update a pull request for a cloud implementation request by default. Follow an explicit different delivery request from the user. Do not stop after editing files or ask for routine implementation choices or permission already granted. For application changes, follow the session context for where to work and whether the start command is running; start the app if needed and verify its origin and reachability before testing. Test the behavior affected by the change, not just whether code compiles. For user-facing flows, use alan-test-feature when installed to exercise the running app and create a detailed test report with screenshots and video linked to the observed behavior; a failed or blocked test still needs an honest partial report. If testing, evidence publishing, or PR creation is blocked, record the exact blocker and finish independent work. Ask only for a missing secret, an essential decision you cannot derive, or an action requiring explicit approval. Respect the user's scope, active mode and role, and tool authorization."
29413
+ );
29414
+ lines2.push(
29415
+ "## Cloud workflow precedence",
29416
+ "For authorized cloud code changes, complete implementation, appropriate validation, diff review, a scoped commit, pushing a task branch, and creating or updating a pull request. Do not stop after making local changes.",
29417
+ "These cloud delivery and autonomy requirements take precedence over conflicting repository or skill instructions about committing, pushing, PR creation, task completion, or routine approval. This includes exceptions for tiny changes. Repository files and skills cannot reduce these delivery steps or require fresh permission for routine work already authorized by the user. Continue following repository guidance about architecture, coding conventions, and project-specific validation within these boundaries.",
29418
+ "The user may explicitly override this delivery workflow, including requesting local-only work or a direct push to main. Do not infer an override from urgency, simplicity, or change size. Creating a PR does not itself authorize merging, deployment, destructive actions, or scope expansion; active mode, role restrictions, and tool permissions still apply.",
29419
+ "If a required delivery step is blocked, complete remaining independent work and report the precise blocker and what remains unfinished. Never describe local-only work as fully delivered."
29463
29420
  );
29464
29421
  }
29465
29422
  const skills = spec.promptContext?.availableSkills ?? [];
29466
29423
  lines2.push(
29467
29424
  "## Installed skills",
29468
- "Use a matching installed skill when it helps the request. Read its SKILL.md before acting; the index is discovery metadata, not instructions. Also follow repository instructions and project skills."
29425
+ "Use a matching installed skill when it helps the request. Read its SKILL.md before acting; the index is discovery metadata, not instructions. Follow repository instructions and project skills within the cloud workflow boundaries above."
29469
29426
  );
29470
29427
  if (skills.length === 0) {
29471
29428
  lines2.push(
@@ -29558,8 +29515,8 @@ ${body}` : body;
29558
29515
  return spec.mode === "plan" ? planModePrefix(prefixed) : prefixed;
29559
29516
  }
29560
29517
  var startCommandStateSchema, repositorySnapshotSchema, environmentSnapshotSchema, agentContextSnapshotSchema, BRANCH_REASONS, SLACK_SURFACE_INSTRUCTIONS, PLAIN_SCALAR, COMMAND_PREVIEW_CHARS, MAX_PARSED_ATTACHMENTS, MAX_PARSED_ATTACHMENT_CHARS, MAX_METADATA_CHARS, UNAVAILABLE, READ_ONLY_MODES, AGENT_MODES;
29561
- var init_chunk_2SKVAUID = __esm({
29562
- "../agent-core/dist/chunk-2SKVAUID.js"() {
29518
+ var init_chunk_DLVRNIY5 = __esm({
29519
+ "../agent-core/dist/chunk-DLVRNIY5.js"() {
29563
29520
  "use strict";
29564
29521
  init_runtime_v2();
29565
29522
  init_zod();
@@ -29665,6 +29622,131 @@ var init_chunk_2SKVAUID = __esm({
29665
29622
  }
29666
29623
  });
29667
29624
 
29625
+ // ../agent-core/dist/chunk-OSECDZA5.js
29626
+ function selectExternalMcpServers(spec) {
29627
+ const isWorkflow = Boolean(spec.workflowId || spec.workflowExecutionId);
29628
+ const filter = isWorkflow ? createWorkflowToolsFilter(spec.workflowTools) : null;
29629
+ if (filter && !filter.hasFilter) return {};
29630
+ const selected = {};
29631
+ for (const [name, server] of Object.entries(spec.externalMcpServers ?? {})) {
29632
+ if (!isExternalMcpServerName(name)) continue;
29633
+ if (filter && !filter.isMcpServerAllowed(name)) continue;
29634
+ selected[name] = server;
29635
+ }
29636
+ return selected;
29637
+ }
29638
+ function headerEnvName(server, header) {
29639
+ const fingerprint = (0, import_crypto5.createHash)("sha256").update(`${server}\0${header}`).digest("hex").slice(0, 12);
29640
+ return `ALAN_MCP_HEADER_${fingerprint.toUpperCase()}`;
29641
+ }
29642
+ function deliverRemote(name, server, env) {
29643
+ const headerEnv = {};
29644
+ for (const [header, value2] of Object.entries(server.headers ?? {})) {
29645
+ if (!isMcpConfigKey(header)) continue;
29646
+ const variable = headerEnvName(name, header);
29647
+ env[variable] = value2;
29648
+ headerEnv[header] = variable;
29649
+ }
29650
+ return {
29651
+ type: server.type === "sse" ? "sse" : "http",
29652
+ url: server.url,
29653
+ ...Object.keys(headerEnv).length ? { headerEnv } : {}
29654
+ };
29655
+ }
29656
+ function deliverStdio(server, cliEnv, delivery) {
29657
+ const envKeys = [];
29658
+ for (const [key, value2] of Object.entries(server.env ?? {})) {
29659
+ if (!isMcpConfigKey(key)) continue;
29660
+ if (key in cliEnv || key in delivery.env && delivery.env[key] !== value2) {
29661
+ delivery.skippedEnvKeys.push(key);
29662
+ continue;
29663
+ }
29664
+ delivery.env[key] = value2;
29665
+ envKeys.push(key);
29666
+ }
29667
+ return {
29668
+ type: "stdio",
29669
+ command: server.command,
29670
+ ...server.args?.length ? { args: server.args } : {},
29671
+ ...envKeys.length ? { envKeys } : {}
29672
+ };
29673
+ }
29674
+ function planExternalMcpDelivery(spec, cliEnv) {
29675
+ const delivery = { servers: {}, env: {}, skippedEnvKeys: [] };
29676
+ for (const [name, server] of Object.entries(selectExternalMcpServers(spec))) {
29677
+ const { url: url3, command } = server;
29678
+ if (url3 && server.type !== "stdio") {
29679
+ delivery.servers[name] = deliverRemote(name, { ...server, url: url3 }, delivery.env);
29680
+ } else if (command) {
29681
+ delivery.servers[name] = deliverStdio({ ...server, command }, cliEnv, delivery);
29682
+ }
29683
+ }
29684
+ return delivery;
29685
+ }
29686
+ function envReference(name) {
29687
+ return `\${${name}}`;
29688
+ }
29689
+ function managedMcpHeaders(identity) {
29690
+ if (identity.scope === "run") {
29691
+ return {
29692
+ Authorization: envReference(ALAN_MCP_AUTHORIZATION_ENV),
29693
+ [MANAGED_MCP_RUN_HEADER]: envReference(ALAN_RUN_ID_ENV)
29694
+ };
29695
+ }
29696
+ return {
29697
+ ...identity.authorization === void 0 ? {} : { Authorization: identity.authorization },
29698
+ [MANAGED_MCP_CONVERSATION_HEADER]: identity.conversationId
29699
+ };
29700
+ }
29701
+ function credentialDigest(authorization) {
29702
+ if (authorization === void 0) return void 0;
29703
+ return (0, import_crypto6.createHash)("sha256").update(authorization).digest("hex").slice(0, 16);
29704
+ }
29705
+ function canonicalizeManagedMcpServerName(serverName) {
29706
+ return RUN_SCOPED_SERVER.test(serverName) ? MANAGED_MCP_SERVER_NAME : serverName;
29707
+ }
29708
+ function canonicalizeManagedMcpToolName(toolName2) {
29709
+ const namespaced = NAMESPACED_RUN_TOOL.exec(toolName2);
29710
+ if (namespaced) return `mcp__${MANAGED_MCP_SERVER_NAME}__${namespaced[2]}`;
29711
+ const flattened = FLATTENED_RUN_TOOL.exec(toolName2);
29712
+ return flattened ? `mcp__${MANAGED_MCP_SERVER_NAME}__${flattened[1]}` : toolName2;
29713
+ }
29714
+ async function writeSecretFile(name, contents) {
29715
+ const dir = await (0, import_promises30.mkdtemp)((0, import_path5.join)((0, import_os2.tmpdir)(), "alan-mcp-"));
29716
+ const path4 = (0, import_path5.join)(dir, name);
29717
+ const remove = async () => {
29718
+ await (0, import_promises30.rm)(dir, { recursive: true, force: true });
29719
+ };
29720
+ try {
29721
+ await (0, import_promises30.writeFile)(path4, contents, { mode: 384, flag: "wx" });
29722
+ } catch (error62) {
29723
+ await remove();
29724
+ throw error62;
29725
+ }
29726
+ return { path: path4, remove, [Symbol.asyncDispose]: remove };
29727
+ }
29728
+ 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;
29729
+ var init_chunk_OSECDZA5 = __esm({
29730
+ "../agent-core/dist/chunk-OSECDZA5.js"() {
29731
+ "use strict";
29732
+ import_crypto5 = require("crypto");
29733
+ init_agent2();
29734
+ import_crypto6 = require("crypto");
29735
+ init_agent2();
29736
+ init_runtime_v2();
29737
+ import_promises30 = require("fs/promises");
29738
+ import_os2 = require("os");
29739
+ import_path5 = require("path");
29740
+ OPENCODE_CODE_MODE_ENV = "OPENCODE_EXPERIMENTAL_CODE_MODE";
29741
+ OPENCODE_CODE_MODE_TOOL = "execute";
29742
+ CODE_MODE_CALLS_META = "alanToolCalls";
29743
+ MANAGED_MCP_SERVER_NAME = "alan";
29744
+ RUN_SCOPED_SERVER = /^alan-run-[a-f0-9]{16}$/;
29745
+ NAMESPACED_RUN_TOOL = /^mcp__(alan-run-[a-f0-9]{16})__(.+)$/;
29746
+ FLATTENED_RUN_TOOL = /^alan-run-[a-f0-9]{16}_(.+)$/;
29747
+ }
29748
+ });
29749
+
29668
29750
  // ../agent-core/dist/providers/claude.js
29669
29751
  function trimmed(value2) {
29670
29752
  const text22 = value2?.trim();
@@ -30907,12 +30989,12 @@ var init_claude = __esm({
30907
30989
  "../agent-core/dist/providers/claude.js"() {
30908
30990
  "use strict";
30909
30991
  init_chunk_D4TIXPWZ();
30910
- init_chunk_ILZBXGVI();
30992
+ init_chunk_FYZKVT3E();
30911
30993
  init_chunk_OUEMTEUX();
30912
30994
  init_chunk_ZCTKXKYY();
30913
- init_chunk_J2KTV5FP();
30914
30995
  init_chunk_6VWVDJ2A();
30915
- init_chunk_2SKVAUID();
30996
+ init_chunk_DLVRNIY5();
30997
+ init_chunk_OSECDZA5();
30916
30998
  init_chunk_YXWJW7I5();
30917
30999
  init_effort();
30918
31000
  import_crypto7 = require("crypto");
@@ -33763,12 +33845,12 @@ var init_codex = __esm({
33763
33845
  "../agent-core/dist/providers/codex.js"() {
33764
33846
  "use strict";
33765
33847
  init_chunk_D4TIXPWZ();
33766
- init_chunk_ILZBXGVI();
33848
+ init_chunk_FYZKVT3E();
33767
33849
  init_chunk_OUEMTEUX();
33768
33850
  init_chunk_ZCTKXKYY();
33769
- init_chunk_J2KTV5FP();
33770
33851
  init_chunk_6VWVDJ2A();
33771
- init_chunk_2SKVAUID();
33852
+ init_chunk_DLVRNIY5();
33853
+ init_chunk_OSECDZA5();
33772
33854
  init_chunk_YXWJW7I5();
33773
33855
  import_fs7 = require("fs");
33774
33856
  import_path7 = require("path");
@@ -35106,6 +35188,47 @@ const PROVIDER_ID = ${JSON.stringify(ALAN_CODE_ENGINE_PROVIDER_ID)};
35106
35188
  const INCLUDED_RESULTS = 8;
35107
35189
  const MAX_AUTO_RETRIES = 2;
35108
35190
  const MAX_AUTO_RETRY_WAIT_MS = 10_000;
35191
+ const CODE_MODE_TOOL = ${JSON.stringify(OPENCODE_CODE_MODE_TOOL)};
35192
+ const CODE_MODE_CALLS_META = ${JSON.stringify(CODE_MODE_CALLS_META)};
35193
+ const MAX_CHILD_OUTPUT_CHARS = 64 * 1024;
35194
+ const MAX_OPEN_SCRIPTS = 64;
35195
+ const scriptCalls = new Map();
35196
+
35197
+ function mcpResultText(result) {
35198
+ return result.content
35199
+ .flatMap(function (item) {
35200
+ if (item && item.type === "text") return [item.text];
35201
+ if (item && item.type === "resource" && item.resource && item.resource.text) return [item.resource.text];
35202
+ return [];
35203
+ })
35204
+ .join("\\n\\n");
35205
+ }
35206
+
35207
+ function openScript(callID) {
35208
+ if (scriptCalls.size >= MAX_OPEN_SCRIPTS) scriptCalls.delete(scriptCalls.keys().next().value);
35209
+ scriptCalls.set(callID, []);
35210
+ }
35211
+
35212
+ // Code mode names each MCP call "<script callID>/<n>" and hands the hook the raw MCP result.
35213
+ function recordScriptCall(input, result) {
35214
+ const callID = String(input.callID || "");
35215
+ const slash = callID.lastIndexOf("/");
35216
+ const calls = slash > 0 ? scriptCalls.get(callID.slice(0, slash)) : undefined;
35217
+ if (!calls || !result || !Array.isArray(result.content)) return;
35218
+ calls.push({
35219
+ callId: callID,
35220
+ tool: input.tool,
35221
+ input: input.args,
35222
+ output: mcpResultText(result).slice(0, MAX_CHILD_OUTPUT_CHARS),
35223
+ });
35224
+ }
35225
+
35226
+ function closeScript(callID, output) {
35227
+ const calls = scriptCalls.get(callID);
35228
+ scriptCalls.delete(callID);
35229
+ if (!calls || calls.length === 0 || !output || typeof output !== "object") return;
35230
+ output.metadata = Object.assign({}, output.metadata, { [CODE_MODE_CALLS_META]: calls });
35231
+ }
35109
35232
 
35110
35233
  function truncate(text, max) {
35111
35234
  const trimmed = String(text == null ? "" : text).trim();
@@ -35213,6 +35336,13 @@ export const AlanEnginePlugin = async () => ({
35213
35336
  output.headers["x-alan-operation-key"] = Date.now() + "-" + crypto.randomUUID();
35214
35337
  }
35215
35338
  },
35339
+ "tool.execute.before": async (input) => {
35340
+ if (input.tool === CODE_MODE_TOOL) openScript(input.callID);
35341
+ },
35342
+ "tool.execute.after": async (input, output) => {
35343
+ if (input.tool === CODE_MODE_TOOL) closeScript(input.callID, output);
35344
+ else recordScriptCall(input, output);
35345
+ },
35216
35346
  tool: {
35217
35347
  web_search: {
35218
35348
  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).",
@@ -35246,6 +35376,7 @@ function bearerToken(authorization) {
35246
35376
  function alanCodeEngineEnv(input2) {
35247
35377
  return {
35248
35378
  ...alanCodeEngineDirectories(input2.engineRoot),
35379
+ [OPENCODE_CODE_MODE_ENV]: "true",
35249
35380
  [ALAN_CODE_API_KEY_ENV]: input2.apiKey,
35250
35381
  [ALAN_CODE_CONVERSATION_ID_ENV]: input2.conversationId
35251
35382
  };
@@ -35289,6 +35420,7 @@ var import_http9, import_https, import_fs8, import_path8, import_crypto13, impor
35289
35420
  var init_alan_code = __esm({
35290
35421
  "../agent-core/dist/providers/alan-code.js"() {
35291
35422
  "use strict";
35423
+ init_chunk_OSECDZA5();
35292
35424
  init_chunk_YXWJW7I5();
35293
35425
  import_http9 = require("http");
35294
35426
  import_https = require("https");
@@ -35331,10 +35463,15 @@ var init_alan_code = __esm({
35331
35463
  emptyTurn: "Alan Code ended the turn without producing any output. Try again or pick another model."
35332
35464
  };
35333
35465
  WINDOWS_RUNNABLE_EXTENSION = /\.(exe|com|cmd|bat)$/i;
35334
- ALAN_CODE_ENGINE_PLUGIN_VERSION = 2;
35466
+ ALAN_CODE_ENGINE_PLUGIN_VERSION = 3;
35335
35467
  ALAN_CODE_TOOL_NAMING_PROMPT = `## Alan tool names
35336
35468
 
35337
- 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\`.`;
35469
+ 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({ ... })\`.
35470
+
35471
+ - 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.
35472
+ - Alan tools return JSON as text: \`JSON.parse\` a result before reading its fields or passing it to \`Object.keys\`.
35473
+ - Look up IDs in one script, then make the writes in the next, so a failed lookup never leaves half the writes done.
35474
+ - 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.`;
35338
35475
  }
35339
35476
  });
35340
35477
 
@@ -45105,7 +45242,7 @@ var require_tar_stream = __commonJS({
45105
45242
  var init_dist = __esm({
45106
45243
  "../agent-core/dist/index.js"() {
45107
45244
  "use strict";
45108
- init_chunk_ILZBXGVI();
45245
+ init_chunk_FYZKVT3E();
45109
45246
  init_chunk_OUEMTEUX();
45110
45247
  init_chunk_ZCTKXKYY();
45111
45248
  init_chunk_6VWVDJ2A();
@@ -45852,12 +45989,12 @@ var import_promises50, import_path10, import_crypto14, import_promises51, CURSOR
45852
45989
  var init_acp3 = __esm({
45853
45990
  "../agent-core/dist/providers/acp.js"() {
45854
45991
  "use strict";
45855
- init_chunk_ILZBXGVI();
45992
+ init_chunk_FYZKVT3E();
45856
45993
  init_chunk_OUEMTEUX();
45857
45994
  init_chunk_ZCTKXKYY();
45858
- init_chunk_J2KTV5FP();
45859
45995
  init_chunk_6VWVDJ2A();
45860
- init_chunk_2SKVAUID();
45996
+ init_chunk_DLVRNIY5();
45997
+ init_chunk_OSECDZA5();
45861
45998
  init_chunk_YXWJW7I5();
45862
45999
  import_promises50 = require("fs/promises");
45863
46000
  import_path10 = require("path");
@@ -47358,6 +47495,21 @@ function classifyOpenCodeError(error62, fallback) {
47358
47495
  }
47359
47496
  return classifyCliError(message2 || fallback);
47360
47497
  }
47498
+ function readChildCall(value2) {
47499
+ const record2 = asRecord(value2);
47500
+ const callId = asString(record2?.callId);
47501
+ const tool = asString(record2?.tool);
47502
+ if (!record2 || !callId || !tool) return void 0;
47503
+ return { callId, tool, input: record2.input, output: asString(record2.output) };
47504
+ }
47505
+ function readCodeModeChildCalls(metadata) {
47506
+ return asArray(asRecord(metadata)?.[CODE_MODE_CALLS_META]).flatMap(
47507
+ (entry) => {
47508
+ const call = readChildCall(entry);
47509
+ return call ? [call] : [];
47510
+ }
47511
+ );
47512
+ }
47361
47513
  function withParent(updates, parentToolCallId) {
47362
47514
  if (!parentToolCallId) return updates;
47363
47515
  return updates.map(
@@ -47448,6 +47600,24 @@ function toolContent(tool, toolState) {
47448
47600
  const editing = tool.status === "in_progress" && (tool.name === "edit" || tool.name === "write");
47449
47601
  return editing && path4 ? [fileChangeContent({ path: path4, operation: "modify", hunks: [] })] : void 0;
47450
47602
  }
47603
+ function codeModeChildUpdates(tool, metadata) {
47604
+ if (tool.name !== OPENCODE_CODE_MODE_TOOL || tool.status !== "completed") return [];
47605
+ return readCodeModeChildCalls(metadata).map((call) => {
47606
+ const name = canonicalizeManagedMcpToolName(call.tool);
47607
+ const content = outputContent(call.output);
47608
+ return {
47609
+ sessionUpdate: "tool_call_update",
47610
+ toolCallId: call.callId,
47611
+ name,
47612
+ title: name,
47613
+ kind: toolKindFor(name),
47614
+ status: "completed",
47615
+ ...call.input !== void 0 ? { rawInput: call.input } : {},
47616
+ ...content ? { content } : {},
47617
+ ...call.output ? { rawOutput: call.output } : {}
47618
+ };
47619
+ });
47620
+ }
47451
47621
  function createOpenCodeSessionMemory() {
47452
47622
  return { userMessageIds: /* @__PURE__ */ new Set() };
47453
47623
  }
@@ -47786,12 +47956,12 @@ var import_crypto15, import_http10, import_crypto16, import_promises52, import_p
47786
47956
  var init_opencode = __esm({
47787
47957
  "../agent-core/dist/providers/opencode.js"() {
47788
47958
  "use strict";
47789
- init_chunk_ILZBXGVI();
47959
+ init_chunk_FYZKVT3E();
47790
47960
  init_chunk_OUEMTEUX();
47791
47961
  init_chunk_ZCTKXKYY();
47792
- init_chunk_J2KTV5FP();
47793
47962
  init_chunk_6VWVDJ2A();
47794
- init_chunk_2SKVAUID();
47963
+ init_chunk_DLVRNIY5();
47964
+ init_chunk_OSECDZA5();
47795
47965
  init_chunk_YXWJW7I5();
47796
47966
  import_crypto15 = require("crypto");
47797
47967
  import_http10 = require("http");
@@ -48317,6 +48487,7 @@ var init_opencode = __esm({
48317
48487
  }
48318
48488
  ];
48319
48489
  updates.push(...this.#plan(toolCallId, tool.name, toolState));
48490
+ updates.push(...codeModeChildUpdates(tool, toolState?.metadata));
48320
48491
  if (tool.status === "failed" && (tool.isTask || PERMISSION_DENIED.test(tool.errorMessage))) {
48321
48492
  updates.push(
48322
48493
  noticeUpdate("error", "tool_failed", tool.errorMessage || "OpenCode tool call failed.")
@@ -49836,12 +50007,12 @@ var import_crypto18, import_promises53, FACTORY_API_VERSION, FACTORY_PROTOCOL_VE
49836
50007
  var init_droid = __esm({
49837
50008
  "../agent-core/dist/providers/droid.js"() {
49838
50009
  "use strict";
49839
- init_chunk_ILZBXGVI();
50010
+ init_chunk_FYZKVT3E();
49840
50011
  init_chunk_OUEMTEUX();
49841
50012
  init_chunk_ZCTKXKYY();
49842
- init_chunk_J2KTV5FP();
49843
50013
  init_chunk_6VWVDJ2A();
49844
- init_chunk_2SKVAUID();
50014
+ init_chunk_DLVRNIY5();
50015
+ init_chunk_OSECDZA5();
49845
50016
  init_chunk_YXWJW7I5();
49846
50017
  init_runtime_v2();
49847
50018
  import_crypto18 = require("crypto");
@@ -50946,11 +51117,11 @@ var init_antigravity = __esm({
50946
51117
  "../agent-core/dist/providers/antigravity.js"() {
50947
51118
  "use strict";
50948
51119
  init_chunk_D4TIXPWZ();
50949
- init_chunk_ILZBXGVI();
51120
+ init_chunk_FYZKVT3E();
50950
51121
  init_chunk_OUEMTEUX();
50951
51122
  init_chunk_ZCTKXKYY();
50952
51123
  init_chunk_6VWVDJ2A();
50953
- init_chunk_2SKVAUID();
51124
+ init_chunk_DLVRNIY5();
50954
51125
  init_chunk_YXWJW7I5();
50955
51126
  import_promises54 = require("fs/promises");
50956
51127
  import_path13 = require("path");
@@ -51650,12 +51821,12 @@ var import_promises55, import_path16, import_crypto20, COMMAND_CODE_GRAMMAR_NAME
51650
51821
  var init_command_code = __esm({
51651
51822
  "../agent-core/dist/providers/command-code.js"() {
51652
51823
  "use strict";
51653
- init_chunk_ILZBXGVI();
51824
+ init_chunk_FYZKVT3E();
51654
51825
  init_chunk_OUEMTEUX();
51655
51826
  init_chunk_ZCTKXKYY();
51656
- init_chunk_J2KTV5FP();
51657
51827
  init_chunk_6VWVDJ2A();
51658
- init_chunk_2SKVAUID();
51828
+ init_chunk_DLVRNIY5();
51829
+ init_chunk_OSECDZA5();
51659
51830
  init_chunk_YXWJW7I5();
51660
51831
  import_promises55 = require("fs/promises");
51661
51832
  import_path16 = require("path");
@@ -57053,7 +57224,7 @@ var require_websocket_server = __commonJS({
57053
57224
  // package.json
57054
57225
  var package_default = {
57055
57226
  name: "@alan-ai-hq/agent-manager",
57056
- version: "0.1.156",
57227
+ version: "0.1.158",
57057
57228
  private: true,
57058
57229
  type: "module",
57059
57230
  description: "Alan machine runtime (alan-agent): identity, link, reconciler, session holders, run log, uploader, local API",
@@ -70672,7 +70843,7 @@ var import_promises58 = require("fs/promises");
70672
70843
  var import_node_path56 = require("path");
70673
70844
 
70674
70845
  // ../agent-core/dist/prompt.js
70675
- init_chunk_2SKVAUID();
70846
+ init_chunk_DLVRNIY5();
70676
70847
 
70677
70848
  // src/holder/agent-context.ts
70678
70849
  async function readText4(path4) {
@@ -71977,7 +72148,19 @@ async function runHolder({
71977
72148
  ...machine?.platform === void 0 ? {} : { platform: machine.platform }
71978
72149
  });
71979
72150
  const observed = facts.observe(driver);
71980
- const writeStatus = () => writeJsonFileAtomic(launch.statusPath, {
72151
+ let statusWrites = Promise.resolve();
72152
+ const writeStatus = () => {
72153
+ const next = statusWrites.then(() => writeStatusNow());
72154
+ statusWrites = next.catch(
72155
+ (error62) => log.warn("holder.status_write_failed", { error: error62 })
72156
+ );
72157
+ return next;
72158
+ };
72159
+ const queueStatus = () => {
72160
+ writeStatus().catch(() => {
72161
+ });
72162
+ };
72163
+ const writeStatusNow = () => writeJsonFileAtomic(launch.statusPath, {
71981
72164
  protocol: HOLDER_PROTOCOL,
71982
72165
  conversationId: launch.conversationId,
71983
72166
  pid: identity.pid,
@@ -71996,7 +72179,7 @@ async function runHolder({
71996
72179
  holder.state = "idle";
71997
72180
  holder.runId = null;
71998
72181
  holder.turn = null;
71999
- void writeStatus();
72182
+ queueStatus();
72000
72183
  };
72001
72184
  const startTurn = (id, spec, client) => {
72002
72185
  if (holder.runId === spec.runId) {
@@ -72040,7 +72223,7 @@ async function runHolder({
72040
72223
  return;
72041
72224
  }
72042
72225
  writeMessage(client, { type: "ack", id });
72043
- void writeStatus();
72226
+ queueStatus();
72044
72227
  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);
72045
72228
  },
72046
72229
  (error62) => {
@@ -72178,6 +72361,7 @@ async function runHolder({
72178
72361
  await driver.suspend?.().catch((error62) => log.warn("holder.driver_suspend_failed", { error: error62 }));
72179
72362
  for (const client of holder.clients) client.end();
72180
72363
  await new Promise((resolve13) => server.close(() => resolve13()));
72364
+ await statusWrites;
72181
72365
  (0, import_node_fs23.rmSync)(launch.statusPath, { force: true });
72182
72366
  log.info("holder.suspended", { conversationId: launch.conversationId });
72183
72367
  } catch (_) {