@alan-ai-hq/agent-manager-linux-x64 0.1.159 → 0.1.161

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 +1072 -338
  2. package/alan-holder.cjs +831 -212
  3. package/package.json +1 -1
package/alan-agent.cjs CHANGED
@@ -637,14 +637,14 @@ function codePointLength(str) {
637
637
  const units = str.length;
638
638
  if (!highSurrogate.test(str))
639
639
  return units;
640
- let count = units;
640
+ let count2 = units;
641
641
  for (let i = 0; i < units - 1; i++) {
642
642
  if ((str.charCodeAt(i) & 64512) === 55296 && (str.charCodeAt(i + 1) & 64512) === 56320) {
643
- count--;
643
+ count2--;
644
644
  i++;
645
645
  }
646
646
  }
647
- return count;
647
+ return count2;
648
648
  }
649
649
  function getLengthableOrigin(input2) {
650
650
  if (Array.isArray(input2))
@@ -5147,8 +5147,8 @@ var init_az = __esm({
5147
5147
  });
5148
5148
 
5149
5149
  // ../../node_modules/zod/v4/locales/be.js
5150
- function getBelarusianPlural(count, one, few, many) {
5151
- const absCount = Math.abs(count);
5150
+ function getBelarusianPlural(count2, one, few, many) {
5151
+ const absCount = Math.abs(count2);
5152
5152
  const lastDigit = absCount % 10;
5153
5153
  const lastTwoDigits = absCount % 100;
5154
5154
  if (lastTwoDigits >= 11 && lastTwoDigits <= 19) {
@@ -7942,8 +7942,8 @@ var init_hu = __esm({
7942
7942
  });
7943
7943
 
7944
7944
  // ../../node_modules/zod/v4/locales/hy.js
7945
- function getArmenianPlural(count, one, many) {
7946
- return Math.abs(count) === 1 ? one : many;
7945
+ function getArmenianPlural(count2, one, many) {
7946
+ return Math.abs(count2) === 1 ? one : many;
7947
7947
  }
7948
7948
  function withDefiniteArticle(word) {
7949
7949
  if (!word)
@@ -10841,8 +10841,8 @@ var init_ro = __esm({
10841
10841
  });
10842
10842
 
10843
10843
  // ../../node_modules/zod/v4/locales/ru.js
10844
- function getRussianPlural(count, one, few, many) {
10845
- const absCount = Math.abs(count);
10844
+ function getRussianPlural(count2, one, few, many) {
10845
+ const absCount = Math.abs(count2);
10846
10846
  const lastDigit = absCount % 10;
10847
10847
  const lastTwoDigits = absCount % 100;
10848
10848
  if (lastTwoDigits >= 11 && lastTwoDigits <= 19) {
@@ -22501,6 +22501,56 @@ var init_run_log_upload = __esm({
22501
22501
  }
22502
22502
  });
22503
22503
 
22504
+ // ../shared/dist/runtime-v2/run-media.js
22505
+ function runMediaPath(runId) {
22506
+ return `/public/machines/me/runs/${encodeURIComponent(runId)}/media`;
22507
+ }
22508
+ function runMediaCompletePath(runId, mediaId) {
22509
+ return `${runMediaPath(runId)}/${encodeURIComponent(mediaId)}/complete`;
22510
+ }
22511
+ var INT4_MAX, runMediaSourceSchema, runMediaUploadRequestSchema, runMediaUploadTargetSchema, runMediaUploadResponseSchema, runMediaCompleteResponseSchema;
22512
+ var init_run_media = __esm({
22513
+ "../shared/dist/runtime-v2/run-media.js"() {
22514
+ "use strict";
22515
+ init_zod();
22516
+ INT4_MAX = 2147483647;
22517
+ runMediaSourceSchema = external_exports.enum(["generated_image", "session_media"]);
22518
+ runMediaUploadRequestSchema = external_exports.object({
22519
+ /** The `id` the transcript update carries; one upload per id and run. */
22520
+ mediaId: external_exports.string().min(1).max(200),
22521
+ source: runMediaSourceSchema,
22522
+ kind: external_exports.enum(["image", "video"]),
22523
+ mimeType: external_exports.string().min(1).max(200),
22524
+ filename: external_exports.string().min(1).max(500),
22525
+ bytes: external_exports.number().int().positive().max(INT4_MAX),
22526
+ sha256: external_exports.string().regex(/^[0-9a-f]{64}$/),
22527
+ width: external_exports.number().int().min(0).max(INT4_MAX).nullish(),
22528
+ height: external_exports.number().int().min(0).max(INT4_MAX).nullish(),
22529
+ toolId: external_exports.string().max(500).optional(),
22530
+ sourcePath: external_exports.string().max(4096).optional(),
22531
+ ts: external_exports.number().int().positive().optional()
22532
+ });
22533
+ runMediaUploadTargetSchema = external_exports.object({
22534
+ url: external_exports.url(),
22535
+ /** Every header the signed PUT expects, besides the body's `content-length`. */
22536
+ headers: external_exports.record(external_exports.string(), external_exports.string()),
22537
+ expiresAt: external_exports.iso.datetime()
22538
+ });
22539
+ runMediaUploadResponseSchema = external_exports.discriminatedUnion("status", [
22540
+ external_exports.object({
22541
+ status: external_exports.literal("upload"),
22542
+ mediaId: external_exports.string(),
22543
+ upload: runMediaUploadTargetSchema
22544
+ }),
22545
+ external_exports.object({ status: external_exports.literal("ready"), mediaId: external_exports.string() })
22546
+ ]);
22547
+ runMediaCompleteResponseSchema = external_exports.object({
22548
+ status: external_exports.literal("ready"),
22549
+ mediaId: external_exports.string()
22550
+ });
22551
+ }
22552
+ });
22553
+
22504
22554
  // ../shared/dist/runtime-v2/skills.js
22505
22555
  var MACHINE_SKILLS_SYNC_PATH, MAX_MACHINE_SKILLS, installedMachineSkillSchema, MAX_SKILL_UPLOADS, machineSkillScanRepositorySchema, machineSkillScanContextSchema, machineLocalSkillsReportSchema, machineSkillUploadSchema, machineSkillsSyncRequestSchema, desiredMachineSkillSchema, machineSkillDownloadSchema, machineSkillsSyncResponseSchema;
22506
22556
  var init_skills = __esm({
@@ -22624,6 +22674,7 @@ var init_runtime_v2 = __esm({
22624
22674
  init_mcp();
22625
22675
  init_run_log();
22626
22676
  init_run_log_upload();
22677
+ init_run_media();
22627
22678
  init_skills();
22628
22679
  init_workspace();
22629
22680
  }
@@ -25470,8 +25521,8 @@ function diffRows(patch) {
25470
25521
  return { kind: "meta", text: line };
25471
25522
  });
25472
25523
  }
25473
- function patchForPath(text3, path4, count) {
25474
- if (count === 1)
25524
+ function patchForPath(text3, path4, count2) {
25525
+ if (count2 === 1)
25475
25526
  return text3;
25476
25527
  const normalized2 = path4.replace(/^\/+/, "");
25477
25528
  return text3.split(/(?=^diff --git )/m).find((part) => {
@@ -26042,6 +26093,13 @@ function applyUpdate(state, update) {
26042
26093
  index.last = state.entries.at(-1);
26043
26094
  return state;
26044
26095
  }
26096
+ function usageContextTokens(meta3) {
26097
+ const usage = meta3?.["alan.dev/usage"];
26098
+ if (typeof usage !== "object" || usage === null || !("contextTokens" in usage))
26099
+ return void 0;
26100
+ const { contextTokens } = usage;
26101
+ return typeof contextTokens === "number" && Number.isFinite(contextTokens) && contextTokens > 0 ? contextTokens : void 0;
26102
+ }
26045
26103
  function awaitingToolCallIds(meta3) {
26046
26104
  const ids = meta3?.[AWAITING_TOOL_CALLS_META];
26047
26105
  return Array.isArray(ids) ? ids.filter((id) => typeof id === "string") : [];
@@ -26093,9 +26151,11 @@ function applyOne(state, index, update) {
26093
26151
  case "usage_update": {
26094
26152
  if (!isUpdate(update, "usage_update"))
26095
26153
  return;
26154
+ const contextTokens = usageContextTokens(update._meta);
26096
26155
  state.usage = {
26097
26156
  used: update.used,
26098
26157
  size: update.size,
26158
+ ...contextTokens === void 0 ? {} : { contextTokens },
26099
26159
  ...update.cost ? { cost: update.cost } : {}
26100
26160
  };
26101
26161
  delete state.thinkingTokens;
@@ -26448,17 +26508,20 @@ function stepSummary(node2) {
26448
26508
  const update = node2.event.update;
26449
26509
  const children = node2.children.map(stepSummary);
26450
26510
  if (update.sessionUpdate === "terminal_update") {
26451
- const { output: _output, ...rest2 } = update;
26452
- return { ...node2, event: { ...node2.event, update: rest2 }, children };
26511
+ const { output: output2, ...rest2 } = update;
26512
+ const omitted = output2 === void 0 ? {} : { outputTruncated: true };
26513
+ return { ...node2, event: { ...node2.event, update: { ...rest2, ...omitted } }, children };
26453
26514
  }
26454
26515
  if (update.sessionUpdate !== "tool_call_update")
26455
26516
  return { ...node2, children };
26456
26517
  const inputRecord = toolInputRecord(update.rawInput);
26457
26518
  if (rendersBesideSteps(update, inputRecord))
26458
26519
  return { ...node2, children };
26459
- const { content, rawOutput: _rawOutput, rawInput, ...rest } = update;
26520
+ const { content, rawOutput, rawInput, ...rest } = update;
26460
26521
  const input2 = stepInput(rawInput, inputRecord);
26461
- const diffs = (Array.isArray(content) ? content : []).map(diffWithoutText).filter((block2) => block2 !== null);
26522
+ const blocks = Array.isArray(content) ? content : [];
26523
+ const diffs = blocks.map(diffWithoutText).filter((block2) => block2 !== null);
26524
+ const outputOmitted = rawOutput !== void 0 && rawOutput !== null && rawOutput !== "" || blocks.length > 0;
26462
26525
  return {
26463
26526
  ...node2,
26464
26527
  event: {
@@ -26467,6 +26530,7 @@ function stepSummary(node2) {
26467
26530
  ...rest,
26468
26531
  ...input2.value === void 0 ? {} : { rawInput: input2.value },
26469
26532
  ...input2.truncated ? { inputTruncated: true } : {},
26533
+ ...outputOmitted ? { outputTruncated: true } : {},
26470
26534
  ...diffs.length > 0 ? { content: diffs } : {}
26471
26535
  }
26472
26536
  },
@@ -26783,9 +26847,14 @@ var init_session_activity = __esm({
26783
26847
  });
26784
26848
 
26785
26849
  // ../shared/dist/agent/acp/transcript-byte-decoder.js
26850
+ var MIN_ELIDED_DATA_BYTES, DATA_KEY, MEDIA_MARKERS;
26786
26851
  var init_transcript_byte_decoder = __esm({
26787
26852
  "../shared/dist/agent/acp/transcript-byte-decoder.js"() {
26788
26853
  "use strict";
26854
+ init_types2();
26855
+ MIN_ELIDED_DATA_BYTES = 16 * 1024;
26856
+ DATA_KEY = new TextEncoder().encode('"data":"');
26857
+ MEDIA_MARKERS = [...MEDIA_SESSION_UPDATE_KINDS].map((kind) => new TextEncoder().encode(JSON.stringify(kind)));
26789
26858
  }
26790
26859
  });
26791
26860
 
@@ -26987,7 +27056,7 @@ var init_acp = __esm({
26987
27056
  }
26988
27057
  });
26989
27058
 
26990
- // ../agent-core/dist/chunk-OUEMTEUX.js
27059
+ // ../agent-core/dist/chunk-RBQC7XZH.js
26991
27060
  function textBlock(text3) {
26992
27061
  return { type: "text", text: text3 };
26993
27062
  }
@@ -27122,8 +27191,8 @@ function readPatchHunks(value2) {
27122
27191
  return hunk ? [hunk] : [];
27123
27192
  });
27124
27193
  }
27125
- function hunkRange(start, count) {
27126
- return count === 1 ? String(start) : `${start},${count}`;
27194
+ function hunkRange(start, count2) {
27195
+ return count2 === 1 ? String(start) : `${start},${count2}`;
27127
27196
  }
27128
27197
  function hunkHeader(hunk) {
27129
27198
  return `@@ -${hunkRange(hunk.oldStart, hunk.oldLines)} +${hunkRange(hunk.newStart, hunk.newLines)} @@`;
@@ -27134,14 +27203,14 @@ function patchPath(path4) {
27134
27203
  function wholeFileHunk(content, deleted) {
27135
27204
  const lines2 = content === "" ? [] : content.split("\n");
27136
27205
  if (lines2.at(-1) === "") lines2.pop();
27137
- const count = lines2.length;
27206
+ const count2 = lines2.length;
27138
27207
  const marked = lines2.map((line) => `${deleted ? "-" : "+"}${line}`);
27139
27208
  if (content && !content.endsWith("\n")) marked.push("\");
27140
27209
  return {
27141
- oldStart: deleted && count ? 1 : 0,
27142
- oldLines: deleted ? count : 0,
27143
- newStart: !deleted && count ? 1 : 0,
27144
- newLines: deleted ? 0 : count,
27210
+ oldStart: deleted && count2 ? 1 : 0,
27211
+ oldLines: deleted ? count2 : 0,
27212
+ newStart: !deleted && count2 ? 1 : 0,
27213
+ newLines: deleted ? 0 : count2,
27145
27214
  lines: marked
27146
27215
  };
27147
27216
  }
@@ -27236,8 +27305,8 @@ function planEntries(todos) {
27236
27305
  });
27237
27306
  }
27238
27307
  var PROVIDER_PAYLOAD_META, TOOL_RESULT_ONLY_META, PARENT_TOOL_CALL_META, SUBAGENT_LAUNCHER_META, SUBAGENT_TASK_ID_META, SUBAGENT_OUTPUT_FILE_META, USAGE_META, TODOS_META, NOTICE_KIND_META, ASK_USER_QUESTIONS_META, USER_ANSWER_META, AWAITING_TOOL_CALLS_META2, EXIT_PLAN_MODE_INPUT_META, BACKGROUND_TASK_META, TASK_PROGRESS_META, RATE_LIMIT_META, MODEL_META, TOOLS_META, SLASH_COMMANDS_META, TOOL_KIND_RULES, ANSWER_PREFIX, ACCEPT_WORDS, MIN_INLINE_MEDIA_CHARS, DATA_URL_PREFIX, BASE64_BODY, PLAN_ENTRY_STATUSES;
27239
- var init_chunk_OUEMTEUX = __esm({
27240
- "../agent-core/dist/chunk-OUEMTEUX.js"() {
27308
+ var init_chunk_RBQC7XZH = __esm({
27309
+ "../agent-core/dist/chunk-RBQC7XZH.js"() {
27241
27310
  "use strict";
27242
27311
  init_chunk_YXWJW7I5();
27243
27312
  init_constants();
@@ -27293,12 +27362,12 @@ var init_chunk_OUEMTEUX = __esm({
27293
27362
  var init_acp2 = __esm({
27294
27363
  "../agent-core/dist/acp.js"() {
27295
27364
  "use strict";
27296
- init_chunk_OUEMTEUX();
27365
+ init_chunk_RBQC7XZH();
27297
27366
  init_chunk_YXWJW7I5();
27298
27367
  }
27299
27368
  });
27300
27369
 
27301
- // ../agent-core/dist/chunk-D4TIXPWZ.js
27370
+ // ../agent-core/dist/chunk-TFIO37PI.js
27302
27371
  function isRecordValue(value2) {
27303
27372
  return value2 !== null;
27304
27373
  }
@@ -27477,10 +27546,10 @@ function readTranscriptTurns(transcript, chunk, baseOffset, skipped = []) {
27477
27546
  return { turns, consumedBytes: consumedEnd - baseOffset };
27478
27547
  }
27479
27548
  var import_fs4, NEWLINE2, TranscriptCursor, TranscriptLineLookup, CONTENT_UPDATES;
27480
- var init_chunk_D4TIXPWZ = __esm({
27481
- "../agent-core/dist/chunk-D4TIXPWZ.js"() {
27549
+ var init_chunk_TFIO37PI = __esm({
27550
+ "../agent-core/dist/chunk-TFIO37PI.js"() {
27482
27551
  "use strict";
27483
- init_chunk_OUEMTEUX();
27552
+ init_chunk_RBQC7XZH();
27484
27553
  init_chunk_YXWJW7I5();
27485
27554
  import_fs4 = require("fs");
27486
27555
  NEWLINE2 = 10;
@@ -28037,7 +28106,7 @@ var init_chunk_ZCTKXKYY = __esm({
28037
28106
  }
28038
28107
  });
28039
28108
 
28040
- // ../agent-core/dist/chunk-FYZKVT3E.js
28109
+ // ../agent-core/dist/chunk-N2M5D7RS.js
28041
28110
  function detectImageMimeType(buffer) {
28042
28111
  if (buffer.length >= 8 && buffer.subarray(0, 8).equals(PNG_SIGNATURE)) return "image/png";
28043
28112
  if (buffer.length >= 3 && buffer[0] === 255 && buffer[1] === 216 && buffer[2] === 255) {
@@ -28173,6 +28242,27 @@ function resultText2(update) {
28173
28242
  if (typeof raw === "string") return raw;
28174
28243
  return raw === void 0 ? "" : JSON.stringify(raw);
28175
28244
  }
28245
+ function mediaUpdate(file2, body) {
28246
+ const fields = {
28247
+ id: file2.mediaId,
28248
+ filename: file2.filename,
28249
+ mimeType: file2.mimeType,
28250
+ size: file2.data.length,
28251
+ ...body,
28252
+ sourcePath: file2.sourcePath,
28253
+ sourceHash: file2.sha256,
28254
+ toolId: file2.toolId,
28255
+ ts: file2.ts,
28256
+ ...file2.width === void 0 ? {} : { width: file2.width },
28257
+ ...file2.height === void 0 ? {} : { height: file2.height }
28258
+ };
28259
+ if (file2.source === "generated_image") {
28260
+ const image = { type: "generated_image", ...fields };
28261
+ return { sessionUpdate: "_alan/generated_image", image };
28262
+ }
28263
+ const media = { type: "session_media", kind: file2.kind, ...fields };
28264
+ return { sessionUpdate: "_alan/session_media", media };
28265
+ }
28176
28266
  function updateRequiredMessage(requirement, found) {
28177
28267
  const { cli, minimumVersion, feature } = requirement;
28178
28268
  const installed = found ? `${cli} ${found}` : `The ${cli} CLI`;
@@ -28457,10 +28547,10 @@ function silentStartError(name, timeoutMs) {
28457
28547
  };
28458
28548
  }
28459
28549
  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"() {
28550
+ var init_chunk_N2M5D7RS = __esm({
28551
+ "../agent-core/dist/chunk-N2M5D7RS.js"() {
28462
28552
  "use strict";
28463
- init_chunk_OUEMTEUX();
28553
+ init_chunk_RBQC7XZH();
28464
28554
  init_chunk_ZCTKXKYY();
28465
28555
  init_chunk_6VWVDJ2A();
28466
28556
  init_chunk_YXWJW7I5();
@@ -28500,8 +28590,12 @@ var init_chunk_FYZKVT3E = __esm({
28500
28590
  this.#cwd = cwd;
28501
28591
  this.#clock = clock;
28502
28592
  }
28503
- /** Updates to record after `update`; nothing for anything but a tool call, which is almost all. */
28593
+ /** Updates to record after `update`, with the bytes inline; nothing for most updates. */
28504
28594
  read(update) {
28595
+ return this.find(update).map((found) => this.inline(found));
28596
+ }
28597
+ /** The media files a completed tool call wrote; nothing for anything but a tool call. */
28598
+ find(update) {
28505
28599
  if (!isUpdate(update, "tool_call_update")) return [];
28506
28600
  const toolCallId = update.toolCallId;
28507
28601
  if (update.name !== void 0 || update.rawInput !== void 0) {
@@ -28547,20 +28641,42 @@ var init_chunk_FYZKVT3E = __esm({
28547
28641
  named: /* @__PURE__ */ new Set([...capturePaths(tool, content, extensions, cwd), ...this.#pathHints])
28548
28642
  });
28549
28643
  }
28550
- #payloadFields(file2, toolId, explicit) {
28551
- const dataChars = base64Length(file2.buffer.length);
28552
- const inline = explicit || this.#mediaDataChars + dataChars <= MAX_TURN_MEDIA_DATA_CHARS;
28644
+ /** The update carrying the file's bytes, unless the turn's budget is spent on media nobody asked for. */
28645
+ inline(found) {
28646
+ const { file: file2 } = found;
28647
+ const dataChars = base64Length(file2.data.length);
28648
+ const inline = found.explicit || this.#mediaDataChars + dataChars <= MAX_TURN_MEDIA_DATA_CHARS;
28553
28649
  if (inline) this.#mediaDataChars += dataChars;
28650
+ return mediaUpdate(
28651
+ file2,
28652
+ inline ? { data: file2.data.toString("base64") } : { inlineDataOmitted: true }
28653
+ );
28654
+ }
28655
+ /** Uploads the file and returns a reference to it; inline as `inline` does when the upload fails. */
28656
+ async publish(found, uploader, signal) {
28657
+ try {
28658
+ await uploader.upload(found.file, signal);
28659
+ return mediaUpdate(found.file, { uploaded: true });
28660
+ } catch {
28661
+ return this.inline(found);
28662
+ }
28663
+ }
28664
+ #found(file2, toolId, source, kind, explicit) {
28554
28665
  return {
28555
- id: (0, import_crypto4.randomUUID)(),
28556
- filename: (0, import_path4.basename)(file2.path),
28557
- mimeType: file2.mimeType,
28558
- size: file2.buffer.length,
28559
- ...inline ? { data: file2.buffer.toString("base64") } : { inlineDataOmitted: true },
28560
- sourcePath: file2.path,
28561
- sourceHash: (0, import_crypto4.createHash)("sha256").update(file2.buffer).digest("hex"),
28562
- toolId,
28563
- ts: this.#clock.now()
28666
+ explicit,
28667
+ file: {
28668
+ mediaId: (0, import_crypto4.randomUUID)(),
28669
+ source,
28670
+ kind,
28671
+ mimeType: file2.mimeType,
28672
+ filename: (0, import_path4.basename)(file2.path),
28673
+ data: file2.buffer,
28674
+ sha256: (0, import_crypto4.createHash)("sha256").update(file2.buffer).digest("hex"),
28675
+ ...kind === "image" ? imageDimensions(file2.buffer, file2.mimeType) : {},
28676
+ toolId,
28677
+ sourcePath: file2.path,
28678
+ ts: this.#clock.now()
28679
+ }
28564
28680
  };
28565
28681
  }
28566
28682
  #generatedImages(toolId, tool, content) {
@@ -28569,14 +28685,7 @@ var init_chunk_FYZKVT3E = __esm({
28569
28685
  mimeByExt: IMAGE_MIME_BY_EXT,
28570
28686
  maxBytes: MAX_IMAGE_BYTES
28571
28687
  });
28572
- return files.map((file2) => {
28573
- const image = {
28574
- type: "generated_image",
28575
- ...this.#payloadFields(file2, toolId, true),
28576
- ...imageDimensions(file2.buffer, file2.mimeType)
28577
- };
28578
- return { sessionUpdate: "_alan/generated_image", image };
28579
- });
28688
+ return files.map((file2) => this.#found(file2, toolId, "generated_image", "image", true));
28580
28689
  }
28581
28690
  #sessionMedia(toolId, tool, content) {
28582
28691
  const isVideo = isAgentBrowserMedia(tool, content, "video");
@@ -28591,13 +28700,7 @@ var init_chunk_FYZKVT3E = __esm({
28591
28700
  );
28592
28701
  return files.map((file2) => {
28593
28702
  this.#pathHints.delete(file2.path);
28594
- const media = {
28595
- type: "session_media",
28596
- kind,
28597
- ...this.#payloadFields(file2, toolId, explicit),
28598
- ...kind === "image" ? imageDimensions(file2.buffer, file2.mimeType) : {}
28599
- };
28600
- return { sessionUpdate: "_alan/session_media", media };
28703
+ return this.#found(file2, toolId, "session_media", kind, explicit);
28601
28704
  });
28602
28705
  }
28603
28706
  };
@@ -30550,9 +30653,29 @@ function backgroundTaskProgress(event, tasks) {
30550
30653
  }
30551
30654
  ];
30552
30655
  }
30656
+ function claudeMessageContextTokens(message2) {
30657
+ if (asString(message2?.model) === "<synthetic>") return void 0;
30658
+ const usage = asRecord(message2?.usage);
30659
+ if (!usage) return void 0;
30660
+ const tokens2 = (asFiniteNumber(usage.input_tokens) ?? 0) + (asFiniteNumber(usage.cache_read_input_tokens) ?? 0) + (asFiniteNumber(usage.cache_creation_input_tokens) ?? 0) + (asFiniteNumber(usage.output_tokens) ?? 0);
30661
+ return tokens2 > 0 ? tokens2 : void 0;
30662
+ }
30663
+ function resultContextWindow(event, model) {
30664
+ const byModel = asRecord(event.modelUsage);
30665
+ if (!byModel) return void 0;
30666
+ const own2 = asFiniteNumber(asRecord(byModel[model])?.contextWindow);
30667
+ if (own2 !== void 0) return own2;
30668
+ let largest;
30669
+ for (const entry of Object.values(byModel)) {
30670
+ const size = asFiniteNumber(asRecord(entry)?.contextWindow);
30671
+ if (size !== void 0 && size > (largest ?? 0)) largest = size;
30672
+ }
30673
+ return largest;
30674
+ }
30553
30675
  function resultUsage(event, context) {
30554
30676
  const usage = asRecord(event.usage);
30555
30677
  const model = asString(event.model).trim() || context.activeModel?.trim() || context.selectedModel?.trim() || "claude";
30678
+ const contextSize = resultContextWindow(event, model);
30556
30679
  return usageUpdate({
30557
30680
  model,
30558
30681
  numTurns: asFiniteNumber(event.num_turns) ?? Math.max(context.iterations, 1),
@@ -30561,7 +30684,9 @@ function resultUsage(event, context) {
30561
30684
  outputTokens: asFiniteNumber(usage?.output_tokens) ?? 0,
30562
30685
  cacheReadTokens: asFiniteNumber(usage?.cache_read_input_tokens) ?? 0,
30563
30686
  cacheCreationTokens: asFiniteNumber(usage?.cache_creation_input_tokens) ?? 0,
30564
- costUsd: asFiniteNumber(event.total_cost_usd) ?? 0
30687
+ costUsd: asFiniteNumber(event.total_cost_usd) ?? 0,
30688
+ ...contextSize === void 0 ? {} : { contextSize },
30689
+ ...context.contextTokens === void 0 ? {} : { contextTokens: context.contextTokens }
30565
30690
  });
30566
30691
  }
30567
30692
  function resultErrorText(event, subtype) {
@@ -30979,7 +31104,8 @@ function scanTurn(records) {
30979
31104
  model: "",
30980
31105
  lastStopReason: "",
30981
31106
  interrupted: false,
30982
- durationMs: void 0
31107
+ durationMs: void 0,
31108
+ contextTokens: void 0
30983
31109
  };
30984
31110
  for (const record2 of records) {
30985
31111
  if (isInterruptMarker(record2)) scan.interrupted = true;
@@ -30992,19 +31118,22 @@ function scanTurn(records) {
30992
31118
  scan.model ||= recordModel;
30993
31119
  const id = asString(message2.id) || asString(record2.uuid);
30994
31120
  scan.usageByMessage.set(id, messageUsage(message2));
31121
+ if (isTopLevel(record2))
31122
+ scan.contextTokens = claudeMessageContextTokens(message2) ?? scan.contextTokens;
30995
31123
  scan.lastStopReason = asString(message2.stop_reason);
30996
31124
  }
30997
31125
  return scan;
30998
31126
  }
30999
31127
  function claudeTurnClosingUpdates(records, state) {
31000
- const { usageByMessage, model, lastStopReason, interrupted, durationMs } = scanTurn(records);
31128
+ const { usageByMessage, model, lastStopReason, interrupted, durationMs, contextTokens } = scanTurn(records);
31001
31129
  const updates = [];
31002
31130
  if (usageByMessage.size > 0) {
31003
31131
  const breakdown = {
31004
31132
  ...totalUsage(usageByMessage.values()),
31005
31133
  model,
31006
31134
  numTurns: usageByMessage.size,
31007
- ...durationMs ? { durationMs } : {}
31135
+ ...durationMs ? { durationMs } : {},
31136
+ ...contextTokens === void 0 ? {} : { contextTokens }
31008
31137
  };
31009
31138
  updates.push(usageUpdate(breakdown, state.model ?? ""));
31010
31139
  }
@@ -31019,9 +31148,9 @@ var import_crypto7, import_fs6, import_path6, import_crypto8, import_promises31,
31019
31148
  var init_claude = __esm({
31020
31149
  "../agent-core/dist/providers/claude.js"() {
31021
31150
  "use strict";
31022
- init_chunk_D4TIXPWZ();
31023
- init_chunk_FYZKVT3E();
31024
- init_chunk_OUEMTEUX();
31151
+ init_chunk_TFIO37PI();
31152
+ init_chunk_N2M5D7RS();
31153
+ init_chunk_RBQC7XZH();
31025
31154
  init_chunk_ZCTKXKYY();
31026
31155
  init_chunk_6VWVDJ2A();
31027
31156
  init_chunk_DLVRNIY5();
@@ -31319,6 +31448,7 @@ var init_claude = __esm({
31319
31448
  #announced = /* @__PURE__ */ new Set();
31320
31449
  #awaitingAskDenialFallback = false;
31321
31450
  #iterations = 0;
31451
+ #contextTokens;
31322
31452
  #providerErrorCode;
31323
31453
  #deferredOnAnswer = false;
31324
31454
  #deferredOnBackground = false;
@@ -31458,6 +31588,7 @@ var init_claude = __esm({
31458
31588
  #handleSystem(event) {
31459
31589
  const subtype = asString(event.subtype);
31460
31590
  if (subtype === "api_retry") this.#noteRetry(event);
31591
+ if (subtype === "compact_boundary") this.#noteCompaction(event);
31461
31592
  if (subtype === "task_started") {
31462
31593
  this.tasks.registerRecord(event, parentToolUseId(event));
31463
31594
  this.taskRecords.track(event, this.tasks.resolveToolUseId(event));
@@ -31542,13 +31673,25 @@ var init_claude = __esm({
31542
31673
  status
31543
31674
  });
31544
31675
  }
31676
+ /** The window was just rewritten; the pre-compaction figure would overstate it until the next call. */
31677
+ #noteCompaction(event) {
31678
+ if (parentToolUseId(event)) return;
31679
+ const after = asFiniteNumber(asRecord(event.compact_metadata)?.post_tokens);
31680
+ this.#contextTokens = after !== void 0 && after > 0 ? after : void 0;
31681
+ }
31682
+ #noteContext(event, message2) {
31683
+ if (parentToolUseId(event)) return;
31684
+ this.#contextTokens = claudeMessageContextTokens(message2) ?? this.#contextTokens;
31685
+ }
31545
31686
  #handleAssistant(event) {
31546
31687
  if (this.#awaitingAskDenialFallback) {
31547
31688
  this.#awaitingAskDenialFallback = false;
31548
31689
  return;
31549
31690
  }
31550
31691
  this.#iterations += 1;
31551
- for (const raw of asArray(asRecord(event.message)?.content)) {
31692
+ const message2 = asRecord(event.message);
31693
+ this.#noteContext(event, message2);
31694
+ for (const raw of asArray(message2?.content)) {
31552
31695
  const block2 = asRecord(raw);
31553
31696
  if (!block2 || asString(block2.type) !== "tool_use") continue;
31554
31697
  const id = asString(block2.id);
@@ -31568,7 +31711,8 @@ var init_claude = __esm({
31568
31711
  resultUsage(event, {
31569
31712
  activeModel: this.grammar.model,
31570
31713
  selectedModel: this.#options.selectedModel,
31571
- iterations: this.#iterations
31714
+ iterations: this.#iterations,
31715
+ ...this.#contextTokens === void 0 ? {} : { contextTokens: this.#contextTokens }
31572
31716
  })
31573
31717
  ];
31574
31718
  if (typeof event.num_turns === "number") this.#iterations = event.num_turns;
@@ -32806,6 +32950,59 @@ function planEntries2(plan2) {
32806
32950
  ];
32807
32951
  });
32808
32952
  }
32953
+ function count(value2) {
32954
+ return asFiniteNumber(value2) ?? 0;
32955
+ }
32956
+ function withTotal(tokens2, reported) {
32957
+ return { ...tokens2, total: reported || tokens2.input + tokens2.output };
32958
+ }
32959
+ function appServerTokens(record2) {
32960
+ return withTotal(
32961
+ {
32962
+ input: count(record2.inputTokens),
32963
+ cachedInput: count(record2.cachedInputTokens),
32964
+ cacheWrite: count(record2.cacheWriteInputTokens),
32965
+ output: count(record2.outputTokens)
32966
+ },
32967
+ count(record2.totalTokens)
32968
+ );
32969
+ }
32970
+ function rolloutTokens(record2) {
32971
+ return withTotal(
32972
+ {
32973
+ input: count(record2.input_tokens),
32974
+ cachedInput: count(record2.cached_input_tokens),
32975
+ cacheWrite: count(record2.cache_write_input_tokens),
32976
+ output: count(record2.output_tokens)
32977
+ },
32978
+ count(record2.total_tokens)
32979
+ );
32980
+ }
32981
+ function subtractTokens(from, amount2) {
32982
+ const minus = (a, b) => Math.max(a - b, 0);
32983
+ return {
32984
+ input: minus(from.input, amount2.input),
32985
+ cachedInput: minus(from.cachedInput, amount2.cachedInput),
32986
+ cacheWrite: minus(from.cacheWrite, amount2.cacheWrite),
32987
+ output: minus(from.output, amount2.output),
32988
+ total: minus(from.total, amount2.total)
32989
+ };
32990
+ }
32991
+ function codexBreakdown(tokens2) {
32992
+ return {
32993
+ inputTokens: Math.max(tokens2.input - tokens2.cachedInput - tokens2.cacheWrite, 0),
32994
+ outputTokens: tokens2.output,
32995
+ cacheReadTokens: tokens2.cachedInput,
32996
+ cacheCreationTokens: tokens2.cacheWrite
32997
+ };
32998
+ }
32999
+ function codexUsageUpdate(spend, extra, fallbackModel) {
33000
+ const update = usageUpdate({ ...codexBreakdown(spend), ...extra }, fallbackModel);
33001
+ return spend.total > 0 && isUpdate(update, "usage_update") ? { ...update, used: spend.total } : update;
33002
+ }
33003
+ function codexContextTokens(last) {
33004
+ return last.total > 0 ? last.total : void 0;
33005
+ }
32809
33006
  function createCodexSessionMemory() {
32810
33007
  return { shownWarnings: /* @__PURE__ */ new Set(), workers: /* @__PURE__ */ new Map() };
32811
33008
  }
@@ -33191,6 +33388,7 @@ function createCodexRolloutState() {
33191
33388
  return {
33192
33389
  recordTime: 0,
33193
33390
  turnUsageSeen: false,
33391
+ turnTokens: new CodexTurnTokens(),
33194
33392
  shellCallIds: /* @__PURE__ */ new Set(),
33195
33393
  announcedCallIds: /* @__PURE__ */ new Set(),
33196
33394
  failedCallIds: /* @__PURE__ */ new Set(),
@@ -33613,31 +33811,29 @@ function compactionNotice2() {
33613
33811
  function num(value2) {
33614
33812
  return asFiniteNumber(value2) ?? 0;
33615
33813
  }
33616
- function tokenBreakdown(usage) {
33617
- return {
33618
- inputTokens: num(usage.input_tokens),
33619
- outputTokens: num(usage.output_tokens) + num(usage.reasoning_output_tokens),
33620
- cacheReadTokens: num(usage.cached_input_tokens),
33621
- cacheCreationTokens: num(usage.cache_write_input_tokens)
33622
- };
33623
- }
33624
- function reportedUsage(breakdown, totalTokens, state) {
33625
- const update = usageUpdate(breakdown, state.model ?? "");
33626
- return totalTokens && update.sessionUpdate === "usage_update" ? { ...update, used: totalTokens } : update;
33814
+ function reportedUsage(spend, state) {
33815
+ return codexUsageUpdate(spend, state.turnTokens.context, state.model ?? "");
33627
33816
  }
33628
33817
  function turnUsage(payload, state) {
33629
33818
  const turn = asRecord(payload.turn_token_usage);
33630
33819
  if (!turn) return [];
33631
33820
  state.turnUsageSeen = true;
33632
- return [reportedUsage(tokenBreakdown(turn), num(turn.total_tokens), state)];
33821
+ return [reportedUsage(rolloutTokens(turn), state)];
33633
33822
  }
33634
33823
  function tokenCount(payload, state) {
33635
- if (state.turnUsageSeen) return [];
33636
33824
  const info = asRecord(payload.info);
33637
- const total = asRecord(info?.total_token_usage);
33638
- if (!total) return [];
33639
- const breakdown = { ...tokenBreakdown(total), contextSize: num(info?.model_context_window) };
33640
- return [reportedUsage(breakdown, num(total.total_tokens), state)];
33825
+ const totalRecord = asRecord(info?.total_token_usage);
33826
+ if (!totalRecord) return [];
33827
+ const total = rolloutTokens(totalRecord);
33828
+ const lastRecord = asRecord(info?.last_token_usage);
33829
+ if (lastRecord)
33830
+ state.turnTokens.note(rolloutTokens(lastRecord), total, num(info?.model_context_window));
33831
+ if (state.turnUsageSeen) return [];
33832
+ return [reportedUsage(state.turnTokens.spend(total), state)];
33833
+ }
33834
+ function turnStarted(state) {
33835
+ state.turnTokens = new CodexTurnTokens();
33836
+ return [{ sessionUpdate: "state_update", state: "running" }];
33641
33837
  }
33642
33838
  function extensionItem(item, state) {
33643
33839
  switch (asString(item.kind)) {
@@ -33730,7 +33926,7 @@ function parseEventMsg(payload, state) {
33730
33926
  case "task_complete":
33731
33927
  return taskComplete(payload);
33732
33928
  case "task_started":
33733
- return [{ sessionUpdate: "state_update", state: "running" }];
33929
+ return turnStarted(state);
33734
33930
  case "turn_aborted":
33735
33931
  return [{ sessionUpdate: "state_update", state: "idle", stopReason: "cancelled" }];
33736
33932
  case "error":
@@ -33878,13 +34074,13 @@ function codexTurnInput(run2, context) {
33878
34074
  ...images.length ? { imagePaths: images.map((image) => image.path) } : {}
33879
34075
  };
33880
34076
  }
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;
34077
+ 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, CodexTurnTokens, 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;
33882
34078
  var init_codex = __esm({
33883
34079
  "../agent-core/dist/providers/codex.js"() {
33884
34080
  "use strict";
33885
- init_chunk_D4TIXPWZ();
33886
- init_chunk_FYZKVT3E();
33887
- init_chunk_OUEMTEUX();
34081
+ init_chunk_TFIO37PI();
34082
+ init_chunk_N2M5D7RS();
34083
+ init_chunk_RBQC7XZH();
33888
34084
  init_chunk_ZCTKXKYY();
33889
34085
  init_chunk_6VWVDJ2A();
33890
34086
  init_chunk_DLVRNIY5();
@@ -33896,6 +34092,7 @@ var init_codex = __esm({
33896
34092
  import_crypto9 = require("crypto");
33897
34093
  import_crypto10 = require("crypto");
33898
34094
  init_runtime_v2();
34095
+ init_acp();
33899
34096
  init_agent2();
33900
34097
  import_crypto11 = require("crypto");
33901
34098
  init_agent2();
@@ -34029,10 +34226,13 @@ var init_codex = __esm({
34029
34226
  #reported = /* @__PURE__ */ new Set();
34030
34227
  #cursor;
34031
34228
  #lastMiss;
34032
- constructor(locate2, clock) {
34229
+ #onTokenCount;
34230
+ /** `onTokenCount` also hears each `token_count` the rollout gains, for the turn's usage. */
34231
+ constructor(locate2, clock, onTokenCount) {
34033
34232
  this.#locate = locate2;
34034
34233
  this.#clock = clock;
34035
34234
  this.#fold = new CodexImageGenerationFold(clock);
34235
+ this.#onTokenCount = onTokenCount;
34036
34236
  }
34037
34237
  get waiting() {
34038
34238
  return this.#fold.waiting;
@@ -34053,7 +34253,10 @@ var init_codex = __esm({
34053
34253
  }
34054
34254
  /** What the rollout gained since the last drain. */
34055
34255
  drain() {
34056
- for (const line of this.#open()?.read() ?? []) this.#fold.foldLine(line.text);
34256
+ for (const line of this.#open()?.read() ?? []) {
34257
+ this.#fold.foldLine(line.text);
34258
+ if (this.#onTokenCount) this.#readTokenCount(line.text, this.#onTokenCount);
34259
+ }
34057
34260
  return this.admit(this.#fold.take());
34058
34261
  }
34059
34262
  /** The turn is over: what is left, then every call still pending as failed. */
@@ -34070,6 +34273,16 @@ var init_codex = __esm({
34070
34273
  }
34071
34274
  return updates;
34072
34275
  }
34276
+ #readTokenCount(text3, onTokenCount) {
34277
+ if (!text3.includes('"token_count"')) return;
34278
+ try {
34279
+ const payload = asRecord(asRecord(JSON.parse(text3))?.payload);
34280
+ const info = asRecord(payload?.info);
34281
+ if (asString(payload?.type) === "token_count" && info) onTokenCount(info);
34282
+ } catch {
34283
+ return;
34284
+ }
34285
+ }
34073
34286
  #open() {
34074
34287
  if (this.#cursor) return this.#cursor;
34075
34288
  const now = this.#clock.monotonic();
@@ -34171,6 +34384,31 @@ var init_codex = __esm({
34171
34384
  ["inProgress", "in_progress"],
34172
34385
  ["completed", "completed"]
34173
34386
  ]);
34387
+ CodexTurnTokens = class {
34388
+ #baseline;
34389
+ #last;
34390
+ #window;
34391
+ /** Records one report; `total` absent means `last` is the whole turn so far. */
34392
+ note(last, total, window2) {
34393
+ if (total) this.#baseline ??= subtractTokens(total, last);
34394
+ this.#last = last;
34395
+ if (window2 !== void 0 && window2 > 0) this.#window = window2;
34396
+ }
34397
+ get hasBaseline() {
34398
+ return this.#baseline !== void 0;
34399
+ }
34400
+ spend(total) {
34401
+ return this.#baseline ? subtractTokens(total, this.#baseline) : total;
34402
+ }
34403
+ /** The context the turn's last call left, and the window, as far as they are known. */
34404
+ get context() {
34405
+ const contextTokens = this.#last ? codexContextTokens(this.#last) : void 0;
34406
+ return {
34407
+ ...this.#window === void 0 ? {} : { contextSize: this.#window },
34408
+ ...contextTokens === void 0 ? {} : { contextTokens }
34409
+ };
34410
+ }
34411
+ };
34174
34412
  CODEX_MCP_STATUS = {
34175
34413
  starting: "starting",
34176
34414
  ready: "connected",
@@ -34217,6 +34455,7 @@ var init_codex = __esm({
34217
34455
  #end;
34218
34456
  #failFast;
34219
34457
  #lastError;
34458
+ #tokens = new CodexTurnTokens();
34220
34459
  codexTurnId;
34221
34460
  constructor(memory, clock = systemClock2) {
34222
34461
  this.#memory = memory;
@@ -34311,19 +34550,16 @@ var init_codex = __esm({
34311
34550
  }
34312
34551
  #usage(params) {
34313
34552
  const usage = asRecord(params.tokenUsage);
34314
- const last = asRecord(usage?.last);
34315
- if (!last) return [];
34316
- const number4 = (value2) => asFiniteNumber(value2) ?? 0;
34553
+ const lastRecord = asRecord(usage?.last);
34554
+ if (!lastRecord) return [];
34555
+ const last = appServerTokens(lastRecord);
34556
+ const totalRecord = asRecord(usage?.total);
34557
+ const total = totalRecord ? appServerTokens(totalRecord) : void 0;
34558
+ this.#tokens.note(last, total, asFiniteNumber(usage?.modelContextWindow));
34317
34559
  return [
34318
- usageUpdate(
34319
- {
34320
- inputTokens: number4(last.inputTokens),
34321
- outputTokens: number4(last.outputTokens) + number4(last.reasoningOutputTokens),
34322
- cacheReadTokens: number4(last.cachedInputTokens),
34323
- cacheCreationTokens: number4(last.cacheWriteInputTokens),
34324
- ...asFiniteNumber(usage?.modelContextWindow) === void 0 ? {} : { contextSize: number4(usage?.modelContextWindow) },
34325
- costUsd: 0
34326
- },
34560
+ codexUsageUpdate(
34561
+ total ? this.#tokens.spend(total) : last,
34562
+ { ...this.#tokens.context, costUsd: 0 },
34327
34563
  this.#memory.model ?? "codex"
34328
34564
  )
34329
34565
  ];
@@ -34864,12 +35100,16 @@ var init_codex = __esm({
34864
35100
  #lastError;
34865
35101
  #answered = false;
34866
35102
  #images;
35103
+ #tokens = new CodexTurnTokens();
35104
+ #resumed;
34867
35105
  constructor(resumeId, rollout) {
34868
35106
  this.#threadId = resumeId;
35107
+ this.#resumed = resumeId !== void 0;
34869
35108
  if (!rollout) return;
34870
35109
  this.#images = new CodexRolloutImages(
34871
35110
  () => this.#threadId ? findCodexRollout(rollout.codexHome, this.#threadId) : void 0,
34872
- rollout.clock
35111
+ rollout.clock,
35112
+ (info) => this.#noteTokenCount(info)
34873
35113
  );
34874
35114
  if (resumeId) this.#images.startAtEnd();
34875
35115
  }
@@ -34931,22 +35171,34 @@ var init_codex = __esm({
34931
35171
  if (mapped) return itemUpdates(mapped, completed);
34932
35172
  return [{ sessionUpdate: "_alan/unhandled", kind: `item/${type || "(untyped)"}` }];
34933
35173
  }
35174
+ /** The rollout's per-call counts: exec's own usage is only the thread's running total. */
35175
+ #noteTokenCount(info) {
35176
+ const last = asRecord(info.last_token_usage);
35177
+ const total = asRecord(info.total_token_usage);
35178
+ if (!last) return;
35179
+ this.#tokens.note(
35180
+ rolloutTokens(last),
35181
+ total ? rolloutTokens(total) : void 0,
35182
+ asFiniteNumber(info.model_context_window)
35183
+ );
35184
+ }
34934
35185
  #completed(usage) {
34935
35186
  this.#end = { status: "completed" };
34936
- const number4 = (value2) => asFiniteNumber(value2) ?? 0;
35187
+ const rolloutUpdates = this.#images?.drain() ?? [];
34937
35188
  return [
34938
- ...usage ? [
34939
- usageUpdate({
34940
- inputTokens: number4(usage.input_tokens),
34941
- outputTokens: number4(usage.output_tokens) + number4(usage.reasoning_output_tokens),
34942
- cacheReadTokens: number4(usage.cached_input_tokens),
34943
- cacheCreationTokens: number4(usage.cache_write_input_tokens),
34944
- costUsd: 0
34945
- })
34946
- ] : [],
35189
+ ...rolloutUpdates,
35190
+ ...usage ? this.#usage(rolloutTokens(usage)) : [],
34947
35191
  { sessionUpdate: "state_update", state: "idle", stopReason: "end_turn" }
34948
35192
  ];
34949
35193
  }
35194
+ /** A resumed turn with no rollout counts cannot separate its spend from earlier turns'. */
35195
+ #usage(threadTotal) {
35196
+ const context = { ...this.#tokens.context, costUsd: 0 };
35197
+ if (this.#resumed && !this.#tokens.hasBaseline) {
35198
+ return context.contextTokens === void 0 ? [] : [usageUpdate(context)];
35199
+ }
35200
+ return [codexUsageUpdate(this.#tokens.spend(threadTotal), context, "")];
35201
+ }
34950
35202
  #failed(error62, fallback) {
34951
35203
  const message2 = errorText(error62?.message) || errorText(error62?.detail) || fallback.trim();
34952
35204
  const classified = message2 ? classifyCliError(normalizeCodexCliErrorMessage(message2)) : this.#lastError ?? specForErrorKind("provider_error");
@@ -35081,6 +35333,14 @@ function resolveAlanCodeModelId(selectedModel, models) {
35081
35333
  if (requested && models.some((model) => model.id === requested)) return requested;
35082
35334
  return models.find((model) => model.isDefault)?.id ?? firstModel.id;
35083
35335
  }
35336
+ function disabledInheritedMcp(own2, inherited) {
35337
+ const disabled = {};
35338
+ for (const name of inherited ?? []) {
35339
+ if (name in own2) continue;
35340
+ disabled[name] = { enabled: false };
35341
+ }
35342
+ return disabled;
35343
+ }
35084
35344
  function parseExisting(existing) {
35085
35345
  if (!existing?.trim()) return {};
35086
35346
  try {
@@ -35108,6 +35368,8 @@ function alanCodeConfigContent(existing, input2) {
35108
35368
  const prompt = input2.prompt ?? ALAN_CODE_BASELINE_PROMPT;
35109
35369
  const hiddenSkills = { skill: { "customize-opencode": "deny" } };
35110
35370
  const plugins = Array.isArray(config2.plugin) ? config2.plugin : [];
35371
+ const ownMcp = field(config2, "mcp");
35372
+ const mcp = { ...ownMcp, ...disabledInheritedMcp(ownMcp, input2.inheritedMcpServers) };
35111
35373
  return JSON.stringify({
35112
35374
  $schema: "https://opencode.ai/config.json",
35113
35375
  ...config2,
@@ -35116,6 +35378,7 @@ function alanCodeConfigContent(existing, input2) {
35116
35378
  // 3.4 GB of a dev machine's engine database was these patches, against 82 sessions. Alan
35117
35379
  // does not use the engine's undo/revert, so the tracking stays off.
35118
35380
  snapshot: false,
35381
+ ...Object.keys(mcp).length ? { mcp } : {},
35119
35382
  model: `${ALAN_CODE_ENGINE_PROVIDER_ID}/${input2.modelId}`,
35120
35383
  enabled_providers: [ALAN_CODE_ENGINE_PROVIDER_ID],
35121
35384
  provider: {
@@ -35434,6 +35697,77 @@ function alanCodeEngineEnv(input2) {
35434
35697
  [ALAN_CODE_CONVERSATION_ID_ENV]: input2.conversationId
35435
35698
  };
35436
35699
  }
35700
+ function openCodeGlobalConfigDirectory(env, home) {
35701
+ const configHome = env.XDG_CONFIG_HOME?.trim() || (0, import_path9.join)(home, ".config");
35702
+ return (0, import_path9.join)(configHome, "opencode");
35703
+ }
35704
+ function stripJsonc(text3) {
35705
+ let out = "";
35706
+ let index = 0;
35707
+ while (index < text3.length) {
35708
+ const skipTo = commentEnd(text3, index);
35709
+ if (skipTo !== void 0) {
35710
+ index = skipTo;
35711
+ continue;
35712
+ }
35713
+ const char = text3[index];
35714
+ if (char === "}" || char === "]") out = out.replace(/,\s*$/, "");
35715
+ const end = char === '"' ? stringLiteralEnd(text3, index) : index + 1;
35716
+ out += text3.slice(index, end);
35717
+ index = end;
35718
+ }
35719
+ return out;
35720
+ }
35721
+ function commentEnd(text3, index) {
35722
+ const pair = text3.slice(index, index + 2);
35723
+ if (pair === "//") {
35724
+ const newline = text3.indexOf("\n", index);
35725
+ return newline === -1 ? text3.length : newline;
35726
+ }
35727
+ if (pair === "/*") {
35728
+ const close2 = text3.indexOf("*/", index + 2);
35729
+ return close2 === -1 ? text3.length : close2 + 2;
35730
+ }
35731
+ return void 0;
35732
+ }
35733
+ function stringLiteralEnd(text3, start) {
35734
+ let index = start + 1;
35735
+ while (index < text3.length) {
35736
+ const char = text3[index];
35737
+ if (char === "\\") {
35738
+ index += 2;
35739
+ } else if (char === '"') {
35740
+ return index + 1;
35741
+ } else {
35742
+ index += 1;
35743
+ }
35744
+ }
35745
+ return text3.length;
35746
+ }
35747
+ function parseJsonc(text3) {
35748
+ try {
35749
+ return JSON.parse(text3);
35750
+ } catch {
35751
+ try {
35752
+ return JSON.parse(stripJsonc(text3));
35753
+ } catch {
35754
+ return void 0;
35755
+ }
35756
+ }
35757
+ }
35758
+ async function inheritedMcpServerNames(configDirectory) {
35759
+ const names = /* @__PURE__ */ new Set();
35760
+ for (const file2 of ["config.json", "opencode.json", "opencode.jsonc"]) {
35761
+ const text3 = await (0, import_promises34.readFile)((0, import_path9.join)(configDirectory, file2), "utf8").catch(() => null);
35762
+ if (text3 === null) continue;
35763
+ const parsed = parseJsonc(text3);
35764
+ const mcp = parsed !== null && typeof parsed === "object" ? parsed.mcp : void 0;
35765
+ if (mcp !== null && typeof mcp === "object") {
35766
+ for (const name of Object.keys(mcp)) names.add(name);
35767
+ }
35768
+ }
35769
+ return [...names];
35770
+ }
35437
35771
  async function writePlugin(directory, apiOrigin) {
35438
35772
  const origin = (0, import_crypto13.createHash)("sha256").update(apiOrigin).digest("hex").slice(0, 12);
35439
35773
  const target = (0, import_path9.join)(directory, `engine-plugin-v${ALAN_CODE_ENGINE_PLUGIN_VERSION}-${origin}.mjs`);
@@ -35448,9 +35782,10 @@ async function prepareAlanCodeProfile(input2) {
35448
35782
  await Promise.all(
35449
35783
  directories.map((directory) => (0, import_promises34.mkdir)(directory, { recursive: true, mode: 448 }))
35450
35784
  );
35451
- const [pluginUrl, models] = await Promise.all([
35785
+ const [pluginUrl, models, inheritedMcpServers] = await Promise.all([
35452
35786
  writePlugin((0, import_path9.join)(input2.engineRoot, "plugin"), input2.access.apiOrigin),
35453
- (input2.loadModels ?? fetchAlanCodeModels)(input2.access)
35787
+ (input2.loadModels ?? fetchAlanCodeModels)(input2.access),
35788
+ input2.globalConfigDirectory === void 0 ? Promise.resolve([]) : inheritedMcpServerNames(input2.globalConfigDirectory)
35454
35789
  ]);
35455
35790
  const modelId = resolveAlanCodeModelId(input2.requestedModel, models);
35456
35791
  return {
@@ -35458,7 +35793,8 @@ async function prepareAlanCodeProfile(input2) {
35458
35793
  baseURL: `${input2.access.apiOrigin}${ALAN_CODE_PROXY_PATH}`,
35459
35794
  modelId,
35460
35795
  models,
35461
- pluginUrl
35796
+ pluginUrl,
35797
+ inheritedMcpServers
35462
35798
  }),
35463
35799
  model: { providerID: ALAN_CODE_ENGINE_PROVIDER_ID, modelID: modelId }
35464
35800
  };
@@ -36096,8 +36432,8 @@ var require_Node = __commonJS({
36096
36432
  };
36097
36433
  const res = toJS.toJS(this, "", ctx);
36098
36434
  if (typeof onAnchor === "function")
36099
- for (const { count, res: res2 } of ctx.anchors.values())
36100
- onAnchor(res2, count);
36435
+ for (const { count: count2, res: res2 } of ctx.anchors.values())
36436
+ onAnchor(res2, count2);
36101
36437
  return typeof reviver === "function" ? applyReviver.applyReviver(reviver, { "": res }, "", res) : res;
36102
36438
  }
36103
36439
  };
@@ -36203,13 +36539,13 @@ var require_Alias = __commonJS({
36203
36539
  const anchor2 = anchors2 && source && anchors2.get(source);
36204
36540
  return anchor2 ? anchor2.count * anchor2.aliasCount : 0;
36205
36541
  } else if (identity.isCollection(node2)) {
36206
- let count = 0;
36542
+ let count2 = 0;
36207
36543
  for (const item of node2.items) {
36208
36544
  const c = getAliasCount(doc, item, anchors2);
36209
- if (c > count)
36210
- count = c;
36545
+ if (c > count2)
36546
+ count2 = c;
36211
36547
  }
36212
- return count;
36548
+ return count2;
36213
36549
  } else if (identity.isPair(node2)) {
36214
36550
  const kc = getAliasCount(doc, node2.key, anchors2);
36215
36551
  const vc = getAliasCount(doc, node2.value, anchors2);
@@ -39162,8 +39498,8 @@ var require_Document = __commonJS({
39162
39498
  };
39163
39499
  const res = toJS.toJS(this.contents, jsonArg ?? "", ctx);
39164
39500
  if (typeof onAnchor === "function")
39165
- for (const { count, res: res2 } of ctx.anchors.values())
39166
- onAnchor(res2, count);
39501
+ for (const { count: count2, res: res2 } of ctx.anchors.values())
39502
+ onAnchor(res2, count2);
39167
39503
  return typeof reviver === "function" ? applyReviver.applyReviver(reviver, { "": res }, "", res) : res;
39168
39504
  }
39169
39505
  /**
@@ -39240,12 +39576,12 @@ var require_errors = __commonJS({
39240
39576
  lineStr = prev + lineStr;
39241
39577
  }
39242
39578
  if (/[^ ]/.test(lineStr)) {
39243
- let count = 1;
39579
+ let count2 = 1;
39244
39580
  const end = error62.linePos[1];
39245
39581
  if (end?.line === line && end.col > col) {
39246
- count = Math.max(1, Math.min(end.col - col, 80 - ci));
39582
+ count2 = Math.max(1, Math.min(end.col - col, 80 - ci));
39247
39583
  }
39248
- const pointer = " ".repeat(ci) + "^".repeat(count);
39584
+ const pointer = " ".repeat(ci) + "^".repeat(count2);
39249
39585
  error62.message += `:
39250
39586
 
39251
39587
  ${lineStr}
@@ -39487,7 +39823,7 @@ var require_resolve_block_map = __commonJS({
39487
39823
  if (ctx.atRoot)
39488
39824
  ctx.atRoot = false;
39489
39825
  let offset = bm.offset;
39490
- let commentEnd = null;
39826
+ let commentEnd2 = null;
39491
39827
  for (const collItem of bm.items) {
39492
39828
  const { start, key, sep: sep4, value: value2 } = collItem;
39493
39829
  const keyProps = resolveProps.resolveProps(start, {
@@ -39507,7 +39843,7 @@ var require_resolve_block_map = __commonJS({
39507
39843
  onError(offset, "BAD_INDENT", startColMsg);
39508
39844
  }
39509
39845
  if (!keyProps.anchor && !keyProps.tag && !sep4) {
39510
- commentEnd = keyProps.end;
39846
+ commentEnd2 = keyProps.end;
39511
39847
  if (keyProps.comment) {
39512
39848
  if (map2.comment)
39513
39849
  map2.comment += "\n" + keyProps.comment;
@@ -39569,9 +39905,9 @@ var require_resolve_block_map = __commonJS({
39569
39905
  map2.items.push(pair);
39570
39906
  }
39571
39907
  }
39572
- if (commentEnd && commentEnd < offset)
39573
- onError(commentEnd, "IMPOSSIBLE", "Map comment with trailing content");
39574
- map2.range = [bm.offset, offset, commentEnd ?? offset];
39908
+ if (commentEnd2 && commentEnd2 < offset)
39909
+ onError(commentEnd2, "IMPOSSIBLE", "Map comment with trailing content");
39910
+ map2.range = [bm.offset, offset, commentEnd2 ?? offset];
39575
39911
  return map2;
39576
39912
  }
39577
39913
  exports2.resolveBlockMap = resolveBlockMap;
@@ -39593,7 +39929,7 @@ var require_resolve_block_seq = __commonJS({
39593
39929
  if (ctx.atKey)
39594
39930
  ctx.atKey = false;
39595
39931
  let offset = bs.offset;
39596
- let commentEnd = null;
39932
+ let commentEnd2 = null;
39597
39933
  for (const { start, value: value2 } of bs.items) {
39598
39934
  const props = resolveProps.resolveProps(start, {
39599
39935
  indicator: "seq-item-ind",
@@ -39610,7 +39946,7 @@ var require_resolve_block_seq = __commonJS({
39610
39946
  else
39611
39947
  onError(offset, "MISSING_CHAR", "Sequence item without - indicator");
39612
39948
  } else {
39613
- commentEnd = props.end;
39949
+ commentEnd2 = props.end;
39614
39950
  if (props.comment)
39615
39951
  seq.comment = props.comment;
39616
39952
  continue;
@@ -39622,7 +39958,7 @@ var require_resolve_block_seq = __commonJS({
39622
39958
  offset = node2.range[2];
39623
39959
  seq.items.push(node2);
39624
39960
  }
39625
- seq.range = [bs.offset, offset, commentEnd ?? offset];
39961
+ seq.range = [bs.offset, offset, commentEnd2 ?? offset];
39626
39962
  return seq;
39627
39963
  }
39628
39964
  exports2.resolveBlockSeq = resolveBlockSeq;
@@ -45295,8 +45631,8 @@ var require_tar_stream = __commonJS({
45295
45631
  var init_dist = __esm({
45296
45632
  "../agent-core/dist/index.js"() {
45297
45633
  "use strict";
45298
- init_chunk_FYZKVT3E();
45299
- init_chunk_OUEMTEUX();
45634
+ init_chunk_N2M5D7RS();
45635
+ init_chunk_RBQC7XZH();
45300
45636
  init_chunk_ZCTKXKYY();
45301
45637
  init_chunk_6VWVDJ2A();
45302
45638
  init_chunk_YXWJW7I5();
@@ -45655,24 +45991,30 @@ function tokens(record2, ...keys) {
45655
45991
  }
45656
45992
  return void 0;
45657
45993
  }
45658
- function promptUsage(result, fallbackModel) {
45659
- const usage = asRecord(result.usage) ?? asRecord(result._meta);
45994
+ function contextOf(update) {
45995
+ const used = asFiniteNumber(update.used);
45996
+ const size = asFiniteNumber(update.size);
45997
+ if (used === void 0 || used <= 0) return void 0;
45998
+ return { contextTokens: used, ...size !== void 0 && size > 0 ? { contextSize: size } : {} };
45999
+ }
46000
+ function promptSpend(result, profile) {
46001
+ const meta3 = asRecord(result._meta);
46002
+ const usage = asRecord(result.usage) ?? asRecord(meta3?.usage) ?? meta3;
45660
46003
  const input2 = tokens(usage, "inputTokens", "input_tokens");
45661
46004
  const output2 = tokens(usage, "outputTokens", "output_tokens");
45662
46005
  if (input2 === void 0 && output2 === void 0) return void 0;
45663
46006
  const thoughts = tokens(usage, "thoughtTokens", "reasoningTokens") ?? 0;
45664
- const meta3 = asRecord(result._meta);
45665
- return usageUpdate(
45666
- {
45667
- inputTokens: input2 ?? 0,
45668
- outputTokens: (output2 ?? 0) + thoughts,
45669
- cacheReadTokens: tokens(usage, "cachedReadTokens", "cacheReadTokens") ?? 0,
45670
- cacheCreationTokens: tokens(usage, "cachedWriteTokens", "cacheWriteTokens") ?? 0,
45671
- costUsd: 0,
45672
- ...asString(meta3?.modelId) ? { model: asString(meta3?.modelId) } : {}
45673
- },
45674
- fallbackModel
45675
- );
46007
+ const cacheRead = tokens(usage, "cachedReadTokens", "cacheReadTokens") ?? 0;
46008
+ const cacheWrite = tokens(usage, "cachedWriteTokens", "cacheWriteTokens") ?? 0;
46009
+ const uncached = profile.promptInputIncludesCache ? Math.max((input2 ?? 0) - cacheRead - cacheWrite, 0) : input2 ?? 0;
46010
+ return {
46011
+ inputTokens: uncached,
46012
+ outputTokens: (output2 ?? 0) + thoughts,
46013
+ cacheReadTokens: cacheRead,
46014
+ cacheCreationTokens: cacheWrite,
46015
+ costUsd: 0,
46016
+ ...asString(meta3?.modelId) ? { model: asString(meta3?.modelId) } : {}
46017
+ };
45676
46018
  }
45677
46019
  function pendingAnswer2(pending, answer) {
45678
46020
  switch (pending.kind) {
@@ -46042,8 +46384,8 @@ var import_promises50, import_path10, import_crypto14, import_promises51, CURSOR
46042
46384
  var init_acp3 = __esm({
46043
46385
  "../agent-core/dist/providers/acp.js"() {
46044
46386
  "use strict";
46045
- init_chunk_FYZKVT3E();
46046
- init_chunk_OUEMTEUX();
46387
+ init_chunk_N2M5D7RS();
46388
+ init_chunk_RBQC7XZH();
46047
46389
  init_chunk_ZCTKXKYY();
46048
46390
  init_chunk_6VWVDJ2A();
46049
46391
  init_chunk_DLVRNIY5();
@@ -46273,9 +46615,52 @@ var init_acp3 = __esm({
46273
46615
  #bursts = /* @__PURE__ */ new Map();
46274
46616
  #counter = 0;
46275
46617
  #failure;
46276
- constructor(prefix, profile) {
46618
+ #context;
46619
+ #spend;
46620
+ #onContext;
46621
+ /** `context` is what the session's last turn left, until this turn reports its own. */
46622
+ constructor(prefix, profile, context) {
46277
46623
  this.#prefix = prefix;
46278
46624
  this.#profile = profile;
46625
+ this.#context = context;
46626
+ }
46627
+ get context() {
46628
+ return this.#context;
46629
+ }
46630
+ /** The prompt's answer: what the turn spent, with the context so far, as one update. */
46631
+ settle(result, fallbackModel) {
46632
+ this.#spend = promptSpend(result, this.#profile);
46633
+ return this.#usage(fallbackModel);
46634
+ }
46635
+ /** Resolves on the next `usage_update`, or after `ms`. */
46636
+ async nextContext(ms, sleep) {
46637
+ await Promise.race([
46638
+ new Promise((resolve13) => {
46639
+ this.#onContext = resolve13;
46640
+ }),
46641
+ sleep(ms)
46642
+ ]);
46643
+ this.#onContext = void 0;
46644
+ }
46645
+ /** Ends a `nextContext` wait at once: the turn is being cancelled. */
46646
+ stopWaiting() {
46647
+ this.#onContext?.();
46648
+ }
46649
+ /**
46650
+ * The chat keeps a turn's last usage update, so each one carries both the spend and the
46651
+ * context. An agent's own `usage_update` is context only and must not read as spend.
46652
+ */
46653
+ #noteContext(update) {
46654
+ const context = contextOf(update);
46655
+ if (!context) return [];
46656
+ this.#context = context;
46657
+ this.#onContext?.();
46658
+ const usage = this.#usage(this.#spend?.model ?? "");
46659
+ return usage ? [usage] : [];
46660
+ }
46661
+ #usage(fallbackModel) {
46662
+ if (!this.#spend && !this.#context) return void 0;
46663
+ return usageUpdate({ ...this.#spend, ...this.#context }, fallbackModel);
46279
46664
  }
46280
46665
  /** The first cause a vendor frame named; the prompt's own error is usually generic. */
46281
46666
  get failure() {
@@ -46305,6 +46690,8 @@ var init_acp3 = __esm({
46305
46690
  entries: Array.isArray(update.entries) ? update.entries : []
46306
46691
  }
46307
46692
  ];
46693
+ case "usage_update":
46694
+ return this.#noteContext(update);
46308
46695
  case "current_mode_update":
46309
46696
  return [
46310
46697
  noticeUpdate("info", "mode_changed", asString(update.currentModeId) || "mode changed")
@@ -46430,7 +46817,13 @@ var init_acp3 = __esm({
46430
46817
  return active.done;
46431
46818
  }
46432
46819
  const prompt = this.#promptBlocks(input2);
46433
- this.#rpc.request("session/prompt", { sessionId, prompt }).then((result) => active.finish(this.#promptOutcome(active, asRecord(result) ?? {}))).catch((error62) => {
46820
+ this.#rpc.request("session/prompt", { sessionId, prompt }).then(async (result) => {
46821
+ const record2 = asRecord(result) ?? {};
46822
+ const trailing = this.#profile.trailingUsageMs;
46823
+ if (trailing && !active.cancelRequested)
46824
+ await active.turn.nextContext(trailing, (ms) => this.#options.clock.sleep(ms));
46825
+ active.finish(this.#promptOutcome(active, record2));
46826
+ }).catch((error62) => {
46434
46827
  if (this.#state === "closed") return;
46435
46828
  active.finish(this.#errorOutcome(active, error62));
46436
46829
  });
@@ -46511,7 +46904,7 @@ var init_acp3 = __esm({
46511
46904
  ];
46512
46905
  }
46513
46906
  #promptOutcome(active, result) {
46514
- const usage = promptUsage(result, this.#config?.model ?? this.#profile.backendKind);
46907
+ const usage = active.turn.settle(result, this.#config?.model ?? this.#profile.backendKind);
46515
46908
  if (usage) this.#emit({ type: "update", turnId: active.id, update: usage });
46516
46909
  const stopReason = asString(result.stopReason);
46517
46910
  const failure22 = active.turn.failure;
@@ -46545,6 +46938,7 @@ var init_acp3 = __esm({
46545
46938
  async #stopTurn(active) {
46546
46939
  if (active.cancelRequested) return active.done.then(() => void 0);
46547
46940
  active.cancelRequested = true;
46941
+ active.turn.stopWaiting();
46548
46942
  const rung = await runCancelLadder({
46549
46943
  clock: this.#options.clock,
46550
46944
  graceMs: this.#options.interruptGraceMs,
@@ -46570,14 +46964,14 @@ var init_acp3 = __esm({
46570
46964
  }
46571
46965
  #startTurn(id) {
46572
46966
  this.#turns += 1;
46573
- const turn = new AcpTurn(`acp-${this.#turns}-${id}`, this.#profile);
46967
+ const turn = new AcpTurn(`acp-${this.#turns}-${id}`, this.#profile, this.#idleTurn.context);
46574
46968
  let finish = () => {
46575
46969
  };
46576
46970
  const done = new Promise((resolve13) => {
46577
46971
  finish = (outcome2) => {
46578
46972
  if (this.#current?.id !== id) return;
46579
46973
  this.#current = void 0;
46580
- this.#idleTurn = new AcpTurn(`acp-between-${this.#turns}`, this.#profile);
46974
+ this.#idleTurn = new AcpTurn(`acp-between-${this.#turns}`, this.#profile, turn.context);
46581
46975
  if (this.#state === "busy") this.#state = "idle";
46582
46976
  this.#host.scanDescendants(true);
46583
46977
  this.#emit({ type: "turn_ended", turnId: id, outcome: outcome2 });
@@ -46816,6 +47210,8 @@ var init_acp3 = __esm({
46816
47210
  }
46817
47211
  };
46818
47212
  grokAcpProfile = {
47213
+ // Grok's ACP `inputTokens` is the full prompt; its own docs say only headless output subtracts cache.
47214
+ promptInputIncludesCache: true,
46819
47215
  backendKind: "grok_cli",
46820
47216
  displayName: "Grok CLI",
46821
47217
  defaultCommand: "grok",
@@ -46846,7 +47242,9 @@ var init_acp3 = __esm({
46846
47242
  requirement: { cli: "kimi", feature: "`kimi acp`" },
46847
47243
  launchArgs: () => ["acp"],
46848
47244
  modelChannel: "session",
46849
- exitsOnStdinEof: true
47245
+ exitsOnStdinEof: true,
47246
+ // Kimi answers the prompt, then reads its context size and pushes `usage_update`.
47247
+ trailingUsageMs: 1e3
46850
47248
  };
46851
47249
  ACP_PROFILES = {
46852
47250
  cursor_agent_cli: cursorAcpProfile,
@@ -47080,9 +47478,19 @@ function createPersistentDriver(provider4, options) {
47080
47478
  }
47081
47479
  };
47082
47480
  const media = new LocalMediaReader(spec.projectPath, clock);
47481
+ const uploader = inputs.media;
47482
+ let uploads = Promise.resolve();
47083
47483
  const recordWithMedia = (update) => {
47084
47484
  record2(update);
47085
- for (const found of media.read(update)) record2(found);
47485
+ const found = media.find(update);
47486
+ if (found.length === 0) return;
47487
+ if (uploader === void 0) {
47488
+ for (const item of found) record2(media.inline(item));
47489
+ return;
47490
+ }
47491
+ uploads = uploads.then(async () => {
47492
+ for (const item of found) record2(await media.publish(item, uploader, signal));
47493
+ });
47086
47494
  };
47087
47495
  const forward = (event) => {
47088
47496
  if (event.type === "session_id") {
@@ -47176,6 +47584,7 @@ function createPersistentDriver(provider4, options) {
47176
47584
  } catch (error62) {
47177
47585
  return { outcome: "failed", message: errorMessage(error62) };
47178
47586
  } finally {
47587
+ await uploads;
47179
47588
  signal.removeEventListener("abort", onAbort);
47180
47589
  if (live.turn === turn) live.turn = void 0;
47181
47590
  }
@@ -47672,8 +48081,22 @@ function codeModeChildUpdates(tool, metadata) {
47672
48081
  };
47673
48082
  });
47674
48083
  }
48084
+ function stepContextTokens(step, total) {
48085
+ const sum = step.inputTokens + step.outputTokens + step.cacheReadTokens + step.cacheCreationTokens;
48086
+ const tokens2 = total !== void 0 && total > 0 ? total : sum;
48087
+ return tokens2 > 0 ? tokens2 : void 0;
48088
+ }
48089
+ function addStepUsage(turn, step) {
48090
+ return {
48091
+ inputTokens: turn.inputTokens + step.inputTokens,
48092
+ outputTokens: turn.outputTokens + step.outputTokens,
48093
+ cacheReadTokens: turn.cacheReadTokens + step.cacheReadTokens,
48094
+ cacheCreationTokens: turn.cacheCreationTokens + step.cacheCreationTokens,
48095
+ costUsd: turn.costUsd === void 0 && step.costUsd === void 0 ? void 0 : (turn.costUsd ?? 0) + (step.costUsd ?? 0)
48096
+ };
48097
+ }
47675
48098
  function createOpenCodeSessionMemory() {
47676
- return { userMessageIds: /* @__PURE__ */ new Set() };
48099
+ return { userMessageIds: /* @__PURE__ */ new Set(), contextWindows: /* @__PURE__ */ new Map() };
47677
48100
  }
47678
48101
  function only(updates) {
47679
48102
  return { updates, actions: [] };
@@ -48006,12 +48429,12 @@ function openCodeTurnInput(run2, context) {
48006
48429
  ...images.length ? { imagePaths: images.map((image) => image.path) } : {}
48007
48430
  };
48008
48431
  }
48009
- var import_crypto15, import_http10, import_crypto16, import_promises52, import_path11, import_path12, import_url2, import_crypto17, IDLE_SOCKET_MS3, OpenCodeHttpError, BASE62, messageIdClock, OpenCodeClient, OPENCODE_CONFIG_ENV, OPENCODE_ENGINE, TEXT_PARTS, STEP_PARTS, STOPPED_BY_USER, OpenCodeSubagents, NAMED_KINDS, OPENCODE_ABORTED_ERROR, PROVIDER_EVENT_META, TASK_TOOL_NAME, TASK_RESULT_TAG, TASK_ERROR_TAG, PERMISSION_DENIED, FILE_OPERATIONS2, PartReader, NOTHING, NON_INTERACTIVE_PERMISSIONS, CONTENT_FILTER_FINISHES, TRUNCATED_FINISHES, OUTPUT_PARTS, OpenCodeTurn, LISTENING, OUTPUT_TAIL_LINES, IMAGE_TYPES, OpenCodeSession, OPENCODE_MIN_VERSION, OPENCODE_REQUIREMENT, OPENCODE_TESTED_LINE, OPENCODE_SUPPORTED_MAJOR, DEFAULTS4, STORE_LOCKED, NON_INTERACTIVE_RULES, TITLE_LENGTH, MAX_VARIANT_LENGTH;
48432
+ var import_crypto15, import_http10, import_crypto16, import_promises52, import_path11, import_path12, import_url2, import_crypto17, IDLE_SOCKET_MS3, OpenCodeHttpError, BASE62, messageIdClock, OpenCodeClient, OPENCODE_CONFIG_ENV, OPENCODE_ENGINE, TEXT_PARTS, STEP_PARTS, STOPPED_BY_USER, OpenCodeSubagents, NAMED_KINDS, OPENCODE_ABORTED_ERROR, PROVIDER_EVENT_META, TASK_TOOL_NAME, TASK_RESULT_TAG, TASK_ERROR_TAG, PERMISSION_DENIED, FILE_OPERATIONS2, NO_USAGE, PartReader, NOTHING, NON_INTERACTIVE_PERMISSIONS, CONTENT_FILTER_FINISHES, TRUNCATED_FINISHES, OUTPUT_PARTS, OpenCodeTurn, LISTENING, OUTPUT_TAIL_LINES, IMAGE_TYPES, OpenCodeSession, OPENCODE_MIN_VERSION, OPENCODE_REQUIREMENT, OPENCODE_TESTED_LINE, OPENCODE_SUPPORTED_MAJOR, DEFAULTS4, STORE_LOCKED, NON_INTERACTIVE_RULES, TITLE_LENGTH, MAX_VARIANT_LENGTH;
48010
48433
  var init_opencode = __esm({
48011
48434
  "../agent-core/dist/providers/opencode.js"() {
48012
48435
  "use strict";
48013
- init_chunk_FYZKVT3E();
48014
- init_chunk_OUEMTEUX();
48436
+ init_chunk_N2M5D7RS();
48437
+ init_chunk_RBQC7XZH();
48015
48438
  init_chunk_ZCTKXKYY();
48016
48439
  init_chunk_6VWVDJ2A();
48017
48440
  init_chunk_DLVRNIY5();
@@ -48193,6 +48616,22 @@ var init_opencode = __esm({
48193
48616
  const providers = Array.isArray(body?.providers) ? body.providers : [];
48194
48617
  return providers.map((provider4) => asString(asRecord(provider4)?.id)).filter(Boolean);
48195
48618
  }
48619
+ /** `provider/model` \u2192 the model's context limit; 0 (a custom model's unknown) is left out. */
48620
+ async modelContextWindows() {
48621
+ const body = asRecord(await this.#call("provider list", "GET", "/config/providers"));
48622
+ const windows = /* @__PURE__ */ new Map();
48623
+ for (const provider4 of Array.isArray(body?.providers) ? body.providers : []) {
48624
+ const record2 = asRecord(provider4);
48625
+ const providerId = asString(record2?.id);
48626
+ for (const [modelId, model] of Object.entries(asRecord(record2?.models) ?? {})) {
48627
+ const limit = asFiniteNumber(asRecord(asRecord(model)?.limit)?.context);
48628
+ if (providerId && limit !== void 0 && limit > 0) {
48629
+ windows.set(`${providerId}/${modelId}`, limit);
48630
+ }
48631
+ }
48632
+ }
48633
+ return windows;
48634
+ }
48196
48635
  /** Asks emitted while disconnected must still get a reply. Older engines may lack these routes. */
48197
48636
  async pendingAsks() {
48198
48637
  const read = async (path4, type) => {
@@ -48424,6 +48863,13 @@ var init_opencode = __esm({
48424
48863
  ["delete", "delete"],
48425
48864
  ["update", "modify"]
48426
48865
  ]);
48866
+ NO_USAGE = {
48867
+ inputTokens: 0,
48868
+ outputTokens: 0,
48869
+ cacheReadTokens: 0,
48870
+ cacheCreationTokens: 0,
48871
+ costUsd: void 0
48872
+ };
48427
48873
  PartReader = class {
48428
48874
  /** messageID \u2192 part ids in arrival order, so a multi-part message keeps its order. */
48429
48875
  #order = /* @__PURE__ */ new Map();
@@ -48433,6 +48879,7 @@ var init_opencode = __esm({
48433
48879
  /** To-do calls already sent as a plan; the running and completed frames repeat the input. */
48434
48880
  #planned = /* @__PURE__ */ new Set();
48435
48881
  #steps = /* @__PURE__ */ new Set();
48882
+ #turnUsage = NO_USAGE;
48436
48883
  #partIds = /* @__PURE__ */ new Set();
48437
48884
  #anonymous = 0;
48438
48885
  #retainedChars = 0;
@@ -48447,6 +48894,9 @@ var init_opencode = __esm({
48447
48894
  }
48448
48895
  /** `provider/model` from the assistant message; step-finish frames do not repeat it. */
48449
48896
  model;
48897
+ /** The model's context limit, when the server listed it. */
48898
+ contextWindow;
48899
+ #contextTokens;
48450
48900
  part(part, parentToolCallId) {
48451
48901
  const id = asString(part.id);
48452
48902
  if (id) this.#partIds.add(id);
@@ -48455,7 +48905,7 @@ var init_opencode = __esm({
48455
48905
  "protocol_violation",
48456
48906
  "Alan Code exceeded the retained event limit. Continue in a new turn."
48457
48907
  );
48458
- return withParent(this.#read(part), parentToolCallId);
48908
+ return withParent(this.#read(part, parentToolCallId !== void 0), parentToolCallId);
48459
48909
  }
48460
48910
  /** A delta names only its part; the role and message come from the part's opening snapshot. */
48461
48911
  delta(partId, field3, delta, parentToolCallId) {
@@ -48467,7 +48917,7 @@ var init_opencode = __esm({
48467
48917
  const update = role === "text" ? { sessionUpdate: "agent_message_chunk", messageId, content } : { sessionUpdate: "agent_thought_chunk", messageId: `${messageId}:reasoning`, content };
48468
48918
  return withParent([update], parentToolCallId);
48469
48919
  }
48470
- #read(part) {
48920
+ #read(part, child) {
48471
48921
  const type = asString(part.type);
48472
48922
  switch (type) {
48473
48923
  case "step-start":
@@ -48483,7 +48933,7 @@ var init_opencode = __esm({
48483
48933
  return this.#tool(part);
48484
48934
  case "step-finish":
48485
48935
  case "step_finish":
48486
- return this.#stepFinish(part);
48936
+ return this.#stepFinish(part, child);
48487
48937
  case "snapshot":
48488
48938
  case "patch":
48489
48939
  return [];
@@ -48549,6 +48999,31 @@ var init_opencode = __esm({
48549
48999
  }
48550
49000
  return updates;
48551
49001
  }
49002
+ #stepUsage(part, tokens2, child) {
49003
+ const cache2 = asRecord(tokens2.cache);
49004
+ const step = {
49005
+ inputTokens: asFiniteNumber(tokens2.input) ?? 0,
49006
+ // OpenCode counts reasoning apart from output, and cache apart from input.
49007
+ outputTokens: (asFiniteNumber(tokens2.output) ?? 0) + (asFiniteNumber(tokens2.reasoning) ?? 0),
49008
+ cacheReadTokens: asFiniteNumber(cache2?.read) ?? 0,
49009
+ cacheCreationTokens: asFiniteNumber(cache2?.write) ?? 0
49010
+ };
49011
+ if (!child) this.#contextTokens = stepContextTokens(step, asFiniteNumber(tokens2.total));
49012
+ this.#turnUsage = addStepUsage(this.#turnUsage, {
49013
+ ...step,
49014
+ costUsd: asFiniteNumber(part.cost)
49015
+ });
49016
+ const { costUsd, ...turnTokens } = this.#turnUsage;
49017
+ return usageUpdate(
49018
+ {
49019
+ ...turnTokens,
49020
+ ...costUsd === void 0 ? {} : { costUsd },
49021
+ ...this.#contextTokens === void 0 ? {} : { contextTokens: this.#contextTokens },
49022
+ ...this.contextWindow === void 0 ? {} : { contextSize: this.contextWindow }
49023
+ },
49024
+ this.model
49025
+ );
49026
+ }
48552
49027
  /** OpenCode's to-do list is the plan, sent once per call although every frame repeats it. */
48553
49028
  #plan(toolCallId, name, toolState) {
48554
49029
  const todos = asRecord(toolState?.input)?.todos;
@@ -48557,28 +49032,12 @@ var init_opencode = __esm({
48557
49032
  this.#planned.add(toolCallId);
48558
49033
  return [todoPlanUpdate(toolCallId, todos)];
48559
49034
  }
48560
- #stepFinish(part) {
49035
+ #stepFinish(part, child) {
48561
49036
  const id = asString(part.id);
48562
49037
  if (id && this.#steps.has(id)) return [];
48563
49038
  if (id) this.#steps.add(id);
48564
- const updates = [];
48565
49039
  const tokens2 = asRecord(part.tokens);
48566
- if (tokens2) {
48567
- const cache2 = asRecord(tokens2.cache);
48568
- const cost = asFiniteNumber(part.cost);
48569
- updates.push(
48570
- usageUpdate(
48571
- {
48572
- inputTokens: asFiniteNumber(tokens2.input) ?? 0,
48573
- outputTokens: asFiniteNumber(tokens2.output) ?? 0,
48574
- cacheReadTokens: asFiniteNumber(cache2?.read) ?? 0,
48575
- cacheCreationTokens: asFiniteNumber(cache2?.write) ?? 0,
48576
- ...cost === void 0 ? {} : { costUsd: cost }
48577
- },
48578
- this.model
48579
- )
48580
- );
48581
- }
49040
+ const updates = tokens2 ? [this.#stepUsage(part, tokens2, child)] : [];
48582
49041
  const reason = asString(part.reason);
48583
49042
  if (reason === "stop") {
48584
49043
  updates.push({ sessionUpdate: "state_update", state: "idle", stopReason: "end_turn" });
@@ -48763,7 +49222,10 @@ var init_opencode = __esm({
48763
49222
  if (finish) this.#finish = finish;
48764
49223
  const provider4 = asString(info.providerID);
48765
49224
  const model = asString(info.modelID);
48766
- if (provider4 && model) this.#parts.model = `${provider4}/${model}`;
49225
+ if (provider4 && model) {
49226
+ this.#parts.model = `${provider4}/${model}`;
49227
+ this.#parts.contextWindow = this.#memory.contextWindows.get(this.#parts.model);
49228
+ }
48767
49229
  const error62 = asRecord(info.error);
48768
49230
  if (!error62 || isAbortError(error62) || this.#error) return [];
48769
49231
  return this.#fail(classifyOpenCodeError(error62, `${this.#engine.label} session error.`));
@@ -48968,6 +49430,9 @@ var init_opencode = __esm({
48968
49430
  /** Subscribes before the session exists, so `session.created` and early asks are seen. */
48969
49431
  async connect(client) {
48970
49432
  this.#client = client;
49433
+ client.modelContextWindows().then((windows) => {
49434
+ this.#memory.contextWindows = windows;
49435
+ }).catch(() => void 0);
48971
49436
  this.#events?.close();
48972
49437
  this.#events = await client.events({
48973
49438
  onEvent: (event) => {
@@ -49376,7 +49841,9 @@ function createAlanCodeHolderDriver(options) {
49376
49841
  });
49377
49842
  const env = options.cliEnvironment;
49378
49843
  const engine = resolveAlanCodeEngine({ env, platform: platform3, packaged: [] });
49379
- const engineRoot = alanCodeEngineRoot(env.HOME?.trim() || (0, import_node_os7.homedir)());
49844
+ const home = env.HOME?.trim() || (0, import_node_os7.homedir)();
49845
+ const engineRoot = alanCodeEngineRoot(home);
49846
+ const globalConfigDirectory = openCodeGlobalConfigDirectory(env, home);
49380
49847
  options.log.info("alan_code.engine", { command: engine.command, source: engine.source });
49381
49848
  const open6 = async (planned) => {
49382
49849
  if (planned.profile === void 0) throw refuseWithoutCredential();
@@ -49414,6 +49881,7 @@ function createAlanCodeHolderDriver(options) {
49414
49881
  conversationId: spec.conversationId
49415
49882
  },
49416
49883
  engineRoot,
49884
+ globalConfigDirectory,
49417
49885
  requestedModel: spec.model
49418
49886
  };
49419
49887
  const skills = options.installedSkills?.() ?? null;
@@ -50061,8 +50529,8 @@ var import_crypto18, import_promises53, FACTORY_API_VERSION, FACTORY_PROTOCOL_VE
50061
50529
  var init_droid = __esm({
50062
50530
  "../agent-core/dist/providers/droid.js"() {
50063
50531
  "use strict";
50064
- init_chunk_FYZKVT3E();
50065
- init_chunk_OUEMTEUX();
50532
+ init_chunk_N2M5D7RS();
50533
+ init_chunk_RBQC7XZH();
50066
50534
  init_chunk_ZCTKXKYY();
50067
50535
  init_chunk_6VWVDJ2A();
50068
50536
  init_chunk_DLVRNIY5();
@@ -50107,7 +50575,10 @@ var init_droid = __esm({
50107
50575
  const notification = asRecord(params.notification);
50108
50576
  if (!notification) return [];
50109
50577
  const sessionId = asString(params.sessionId);
50110
- if (!sessionId || sessionId === this.#sessionId) return this.#read(notification);
50578
+ if (!sessionId || sessionId === this.#sessionId) {
50579
+ this.#noteContext(notification);
50580
+ return this.#read(notification);
50581
+ }
50111
50582
  const launcher = this.#memory.childLaunchers.get(sessionId);
50112
50583
  if (!launcher) return [];
50113
50584
  return this.#read(notification).map(
@@ -50117,6 +50588,14 @@ var init_droid = __esm({
50117
50588
  })
50118
50589
  );
50119
50590
  }
50591
+ /** Droid's own context figure: the last call's input, cache reads and output. */
50592
+ #noteContext(notification) {
50593
+ if (asString(notification.type) !== "session_token_usage_changed") return;
50594
+ const last = asRecord(notification.lastCallTokenUsage);
50595
+ if (!last) return;
50596
+ const tokens2 = (asFiniteNumber(last.inputTokens) ?? 0) + (asFiniteNumber(last.cacheReadTokens) ?? 0) + (asFiniteNumber(last.outputTokens) ?? 0);
50597
+ if (tokens2 > 0) this.#memory.contextTokens = tokens2;
50598
+ }
50120
50599
  #read(notification) {
50121
50600
  const type = asString(notification.type);
50122
50601
  if (SILENT2.has(type)) return [];
@@ -50191,6 +50670,7 @@ var init_droid = __esm({
50191
50670
  cacheCreationTokens: number4(usage?.cacheCreationTokens),
50192
50671
  numTurns: 1,
50193
50672
  ...duration3 === void 0 ? {} : { durationMs: duration3 },
50673
+ ...this.#memory.contextTokens === void 0 ? {} : { contextTokens: this.#memory.contextTokens },
50194
50674
  costUsd: 0
50195
50675
  },
50196
50676
  this.#memory.model ?? "droid"
@@ -50999,6 +51479,23 @@ function providerError2(_grammar, frame) {
50999
51479
  function spellings(types, handle) {
51000
51480
  return types.map((type) => [type, handle]);
51001
51481
  }
51482
+ function stepTokens(stats) {
51483
+ return {
51484
+ inputTokens: firstNumber2(stats.input_tokens, stats.input),
51485
+ outputTokens: firstNumber2(stats.output_tokens) + firstNumber2(stats.thinking_tokens),
51486
+ cacheReadTokens: firstNumber2(stats.cache_read_tokens, stats.cached_input_tokens, stats.cached),
51487
+ cacheCreationTokens: 0
51488
+ };
51489
+ }
51490
+ function addStepTokens(total, step) {
51491
+ if (!total) return step;
51492
+ return {
51493
+ inputTokens: total.inputTokens + step.inputTokens,
51494
+ outputTokens: total.outputTokens + step.outputTokens,
51495
+ cacheReadTokens: total.cacheReadTokens + step.cacheReadTokens,
51496
+ cacheCreationTokens: total.cacheCreationTokens + step.cacheCreationTokens
51497
+ };
51498
+ }
51002
51499
  function firstNumber2(...values) {
51003
51500
  for (const value2 of values) {
51004
51501
  const number4 = asFiniteNumber(value2);
@@ -51170,9 +51667,9 @@ var import_promises54, import_path13, import_fs9, import_path14, import_path15,
51170
51667
  var init_antigravity = __esm({
51171
51668
  "../agent-core/dist/providers/antigravity.js"() {
51172
51669
  "use strict";
51173
- init_chunk_D4TIXPWZ();
51174
- init_chunk_FYZKVT3E();
51175
- init_chunk_OUEMTEUX();
51670
+ init_chunk_TFIO37PI();
51671
+ init_chunk_N2M5D7RS();
51672
+ init_chunk_RBQC7XZH();
51176
51673
  init_chunk_ZCTKXKYY();
51177
51674
  init_chunk_6VWVDJ2A();
51178
51675
  init_chunk_DLVRNIY5();
@@ -51530,6 +52027,11 @@ var init_antigravity = __esm({
51530
52027
  /** What `--conversation` takes: a frame's `conversation_id` wins over its `session_id`. */
51531
52028
  #conversationId;
51532
52029
  #forkReported = false;
52030
+ /** The conversation this turn runs in; a subagent's steps come under another id. */
52031
+ #rootConversation;
52032
+ /** The sum of this turn's own steps: the result's usage is the whole conversation's. */
52033
+ #stepSpend;
52034
+ #contextTokens;
51533
52035
  constructor(options) {
51534
52036
  this.#options = options;
51535
52037
  this.#conversationId = options.resumeId;
@@ -51576,7 +52078,9 @@ var init_antigravity = __esm({
51576
52078
  const type = asString(frame.type);
51577
52079
  if (!type) return [];
51578
52080
  this.#conversationId = antigravityString(frame, "conversation_id") ?? antigravityString(frame, "session_id") ?? this.#conversationId;
52081
+ this.#rootConversation ??= this.#conversationId;
51579
52082
  this.#track(type, frame);
52083
+ this.#noteStep(type, frame);
51580
52084
  const forked = this.#silentFork();
51581
52085
  if (SESSION_START_TYPES.has(type)) {
51582
52086
  return [
@@ -51591,6 +52095,29 @@ var init_antigravity = __esm({
51591
52095
  if (RESULT_TYPES.has(type)) return [...forked, ...this.#onResult(type, frame)];
51592
52096
  return [...forked, ...this.#transcripts?.read() ?? []];
51593
52097
  }
52098
+ /** A finished answer step of this conversation: one model call, with its own usage. */
52099
+ #noteStep(type, frame) {
52100
+ if (type !== "assistant_message" || asString(frame.state).toUpperCase() !== "DONE") return;
52101
+ const usage = asRecord(frame.usage);
52102
+ if (!usage) return;
52103
+ const conversation = antigravityString(frame, "conversation_id");
52104
+ if (conversation && this.#rootConversation && conversation !== this.#rootConversation) return;
52105
+ const step = stepTokens(usage);
52106
+ this.#stepSpend = addStepTokens(this.#stepSpend, step);
52107
+ const context = step.inputTokens + step.cacheReadTokens + step.outputTokens;
52108
+ if (context > 0) this.#contextTokens = context;
52109
+ }
52110
+ /**
52111
+ * agy's result usage is cumulative over the conversation, so a resumed turn's spend comes
52112
+ * from its steps; a first turn's result is its own.
52113
+ */
52114
+ #turnSpend(frame) {
52115
+ const steps = this.#stepSpend;
52116
+ this.#stepSpend = void 0;
52117
+ if (steps) return steps;
52118
+ if (this.#options.resumeId) return void 0;
52119
+ return stepTokens(asRecord(frame.usage) ?? asRecord(frame.stats) ?? frame);
52120
+ }
51594
52121
  #track(type, frame) {
51595
52122
  const transcripts = this.#transcripts;
51596
52123
  if (!transcripts) return;
@@ -51608,6 +52135,22 @@ var init_antigravity = __esm({
51608
52135
  this.#forkReported = true;
51609
52136
  return [noticeUpdate("warning", "session_resume_failed", RESUME_FORKED)];
51610
52137
  }
52138
+ #resultUsage(frame) {
52139
+ const spend = this.#turnSpend(frame);
52140
+ const contextTokens = this.#contextTokens;
52141
+ if (!spend && contextTokens === void 0) return [];
52142
+ const stats = asRecord(frame.usage) ?? asRecord(frame.stats) ?? frame;
52143
+ return [
52144
+ usageUpdate({
52145
+ model: formatAntigravityModelName(this.#model()),
52146
+ numTurns: Math.max(this.#iterations, 1),
52147
+ durationMs: asFiniteNumber(stats.duration_ms) ?? 0,
52148
+ ...spend,
52149
+ ...contextTokens === void 0 ? {} : { contextTokens },
52150
+ costUsd: 0
52151
+ })
52152
+ ];
52153
+ }
51611
52154
  #onResult(type, frame) {
51612
52155
  const updates = [];
51613
52156
  this.#iterations = Math.max(this.#iterations, asFiniteNumber(frame.num_turns) ?? 1);
@@ -51616,23 +52159,7 @@ var init_antigravity = __esm({
51616
52159
  updates.push(agentText(`antigravity-${this.#conversationId ?? "run"}-result`, resultText3));
51617
52160
  this.#resultShown = true;
51618
52161
  }
51619
- const stats = asRecord(frame.usage) ?? asRecord(frame.stats) ?? frame;
51620
- updates.push(
51621
- usageUpdate({
51622
- model: formatAntigravityModelName(this.#model()),
51623
- numTurns: Math.max(this.#iterations, 1),
51624
- durationMs: asFiniteNumber(stats.duration_ms) ?? 0,
51625
- inputTokens: firstNumber2(stats.input_tokens, stats.input),
51626
- outputTokens: firstNumber2(stats.output_tokens),
51627
- cacheReadTokens: firstNumber2(
51628
- stats.cache_read_tokens,
51629
- stats.cached_input_tokens,
51630
- stats.cached
51631
- ),
51632
- cacheCreationTokens: 0,
51633
- costUsd: 0
51634
- })
51635
- );
52162
+ updates.push(...this.#resultUsage(frame));
51636
52163
  const status = asString(frame.status).toLowerCase();
51637
52164
  const succeeded = !status || SUCCESSFUL_STATUSES.has(status);
51638
52165
  if (succeeded) {
@@ -51875,8 +52402,8 @@ var import_promises55, import_path16, import_crypto20, COMMAND_CODE_GRAMMAR_NAME
51875
52402
  var init_command_code = __esm({
51876
52403
  "../agent-core/dist/providers/command-code.js"() {
51877
52404
  "use strict";
51878
- init_chunk_FYZKVT3E();
51879
- init_chunk_OUEMTEUX();
52405
+ init_chunk_N2M5D7RS();
52406
+ init_chunk_RBQC7XZH();
51880
52407
  init_chunk_ZCTKXKYY();
51881
52408
  init_chunk_6VWVDJ2A();
51882
52409
  init_chunk_DLVRNIY5();
@@ -52241,6 +52768,7 @@ var init_command_code = __esm({
52241
52768
  #streamed = false;
52242
52769
  #totals;
52243
52770
  #result;
52771
+ #contextTokens;
52244
52772
  constructor(options) {
52245
52773
  this.#options = options;
52246
52774
  if (options.resumeId) this.#grammar.sessionId = options.resumeId;
@@ -52283,6 +52811,8 @@ var init_command_code = __esm({
52283
52811
  #onEvent(event) {
52284
52812
  switch (commandCodeString(event.type)) {
52285
52813
  case "model_request_end":
52814
+ this.#noteContext(event.usage);
52815
+ return this.#usage(event.usage);
52286
52816
  case "turn_end":
52287
52817
  return this.#usage(event.usage);
52288
52818
  case "run_end": {
@@ -52334,7 +52864,28 @@ var init_command_code = __esm({
52334
52864
  durationMs: durationMs ?? previous?.durationMs ?? 0
52335
52865
  };
52336
52866
  this.#totals = totals;
52337
- return [usageUpdate({ model: this.#model(), numTurns: 1, ...totals, costUsd: 0 })];
52867
+ return [
52868
+ usageUpdate({
52869
+ model: this.#model(),
52870
+ numTurns: 1,
52871
+ ...totals,
52872
+ // Command Code's own cost estimate takes cache out of inputTokens, which counts it.
52873
+ inputTokens: Math.max(
52874
+ totals.inputTokens - totals.cacheReadTokens - totals.cacheCreationTokens,
52875
+ 0
52876
+ ),
52877
+ ...this.#contextTokens === void 0 ? {} : { contextTokens: this.#contextTokens },
52878
+ costUsd: 0
52879
+ })
52880
+ ];
52881
+ }
52882
+ /** One model call's prompt, cache included, plus its reply: what it left in the window. */
52883
+ #noteContext(usage) {
52884
+ const record2 = asRecord(usage);
52885
+ const input2 = asFiniteNumber(record2?.inputTokens) ?? asFiniteNumber(record2?.input_tokens);
52886
+ if (input2 === void 0 || input2 <= 0) return;
52887
+ const output2 = asFiniteNumber(record2?.outputTokens) ?? asFiniteNumber(record2?.output_tokens);
52888
+ this.#contextTokens = input2 + (output2 ?? 0);
52338
52889
  }
52339
52890
  };
52340
52891
  COMMAND_CODE_MAX_TURNS = 1e4;
@@ -57278,7 +57829,7 @@ var require_websocket_server = __commonJS({
57278
57829
  // package.json
57279
57830
  var package_default = {
57280
57831
  name: "@alan-ai-hq/agent-manager",
57281
- version: "0.1.159",
57832
+ version: "0.1.161",
57282
57833
  private: true,
57283
57834
  type: "module",
57284
57835
  description: "Alan machine runtime (alan-agent): identity, link, reconciler, session holders, run log, uploader, local API",
@@ -58098,6 +58649,7 @@ function createGitHubProxyForwarder(options) {
58098
58649
  init_runtime_v2();
58099
58650
  init_zod();
58100
58651
  var REQUEST_TIMEOUT_MS3 = 3e4;
58652
+ var MEDIA_PUT_TIMEOUT_MS = 3e5;
58101
58653
  var credentialRefusalSchema = external_exports.object({ message: external_exports.string().trim().min(1) });
58102
58654
  function credentialFailureMessage(response, fallback) {
58103
58655
  if (response.status !== 409) return fallback;
@@ -58166,6 +58718,33 @@ function createHolderApiClient({
58166
58718
  throw new RuntimeFault("io_failed", `MCP credential request failed: ${response.status}`);
58167
58719
  }
58168
58720
  return machineMcpCredentialSchema.parse(jsonBody(response));
58721
+ },
58722
+ uploadRunMedia: async (runId, media, data, signal) => {
58723
+ const reserved = await request2("POST", runMediaPath(runId), signal, media);
58724
+ if (!isOk(reserved)) {
58725
+ throw new RuntimeFault("io_failed", `Media upload request failed: ${reserved.status}`);
58726
+ }
58727
+ const reservation = runMediaUploadResponseSchema.parse(jsonBody(reserved));
58728
+ if (reservation.status === "ready") return;
58729
+ const stored = await transport.send({
58730
+ method: "PUT",
58731
+ url: new URL(reservation.upload.url),
58732
+ headers: {
58733
+ ...reservation.upload.headers,
58734
+ "content-length": String(data.byteLength)
58735
+ },
58736
+ body: data,
58737
+ redirect: "error",
58738
+ signal: AbortSignal.any([signal, AbortSignal.timeout(MEDIA_PUT_TIMEOUT_MS)])
58739
+ });
58740
+ if (!isOk(stored)) {
58741
+ throw new RuntimeFault("io_failed", `Media upload failed: ${stored.status}`);
58742
+ }
58743
+ const completed = await request2("POST", runMediaCompletePath(runId, media.mediaId), signal);
58744
+ if (!isOk(completed)) {
58745
+ throw new RuntimeFault("io_failed", `Media upload completion failed: ${completed.status}`);
58746
+ }
58747
+ runMediaCompleteResponseSchema.parse(jsonBody(completed));
58169
58748
  }
58170
58749
  };
58171
58750
  }
@@ -58757,15 +59336,15 @@ var BRANCH_LABEL_MAX_LENGTH = 256;
58757
59336
  var HASH_OBJECT_BATCH = 128;
58758
59337
  function countPorcelainEntries(output2) {
58759
59338
  const records = output2.split("\0");
58760
- let count = 0;
59339
+ let count2 = 0;
58761
59340
  for (let index = 0; index < records.length; index += 1) {
58762
59341
  const record2 = records[index];
58763
59342
  if (!record2) continue;
58764
- count += 1;
59343
+ count2 += 1;
58765
59344
  const status = record2.slice(0, 2);
58766
59345
  if (status.includes("R") || status.includes("C")) index += 1;
58767
59346
  }
58768
- return count;
59347
+ return count2;
58769
59348
  }
58770
59349
  function sanitizeBranch(value2) {
58771
59350
  const printable = Array.from(value2.trim()).filter((character) => {
@@ -60730,6 +61309,7 @@ function runtimePaths(stateDir) {
60730
61309
 
60731
61310
  // src/platform/process-memory.ts
60732
61311
  var import_node_child_process4 = require("child_process");
61312
+ var import_node_fs7 = require("fs");
60733
61313
  var import_promises16 = require("fs/promises");
60734
61314
  var import_node_os2 = require("os");
60735
61315
  var import_node_util3 = require("util");
@@ -60797,12 +61377,52 @@ function readMemoryPressure() {
60797
61377
  if (process.platform === "linux") return linuxPressure();
60798
61378
  return Promise.resolve("normal");
60799
61379
  }
61380
+ function parseDarwinVmStat(output2) {
61381
+ const pageSize = Number(/page size of (\d+) bytes/.exec(output2)?.[1]);
61382
+ if (!Number.isFinite(pageSize) || pageSize <= 0) return null;
61383
+ const pages = (name) => {
61384
+ const match = new RegExp(`^Pages ${name}:\\s+(\\d+)\\.?$`, "m").exec(output2);
61385
+ return match ? Number(match[1]) : null;
61386
+ };
61387
+ const free = pages("free");
61388
+ if (free === null) return null;
61389
+ return (free + (pages("inactive") ?? 0) + (pages("speculative") ?? 0)) * pageSize;
61390
+ }
61391
+ function parseLinuxMemInfo(output2) {
61392
+ const kilobytes = /^MemAvailable:\s+(\d+)\s+kB$/m.exec(output2)?.[1];
61393
+ return kilobytes === void 0 ? null : Number(kilobytes) * 1024;
61394
+ }
61395
+ var CAPACITY_PROBE_TTL_MS = 2e3;
61396
+ var AvailableMemoryProbe = class {
61397
+ cached = null;
61398
+ read(now) {
61399
+ if (this.cached !== null && now - this.cached.at < CAPACITY_PROBE_TTL_MS) {
61400
+ return this.cached.bytes;
61401
+ }
61402
+ let bytes = null;
61403
+ try {
61404
+ if (process.platform === "darwin") {
61405
+ bytes = parseDarwinVmStat(
61406
+ (0, import_node_child_process4.execFileSync)("vm_stat", { encoding: "utf8", timeout: PROBE_TIMEOUT_MS })
61407
+ );
61408
+ } else if (process.platform === "linux") {
61409
+ bytes = parseLinuxMemInfo((0, import_node_fs7.readFileSync)("/proc/meminfo", "utf8"));
61410
+ }
61411
+ } catch {
61412
+ bytes = null;
61413
+ }
61414
+ this.cached = { at: now, bytes };
61415
+ return bytes;
61416
+ }
61417
+ };
61418
+ var availableMemoryProbe = new AvailableMemoryProbe();
60800
61419
  function readMemoryCapacity() {
60801
61420
  const constrained = process.constrainedMemory();
60802
- return {
60803
- totalBytes: constrained > 0 ? Math.min((0, import_node_os2.totalmem)(), constrained) : (0, import_node_os2.totalmem)(),
60804
- availableBytes: typeof process.availableMemory === "function" ? process.availableMemory() : (0, import_node_os2.freemem)()
60805
- };
61421
+ const totalBytes = constrained > 0 ? Math.min((0, import_node_os2.totalmem)(), constrained) : (0, import_node_os2.totalmem)();
61422
+ const reported = typeof process.availableMemory === "function" ? process.availableMemory() : (0, import_node_os2.freemem)();
61423
+ const probed = constrained > 0 && process.platform === "linux" ? null : availableMemoryProbe.read(Date.now());
61424
+ const availableBytes = Math.min(totalBytes, Math.max(reported, probed ?? reported));
61425
+ return { totalBytes, availableBytes };
60806
61426
  }
60807
61427
  async function processMemoryRows() {
60808
61428
  if (process.platform === "win32") {
@@ -61282,7 +61902,7 @@ var import_promises20 = require("fs/promises");
61282
61902
  var import_node_path17 = require("path");
61283
61903
 
61284
61904
  // src/platform/service/windows-service.ts
61285
- var import_node_fs7 = require("fs");
61905
+ var import_node_fs8 = require("fs");
61286
61906
  var import_promises19 = require("fs/promises");
61287
61907
  var import_node_path16 = require("path");
61288
61908
 
@@ -61512,7 +62132,7 @@ function windowsManager(host, profile) {
61512
62132
  name: files.runValue,
61513
62133
  definitionPath: files.config,
61514
62134
  install: async (spec, { restart }) => {
61515
- if (process.platform === "win32" && !(0, import_node_fs7.existsSync)(files.helper)) {
62135
+ if (process.platform === "win32" && !(0, import_node_fs8.existsSync)(files.helper)) {
61516
62136
  throw new RuntimeFault("io_failed", `Windows helper is missing: ${files.helper}`);
61517
62137
  }
61518
62138
  await (0, import_promises19.mkdir)((0, import_node_path16.dirname)(spec.logPath), { recursive: true });
@@ -62207,7 +62827,7 @@ function systemAssertionSpawner(log) {
62207
62827
  // src/platform/spawn-detached.ts
62208
62828
  var import_node_child_process8 = require("child_process");
62209
62829
  var import_node_crypto12 = require("crypto");
62210
- var import_node_fs8 = require("fs");
62830
+ var import_node_fs9 = require("fs");
62211
62831
  var import_node_path21 = require("path");
62212
62832
  var WINDOWS_UNSAFE_ENV = "NODE_PENDING_PIPE_INSTANCES";
62213
62833
  var SYSTEMD_RUN = "systemd-run";
@@ -62262,8 +62882,8 @@ function isolatedCommand(request2, isolation) {
62262
62882
  };
62263
62883
  }
62264
62884
  function spawnDetached(request2, isolation) {
62265
- (0, import_node_fs8.mkdirSync)((0, import_node_path21.dirname)(request2.outputPath), { recursive: true, mode: 448 });
62266
- const output2 = (0, import_node_fs8.openSync)(request2.outputPath, "a", 384);
62885
+ (0, import_node_fs9.mkdirSync)((0, import_node_path21.dirname)(request2.outputPath), { recursive: true, mode: 448 });
62886
+ const output2 = (0, import_node_fs9.openSync)(request2.outputPath, "a", 384);
62267
62887
  const { command, args } = isolatedCommand(request2, isolation);
62268
62888
  try {
62269
62889
  const child = (0, import_node_child_process8.spawn)(command, args, {
@@ -62279,7 +62899,7 @@ function spawnDetached(request2, isolation) {
62279
62899
  child.unref();
62280
62900
  return { pid: child.pid };
62281
62901
  } finally {
62282
- (0, import_node_fs8.closeSync)(output2);
62902
+ (0, import_node_fs9.closeSync)(output2);
62283
62903
  }
62284
62904
  }
62285
62905
 
@@ -62319,7 +62939,7 @@ function createUpdateGate(deps) {
62319
62939
 
62320
62940
  // src/platform/wake-clock.ts
62321
62941
  var import_node_child_process9 = require("child_process");
62322
- var import_node_fs9 = require("fs");
62942
+ var import_node_fs10 = require("fs");
62323
62943
  var import_node_readline = require("readline");
62324
62944
  var PTP_DEVICE = "/dev/ptp0";
62325
62945
  var RESPAWN_BASE_MS = 1e3;
@@ -62403,7 +63023,7 @@ function systemWakeClockSpawner(log) {
62403
63023
  function startWakeClock(options) {
62404
63024
  const { clock, log } = options;
62405
63025
  const platform3 = options.platform ?? process.platform;
62406
- const hasPtpDevice = options.hasPtpDevice ?? (() => (0, import_node_fs9.existsSync)(PTP_DEVICE));
63026
+ const hasPtpDevice = options.hasPtpDevice ?? (() => (0, import_node_fs10.existsSync)(PTP_DEVICE));
62407
63027
  if (platform3 !== "linux" || !hasPtpDevice()) return { [Symbol.dispose]: () => {
62408
63028
  } };
62409
63029
  const spawner = options.spawner ?? systemWakeClockSpawner(log);
@@ -64537,7 +65157,7 @@ function fingerprintWholeText(fingerprint) {
64537
65157
  }
64538
65158
 
64539
65159
  // src/capabilities/native-ingest/hook-config.ts
64540
- var import_node_fs10 = require("fs");
65160
+ var import_node_fs11 = require("fs");
64541
65161
  var import_node_path28 = require("path");
64542
65162
 
64543
65163
  // src/capabilities/native-ingest/provider-paths.ts
@@ -64615,9 +65235,9 @@ function hookHandler(provider4, event, options) {
64615
65235
  return { type: "command", command: posixCommand(argv, environment), timeout: 5 };
64616
65236
  }
64617
65237
  function readSettings(path4, backupWhenMalformed, now) {
64618
- if (!(0, import_node_fs10.existsSync)(path4)) return {};
65238
+ if (!(0, import_node_fs11.existsSync)(path4)) return {};
64619
65239
  try {
64620
- const value2 = JSON.parse((0, import_node_fs10.readFileSync)(path4, "utf8"));
65240
+ const value2 = JSON.parse((0, import_node_fs11.readFileSync)(path4, "utf8"));
64621
65241
  if (!isRecord4(value2)) throw new Error("settings root must be an object");
64622
65242
  if (value2.hooks !== void 0 && !isRecord4(value2.hooks)) {
64623
65243
  throw new Error("settings `hooks` must be an object");
@@ -64627,7 +65247,7 @@ function readSettings(path4, backupWhenMalformed, now) {
64627
65247
  const reason = error62 instanceof Error ? error62.message : String(error62);
64628
65248
  if (!backupWhenMalformed) throw new Error(`${path4} is malformed: ${reason}`);
64629
65249
  const backup = `${path4}.malformed-${now}.bak`;
64630
- (0, import_node_fs10.copyFileSync)(path4, backup);
65250
+ (0, import_node_fs11.copyFileSync)(path4, backup);
64631
65251
  throw new Error(`${path4} is malformed and was copied to ${backup}: ${reason}`);
64632
65252
  }
64633
65253
  }
@@ -64635,14 +65255,14 @@ function hooksOf(settings2) {
64635
65255
  return isRecord4(settings2.hooks) ? settings2.hooks : {};
64636
65256
  }
64637
65257
  function writeSettings(path4, settings2) {
64638
- (0, import_node_fs10.mkdirSync)((0, import_node_path28.dirname)(path4), { recursive: true, mode: 448 });
65258
+ (0, import_node_fs11.mkdirSync)((0, import_node_path28.dirname)(path4), { recursive: true, mode: 448 });
64639
65259
  const temporary = `${path4}.${process.pid}.tmp`;
64640
65260
  try {
64641
- (0, import_node_fs10.writeFileSync)(temporary, `${JSON.stringify(settings2, null, 2)}
65261
+ (0, import_node_fs11.writeFileSync)(temporary, `${JSON.stringify(settings2, null, 2)}
64642
65262
  `, { mode: 384 });
64643
- (0, import_node_fs10.renameSync)(temporary, path4);
65263
+ (0, import_node_fs11.renameSync)(temporary, path4);
64644
65264
  } finally {
64645
- (0, import_node_fs10.rmSync)(temporary, { force: true });
65265
+ (0, import_node_fs11.rmSync)(temporary, { force: true });
64646
65266
  }
64647
65267
  }
64648
65268
  function isIngestionHandler(handler) {
@@ -64687,7 +65307,7 @@ function installIngestionHooks(provider4, options, now) {
64687
65307
  }
64688
65308
  function removeIngestionHooks(provider4, where, now) {
64689
65309
  const path4 = providerHookSettingsPath(provider4, where);
64690
- if (!(0, import_node_fs10.existsSync)(path4)) return { provider: provider4, path: path4, changed: false };
65310
+ if (!(0, import_node_fs11.existsSync)(path4)) return { provider: provider4, path: path4, changed: false };
64691
65311
  const settings2 = readSettings(path4, true, now);
64692
65312
  const hooks = hooksOf(settings2);
64693
65313
  const nextHooks = {};
@@ -64724,7 +65344,7 @@ function ingestionHookStatus(provider4, options) {
64724
65344
  }
64725
65345
 
64726
65346
  // src/capabilities/native-ingest/hook-input.ts
64727
- var import_node_fs11 = require("fs");
65347
+ var import_node_fs12 = require("fs");
64728
65348
  var import_node_path29 = require("path");
64729
65349
  var ALAN_MANAGED_SESSION_ENV = "ALAN_MANAGED_SESSION";
64730
65350
  var MAX_HOOK_STDIN_BYTES = 256 * 1024 * 1024;
@@ -64754,17 +65374,17 @@ function codexSessionIdFromTranscriptPath(transcriptPath) {
64754
65374
  );
64755
65375
  return match?.[1] ?? null;
64756
65376
  }
64757
- function lastBytes(chunks, count) {
65377
+ function lastBytes(chunks, count2) {
64758
65378
  const kept = [];
64759
65379
  let size = 0;
64760
- for (let index = chunks.length - 1; index >= 0 && size < count; index -= 1) {
65380
+ for (let index = chunks.length - 1; index >= 0 && size < count2; index -= 1) {
64761
65381
  const chunk = chunks[index];
64762
65382
  if (chunk === void 0) continue;
64763
65383
  kept.unshift(chunk);
64764
65384
  size += chunk.length;
64765
65385
  }
64766
65386
  const joined = Buffer.concat(kept);
64767
- return joined.subarray(Math.max(0, joined.length - count));
65387
+ return joined.subarray(Math.max(0, joined.length - count2));
64768
65388
  }
64769
65389
  async function readHookStdin(stream, maxBytes = MAX_HOOK_STDIN_BYTES) {
64770
65390
  const chunks = [];
@@ -64824,10 +65444,10 @@ function hookPayload(input2) {
64824
65444
  }
64825
65445
  function realpathOrSelf(path4) {
64826
65446
  try {
64827
- return (0, import_node_fs11.realpathSync)(path4);
65447
+ return (0, import_node_fs12.realpathSync)(path4);
64828
65448
  } catch {
64829
65449
  try {
64830
- return (0, import_node_path29.join)((0, import_node_fs11.realpathSync)((0, import_node_path29.dirname)(path4)), (0, import_node_path29.basename)(path4));
65450
+ return (0, import_node_path29.join)((0, import_node_fs12.realpathSync)((0, import_node_path29.dirname)(path4)), (0, import_node_path29.basename)(path4));
64831
65451
  } catch {
64832
65452
  return path4;
64833
65453
  }
@@ -64858,7 +65478,7 @@ function parseHookSignal(input2) {
64858
65478
  }
64859
65479
 
64860
65480
  // src/capabilities/native-ingest/ingest.ts
64861
- var import_node_fs12 = require("fs");
65481
+ var import_node_fs13 = require("fs");
64862
65482
 
64863
65483
  // ../shared/dist/types/native-agent-session.js
64864
65484
  var nativeAgentProviderBackendKinds = {
@@ -65628,7 +66248,7 @@ function workerKey(provider4, externalSessionId) {
65628
66248
  return `${provider4}\0${externalSessionId}`;
65629
66249
  }
65630
66250
  function holdFor(entry) {
65631
- const stats = (0, import_node_fs12.statSync)(entry.transcriptPath, { bigint: true, throwIfNoEntry: false });
66251
+ const stats = (0, import_node_fs13.statSync)(entry.transcriptPath, { bigint: true, throwIfNoEntry: false });
65632
66252
  if (!stats) return [];
65633
66253
  return [
65634
66254
  {
@@ -65829,7 +66449,7 @@ async function startNativeIngest(deps) {
65829
66449
  return "accepted";
65830
66450
  };
65831
66451
  const hasUnreadBytes = (entry, now) => {
65832
- const stats = (0, import_node_fs12.statSync)(entry.transcriptPath, { bigint: true, throwIfNoEntry: false });
66452
+ const stats = (0, import_node_fs13.statSync)(entry.transcriptPath, { bigint: true, throwIfNoEntry: false });
65833
66453
  if (!stats || now - Number(stats.mtimeMs) > timing.sweepRecencyMs) return false;
65834
66454
  const replaced = String(stats.dev) !== entry.device || String(stats.ino) !== entry.inode;
65835
66455
  return replaced || Number(stats.size) > entry.cursor.offset;
@@ -65873,7 +66493,7 @@ async function startNativeIngest(deps) {
65873
66493
  const recordAlanRun = async (hold, runId) => {
65874
66494
  const entry = store.get(hold.provider, hold.externalSessionId);
65875
66495
  if (!entry || entry.dead) return;
65876
- const stats = (0, import_node_fs12.statSync)(entry.transcriptPath, { bigint: true, throwIfNoEntry: false });
66496
+ const stats = (0, import_node_fs13.statSync)(entry.transcriptPath, { bigint: true, throwIfNoEntry: false });
65877
66497
  if (!stats) return;
65878
66498
  const identity = { device: String(stats.dev), inode: String(stats.ino) };
65879
66499
  const size = Number(stats.size);
@@ -65947,7 +66567,7 @@ async function startNativeIngest(deps) {
65947
66567
  init_alan_code();
65948
66568
 
65949
66569
  // src/capabilities/providers/commands.ts
65950
- var import_node_fs13 = require("fs");
66570
+ var import_node_fs14 = require("fs");
65951
66571
  var import_promises35 = require("fs/promises");
65952
66572
  var import_node_path32 = require("path");
65953
66573
  var PROVIDER_COMMANDS = [
@@ -65985,7 +66605,7 @@ function pathDelimiter(platform3) {
65985
66605
  async function isRunnable(path4, platform3) {
65986
66606
  try {
65987
66607
  if (!(await (0, import_promises35.stat)(path4)).isFile()) return false;
65988
- if (platform3 !== "win32") await (0, import_promises35.access)(path4, import_node_fs13.constants.X_OK);
66608
+ if (platform3 !== "win32") await (0, import_promises35.access)(path4, import_node_fs14.constants.X_OK);
65989
66609
  return true;
65990
66610
  } catch {
65991
66611
  return false;
@@ -66168,7 +66788,7 @@ init_runtime_v2();
66168
66788
 
66169
66789
  // src/capabilities/providers/account-label.ts
66170
66790
  var import_node_child_process12 = require("child_process");
66171
- var import_node_fs14 = require("fs");
66791
+ var import_node_fs15 = require("fs");
66172
66792
  var import_node_path33 = require("path");
66173
66793
  var import_node_url3 = require("url");
66174
66794
  var ACCOUNT_TIMEOUT_MS = 2e4;
@@ -66271,7 +66891,7 @@ async function claudeLabel(executable, env) {
66271
66891
  const childEnv = { ...env };
66272
66892
  delete childEnv.FORCE_CODE_TERMINAL;
66273
66893
  const bundledSdk = typeof __dirname === "string" ? (0, import_node_path33.join)(__dirname, "claude-sdk.mjs") : "";
66274
- const sdkSpecifier = (0, import_node_fs14.existsSync)(bundledSdk) ? (0, import_node_url3.pathToFileURL)(bundledSdk).href : "@anthropic-ai/claude-agent-sdk";
66894
+ const sdkSpecifier = (0, import_node_fs15.existsSync)(bundledSdk) ? (0, import_node_url3.pathToFileURL)(bundledSdk).href : "@anthropic-ai/claude-agent-sdk";
66275
66895
  const { query } = await import(sdkSpecifier);
66276
66896
  const session = query({
66277
66897
  prompt: idlePrompt(abort.signal),
@@ -66681,7 +67301,7 @@ var import_node_path37 = require("path");
66681
67301
  // ../shared/dist/node/shell-environment.js
66682
67302
  var import_node_child_process13 = require("child_process");
66683
67303
  var import_node_crypto16 = require("crypto");
66684
- var import_node_fs16 = require("fs");
67304
+ var import_node_fs17 = require("fs");
66685
67305
  var import_node_os6 = require("os");
66686
67306
  var import_node_path36 = require("path");
66687
67307
 
@@ -66690,7 +67310,7 @@ var import_node_os5 = require("os");
66690
67310
  var import_node_path35 = require("path");
66691
67311
 
66692
67312
  // ../shared/dist/node/version-manager-paths.js
66693
- var import_node_fs15 = require("fs");
67313
+ var import_node_fs16 = require("fs");
66694
67314
  var import_node_path34 = require("path");
66695
67315
  function compareNodeVersionsDesc(a, b) {
66696
67316
  const parse7 = (value2) => value2.replace(/^v/, "").split(".").map((part) => Number.parseInt(part, 10) || 0);
@@ -66705,19 +67325,19 @@ function compareNodeVersionsDesc(a, b) {
66705
67325
  }
66706
67326
  function resolveNvmDefaultBin(home) {
66707
67327
  const versionsDir = (0, import_node_path34.join)(home, ".nvm", "versions", "node");
66708
- if (!(0, import_node_fs15.existsSync)(versionsDir))
67328
+ if (!(0, import_node_fs16.existsSync)(versionsDir))
66709
67329
  return null;
66710
67330
  let alias = null;
66711
67331
  try {
66712
67332
  const aliasFile = (0, import_node_path34.join)(home, ".nvm", "alias", "default");
66713
- if ((0, import_node_fs15.existsSync)(aliasFile))
66714
- alias = (0, import_node_fs15.readFileSync)(aliasFile, "utf8").trim();
67333
+ if ((0, import_node_fs16.existsSync)(aliasFile))
67334
+ alias = (0, import_node_fs16.readFileSync)(aliasFile, "utf8").trim();
66715
67335
  } catch {
66716
67336
  alias = null;
66717
67337
  }
66718
67338
  let installed;
66719
67339
  try {
66720
- installed = (0, import_node_fs15.readdirSync)(versionsDir).filter((entry) => entry.startsWith("v"));
67340
+ installed = (0, import_node_fs16.readdirSync)(versionsDir).filter((entry) => entry.startsWith("v"));
66721
67341
  } catch {
66722
67342
  return null;
66723
67343
  }
@@ -66728,7 +67348,7 @@ function resolveNvmDefaultBin(home) {
66728
67348
  if (!chosen)
66729
67349
  return null;
66730
67350
  const bin = (0, import_node_path34.join)(versionsDir, chosen, "bin");
66731
- return (0, import_node_fs15.existsSync)(bin) ? bin : null;
67351
+ return (0, import_node_fs16.existsSync)(bin) ? bin : null;
66732
67352
  }
66733
67353
  function resolveVersionManagerBinDirs(home, platform3 = process.platform) {
66734
67354
  if (platform3 === "win32")
@@ -66747,7 +67367,7 @@ function resolveVersionManagerBinDirs(home, platform3 = process.platform) {
66747
67367
  if (!dir || seen.has(dir))
66748
67368
  continue;
66749
67369
  seen.add(dir);
66750
- if ((0, import_node_fs15.existsSync)(dir))
67370
+ if ((0, import_node_fs16.existsSync)(dir))
66751
67371
  resolved.push(dir);
66752
67372
  }
66753
67373
  return resolved;
@@ -66789,7 +67409,7 @@ function promoteUserBinDirs(path4, home, versionManagerDirs) {
66789
67409
  // ../shared/dist/node/shell-environment.js
66790
67410
  function isExecutableFile(path4) {
66791
67411
  try {
66792
- (0, import_node_fs16.accessSync)(path4, import_node_fs16.constants.X_OK);
67412
+ (0, import_node_fs17.accessSync)(path4, import_node_fs17.constants.X_OK);
66793
67413
  return true;
66794
67414
  } catch {
66795
67415
  return false;
@@ -68699,7 +69319,7 @@ async function publishLocalSkill(options) {
68699
69319
 
68700
69320
  // src/capabilities/skills/native-index.ts
68701
69321
  var import_node_crypto23 = require("crypto");
68702
- var import_node_fs17 = require("fs");
69322
+ var import_node_fs18 = require("fs");
68703
69323
  var import_promises45 = require("fs/promises");
68704
69324
  var import_node_path45 = require("path");
68705
69325
  var ALAN_SKILLS_PLUGIN_NAME = "alan";
@@ -68850,7 +69470,7 @@ async function reconcileNativeIndex(layout, installed, options) {
68850
69470
  };
68851
69471
  }
68852
69472
  function installedSkillFolders(layout) {
68853
- return (0, import_node_fs17.existsSync)((0, import_node_path45.join)(layout.pluginDir, ".claude-plugin", "plugin.json")) ? { pluginDir: layout.pluginDir, skillsDir: layout.pluginSkillsDir } : null;
69473
+ return (0, import_node_fs18.existsSync)((0, import_node_path45.join)(layout.pluginDir, ".claude-plugin", "plugin.json")) ? { pluginDir: layout.pluginDir, skillsDir: layout.pluginSkillsDir } : null;
68854
69474
  }
68855
69475
 
68856
69476
  // src/capabilities/skills/sync.ts
@@ -70739,10 +71359,10 @@ async function reapLeftoverEngines(path4, options) {
70739
71359
  }
70740
71360
 
70741
71361
  // src/holder/launch-command.ts
70742
- var import_node_fs18 = require("fs");
71362
+ var import_node_fs19 = require("fs");
70743
71363
  var import_node_path53 = require("path");
70744
71364
  var HOLDER_BUNDLE = "alan-holder.cjs";
70745
- function holderArguments(runtimeArgs, nodeFlags, exists6 = import_node_fs18.existsSync) {
71365
+ function holderArguments(runtimeArgs, nodeFlags, exists6 = import_node_fs19.existsSync) {
70746
71366
  const bundle = runtimeArgs.at(-1);
70747
71367
  const lean = bundle === void 0 ? void 0 : (0, import_node_path53.join)((0, import_node_path53.dirname)(bundle), HOLDER_BUNDLE);
70748
71368
  const script = lean !== void 0 && exists6(lean) ? [...runtimeArgs.slice(0, -1), lean] : runtimeArgs;
@@ -70831,6 +71451,13 @@ function attachmentPath(spec, attachment, index, runDir) {
70831
71451
  }
70832
71452
  return (0, import_node_path54.join)(runDir, `${index}-${safeFilename(attachment.filename)}`);
70833
71453
  }
71454
+ function runMediaUploader(source, runId) {
71455
+ const upload = source.uploadMedia?.bind(source);
71456
+ if (upload === void 0) return void 0;
71457
+ return {
71458
+ upload: ({ data, ...media }, signal) => upload(runId, { ...media, bytes: data.byteLength }, data, signal)
71459
+ };
71460
+ }
70834
71461
  async function prepareRunInputs(spec, { source, tmpDir, signal, skills = [] }) {
70835
71462
  const dir = (0, import_node_path54.join)(tmpDir, "runs", spec.runId);
70836
71463
  const cleanup = async () => {
@@ -70857,9 +71484,11 @@ async function prepareRunInputs(spec, { source, tmpDir, signal, skills = [] }) {
70857
71484
  ...attachment.height === void 0 ? {} : { height: attachment.height }
70858
71485
  });
70859
71486
  }
71487
+ const media = runMediaUploader(source, spec.runId);
70860
71488
  return {
70861
71489
  attachments,
70862
71490
  providerEnv: credential.env,
71491
+ ...media === void 0 ? {} : { media },
70863
71492
  ...credential.codex === void 0 ? {} : { codex: credential.codex },
70864
71493
  skills,
70865
71494
  [Symbol.asyncDispose]: cleanup
@@ -70872,20 +71501,20 @@ async function prepareRunInputs(spec, { source, tmpDir, signal, skills = [] }) {
70872
71501
 
70873
71502
  // src/holder/serve.ts
70874
71503
  var import_node_crypto30 = require("crypto");
70875
- var import_node_fs23 = require("fs");
71504
+ var import_node_fs24 = require("fs");
70876
71505
  var import_node_net3 = require("net");
70877
71506
  var import_node_path66 = require("path");
70878
71507
  init_runtime_v2();
70879
71508
 
70880
71509
  // src/holder/admission.ts
70881
- var import_node_fs20 = require("fs");
71510
+ var import_node_fs21 = require("fs");
70882
71511
  var import_promises61 = require("fs/promises");
70883
71512
  var import_node_os10 = require("os");
70884
71513
  var import_node_path60 = require("path");
70885
71514
  init_constants();
70886
71515
 
70887
71516
  // ../shared/dist/node/local-workspace.js
70888
- var import_node_fs19 = require("fs");
71517
+ var import_node_fs20 = require("fs");
70889
71518
  var import_node_os9 = require("os");
70890
71519
  var import_node_path55 = require("path");
70891
71520
  function resolveAlanDefaultWorkspacePath(homeDirectory = (0, import_node_os9.homedir)()) {
@@ -71305,7 +71934,7 @@ async function inspectReadiness(path4) {
71305
71934
  if (!(await (0, import_promises61.stat)(path4)).isDirectory()) {
71306
71935
  return { ready: false, missing: true, message: MESSAGES.missing };
71307
71936
  }
71308
- await (0, import_promises61.access)(path4, import_node_fs20.constants.R_OK | import_node_fs20.constants.W_OK | import_node_fs20.constants.X_OK);
71937
+ await (0, import_promises61.access)(path4, import_node_fs21.constants.R_OK | import_node_fs21.constants.W_OK | import_node_fs21.constants.X_OK);
71309
71938
  return { ready: true };
71310
71939
  } catch (error62) {
71311
71940
  const code = errnoCode(error62) ?? "";
@@ -71350,7 +71979,7 @@ async function admitDefaultWorkspace(spec, context, skills) {
71350
71979
  const path4 = resolveAlanDefaultWorkspacePath(env.HOME || env.USERPROFILE || (0, import_node_os10.homedir)());
71351
71980
  try {
71352
71981
  await (0, import_promises61.mkdir)(path4, { recursive: true, mode: 448 });
71353
- await (0, import_promises61.access)(path4, import_node_fs20.constants.R_OK | import_node_fs20.constants.W_OK | import_node_fs20.constants.X_OK);
71982
+ await (0, import_promises61.access)(path4, import_node_fs21.constants.R_OK | import_node_fs21.constants.W_OK | import_node_fs21.constants.X_OK);
71354
71983
  return { kind: "admitted", spec: { ...spec, projectPath: path4 }, skills };
71355
71984
  } catch (error62) {
71356
71985
  const code = errnoCode(error62);
@@ -71599,7 +72228,7 @@ ${added.join("\n")}
71599
72228
 
71600
72229
  // src/run-log/complete.ts
71601
72230
  var import_node_crypto29 = require("crypto");
71602
- var import_node_fs21 = require("fs");
72231
+ var import_node_fs22 = require("fs");
71603
72232
  var import_node_path63 = require("path");
71604
72233
 
71605
72234
  // src/run-log/directory.ts
@@ -71650,23 +72279,23 @@ async function isRunClaimed(runsDir, runId) {
71650
72279
  // src/run-log/complete.ts
71651
72280
  function writeLogFile(path4, dir, text3) {
71652
72281
  const temp = (0, import_node_path63.join)(dir, `.log.${(0, import_node_crypto29.randomUUID)()}.tmp`);
71653
- const fd = (0, import_node_fs21.openSync)(temp, "wx", 384);
72282
+ const fd = (0, import_node_fs22.openSync)(temp, "wx", 384);
71654
72283
  try {
71655
- (0, import_node_fs21.writeSync)(fd, text3);
71656
- (0, import_node_fs21.fsyncSync)(fd);
72284
+ (0, import_node_fs22.writeSync)(fd, text3);
72285
+ (0, import_node_fs22.fsyncSync)(fd);
71657
72286
  } finally {
71658
- (0, import_node_fs21.closeSync)(fd);
72287
+ (0, import_node_fs22.closeSync)(fd);
71659
72288
  }
71660
72289
  try {
71661
- (0, import_node_fs21.renameSync)(temp, path4);
72290
+ (0, import_node_fs22.renameSync)(temp, path4);
71662
72291
  } finally {
71663
- (0, import_node_fs21.rmSync)(temp, { force: true });
72292
+ (0, import_node_fs22.rmSync)(temp, { force: true });
71664
72293
  }
71665
72294
  }
71666
72295
  async function writeCompleteRunLog(runsDir, meta3, records) {
71667
72296
  const paths = runDirectory(runsDir, meta3.runId);
71668
72297
  if (!await isRunClaimed(runsDir, meta3.runId)) {
71669
- (0, import_node_fs21.mkdirSync)(paths.dir, { recursive: true, mode: 448 });
72298
+ (0, import_node_fs22.mkdirSync)(paths.dir, { recursive: true, mode: 448 });
71670
72299
  const text3 = records.map((record2, index) => {
71671
72300
  const line = { seq: index + 1, at: record2.at, update: record2.update };
71672
72301
  return `${JSON.stringify(line)}
@@ -71923,13 +72552,13 @@ function runEnded(input2) {
71923
72552
  var decoder = new TextDecoder();
71924
72553
 
71925
72554
  // src/run-log/writer.ts
71926
- var import_node_fs22 = require("fs");
72555
+ var import_node_fs23 = require("fs");
71927
72556
  var import_node_path65 = require("path");
71928
72557
  init_runtime_v2();
71929
72558
  function lastSeq(fd, size) {
71930
72559
  for (const length of tailWindows(size)) {
71931
72560
  const buffer = Buffer.alloc(length);
71932
- (0, import_node_fs22.readSync)(fd, buffer, 0, length, size - length);
72561
+ (0, import_node_fs23.readSync)(fd, buffer, 0, length, size - length);
71933
72562
  const last = lastLine(buffer.toString("utf8").trimEnd(), length === size);
71934
72563
  if (last === void 0) continue;
71935
72564
  if (last.length === 0) return 0;
@@ -71940,13 +72569,13 @@ function lastSeq(fd, size) {
71940
72569
  throw new RuntimeFault("record_too_large", "Run log tail record is larger than any record");
71941
72570
  }
71942
72571
  function openRunLog(path4, clock) {
71943
- (0, import_node_fs22.mkdirSync)((0, import_node_path65.dirname)(path4), { recursive: true, mode: 448 });
71944
- const fd = (0, import_node_fs22.openSync)(path4, "a+", 384);
71945
- let size = (0, import_node_fs22.fstatSync)(fd).size;
72572
+ (0, import_node_fs23.mkdirSync)((0, import_node_path65.dirname)(path4), { recursive: true, mode: 448 });
72573
+ const fd = (0, import_node_fs23.openSync)(path4, "a+", 384);
72574
+ let size = (0, import_node_fs23.fstatSync)(fd).size;
71946
72575
  let seq = lastSeq(fd, size);
71947
72576
  let dirty = false;
71948
72577
  const sync = () => {
71949
- (0, import_node_fs22.fsyncSync)(fd);
72578
+ (0, import_node_fs23.fsyncSync)(fd);
71950
72579
  dirty = false;
71951
72580
  };
71952
72581
  return {
@@ -71960,7 +72589,7 @@ function openRunLog(path4, clock) {
71960
72589
  };
71961
72590
  const line = Buffer.from(`${JSON.stringify(record2)}
71962
72591
  `, "utf8");
71963
- (0, import_node_fs22.writeSync)(fd, line);
72592
+ (0, import_node_fs23.writeSync)(fd, line);
71964
72593
  size += line.length;
71965
72594
  dirty = true;
71966
72595
  if (isRunLifecycleKind(update.sessionUpdate)) sync();
@@ -71972,7 +72601,7 @@ function openRunLog(path4, clock) {
71972
72601
  },
71973
72602
  [Symbol.dispose]: () => {
71974
72603
  if (dirty) sync();
71975
- (0, import_node_fs22.closeSync)(fd);
72604
+ (0, import_node_fs23.closeSync)(fd);
71976
72605
  }
71977
72606
  };
71978
72607
  }
@@ -72416,7 +73045,7 @@ async function runHolder({
72416
73045
  for (const client of holder.clients) client.end();
72417
73046
  await new Promise((resolve13) => server.close(() => resolve13()));
72418
73047
  await statusWrites;
72419
- (0, import_node_fs23.rmSync)(launch.statusPath, { force: true });
73048
+ (0, import_node_fs24.rmSync)(launch.statusPath, { force: true });
72420
73049
  log.info("holder.suspended", { conversationId: launch.conversationId });
72421
73050
  } catch (_) {
72422
73051
  var _error = _, _hasError = true;
@@ -72429,6 +73058,7 @@ async function runHolder({
72429
73058
  var GIB = 1024 ** 3;
72430
73059
  var MIN_RUN_BYTES = 1.25 * GIB;
72431
73060
  function memoryAllowsStart(capacity, activeRuns, pendingStarts = 0) {
73061
+ if (activeRuns + pendingStarts === 0) return true;
72432
73062
  const headroom = Math.max(512 * 1024 ** 2, capacity.totalBytes * 0.2);
72433
73063
  const slots = Math.max(1, Math.floor((capacity.totalBytes - headroom) / MIN_RUN_BYTES));
72434
73064
  return activeRuns + pendingStarts < slots && capacity.availableBytes >= MIN_RUN_BYTES * (pendingStarts + 1);
@@ -72446,6 +73076,7 @@ function runOccupancy(held, reserved, exclude = null) {
72446
73076
 
72447
73077
  // src/sessions/suspend-policy.ts
72448
73078
  var GIB2 = 1024 ** 3;
73079
+ var SESSION_MEMORY_CEILING_BYTES = 2.5 * GIB2;
72449
73080
  var MEMORY_BUDGET_SHARE = 0.15;
72450
73081
  var MEMORY_BUDGET_MIN_BYTES = GIB2;
72451
73082
  var MEMORY_BUDGET_MAX_BYTES = 4 * GIB2;
@@ -72479,7 +73110,9 @@ function memoryOf(holder) {
72479
73110
  function ownReason({ holder, idleSinceMs }, policy, nowMs) {
72480
73111
  if (holder.facts.loginFailed) return "login_error";
72481
73112
  if (holder.facts.cliBinaryChanged) return "cli_changed";
72482
- if (memoryOf(holder) > Math.min(policy.memoryBudgetBytes, 1.25 * GIB2)) return "memory_budget";
73113
+ if (memoryOf(holder) > Math.min(policy.memoryBudgetBytes, SESSION_MEMORY_CEILING_BYTES)) {
73114
+ return "memory_budget";
73115
+ }
72483
73116
  if (nowMs - idleSinceMs >= policy.idleMs) return "idle";
72484
73117
  if (nowMs - holder.facts.startedAtMs >= policy.maxAgeMs) return "age";
72485
73118
  return null;
@@ -72494,8 +73127,8 @@ function planSuspends(holders, policy, nowMs, pressure, opened = null) {
72494
73127
  if (reason === null) kept.push(entry);
72495
73128
  else decisions.push({ conversationId: entry.holder.conversationId, reason });
72496
73129
  }
72497
- const suspend = (count, reason) => {
72498
- for (const { holder } of kept.splice(0, Math.max(0, count))) {
73130
+ const suspend = (count2, reason) => {
73131
+ for (const { holder } of kept.splice(0, Math.max(0, count2))) {
72499
73132
  decisions.push({ conversationId: holder.conversationId, reason });
72500
73133
  }
72501
73134
  };
@@ -72868,7 +73501,20 @@ async function openSessions(deps) {
72868
73501
  return "started";
72869
73502
  }
72870
73503
  if (!await claimCapacity(run2.runId)) {
72871
- log.info("sessions.resource_wait", { runId: run2.runId });
73504
+ const capacity = memoryCapacity();
73505
+ const { active, pending } = runOccupancy(
73506
+ await heldRuns(),
73507
+ [...admitted, ...launched.keys()],
73508
+ run2.runId
73509
+ );
73510
+ log.info("sessions.resource_wait", {
73511
+ runId: run2.runId,
73512
+ active,
73513
+ pending,
73514
+ maxActiveRuns,
73515
+ totalMiB: Math.round(capacity.totalBytes / 2 ** 20),
73516
+ availableMiB: Math.round(capacity.availableBytes / 2 ** 20)
73517
+ });
72872
73518
  return "waiting";
72873
73519
  }
72874
73520
  try {
@@ -72991,7 +73637,8 @@ var envSchema = external_exports.object({
72991
73637
  ALAN_RUNTIME_LOG_LEVEL: external_exports.enum(["debug", "info", "warn", "error"]).default("info"),
72992
73638
  ALAN_RUNTIME_SUSPEND_IDLE_MS: external_exports.coerce.number().int().positive().optional(),
72993
73639
  ALAN_RUNTIME_SUSPEND_CHECK_MS: external_exports.coerce.number().int().positive().default(3e4),
72994
- ALAN_RUNTIME_DESIRED_RESYNC_MS: external_exports.coerce.number().int().positive().default(6e5),
73640
+ // A two-minute conditional GET bounds recovery after a lost poke; unchanged state returns 304.
73641
+ ALAN_RUNTIME_DESIRED_RESYNC_MS: external_exports.coerce.number().int().positive().default(12e4),
72995
73642
  ALAN_MAX_ACTIVE_RUNS: external_exports.coerce.number().int().optional(),
72996
73643
  ALAN_RUNTIME_API_URL: external_exports.url().optional(),
72997
73644
  ALAN_RUNTIME_CREDENTIAL_STORE: external_exports.enum(CREDENTIAL_STORE_KINDS).optional(),
@@ -74515,7 +75162,8 @@ async function machineAccess(paths, log, conversationId, transport) {
74515
75162
  fetchProviderCredential: async (runId, signal) => {
74516
75163
  void managedMcp?.authorization(signal);
74517
75164
  return (await api()).fetchProviderCredential(runId, signal);
74518
- }
75165
+ },
75166
+ uploadMedia: async (runId, media, data, signal) => (await api()).uploadRunMedia(runId, media, data, signal)
74519
75167
  };
74520
75168
  const codexCredentials = {
74521
75169
  refresh: async (runId, rejectedAccessTokenSha256) => (await api()).refreshCodexCredential(
@@ -75167,7 +75815,7 @@ async function runLogout(argv, signal) {
75167
75815
  }
75168
75816
 
75169
75817
  // src/cli/commands/run.ts
75170
- var import_node_fs25 = require("fs");
75818
+ var import_node_fs26 = require("fs");
75171
75819
  var import_node_path82 = require("path");
75172
75820
 
75173
75821
  // src/local-api/app-attachments.ts
@@ -75722,7 +76370,7 @@ var machineFeatureRoutes = [
75722
76370
  ];
75723
76371
 
75724
76372
  // src/local-api/run-log-routes.ts
75725
- var import_node_fs24 = require("fs");
76373
+ var import_node_fs25 = require("fs");
75726
76374
  init_runtime_v2();
75727
76375
  var RUN_ENDED = "_alan/run.ended";
75728
76376
  var decoder2 = new TextDecoder();
@@ -75739,7 +76387,7 @@ async function openWhenWritten(deps, runId, res, signal) {
75739
76387
  const path4 = runDirectory(deps.runsDir, runId).log;
75740
76388
  while (!signal.aborted) {
75741
76389
  const appended = deps.appends.nextAppend(runId, signal);
75742
- if ((0, import_node_fs24.existsSync)(path4) || !await deps.isHeld(runId, signal)) return openReader(res, path4);
76390
+ if ((0, import_node_fs25.existsSync)(path4) || !await deps.isHeld(runId, signal)) return openReader(res, path4);
75743
76391
  await appended;
75744
76392
  }
75745
76393
  return null;
@@ -76512,11 +77160,11 @@ var SEPARATOR = String.fromCharCode(30);
76512
77160
  var encodePayload = (packets, callback) => {
76513
77161
  const length = packets.length;
76514
77162
  const encodedPackets = new Array(length);
76515
- let count = 0;
77163
+ let count2 = 0;
76516
77164
  packets.forEach((packet, i) => {
76517
77165
  encodePacket(packet, false, (encodedPacket) => {
76518
77166
  encodedPackets[i] = encodedPacket;
76519
- if (++count === length) {
77167
+ if (++count2 === length) {
76520
77168
  callback(encodedPackets.join(SEPARATOR));
76521
77169
  }
76522
77170
  });
@@ -80646,6 +81294,9 @@ init_zod();
80646
81294
  var RETRY_DELAYS_MS = [250, 500, 1e3, 2e3, 5e3, 1e4, 3e4];
80647
81295
  var PARK_MS = 5 * 6e4;
80648
81296
  var UNAUTHORIZED = 401;
81297
+ var CREDENTIAL_PARK_MS = 5 * 6e4;
81298
+ var CREDENTIAL_PARK_MAX_MS = 60 * 6e4;
81299
+ var UPLOAD_COALESCE_MS = 500;
80649
81300
  var RETRY_JITTER = 0.2;
80650
81301
  var uploadProgressSchema = external_exports.object({
80651
81302
  admittedOffset: external_exports.number().int().nonnegative(),
@@ -80666,43 +81317,78 @@ function startUploader({
80666
81317
  log,
80667
81318
  archive,
80668
81319
  random = Math.random,
80669
- onUnauthorized
81320
+ onUnauthorized,
81321
+ accessToken = () => ""
80670
81322
  }) {
80671
81323
  const controller = new AbortController();
80672
81324
  const active = /* @__PURE__ */ new Map();
80673
81325
  const again = /* @__PURE__ */ new Set();
81326
+ const againNow = /* @__PURE__ */ new Set();
81327
+ const lastSentAt = /* @__PURE__ */ new Map();
81328
+ const coalescing = /* @__PURE__ */ new Map();
80674
81329
  const sealed = /* @__PURE__ */ new Set();
80675
81330
  const receiptBackoff = /* @__PURE__ */ new Map();
80676
81331
  let pendingRuns = /* @__PURE__ */ new Map();
80677
81332
  const retrying = /* @__PURE__ */ new Set();
80678
81333
  let renewing = null;
80679
- const retryDelay = (failures) => {
80680
- const base = RETRY_DELAYS_MS[Math.min(failures, RETRY_DELAYS_MS.length - 1)] ?? 3e4;
80681
- return Math.round(base * (1 - RETRY_JITTER + 2 * RETRY_JITTER * random()));
80682
- };
81334
+ let credentialPark = null;
81335
+ let revoked = false;
81336
+ const jitter = (ms) => Math.round(ms * (1 - RETRY_JITTER + 2 * RETRY_JITTER * random()));
81337
+ const retryDelay = (failures) => jitter(RETRY_DELAYS_MS[Math.min(failures, RETRY_DELAYS_MS.length - 1)] ?? 3e4);
80683
81338
  const renewCredential = () => {
80684
- if (onUnauthorized === void 0) return Promise.resolve();
80685
- renewing ??= onUnauthorized().catch((error62) => log.warn("upload.renew_failed", { error: error62 })).finally(() => {
81339
+ if (onUnauthorized === void 0) return Promise.resolve("unchanged");
81340
+ renewing ??= onUnauthorized().catch((error62) => {
81341
+ log.warn("upload.renew_failed", { error: error62 });
81342
+ return "unchanged";
81343
+ }).finally(() => {
80686
81344
  renewing = null;
80687
81345
  });
80688
81346
  return renewing;
80689
81347
  };
81348
+ const credentialParked = () => {
81349
+ if (credentialPark === null) return false;
81350
+ if (accessToken() !== credentialPark.token) {
81351
+ credentialPark = null;
81352
+ return false;
81353
+ }
81354
+ return credentialPark.until > clock.now();
81355
+ };
81356
+ const parkForCredential = (token) => {
81357
+ if (credentialParked()) return;
81358
+ const failures = (credentialPark?.failures ?? 0) + 1;
81359
+ const delay4 = Math.min(CREDENTIAL_PARK_MS * 2 ** (failures - 1), CREDENTIAL_PARK_MAX_MS);
81360
+ credentialPark = { failures, until: clock.now() + jitter(delay4), token };
81361
+ log.warn("upload.credential_parked", { failures, parkedUntil: credentialPark.until });
81362
+ };
81363
+ const unauthorized = async (runId, tokenAtStart) => {
81364
+ const renewal = await renewCredential();
81365
+ if (renewal === "revoked") {
81366
+ revoked = true;
81367
+ log.error("upload.credential_revoked", { runId });
81368
+ return;
81369
+ }
81370
+ if (renewal === "renewed" || accessToken() !== tokenAtStart) {
81371
+ credentialPark = null;
81372
+ deferReceipt(runId);
81373
+ return;
81374
+ }
81375
+ parkForCredential(tokenAtStart);
81376
+ };
80690
81377
  const deferReceipt = (runId) => {
80691
81378
  const failures = (receiptBackoff.get(runId)?.failures ?? 0) + 1;
80692
81379
  receiptBackoff.set(runId, { failures, notBefore: clock.now() + retryDelay(failures) });
80693
81380
  };
80694
- const reject = async (runId, progressPath, progress, rejection2) => {
81381
+ const reject = async (runId, progressPath, progress, rejection2, tokenAtStart) => {
80695
81382
  log.error("upload.rejected", { runId, status: rejection2.status, message: rejection2.message });
80696
81383
  if (rejection2.status === UNAUTHORIZED) {
80697
- await renewCredential();
80698
- deferReceipt(runId);
81384
+ await unauthorized(runId, tokenAtStart);
80699
81385
  return;
80700
81386
  }
80701
81387
  const parkedUntil = clock.now() + PARK_MS;
80702
81388
  await writeJsonFileAtomic(progressPath, { ...progress, parkedUntil });
80703
81389
  log.warn("upload.parked", { runId, parkedUntil });
80704
81390
  };
80705
- const progressOf = async (runId, target, path4) => {
81391
+ const progressOf = async (runId, target, path4, tokenAtStart) => {
80706
81392
  const stored = await readJsonFile(path4, uploadProgressSchema);
80707
81393
  if (stored.kind === "ok") return stored.value;
80708
81394
  const listed = pendingRuns.get(runId);
@@ -80715,6 +81401,7 @@ function startUploader({
80715
81401
  switch (receipt.kind) {
80716
81402
  case "read": {
80717
81403
  receiptBackoff.delete(runId);
81404
+ credentialPark = null;
80718
81405
  log.debug("upload.resumed", {
80719
81406
  runId,
80720
81407
  admittedOffset: receipt.receipt?.admittedOffset ?? 0
@@ -80724,7 +81411,7 @@ function startUploader({
80724
81411
  return progress;
80725
81412
  }
80726
81413
  case "rejected":
80727
- await reject(runId, path4, progressFromReceipt(null), receipt);
81414
+ await reject(runId, path4, progressFromReceipt(null), receipt, tokenAtStart);
80728
81415
  return null;
80729
81416
  case "retry": {
80730
81417
  deferReceipt(runId);
@@ -80736,6 +81423,7 @@ function startUploader({
80736
81423
  };
80737
81424
  const sendNext = async (upload2, progress) => {
80738
81425
  const ended = (await readLastRecord(upload2.logPath))?.update.sessionUpdate === "_alan/run.ended";
81426
+ const size = await upload2.reader.size();
80739
81427
  const chunk = await upload2.reader.readFrom(
80740
81428
  toByteOffset(progress.admittedOffset),
80741
81429
  MAX_RUN_LOG_CHUNK_BYTES
@@ -80750,14 +81438,14 @@ function startUploader({
80750
81438
  sealed: atEnd || outcome2.receipt.finalOffset !== null
80751
81439
  };
80752
81440
  await writeJsonFileAtomic(upload2.progressPath, next);
80753
- return { kind: "advanced", progress: next };
81441
+ return { kind: "advanced", progress: next, more: ended || chunk.to < size };
80754
81442
  }
80755
81443
  case "offset_conflict": {
80756
81444
  const receipt = await api.readReceipt(upload2.target, controller.signal);
80757
81445
  if (receipt.kind === "read") {
80758
81446
  const next = progressFromReceipt(receipt.receipt);
80759
81447
  await writeJsonFileAtomic(upload2.progressPath, next);
80760
- return { kind: "advanced", progress: next };
81448
+ return { kind: "advanced", progress: next, more: true };
80761
81449
  }
80762
81450
  return receipt.kind === "retry" ? receipt : { kind: "rejected", rejection: receipt };
80763
81451
  }
@@ -80774,7 +81462,18 @@ function startUploader({
80774
81462
  log.warn("upload.retrying", { runId, status, delayMs: delay4 });
80775
81463
  await clock.sleep(delay4, controller.signal);
80776
81464
  };
80777
- const drain = async (runUpload, initial) => {
81465
+ const recordAccepted = (runId, progress) => {
81466
+ receiptBackoff.delete(runId);
81467
+ credentialPark = null;
81468
+ if (!progress.sealed) {
81469
+ lastSentAt.set(runId, clock.monotonic());
81470
+ return;
81471
+ }
81472
+ sealed.add(runId);
81473
+ lastSentAt.delete(runId);
81474
+ log.info("upload.sealed", { runId, bytes: progress.admittedOffset });
81475
+ };
81476
+ const drain = async (runUpload, initial, tokenAtStart) => {
80778
81477
  const { runId } = runUpload.target;
80779
81478
  let progress = initial;
80780
81479
  let failures = 0;
@@ -80782,7 +81481,7 @@ function startUploader({
80782
81481
  const step = await sendNext(runUpload, progress);
80783
81482
  if (step.kind === "caught_up") return "settled";
80784
81483
  if (step.kind === "rejected") {
80785
- await reject(runId, runUpload.progressPath, progress, step.rejection);
81484
+ await reject(runId, runUpload.progressPath, progress, step.rejection, tokenAtStart);
80786
81485
  return "retry_later";
80787
81486
  }
80788
81487
  if (step.kind === "retry") {
@@ -80791,13 +81490,9 @@ function startUploader({
80791
81490
  continue;
80792
81491
  }
80793
81492
  failures = 0;
80794
- receiptBackoff.delete(runId);
80795
81493
  progress = step.progress;
80796
- if (progress.sealed) {
80797
- sealed.add(runId);
80798
- log.info("upload.sealed", { runId, bytes: progress.admittedOffset });
80799
- return "settled";
80800
- }
81494
+ recordAccepted(runId, progress);
81495
+ if (progress.sealed || !step.more) return "settled";
80801
81496
  }
80802
81497
  return "settled";
80803
81498
  };
@@ -80808,9 +81503,11 @@ function startUploader({
80808
81503
  const meta3 = await readRunMeta(dir.meta);
80809
81504
  if (meta3 === null) return "settled";
80810
81505
  const target = { conversationId: meta3.conversationId, runId };
81506
+ if (credentialParked()) return "retry_later";
80811
81507
  const backoff = receiptBackoff.get(runId);
80812
81508
  if (backoff !== void 0 && backoff.notBefore > clock.now()) return "retry_later";
80813
- const progress = await progressOf(runId, target, dir.upload);
81509
+ const tokenAtStart = accessToken();
81510
+ const progress = await progressOf(runId, target, dir.upload, tokenAtStart);
80814
81511
  if (progress === null) return "retry_later";
80815
81512
  if (progress.sealed) {
80816
81513
  sealed.add(runId);
@@ -80820,11 +81517,12 @@ function startUploader({
80820
81517
  return "retry_later";
80821
81518
  }
80822
81519
  const reader = __using(_stack, await openRunLogReader(dir.log), true);
80823
- const attempt2 = await drain(
81520
+ const attempt3 = await drain(
80824
81521
  { target, reader, logPath: dir.log, progressPath: dir.upload },
80825
- progress
81522
+ progress,
81523
+ tokenAtStart
80826
81524
  );
80827
- return attempt2;
81525
+ return attempt3;
80828
81526
  } catch (_) {
80829
81527
  var _error = _, _hasError = true;
80830
81528
  } finally {
@@ -80832,20 +81530,48 @@ function startUploader({
80832
81530
  _promise2 && await _promise2;
80833
81531
  }
80834
81532
  };
80835
- const run2 = (runId) => {
81533
+ const coalesce = async (runId) => {
81534
+ const delay4 = (lastSentAt.get(runId) ?? Number.NEGATIVE_INFINITY) + UPLOAD_COALESCE_MS;
81535
+ const remaining = delay4 - clock.monotonic();
81536
+ if (remaining <= 0) return;
81537
+ const wake = new AbortController();
81538
+ coalescing.set(runId, wake);
81539
+ try {
81540
+ await clock.sleep(remaining, AbortSignal.any([wake.signal, controller.signal]));
81541
+ } catch {
81542
+ } finally {
81543
+ coalescing.delete(runId);
81544
+ }
81545
+ };
81546
+ const attempt2 = async (runId, timing) => {
81547
+ if (timing === "coalesced") await coalesce(runId);
81548
+ again.delete(runId);
81549
+ againNow.delete(runId);
81550
+ if (controller.signal.aborted) return "settled";
81551
+ return upload(runId);
81552
+ };
81553
+ const run2 = (runId, timing = "immediate") => {
81554
+ if (revoked) return;
80836
81555
  if (active.has(runId)) {
80837
81556
  again.add(runId);
81557
+ if (timing === "immediate") {
81558
+ againNow.add(runId);
81559
+ coalescing.get(runId)?.abort();
81560
+ }
80838
81561
  return;
80839
81562
  }
80840
- const task = upload(runId).then((attempt2) => {
80841
- if (attempt2 === "settled") retrying.delete(runId);
81563
+ const task = attempt2(runId, timing).then((attempt3) => {
81564
+ if (attempt3 === "settled") retrying.delete(runId);
80842
81565
  else retrying.add(runId);
80843
81566
  }).catch((error62) => {
80844
81567
  retrying.add(runId);
80845
81568
  if (!controller.signal.aborted) log.warn("upload.failed", { runId, error: error62 });
80846
81569
  }).finally(() => {
80847
81570
  active.delete(runId);
80848
- if (again.delete(runId) && !controller.signal.aborted) run2(runId);
81571
+ const now = againNow.delete(runId);
81572
+ if (again.delete(runId) && !controller.signal.aborted) {
81573
+ run2(runId, now ? "immediate" : "coalesced");
81574
+ }
80849
81575
  });
80850
81576
  active.set(runId, task);
80851
81577
  };
@@ -80892,7 +81618,8 @@ function startUploader({
80892
81618
  return found;
80893
81619
  };
80894
81620
  return {
80895
- notify: run2,
81621
+ notify: (runId) => run2(runId, "coalesced"),
81622
+ uploadNow: (runId) => run2(runId, "immediate"),
80896
81623
  sweep: sweep2,
80897
81624
  pending: (uploads) => {
80898
81625
  pendingRuns = new Map(
@@ -81300,6 +82027,7 @@ async function startMachinePlane(deps) {
81300
82027
  () => identity.renewAfterRejection(stopped.signal)
81301
82028
  );
81302
82029
  if (renewal.kind === "revoked") deps.onRevoked();
82030
+ return renewal;
81303
82031
  };
81304
82032
  const sessionsOpened = Promise.withResolvers();
81305
82033
  const planeOpened = Promise.withResolvers();
@@ -81342,7 +82070,9 @@ async function startMachinePlane(deps) {
81342
82070
  refreshDesired();
81343
82071
  },
81344
82072
  onConnectRefused: (error62) => updates.connectRefused(error62),
81345
- refreshCredential: renewAfterRejection,
82073
+ refreshCredential: async () => {
82074
+ await renewAfterRejection();
82075
+ },
81346
82076
  onStateChange: deps.onStatusChange,
81347
82077
  answerWorkspaceQuery: (request2) => workspaces.answer(request2),
81348
82078
  respond: (request2) => sessions.respond(request2),
@@ -81404,7 +82134,11 @@ async function startMachinePlane(deps) {
81404
82134
  clock,
81405
82135
  log,
81406
82136
  archive,
81407
- onUnauthorized: renewAfterRejection
82137
+ onUnauthorized: async () => {
82138
+ const renewal = await renewAfterRejection();
82139
+ return renewal.kind === "renewed" || renewal.kind === "revoked" ? renewal.kind : "unchanged";
82140
+ },
82141
+ accessToken: identity.accessToken
81408
82142
  })
81409
82143
  );
81410
82144
  const nativeIngest = stack.use(
@@ -81468,7 +82202,7 @@ async function startMachinePlane(deps) {
81468
82202
  onTurnEnded: (runId) => {
81469
82203
  runsShownRunning.delete(runId);
81470
82204
  deps.onStatusChange();
81471
- uploader.notify(runId);
82205
+ uploader.uploadNow(runId);
81472
82206
  appends.notify(runId);
81473
82207
  nativeIngest.runEnded(runId);
81474
82208
  followActiveRuns().catch((error62) => log.warn("power.follow_failed", { error: error62 }));
@@ -82001,7 +82735,7 @@ function lockWaitMs(argv) {
82001
82735
  async function openManagedProviders(config2, paths) {
82002
82736
  const providerEnv = readCliEnvironment();
82003
82737
  const bundledNpm = (0, import_node_path82.join)((0, import_node_path82.dirname)(process.execPath), "npm", "bin", "npm-cli.js");
82004
- const providerToolchain = config2.providerToolchain ?? (process.platform === "win32" && (0, import_node_fs25.existsSync)(bundledNpm) ? { node: process.execPath, npmCli: bundledNpm } : null);
82738
+ const providerToolchain = config2.providerToolchain ?? (process.platform === "win32" && (0, import_node_fs26.existsSync)(bundledNpm) ? { node: process.execPath, npmCli: bundledNpm } : null);
82005
82739
  const npmPath = providerToolchain?.node ?? await resolveCommandOnPath("npm", providerEnv, process.platform);
82006
82740
  const npmOptions = npmPath === null || process.platform === "win32" && providerToolchain === null ? null : {
82007
82741
  command: npmPath,