@alan-ai-hq/agent-manager-linux-x64 0.1.160 → 0.1.162

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 +788 -285
  2. package/alan-holder.cjs +670 -196
  3. package/package.json +1 -1
package/alan-holder.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) {
@@ -25309,7 +25309,7 @@ var init_acp = __esm({
25309
25309
  }
25310
25310
  });
25311
25311
 
25312
- // ../agent-core/dist/chunk-OUEMTEUX.js
25312
+ // ../agent-core/dist/chunk-RBQC7XZH.js
25313
25313
  function textBlock(text2) {
25314
25314
  return { type: "text", text: text2 };
25315
25315
  }
@@ -25444,8 +25444,8 @@ function readPatchHunks(value) {
25444
25444
  return hunk ? [hunk] : [];
25445
25445
  });
25446
25446
  }
25447
- function hunkRange(start, count) {
25448
- return count === 1 ? String(start) : `${start},${count}`;
25447
+ function hunkRange(start, count2) {
25448
+ return count2 === 1 ? String(start) : `${start},${count2}`;
25449
25449
  }
25450
25450
  function hunkHeader(hunk) {
25451
25451
  return `@@ -${hunkRange(hunk.oldStart, hunk.oldLines)} +${hunkRange(hunk.newStart, hunk.newLines)} @@`;
@@ -25456,14 +25456,14 @@ function patchPath(path) {
25456
25456
  function wholeFileHunk(content, deleted) {
25457
25457
  const lines = content === "" ? [] : content.split("\n");
25458
25458
  if (lines.at(-1) === "") lines.pop();
25459
- const count = lines.length;
25459
+ const count2 = lines.length;
25460
25460
  const marked = lines.map((line) => `${deleted ? "-" : "+"}${line}`);
25461
25461
  if (content && !content.endsWith("\n")) marked.push("\");
25462
25462
  return {
25463
- oldStart: deleted && count ? 1 : 0,
25464
- oldLines: deleted ? count : 0,
25465
- newStart: !deleted && count ? 1 : 0,
25466
- newLines: deleted ? 0 : count,
25463
+ oldStart: deleted && count2 ? 1 : 0,
25464
+ oldLines: deleted ? count2 : 0,
25465
+ newStart: !deleted && count2 ? 1 : 0,
25466
+ newLines: deleted ? 0 : count2,
25467
25467
  lines: marked
25468
25468
  };
25469
25469
  }
@@ -25558,8 +25558,8 @@ function planEntries(todos) {
25558
25558
  });
25559
25559
  }
25560
25560
  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_META, 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;
25561
- var init_chunk_OUEMTEUX = __esm({
25562
- "../agent-core/dist/chunk-OUEMTEUX.js"() {
25561
+ var init_chunk_RBQC7XZH = __esm({
25562
+ "../agent-core/dist/chunk-RBQC7XZH.js"() {
25563
25563
  "use strict";
25564
25564
  init_chunk_YXWJW7I5();
25565
25565
  init_constants();
@@ -25615,17 +25615,17 @@ var init_chunk_OUEMTEUX = __esm({
25615
25615
  var init_acp2 = __esm({
25616
25616
  "../agent-core/dist/acp.js"() {
25617
25617
  "use strict";
25618
- init_chunk_OUEMTEUX();
25618
+ init_chunk_RBQC7XZH();
25619
25619
  init_chunk_YXWJW7I5();
25620
25620
  }
25621
25621
  });
25622
25622
 
25623
- // ../agent-core/dist/chunk-D4TIXPWZ.js
25623
+ // ../agent-core/dist/chunk-TFIO37PI.js
25624
25624
  var import_fs4, NEWLINE2, TranscriptCursor, TranscriptLineLookup;
25625
- var init_chunk_D4TIXPWZ = __esm({
25626
- "../agent-core/dist/chunk-D4TIXPWZ.js"() {
25625
+ var init_chunk_TFIO37PI = __esm({
25626
+ "../agent-core/dist/chunk-TFIO37PI.js"() {
25627
25627
  "use strict";
25628
- init_chunk_OUEMTEUX();
25628
+ init_chunk_RBQC7XZH();
25629
25629
  init_chunk_YXWJW7I5();
25630
25630
  import_fs4 = require("fs");
25631
25631
  NEWLINE2 = 10;
@@ -26173,7 +26173,7 @@ var init_chunk_ZCTKXKYY = __esm({
26173
26173
  }
26174
26174
  });
26175
26175
 
26176
- // ../agent-core/dist/chunk-WD7O4DYQ.js
26176
+ // ../agent-core/dist/chunk-N2M5D7RS.js
26177
26177
  function detectImageMimeType(buffer) {
26178
26178
  if (buffer.length >= 8 && buffer.subarray(0, 8).equals(PNG_SIGNATURE)) return "image/png";
26179
26179
  if (buffer.length >= 3 && buffer[0] === 255 && buffer[1] === 216 && buffer[2] === 255) {
@@ -26614,10 +26614,10 @@ function silentStartError(name, timeoutMs) {
26614
26614
  };
26615
26615
  }
26616
26616
  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;
26617
- var init_chunk_WD7O4DYQ = __esm({
26618
- "../agent-core/dist/chunk-WD7O4DYQ.js"() {
26617
+ var init_chunk_N2M5D7RS = __esm({
26618
+ "../agent-core/dist/chunk-N2M5D7RS.js"() {
26619
26619
  "use strict";
26620
- init_chunk_OUEMTEUX();
26620
+ init_chunk_RBQC7XZH();
26621
26621
  init_chunk_ZCTKXKYY();
26622
26622
  init_chunk_6VWVDJ2A();
26623
26623
  init_chunk_YXWJW7I5();
@@ -28720,9 +28720,29 @@ function backgroundTaskProgress(event, tasks) {
28720
28720
  }
28721
28721
  ];
28722
28722
  }
28723
+ function claudeMessageContextTokens(message) {
28724
+ if (asString(message?.model) === "<synthetic>") return void 0;
28725
+ const usage = asRecord(message?.usage);
28726
+ if (!usage) return void 0;
28727
+ 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);
28728
+ return tokens2 > 0 ? tokens2 : void 0;
28729
+ }
28730
+ function resultContextWindow(event, model) {
28731
+ const byModel = asRecord(event.modelUsage);
28732
+ if (!byModel) return void 0;
28733
+ const own2 = asFiniteNumber(asRecord(byModel[model])?.contextWindow);
28734
+ if (own2 !== void 0) return own2;
28735
+ let largest;
28736
+ for (const entry of Object.values(byModel)) {
28737
+ const size = asFiniteNumber(asRecord(entry)?.contextWindow);
28738
+ if (size !== void 0 && size > (largest ?? 0)) largest = size;
28739
+ }
28740
+ return largest;
28741
+ }
28723
28742
  function resultUsage(event, context) {
28724
28743
  const usage = asRecord(event.usage);
28725
28744
  const model = asString(event.model).trim() || context.activeModel?.trim() || context.selectedModel?.trim() || "claude";
28745
+ const contextSize = resultContextWindow(event, model);
28726
28746
  return usageUpdate({
28727
28747
  model,
28728
28748
  numTurns: asFiniteNumber(event.num_turns) ?? Math.max(context.iterations, 1),
@@ -28731,7 +28751,9 @@ function resultUsage(event, context) {
28731
28751
  outputTokens: asFiniteNumber(usage?.output_tokens) ?? 0,
28732
28752
  cacheReadTokens: asFiniteNumber(usage?.cache_read_input_tokens) ?? 0,
28733
28753
  cacheCreationTokens: asFiniteNumber(usage?.cache_creation_input_tokens) ?? 0,
28734
- costUsd: asFiniteNumber(event.total_cost_usd) ?? 0
28754
+ costUsd: asFiniteNumber(event.total_cost_usd) ?? 0,
28755
+ ...contextSize === void 0 ? {} : { contextSize },
28756
+ ...context.contextTokens === void 0 ? {} : { contextTokens: context.contextTokens }
28735
28757
  });
28736
28758
  }
28737
28759
  function resultErrorText(event, subtype) {
@@ -28995,9 +29017,9 @@ var import_crypto7, import_fs6, import_path6, import_crypto8, import_promises15,
28995
29017
  var init_claude = __esm({
28996
29018
  "../agent-core/dist/providers/claude.js"() {
28997
29019
  "use strict";
28998
- init_chunk_D4TIXPWZ();
28999
- init_chunk_WD7O4DYQ();
29000
- init_chunk_OUEMTEUX();
29020
+ init_chunk_TFIO37PI();
29021
+ init_chunk_N2M5D7RS();
29022
+ init_chunk_RBQC7XZH();
29001
29023
  init_chunk_ZCTKXKYY();
29002
29024
  init_chunk_6VWVDJ2A();
29003
29025
  init_chunk_DLVRNIY5();
@@ -29295,6 +29317,7 @@ var init_claude = __esm({
29295
29317
  #announced = /* @__PURE__ */ new Set();
29296
29318
  #awaitingAskDenialFallback = false;
29297
29319
  #iterations = 0;
29320
+ #contextTokens;
29298
29321
  #providerErrorCode;
29299
29322
  #deferredOnAnswer = false;
29300
29323
  #deferredOnBackground = false;
@@ -29434,6 +29457,7 @@ var init_claude = __esm({
29434
29457
  #handleSystem(event) {
29435
29458
  const subtype = asString(event.subtype);
29436
29459
  if (subtype === "api_retry") this.#noteRetry(event);
29460
+ if (subtype === "compact_boundary") this.#noteCompaction(event);
29437
29461
  if (subtype === "task_started") {
29438
29462
  this.tasks.registerRecord(event, parentToolUseId(event));
29439
29463
  this.taskRecords.track(event, this.tasks.resolveToolUseId(event));
@@ -29518,13 +29542,25 @@ var init_claude = __esm({
29518
29542
  status
29519
29543
  });
29520
29544
  }
29545
+ /** The window was just rewritten; the pre-compaction figure would overstate it until the next call. */
29546
+ #noteCompaction(event) {
29547
+ if (parentToolUseId(event)) return;
29548
+ const after = asFiniteNumber(asRecord(event.compact_metadata)?.post_tokens);
29549
+ this.#contextTokens = after !== void 0 && after > 0 ? after : void 0;
29550
+ }
29551
+ #noteContext(event, message) {
29552
+ if (parentToolUseId(event)) return;
29553
+ this.#contextTokens = claudeMessageContextTokens(message) ?? this.#contextTokens;
29554
+ }
29521
29555
  #handleAssistant(event) {
29522
29556
  if (this.#awaitingAskDenialFallback) {
29523
29557
  this.#awaitingAskDenialFallback = false;
29524
29558
  return;
29525
29559
  }
29526
29560
  this.#iterations += 1;
29527
- for (const raw of asArray(asRecord(event.message)?.content)) {
29561
+ const message = asRecord(event.message);
29562
+ this.#noteContext(event, message);
29563
+ for (const raw of asArray(message?.content)) {
29528
29564
  const block2 = asRecord(raw);
29529
29565
  if (!block2 || asString(block2.type) !== "tool_use") continue;
29530
29566
  const id = asString(block2.id);
@@ -29544,7 +29580,8 @@ var init_claude = __esm({
29544
29580
  resultUsage(event, {
29545
29581
  activeModel: this.grammar.model,
29546
29582
  selectedModel: this.#options.selectedModel,
29547
- iterations: this.#iterations
29583
+ iterations: this.#iterations,
29584
+ ...this.#contextTokens === void 0 ? {} : { contextTokens: this.#contextTokens }
29548
29585
  })
29549
29586
  ];
29550
29587
  if (typeof event.num_turns === "number") this.#iterations = event.num_turns;
@@ -30759,6 +30796,59 @@ function planEntries2(plan2) {
30759
30796
  ];
30760
30797
  });
30761
30798
  }
30799
+ function count(value) {
30800
+ return asFiniteNumber(value) ?? 0;
30801
+ }
30802
+ function withTotal(tokens2, reported) {
30803
+ return { ...tokens2, total: reported || tokens2.input + tokens2.output };
30804
+ }
30805
+ function appServerTokens(record2) {
30806
+ return withTotal(
30807
+ {
30808
+ input: count(record2.inputTokens),
30809
+ cachedInput: count(record2.cachedInputTokens),
30810
+ cacheWrite: count(record2.cacheWriteInputTokens),
30811
+ output: count(record2.outputTokens)
30812
+ },
30813
+ count(record2.totalTokens)
30814
+ );
30815
+ }
30816
+ function rolloutTokens(record2) {
30817
+ return withTotal(
30818
+ {
30819
+ input: count(record2.input_tokens),
30820
+ cachedInput: count(record2.cached_input_tokens),
30821
+ cacheWrite: count(record2.cache_write_input_tokens),
30822
+ output: count(record2.output_tokens)
30823
+ },
30824
+ count(record2.total_tokens)
30825
+ );
30826
+ }
30827
+ function subtractTokens(from, amount2) {
30828
+ const minus = (a, b) => Math.max(a - b, 0);
30829
+ return {
30830
+ input: minus(from.input, amount2.input),
30831
+ cachedInput: minus(from.cachedInput, amount2.cachedInput),
30832
+ cacheWrite: minus(from.cacheWrite, amount2.cacheWrite),
30833
+ output: minus(from.output, amount2.output),
30834
+ total: minus(from.total, amount2.total)
30835
+ };
30836
+ }
30837
+ function codexBreakdown(tokens2) {
30838
+ return {
30839
+ inputTokens: Math.max(tokens2.input - tokens2.cachedInput - tokens2.cacheWrite, 0),
30840
+ outputTokens: tokens2.output,
30841
+ cacheReadTokens: tokens2.cachedInput,
30842
+ cacheCreationTokens: tokens2.cacheWrite
30843
+ };
30844
+ }
30845
+ function codexUsageUpdate(spend, extra, fallbackModel) {
30846
+ const update = usageUpdate({ ...codexBreakdown(spend), ...extra }, fallbackModel);
30847
+ return spend.total > 0 && isUpdate(update, "usage_update") ? { ...update, used: spend.total } : update;
30848
+ }
30849
+ function codexContextTokens(last) {
30850
+ return last.total > 0 ? last.total : void 0;
30851
+ }
30762
30852
  function createCodexSessionMemory() {
30763
30853
  return { shownWarnings: /* @__PURE__ */ new Set(), workers: /* @__PURE__ */ new Map() };
30764
30854
  }
@@ -31210,13 +31300,13 @@ function codexTurnInput(run, context) {
31210
31300
  ...images.length ? { imagePaths: images.map((image) => image.path) } : {}
31211
31301
  };
31212
31302
  }
31213
- 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;
31303
+ 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;
31214
31304
  var init_codex = __esm({
31215
31305
  "../agent-core/dist/providers/codex.js"() {
31216
31306
  "use strict";
31217
- init_chunk_D4TIXPWZ();
31218
- init_chunk_WD7O4DYQ();
31219
- init_chunk_OUEMTEUX();
31307
+ init_chunk_TFIO37PI();
31308
+ init_chunk_N2M5D7RS();
31309
+ init_chunk_RBQC7XZH();
31220
31310
  init_chunk_ZCTKXKYY();
31221
31311
  init_chunk_6VWVDJ2A();
31222
31312
  init_chunk_DLVRNIY5();
@@ -31228,6 +31318,7 @@ var init_codex = __esm({
31228
31318
  import_crypto9 = require("crypto");
31229
31319
  import_crypto10 = require("crypto");
31230
31320
  init_runtime_v2();
31321
+ init_acp();
31231
31322
  init_agent2();
31232
31323
  import_crypto11 = require("crypto");
31233
31324
  init_agent2();
@@ -31361,10 +31452,13 @@ var init_codex = __esm({
31361
31452
  #reported = /* @__PURE__ */ new Set();
31362
31453
  #cursor;
31363
31454
  #lastMiss;
31364
- constructor(locate, clock) {
31455
+ #onTokenCount;
31456
+ /** `onTokenCount` also hears each `token_count` the rollout gains, for the turn's usage. */
31457
+ constructor(locate, clock, onTokenCount) {
31365
31458
  this.#locate = locate;
31366
31459
  this.#clock = clock;
31367
31460
  this.#fold = new CodexImageGenerationFold(clock);
31461
+ this.#onTokenCount = onTokenCount;
31368
31462
  }
31369
31463
  get waiting() {
31370
31464
  return this.#fold.waiting;
@@ -31385,7 +31479,10 @@ var init_codex = __esm({
31385
31479
  }
31386
31480
  /** What the rollout gained since the last drain. */
31387
31481
  drain() {
31388
- for (const line of this.#open()?.read() ?? []) this.#fold.foldLine(line.text);
31482
+ for (const line of this.#open()?.read() ?? []) {
31483
+ this.#fold.foldLine(line.text);
31484
+ if (this.#onTokenCount) this.#readTokenCount(line.text, this.#onTokenCount);
31485
+ }
31389
31486
  return this.admit(this.#fold.take());
31390
31487
  }
31391
31488
  /** The turn is over: what is left, then every call still pending as failed. */
@@ -31402,6 +31499,16 @@ var init_codex = __esm({
31402
31499
  }
31403
31500
  return updates;
31404
31501
  }
31502
+ #readTokenCount(text2, onTokenCount) {
31503
+ if (!text2.includes('"token_count"')) return;
31504
+ try {
31505
+ const payload = asRecord(asRecord(JSON.parse(text2))?.payload);
31506
+ const info = asRecord(payload?.info);
31507
+ if (asString(payload?.type) === "token_count" && info) onTokenCount(info);
31508
+ } catch {
31509
+ return;
31510
+ }
31511
+ }
31405
31512
  #open() {
31406
31513
  if (this.#cursor) return this.#cursor;
31407
31514
  const now = this.#clock.monotonic();
@@ -31503,6 +31610,31 @@ var init_codex = __esm({
31503
31610
  ["inProgress", "in_progress"],
31504
31611
  ["completed", "completed"]
31505
31612
  ]);
31613
+ CodexTurnTokens = class {
31614
+ #baseline;
31615
+ #last;
31616
+ #window;
31617
+ /** Records one report; `total` absent means `last` is the whole turn so far. */
31618
+ note(last, total, window) {
31619
+ if (total) this.#baseline ??= subtractTokens(total, last);
31620
+ this.#last = last;
31621
+ if (window !== void 0 && window > 0) this.#window = window;
31622
+ }
31623
+ get hasBaseline() {
31624
+ return this.#baseline !== void 0;
31625
+ }
31626
+ spend(total) {
31627
+ return this.#baseline ? subtractTokens(total, this.#baseline) : total;
31628
+ }
31629
+ /** The context the turn's last call left, and the window, as far as they are known. */
31630
+ get context() {
31631
+ const contextTokens = this.#last ? codexContextTokens(this.#last) : void 0;
31632
+ return {
31633
+ ...this.#window === void 0 ? {} : { contextSize: this.#window },
31634
+ ...contextTokens === void 0 ? {} : { contextTokens }
31635
+ };
31636
+ }
31637
+ };
31506
31638
  CODEX_MCP_STATUS = {
31507
31639
  starting: "starting",
31508
31640
  ready: "connected",
@@ -31549,6 +31681,7 @@ var init_codex = __esm({
31549
31681
  #end;
31550
31682
  #failFast;
31551
31683
  #lastError;
31684
+ #tokens = new CodexTurnTokens();
31552
31685
  codexTurnId;
31553
31686
  constructor(memory, clock = systemClock2) {
31554
31687
  this.#memory = memory;
@@ -31643,19 +31776,16 @@ var init_codex = __esm({
31643
31776
  }
31644
31777
  #usage(params) {
31645
31778
  const usage = asRecord(params.tokenUsage);
31646
- const last = asRecord(usage?.last);
31647
- if (!last) return [];
31648
- const number4 = (value) => asFiniteNumber(value) ?? 0;
31779
+ const lastRecord = asRecord(usage?.last);
31780
+ if (!lastRecord) return [];
31781
+ const last = appServerTokens(lastRecord);
31782
+ const totalRecord = asRecord(usage?.total);
31783
+ const total = totalRecord ? appServerTokens(totalRecord) : void 0;
31784
+ this.#tokens.note(last, total, asFiniteNumber(usage?.modelContextWindow));
31649
31785
  return [
31650
- usageUpdate(
31651
- {
31652
- inputTokens: number4(last.inputTokens),
31653
- outputTokens: number4(last.outputTokens) + number4(last.reasoningOutputTokens),
31654
- cacheReadTokens: number4(last.cachedInputTokens),
31655
- cacheCreationTokens: number4(last.cacheWriteInputTokens),
31656
- ...asFiniteNumber(usage?.modelContextWindow) === void 0 ? {} : { contextSize: number4(usage?.modelContextWindow) },
31657
- costUsd: 0
31658
- },
31786
+ codexUsageUpdate(
31787
+ total ? this.#tokens.spend(total) : last,
31788
+ { ...this.#tokens.context, costUsd: 0 },
31659
31789
  this.#memory.model ?? "codex"
31660
31790
  )
31661
31791
  ];
@@ -32196,12 +32326,16 @@ var init_codex = __esm({
32196
32326
  #lastError;
32197
32327
  #answered = false;
32198
32328
  #images;
32329
+ #tokens = new CodexTurnTokens();
32330
+ #resumed;
32199
32331
  constructor(resumeId, rollout) {
32200
32332
  this.#threadId = resumeId;
32333
+ this.#resumed = resumeId !== void 0;
32201
32334
  if (!rollout) return;
32202
32335
  this.#images = new CodexRolloutImages(
32203
32336
  () => this.#threadId ? findCodexRollout(rollout.codexHome, this.#threadId) : void 0,
32204
- rollout.clock
32337
+ rollout.clock,
32338
+ (info) => this.#noteTokenCount(info)
32205
32339
  );
32206
32340
  if (resumeId) this.#images.startAtEnd();
32207
32341
  }
@@ -32263,22 +32397,34 @@ var init_codex = __esm({
32263
32397
  if (mapped) return itemUpdates(mapped, completed);
32264
32398
  return [{ sessionUpdate: "_alan/unhandled", kind: `item/${type || "(untyped)"}` }];
32265
32399
  }
32400
+ /** The rollout's per-call counts: exec's own usage is only the thread's running total. */
32401
+ #noteTokenCount(info) {
32402
+ const last = asRecord(info.last_token_usage);
32403
+ const total = asRecord(info.total_token_usage);
32404
+ if (!last) return;
32405
+ this.#tokens.note(
32406
+ rolloutTokens(last),
32407
+ total ? rolloutTokens(total) : void 0,
32408
+ asFiniteNumber(info.model_context_window)
32409
+ );
32410
+ }
32266
32411
  #completed(usage) {
32267
32412
  this.#end = { status: "completed" };
32268
- const number4 = (value) => asFiniteNumber(value) ?? 0;
32413
+ const rolloutUpdates = this.#images?.drain() ?? [];
32269
32414
  return [
32270
- ...usage ? [
32271
- usageUpdate({
32272
- inputTokens: number4(usage.input_tokens),
32273
- outputTokens: number4(usage.output_tokens) + number4(usage.reasoning_output_tokens),
32274
- cacheReadTokens: number4(usage.cached_input_tokens),
32275
- cacheCreationTokens: number4(usage.cache_write_input_tokens),
32276
- costUsd: 0
32277
- })
32278
- ] : [],
32415
+ ...rolloutUpdates,
32416
+ ...usage ? this.#usage(rolloutTokens(usage)) : [],
32279
32417
  { sessionUpdate: "state_update", state: "idle", stopReason: "end_turn" }
32280
32418
  ];
32281
32419
  }
32420
+ /** A resumed turn with no rollout counts cannot separate its spend from earlier turns'. */
32421
+ #usage(threadTotal) {
32422
+ const context = { ...this.#tokens.context, costUsd: 0 };
32423
+ if (this.#resumed && !this.#tokens.hasBaseline) {
32424
+ return context.contextTokens === void 0 ? [] : [usageUpdate(context)];
32425
+ }
32426
+ return [codexUsageUpdate(this.#tokens.spend(threadTotal), context, "")];
32427
+ }
32282
32428
  #failed(error62, fallback) {
32283
32429
  const message = errorText(error62?.message) || errorText(error62?.detail) || fallback.trim();
32284
32430
  const classified = message ? classifyCliError(normalizeCodexCliErrorMessage(message)) : this.#lastError ?? specForErrorKind("provider_error");
@@ -32348,6 +32494,14 @@ function resolveAlanCodeModelId(selectedModel, models) {
32348
32494
  if (requested && models.some((model) => model.id === requested)) return requested;
32349
32495
  return models.find((model) => model.isDefault)?.id ?? firstModel.id;
32350
32496
  }
32497
+ function disabledInheritedMcp(own2, inherited) {
32498
+ const disabled = {};
32499
+ for (const name of inherited ?? []) {
32500
+ if (name in own2) continue;
32501
+ disabled[name] = { enabled: false };
32502
+ }
32503
+ return disabled;
32504
+ }
32351
32505
  function parseExisting(existing) {
32352
32506
  if (!existing?.trim()) return {};
32353
32507
  try {
@@ -32375,6 +32529,8 @@ function alanCodeConfigContent(existing, input2) {
32375
32529
  const prompt = input2.prompt ?? ALAN_CODE_BASELINE_PROMPT;
32376
32530
  const hiddenSkills = { skill: { "customize-opencode": "deny" } };
32377
32531
  const plugins = Array.isArray(config2.plugin) ? config2.plugin : [];
32532
+ const ownMcp = field(config2, "mcp");
32533
+ const mcp = { ...ownMcp, ...disabledInheritedMcp(ownMcp, input2.inheritedMcpServers) };
32378
32534
  return JSON.stringify({
32379
32535
  $schema: "https://opencode.ai/config.json",
32380
32536
  ...config2,
@@ -32383,6 +32539,7 @@ function alanCodeConfigContent(existing, input2) {
32383
32539
  // 3.4 GB of a dev machine's engine database was these patches, against 82 sessions. Alan
32384
32540
  // does not use the engine's undo/revert, so the tracking stays off.
32385
32541
  snapshot: false,
32542
+ ...Object.keys(mcp).length ? { mcp } : {},
32386
32543
  model: `${ALAN_CODE_ENGINE_PROVIDER_ID}/${input2.modelId}`,
32387
32544
  enabled_providers: [ALAN_CODE_ENGINE_PROVIDER_ID],
32388
32545
  provider: {
@@ -32701,6 +32858,77 @@ function alanCodeEngineEnv(input2) {
32701
32858
  [ALAN_CODE_CONVERSATION_ID_ENV]: input2.conversationId
32702
32859
  };
32703
32860
  }
32861
+ function openCodeGlobalConfigDirectory(env, home) {
32862
+ const configHome = env.XDG_CONFIG_HOME?.trim() || (0, import_path9.join)(home, ".config");
32863
+ return (0, import_path9.join)(configHome, "opencode");
32864
+ }
32865
+ function stripJsonc(text2) {
32866
+ let out = "";
32867
+ let index = 0;
32868
+ while (index < text2.length) {
32869
+ const skipTo = commentEnd(text2, index);
32870
+ if (skipTo !== void 0) {
32871
+ index = skipTo;
32872
+ continue;
32873
+ }
32874
+ const char = text2[index];
32875
+ if (char === "}" || char === "]") out = out.replace(/,\s*$/, "");
32876
+ const end = char === '"' ? stringLiteralEnd(text2, index) : index + 1;
32877
+ out += text2.slice(index, end);
32878
+ index = end;
32879
+ }
32880
+ return out;
32881
+ }
32882
+ function commentEnd(text2, index) {
32883
+ const pair = text2.slice(index, index + 2);
32884
+ if (pair === "//") {
32885
+ const newline = text2.indexOf("\n", index);
32886
+ return newline === -1 ? text2.length : newline;
32887
+ }
32888
+ if (pair === "/*") {
32889
+ const close = text2.indexOf("*/", index + 2);
32890
+ return close === -1 ? text2.length : close + 2;
32891
+ }
32892
+ return void 0;
32893
+ }
32894
+ function stringLiteralEnd(text2, start) {
32895
+ let index = start + 1;
32896
+ while (index < text2.length) {
32897
+ const char = text2[index];
32898
+ if (char === "\\") {
32899
+ index += 2;
32900
+ } else if (char === '"') {
32901
+ return index + 1;
32902
+ } else {
32903
+ index += 1;
32904
+ }
32905
+ }
32906
+ return text2.length;
32907
+ }
32908
+ function parseJsonc(text2) {
32909
+ try {
32910
+ return JSON.parse(text2);
32911
+ } catch {
32912
+ try {
32913
+ return JSON.parse(stripJsonc(text2));
32914
+ } catch {
32915
+ return void 0;
32916
+ }
32917
+ }
32918
+ }
32919
+ async function inheritedMcpServerNames(configDirectory) {
32920
+ const names = /* @__PURE__ */ new Set();
32921
+ for (const file2 of ["config.json", "opencode.json", "opencode.jsonc"]) {
32922
+ const text2 = await (0, import_promises16.readFile)((0, import_path9.join)(configDirectory, file2), "utf8").catch(() => null);
32923
+ if (text2 === null) continue;
32924
+ const parsed = parseJsonc(text2);
32925
+ const mcp = parsed !== null && typeof parsed === "object" ? parsed.mcp : void 0;
32926
+ if (mcp !== null && typeof mcp === "object") {
32927
+ for (const name of Object.keys(mcp)) names.add(name);
32928
+ }
32929
+ }
32930
+ return [...names];
32931
+ }
32704
32932
  async function writePlugin(directory, apiOrigin) {
32705
32933
  const origin = (0, import_crypto13.createHash)("sha256").update(apiOrigin).digest("hex").slice(0, 12);
32706
32934
  const target = (0, import_path9.join)(directory, `engine-plugin-v${ALAN_CODE_ENGINE_PLUGIN_VERSION}-${origin}.mjs`);
@@ -32715,9 +32943,10 @@ async function prepareAlanCodeProfile(input2) {
32715
32943
  await Promise.all(
32716
32944
  directories.map((directory) => (0, import_promises16.mkdir)(directory, { recursive: true, mode: 448 }))
32717
32945
  );
32718
- const [pluginUrl, models] = await Promise.all([
32946
+ const [pluginUrl, models, inheritedMcpServers] = await Promise.all([
32719
32947
  writePlugin((0, import_path9.join)(input2.engineRoot, "plugin"), input2.access.apiOrigin),
32720
- (input2.loadModels ?? fetchAlanCodeModels)(input2.access)
32948
+ (input2.loadModels ?? fetchAlanCodeModels)(input2.access),
32949
+ input2.globalConfigDirectory === void 0 ? Promise.resolve([]) : inheritedMcpServerNames(input2.globalConfigDirectory)
32721
32950
  ]);
32722
32951
  const modelId = resolveAlanCodeModelId(input2.requestedModel, models);
32723
32952
  return {
@@ -32725,7 +32954,8 @@ async function prepareAlanCodeProfile(input2) {
32725
32954
  baseURL: `${input2.access.apiOrigin}${ALAN_CODE_PROXY_PATH}`,
32726
32955
  modelId,
32727
32956
  models,
32728
- pluginUrl
32957
+ pluginUrl,
32958
+ inheritedMcpServers
32729
32959
  }),
32730
32960
  model: { providerID: ALAN_CODE_ENGINE_PROVIDER_ID, modelID: modelId }
32731
32961
  };
@@ -33363,8 +33593,8 @@ var require_Node = __commonJS({
33363
33593
  };
33364
33594
  const res = toJS.toJS(this, "", ctx);
33365
33595
  if (typeof onAnchor === "function")
33366
- for (const { count, res: res2 } of ctx.anchors.values())
33367
- onAnchor(res2, count);
33596
+ for (const { count: count2, res: res2 } of ctx.anchors.values())
33597
+ onAnchor(res2, count2);
33368
33598
  return typeof reviver === "function" ? applyReviver.applyReviver(reviver, { "": res }, "", res) : res;
33369
33599
  }
33370
33600
  };
@@ -33470,13 +33700,13 @@ var require_Alias = __commonJS({
33470
33700
  const anchor2 = anchors2 && source && anchors2.get(source);
33471
33701
  return anchor2 ? anchor2.count * anchor2.aliasCount : 0;
33472
33702
  } else if (identity.isCollection(node2)) {
33473
- let count = 0;
33703
+ let count2 = 0;
33474
33704
  for (const item of node2.items) {
33475
33705
  const c = getAliasCount(doc, item, anchors2);
33476
- if (c > count)
33477
- count = c;
33706
+ if (c > count2)
33707
+ count2 = c;
33478
33708
  }
33479
- return count;
33709
+ return count2;
33480
33710
  } else if (identity.isPair(node2)) {
33481
33711
  const kc = getAliasCount(doc, node2.key, anchors2);
33482
33712
  const vc = getAliasCount(doc, node2.value, anchors2);
@@ -36429,8 +36659,8 @@ var require_Document = __commonJS({
36429
36659
  };
36430
36660
  const res = toJS.toJS(this.contents, jsonArg ?? "", ctx);
36431
36661
  if (typeof onAnchor === "function")
36432
- for (const { count, res: res2 } of ctx.anchors.values())
36433
- onAnchor(res2, count);
36662
+ for (const { count: count2, res: res2 } of ctx.anchors.values())
36663
+ onAnchor(res2, count2);
36434
36664
  return typeof reviver === "function" ? applyReviver.applyReviver(reviver, { "": res }, "", res) : res;
36435
36665
  }
36436
36666
  /**
@@ -36507,12 +36737,12 @@ var require_errors = __commonJS({
36507
36737
  lineStr = prev + lineStr;
36508
36738
  }
36509
36739
  if (/[^ ]/.test(lineStr)) {
36510
- let count = 1;
36740
+ let count2 = 1;
36511
36741
  const end = error62.linePos[1];
36512
36742
  if (end?.line === line && end.col > col) {
36513
- count = Math.max(1, Math.min(end.col - col, 80 - ci));
36743
+ count2 = Math.max(1, Math.min(end.col - col, 80 - ci));
36514
36744
  }
36515
- const pointer = " ".repeat(ci) + "^".repeat(count);
36745
+ const pointer = " ".repeat(ci) + "^".repeat(count2);
36516
36746
  error62.message += `:
36517
36747
 
36518
36748
  ${lineStr}
@@ -36754,7 +36984,7 @@ var require_resolve_block_map = __commonJS({
36754
36984
  if (ctx.atRoot)
36755
36985
  ctx.atRoot = false;
36756
36986
  let offset = bm.offset;
36757
- let commentEnd = null;
36987
+ let commentEnd2 = null;
36758
36988
  for (const collItem of bm.items) {
36759
36989
  const { start, key, sep: sep4, value } = collItem;
36760
36990
  const keyProps = resolveProps.resolveProps(start, {
@@ -36774,7 +37004,7 @@ var require_resolve_block_map = __commonJS({
36774
37004
  onError(offset, "BAD_INDENT", startColMsg);
36775
37005
  }
36776
37006
  if (!keyProps.anchor && !keyProps.tag && !sep4) {
36777
- commentEnd = keyProps.end;
37007
+ commentEnd2 = keyProps.end;
36778
37008
  if (keyProps.comment) {
36779
37009
  if (map2.comment)
36780
37010
  map2.comment += "\n" + keyProps.comment;
@@ -36836,9 +37066,9 @@ var require_resolve_block_map = __commonJS({
36836
37066
  map2.items.push(pair);
36837
37067
  }
36838
37068
  }
36839
- if (commentEnd && commentEnd < offset)
36840
- onError(commentEnd, "IMPOSSIBLE", "Map comment with trailing content");
36841
- map2.range = [bm.offset, offset, commentEnd ?? offset];
37069
+ if (commentEnd2 && commentEnd2 < offset)
37070
+ onError(commentEnd2, "IMPOSSIBLE", "Map comment with trailing content");
37071
+ map2.range = [bm.offset, offset, commentEnd2 ?? offset];
36842
37072
  return map2;
36843
37073
  }
36844
37074
  exports2.resolveBlockMap = resolveBlockMap;
@@ -36860,7 +37090,7 @@ var require_resolve_block_seq = __commonJS({
36860
37090
  if (ctx.atKey)
36861
37091
  ctx.atKey = false;
36862
37092
  let offset = bs.offset;
36863
- let commentEnd = null;
37093
+ let commentEnd2 = null;
36864
37094
  for (const { start, value } of bs.items) {
36865
37095
  const props = resolveProps.resolveProps(start, {
36866
37096
  indicator: "seq-item-ind",
@@ -36877,7 +37107,7 @@ var require_resolve_block_seq = __commonJS({
36877
37107
  else
36878
37108
  onError(offset, "MISSING_CHAR", "Sequence item without - indicator");
36879
37109
  } else {
36880
- commentEnd = props.end;
37110
+ commentEnd2 = props.end;
36881
37111
  if (props.comment)
36882
37112
  seq.comment = props.comment;
36883
37113
  continue;
@@ -36889,7 +37119,7 @@ var require_resolve_block_seq = __commonJS({
36889
37119
  offset = node2.range[2];
36890
37120
  seq.items.push(node2);
36891
37121
  }
36892
- seq.range = [bs.offset, offset, commentEnd ?? offset];
37122
+ seq.range = [bs.offset, offset, commentEnd2 ?? offset];
36893
37123
  return seq;
36894
37124
  }
36895
37125
  exports2.resolveBlockSeq = resolveBlockSeq;
@@ -40126,8 +40356,8 @@ var require_dist = __commonJS({
40126
40356
  var init_dist = __esm({
40127
40357
  "../agent-core/dist/index.js"() {
40128
40358
  "use strict";
40129
- init_chunk_WD7O4DYQ();
40130
- init_chunk_OUEMTEUX();
40359
+ init_chunk_N2M5D7RS();
40360
+ init_chunk_RBQC7XZH();
40131
40361
  init_chunk_ZCTKXKYY();
40132
40362
  init_chunk_6VWVDJ2A();
40133
40363
  init_chunk_YXWJW7I5();
@@ -40486,24 +40716,30 @@ function tokens(record2, ...keys) {
40486
40716
  }
40487
40717
  return void 0;
40488
40718
  }
40489
- function promptUsage(result, fallbackModel) {
40490
- const usage = asRecord(result.usage) ?? asRecord(result._meta);
40719
+ function contextOf(update) {
40720
+ const used = asFiniteNumber(update.used);
40721
+ const size = asFiniteNumber(update.size);
40722
+ if (used === void 0 || used <= 0) return void 0;
40723
+ return { contextTokens: used, ...size !== void 0 && size > 0 ? { contextSize: size } : {} };
40724
+ }
40725
+ function promptSpend(result, profile) {
40726
+ const meta3 = asRecord(result._meta);
40727
+ const usage = asRecord(result.usage) ?? asRecord(meta3?.usage) ?? meta3;
40491
40728
  const input2 = tokens(usage, "inputTokens", "input_tokens");
40492
40729
  const output2 = tokens(usage, "outputTokens", "output_tokens");
40493
40730
  if (input2 === void 0 && output2 === void 0) return void 0;
40494
40731
  const thoughts = tokens(usage, "thoughtTokens", "reasoningTokens") ?? 0;
40495
- const meta3 = asRecord(result._meta);
40496
- return usageUpdate(
40497
- {
40498
- inputTokens: input2 ?? 0,
40499
- outputTokens: (output2 ?? 0) + thoughts,
40500
- cacheReadTokens: tokens(usage, "cachedReadTokens", "cacheReadTokens") ?? 0,
40501
- cacheCreationTokens: tokens(usage, "cachedWriteTokens", "cacheWriteTokens") ?? 0,
40502
- costUsd: 0,
40503
- ...asString(meta3?.modelId) ? { model: asString(meta3?.modelId) } : {}
40504
- },
40505
- fallbackModel
40506
- );
40732
+ const cacheRead = tokens(usage, "cachedReadTokens", "cacheReadTokens") ?? 0;
40733
+ const cacheWrite = tokens(usage, "cachedWriteTokens", "cacheWriteTokens") ?? 0;
40734
+ const uncached = profile.promptInputIncludesCache ? Math.max((input2 ?? 0) - cacheRead - cacheWrite, 0) : input2 ?? 0;
40735
+ return {
40736
+ inputTokens: uncached,
40737
+ outputTokens: (output2 ?? 0) + thoughts,
40738
+ cacheReadTokens: cacheRead,
40739
+ cacheCreationTokens: cacheWrite,
40740
+ costUsd: 0,
40741
+ ...asString(meta3?.modelId) ? { model: asString(meta3?.modelId) } : {}
40742
+ };
40507
40743
  }
40508
40744
  function pendingAnswer2(pending, answer) {
40509
40745
  switch (pending.kind) {
@@ -40873,8 +41109,8 @@ var import_promises24, import_path10, import_crypto14, import_promises25, CURSOR
40873
41109
  var init_acp3 = __esm({
40874
41110
  "../agent-core/dist/providers/acp.js"() {
40875
41111
  "use strict";
40876
- init_chunk_WD7O4DYQ();
40877
- init_chunk_OUEMTEUX();
41112
+ init_chunk_N2M5D7RS();
41113
+ init_chunk_RBQC7XZH();
40878
41114
  init_chunk_ZCTKXKYY();
40879
41115
  init_chunk_6VWVDJ2A();
40880
41116
  init_chunk_DLVRNIY5();
@@ -41104,9 +41340,52 @@ var init_acp3 = __esm({
41104
41340
  #bursts = /* @__PURE__ */ new Map();
41105
41341
  #counter = 0;
41106
41342
  #failure;
41107
- constructor(prefix, profile) {
41343
+ #context;
41344
+ #spend;
41345
+ #onContext;
41346
+ /** `context` is what the session's last turn left, until this turn reports its own. */
41347
+ constructor(prefix, profile, context) {
41108
41348
  this.#prefix = prefix;
41109
41349
  this.#profile = profile;
41350
+ this.#context = context;
41351
+ }
41352
+ get context() {
41353
+ return this.#context;
41354
+ }
41355
+ /** The prompt's answer: what the turn spent, with the context so far, as one update. */
41356
+ settle(result, fallbackModel) {
41357
+ this.#spend = promptSpend(result, this.#profile);
41358
+ return this.#usage(fallbackModel);
41359
+ }
41360
+ /** Resolves on the next `usage_update`, or after `ms`. */
41361
+ async nextContext(ms, sleep) {
41362
+ await Promise.race([
41363
+ new Promise((resolve8) => {
41364
+ this.#onContext = resolve8;
41365
+ }),
41366
+ sleep(ms)
41367
+ ]);
41368
+ this.#onContext = void 0;
41369
+ }
41370
+ /** Ends a `nextContext` wait at once: the turn is being cancelled. */
41371
+ stopWaiting() {
41372
+ this.#onContext?.();
41373
+ }
41374
+ /**
41375
+ * The chat keeps a turn's last usage update, so each one carries both the spend and the
41376
+ * context. An agent's own `usage_update` is context only and must not read as spend.
41377
+ */
41378
+ #noteContext(update) {
41379
+ const context = contextOf(update);
41380
+ if (!context) return [];
41381
+ this.#context = context;
41382
+ this.#onContext?.();
41383
+ const usage = this.#usage(this.#spend?.model ?? "");
41384
+ return usage ? [usage] : [];
41385
+ }
41386
+ #usage(fallbackModel) {
41387
+ if (!this.#spend && !this.#context) return void 0;
41388
+ return usageUpdate({ ...this.#spend, ...this.#context }, fallbackModel);
41110
41389
  }
41111
41390
  /** The first cause a vendor frame named; the prompt's own error is usually generic. */
41112
41391
  get failure() {
@@ -41136,6 +41415,8 @@ var init_acp3 = __esm({
41136
41415
  entries: Array.isArray(update.entries) ? update.entries : []
41137
41416
  }
41138
41417
  ];
41418
+ case "usage_update":
41419
+ return this.#noteContext(update);
41139
41420
  case "current_mode_update":
41140
41421
  return [
41141
41422
  noticeUpdate("info", "mode_changed", asString(update.currentModeId) || "mode changed")
@@ -41261,7 +41542,13 @@ var init_acp3 = __esm({
41261
41542
  return active.done;
41262
41543
  }
41263
41544
  const prompt = this.#promptBlocks(input2);
41264
- this.#rpc.request("session/prompt", { sessionId, prompt }).then((result) => active.finish(this.#promptOutcome(active, asRecord(result) ?? {}))).catch((error62) => {
41545
+ this.#rpc.request("session/prompt", { sessionId, prompt }).then(async (result) => {
41546
+ const record2 = asRecord(result) ?? {};
41547
+ const trailing = this.#profile.trailingUsageMs;
41548
+ if (trailing && !active.cancelRequested)
41549
+ await active.turn.nextContext(trailing, (ms) => this.#options.clock.sleep(ms));
41550
+ active.finish(this.#promptOutcome(active, record2));
41551
+ }).catch((error62) => {
41265
41552
  if (this.#state === "closed") return;
41266
41553
  active.finish(this.#errorOutcome(active, error62));
41267
41554
  });
@@ -41342,7 +41629,7 @@ var init_acp3 = __esm({
41342
41629
  ];
41343
41630
  }
41344
41631
  #promptOutcome(active, result) {
41345
- const usage = promptUsage(result, this.#config?.model ?? this.#profile.backendKind);
41632
+ const usage = active.turn.settle(result, this.#config?.model ?? this.#profile.backendKind);
41346
41633
  if (usage) this.#emit({ type: "update", turnId: active.id, update: usage });
41347
41634
  const stopReason = asString(result.stopReason);
41348
41635
  const failure22 = active.turn.failure;
@@ -41376,6 +41663,7 @@ var init_acp3 = __esm({
41376
41663
  async #stopTurn(active) {
41377
41664
  if (active.cancelRequested) return active.done.then(() => void 0);
41378
41665
  active.cancelRequested = true;
41666
+ active.turn.stopWaiting();
41379
41667
  const rung = await runCancelLadder({
41380
41668
  clock: this.#options.clock,
41381
41669
  graceMs: this.#options.interruptGraceMs,
@@ -41401,14 +41689,14 @@ var init_acp3 = __esm({
41401
41689
  }
41402
41690
  #startTurn(id) {
41403
41691
  this.#turns += 1;
41404
- const turn = new AcpTurn(`acp-${this.#turns}-${id}`, this.#profile);
41692
+ const turn = new AcpTurn(`acp-${this.#turns}-${id}`, this.#profile, this.#idleTurn.context);
41405
41693
  let finish = () => {
41406
41694
  };
41407
41695
  const done = new Promise((resolve8) => {
41408
41696
  finish = (outcome2) => {
41409
41697
  if (this.#current?.id !== id) return;
41410
41698
  this.#current = void 0;
41411
- this.#idleTurn = new AcpTurn(`acp-between-${this.#turns}`, this.#profile);
41699
+ this.#idleTurn = new AcpTurn(`acp-between-${this.#turns}`, this.#profile, turn.context);
41412
41700
  if (this.#state === "busy") this.#state = "idle";
41413
41701
  this.#host.scanDescendants(true);
41414
41702
  this.#emit({ type: "turn_ended", turnId: id, outcome: outcome2 });
@@ -41647,6 +41935,8 @@ var init_acp3 = __esm({
41647
41935
  }
41648
41936
  };
41649
41937
  grokAcpProfile = {
41938
+ // Grok's ACP `inputTokens` is the full prompt; its own docs say only headless output subtracts cache.
41939
+ promptInputIncludesCache: true,
41650
41940
  backendKind: "grok_cli",
41651
41941
  displayName: "Grok CLI",
41652
41942
  defaultCommand: "grok",
@@ -41677,7 +41967,9 @@ var init_acp3 = __esm({
41677
41967
  requirement: { cli: "kimi", feature: "`kimi acp`" },
41678
41968
  launchArgs: () => ["acp"],
41679
41969
  modelChannel: "session",
41680
- exitsOnStdinEof: true
41970
+ exitsOnStdinEof: true,
41971
+ // Kimi answers the prompt, then reads its context size and pushes `usage_update`.
41972
+ trailingUsageMs: 1e3
41681
41973
  };
41682
41974
  ACP_PROFILES = {
41683
41975
  cursor_agent_cli: cursorAcpProfile,
@@ -41708,8 +42000,9 @@ var init_driver = __esm({
41708
42000
  });
41709
42001
 
41710
42002
  // src/holder/drivers/persistent.ts
41711
- function sessionContextFor(opened, inputs) {
41712
- return opened.fresh ? inputs.agentContext?.full : inputs.agentContext?.update;
42003
+ async function sessionContextFor(opened, inputs) {
42004
+ const text2 = await inputs.agentContext;
42005
+ return opened.fresh ? text2?.full : text2?.update;
41713
42006
  }
41714
42007
  function steerEcho(request2) {
41715
42008
  return {
@@ -41958,7 +42251,7 @@ function createPersistentDriver(provider4, options) {
41958
42251
  };
41959
42252
  signal.addEventListener("abort", onAbort, { once: true });
41960
42253
  try {
41961
- const contextPrefix = [sessionContextFor(opened, inputs), opened.contextPrefix].filter((part) => part !== void 0).join("\n\n");
42254
+ const contextPrefix = [await sessionContextFor(opened, inputs), opened.contextPrefix].filter((part) => part !== void 0).join("\n\n");
41962
42255
  const input2 = await provider4.turnInput(spec, inputs, contextPrefix || void 0);
41963
42256
  if (signal.aborted) return { outcome: "aborted" };
41964
42257
  const timeoutMs = options.firstOutputTimeoutMs ?? FIRST_OUTPUT_TIMEOUT_MS;
@@ -42514,8 +42807,22 @@ function codeModeChildUpdates(tool, metadata) {
42514
42807
  };
42515
42808
  });
42516
42809
  }
42810
+ function stepContextTokens(step, total) {
42811
+ const sum = step.inputTokens + step.outputTokens + step.cacheReadTokens + step.cacheCreationTokens;
42812
+ const tokens2 = total !== void 0 && total > 0 ? total : sum;
42813
+ return tokens2 > 0 ? tokens2 : void 0;
42814
+ }
42815
+ function addStepUsage(turn, step) {
42816
+ return {
42817
+ inputTokens: turn.inputTokens + step.inputTokens,
42818
+ outputTokens: turn.outputTokens + step.outputTokens,
42819
+ cacheReadTokens: turn.cacheReadTokens + step.cacheReadTokens,
42820
+ cacheCreationTokens: turn.cacheCreationTokens + step.cacheCreationTokens,
42821
+ costUsd: turn.costUsd === void 0 && step.costUsd === void 0 ? void 0 : (turn.costUsd ?? 0) + (step.costUsd ?? 0)
42822
+ };
42823
+ }
42517
42824
  function createOpenCodeSessionMemory() {
42518
- return { userMessageIds: /* @__PURE__ */ new Set() };
42825
+ return { userMessageIds: /* @__PURE__ */ new Set(), contextWindows: /* @__PURE__ */ new Map() };
42519
42826
  }
42520
42827
  function only(updates) {
42521
42828
  return { updates, actions: [] };
@@ -42848,12 +43155,12 @@ function openCodeTurnInput(run, context) {
42848
43155
  ...images.length ? { imagePaths: images.map((image) => image.path) } : {}
42849
43156
  };
42850
43157
  }
42851
- var import_crypto15, import_http4, import_crypto16, import_promises26, import_path11, import_path12, import_url2, import_crypto17, IDLE_SOCKET_MS2, 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_OPERATIONS, 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;
43158
+ var import_crypto15, import_http4, import_crypto16, import_promises26, import_path11, import_path12, import_url2, import_crypto17, IDLE_SOCKET_MS2, 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_OPERATIONS, 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;
42852
43159
  var init_opencode = __esm({
42853
43160
  "../agent-core/dist/providers/opencode.js"() {
42854
43161
  "use strict";
42855
- init_chunk_WD7O4DYQ();
42856
- init_chunk_OUEMTEUX();
43162
+ init_chunk_N2M5D7RS();
43163
+ init_chunk_RBQC7XZH();
42857
43164
  init_chunk_ZCTKXKYY();
42858
43165
  init_chunk_6VWVDJ2A();
42859
43166
  init_chunk_DLVRNIY5();
@@ -43035,6 +43342,22 @@ var init_opencode = __esm({
43035
43342
  const providers = Array.isArray(body?.providers) ? body.providers : [];
43036
43343
  return providers.map((provider4) => asString(asRecord(provider4)?.id)).filter(Boolean);
43037
43344
  }
43345
+ /** `provider/model` \u2192 the model's context limit; 0 (a custom model's unknown) is left out. */
43346
+ async modelContextWindows() {
43347
+ const body = asRecord(await this.#call("provider list", "GET", "/config/providers"));
43348
+ const windows = /* @__PURE__ */ new Map();
43349
+ for (const provider4 of Array.isArray(body?.providers) ? body.providers : []) {
43350
+ const record2 = asRecord(provider4);
43351
+ const providerId = asString(record2?.id);
43352
+ for (const [modelId, model] of Object.entries(asRecord(record2?.models) ?? {})) {
43353
+ const limit = asFiniteNumber(asRecord(asRecord(model)?.limit)?.context);
43354
+ if (providerId && limit !== void 0 && limit > 0) {
43355
+ windows.set(`${providerId}/${modelId}`, limit);
43356
+ }
43357
+ }
43358
+ }
43359
+ return windows;
43360
+ }
43038
43361
  /** Asks emitted while disconnected must still get a reply. Older engines may lack these routes. */
43039
43362
  async pendingAsks() {
43040
43363
  const read = async (path, type) => {
@@ -43266,6 +43589,13 @@ var init_opencode = __esm({
43266
43589
  ["delete", "delete"],
43267
43590
  ["update", "modify"]
43268
43591
  ]);
43592
+ NO_USAGE = {
43593
+ inputTokens: 0,
43594
+ outputTokens: 0,
43595
+ cacheReadTokens: 0,
43596
+ cacheCreationTokens: 0,
43597
+ costUsd: void 0
43598
+ };
43269
43599
  PartReader = class {
43270
43600
  /** messageID \u2192 part ids in arrival order, so a multi-part message keeps its order. */
43271
43601
  #order = /* @__PURE__ */ new Map();
@@ -43275,6 +43605,7 @@ var init_opencode = __esm({
43275
43605
  /** To-do calls already sent as a plan; the running and completed frames repeat the input. */
43276
43606
  #planned = /* @__PURE__ */ new Set();
43277
43607
  #steps = /* @__PURE__ */ new Set();
43608
+ #turnUsage = NO_USAGE;
43278
43609
  #partIds = /* @__PURE__ */ new Set();
43279
43610
  #anonymous = 0;
43280
43611
  #retainedChars = 0;
@@ -43289,6 +43620,9 @@ var init_opencode = __esm({
43289
43620
  }
43290
43621
  /** `provider/model` from the assistant message; step-finish frames do not repeat it. */
43291
43622
  model;
43623
+ /** The model's context limit, when the server listed it. */
43624
+ contextWindow;
43625
+ #contextTokens;
43292
43626
  part(part, parentToolCallId) {
43293
43627
  const id = asString(part.id);
43294
43628
  if (id) this.#partIds.add(id);
@@ -43297,7 +43631,7 @@ var init_opencode = __esm({
43297
43631
  "protocol_violation",
43298
43632
  "Alan Code exceeded the retained event limit. Continue in a new turn."
43299
43633
  );
43300
- return withParent(this.#read(part), parentToolCallId);
43634
+ return withParent(this.#read(part, parentToolCallId !== void 0), parentToolCallId);
43301
43635
  }
43302
43636
  /** A delta names only its part; the role and message come from the part's opening snapshot. */
43303
43637
  delta(partId, field2, delta, parentToolCallId) {
@@ -43309,7 +43643,7 @@ var init_opencode = __esm({
43309
43643
  const update = role === "text" ? { sessionUpdate: "agent_message_chunk", messageId, content } : { sessionUpdate: "agent_thought_chunk", messageId: `${messageId}:reasoning`, content };
43310
43644
  return withParent([update], parentToolCallId);
43311
43645
  }
43312
- #read(part) {
43646
+ #read(part, child) {
43313
43647
  const type = asString(part.type);
43314
43648
  switch (type) {
43315
43649
  case "step-start":
@@ -43325,7 +43659,7 @@ var init_opencode = __esm({
43325
43659
  return this.#tool(part);
43326
43660
  case "step-finish":
43327
43661
  case "step_finish":
43328
- return this.#stepFinish(part);
43662
+ return this.#stepFinish(part, child);
43329
43663
  case "snapshot":
43330
43664
  case "patch":
43331
43665
  return [];
@@ -43391,6 +43725,31 @@ var init_opencode = __esm({
43391
43725
  }
43392
43726
  return updates;
43393
43727
  }
43728
+ #stepUsage(part, tokens2, child) {
43729
+ const cache = asRecord(tokens2.cache);
43730
+ const step = {
43731
+ inputTokens: asFiniteNumber(tokens2.input) ?? 0,
43732
+ // OpenCode counts reasoning apart from output, and cache apart from input.
43733
+ outputTokens: (asFiniteNumber(tokens2.output) ?? 0) + (asFiniteNumber(tokens2.reasoning) ?? 0),
43734
+ cacheReadTokens: asFiniteNumber(cache?.read) ?? 0,
43735
+ cacheCreationTokens: asFiniteNumber(cache?.write) ?? 0
43736
+ };
43737
+ if (!child) this.#contextTokens = stepContextTokens(step, asFiniteNumber(tokens2.total));
43738
+ this.#turnUsage = addStepUsage(this.#turnUsage, {
43739
+ ...step,
43740
+ costUsd: asFiniteNumber(part.cost)
43741
+ });
43742
+ const { costUsd, ...turnTokens } = this.#turnUsage;
43743
+ return usageUpdate(
43744
+ {
43745
+ ...turnTokens,
43746
+ ...costUsd === void 0 ? {} : { costUsd },
43747
+ ...this.#contextTokens === void 0 ? {} : { contextTokens: this.#contextTokens },
43748
+ ...this.contextWindow === void 0 ? {} : { contextSize: this.contextWindow }
43749
+ },
43750
+ this.model
43751
+ );
43752
+ }
43394
43753
  /** OpenCode's to-do list is the plan, sent once per call although every frame repeats it. */
43395
43754
  #plan(toolCallId, name, toolState) {
43396
43755
  const todos = asRecord(toolState?.input)?.todos;
@@ -43399,28 +43758,12 @@ var init_opencode = __esm({
43399
43758
  this.#planned.add(toolCallId);
43400
43759
  return [todoPlanUpdate(toolCallId, todos)];
43401
43760
  }
43402
- #stepFinish(part) {
43761
+ #stepFinish(part, child) {
43403
43762
  const id = asString(part.id);
43404
43763
  if (id && this.#steps.has(id)) return [];
43405
43764
  if (id) this.#steps.add(id);
43406
- const updates = [];
43407
43765
  const tokens2 = asRecord(part.tokens);
43408
- if (tokens2) {
43409
- const cache = asRecord(tokens2.cache);
43410
- const cost = asFiniteNumber(part.cost);
43411
- updates.push(
43412
- usageUpdate(
43413
- {
43414
- inputTokens: asFiniteNumber(tokens2.input) ?? 0,
43415
- outputTokens: asFiniteNumber(tokens2.output) ?? 0,
43416
- cacheReadTokens: asFiniteNumber(cache?.read) ?? 0,
43417
- cacheCreationTokens: asFiniteNumber(cache?.write) ?? 0,
43418
- ...cost === void 0 ? {} : { costUsd: cost }
43419
- },
43420
- this.model
43421
- )
43422
- );
43423
- }
43766
+ const updates = tokens2 ? [this.#stepUsage(part, tokens2, child)] : [];
43424
43767
  const reason = asString(part.reason);
43425
43768
  if (reason === "stop") {
43426
43769
  updates.push({ sessionUpdate: "state_update", state: "idle", stopReason: "end_turn" });
@@ -43605,7 +43948,10 @@ var init_opencode = __esm({
43605
43948
  if (finish) this.#finish = finish;
43606
43949
  const provider4 = asString(info.providerID);
43607
43950
  const model = asString(info.modelID);
43608
- if (provider4 && model) this.#parts.model = `${provider4}/${model}`;
43951
+ if (provider4 && model) {
43952
+ this.#parts.model = `${provider4}/${model}`;
43953
+ this.#parts.contextWindow = this.#memory.contextWindows.get(this.#parts.model);
43954
+ }
43609
43955
  const error62 = asRecord(info.error);
43610
43956
  if (!error62 || isAbortError(error62) || this.#error) return [];
43611
43957
  return this.#fail(classifyOpenCodeError(error62, `${this.#engine.label} session error.`));
@@ -43810,6 +44156,9 @@ var init_opencode = __esm({
43810
44156
  /** Subscribes before the session exists, so `session.created` and early asks are seen. */
43811
44157
  async connect(client) {
43812
44158
  this.#client = client;
44159
+ client.modelContextWindows().then((windows) => {
44160
+ this.#memory.contextWindows = windows;
44161
+ }).catch(() => void 0);
43813
44162
  this.#events?.close();
43814
44163
  this.#events = await client.events({
43815
44164
  onEvent: (event) => {
@@ -44218,7 +44567,9 @@ function createAlanCodeHolderDriver(options) {
44218
44567
  });
44219
44568
  const env = options.cliEnvironment;
44220
44569
  const engine = resolveAlanCodeEngine({ env, platform, packaged: [] });
44221
- const engineRoot = alanCodeEngineRoot(env.HOME?.trim() || (0, import_node_os3.homedir)());
44570
+ const home = env.HOME?.trim() || (0, import_node_os3.homedir)();
44571
+ const engineRoot = alanCodeEngineRoot(home);
44572
+ const globalConfigDirectory = openCodeGlobalConfigDirectory(env, home);
44222
44573
  options.log.info("alan_code.engine", { command: engine.command, source: engine.source });
44223
44574
  const open4 = async (planned) => {
44224
44575
  if (planned.profile === void 0) throw refuseWithoutCredential();
@@ -44256,6 +44607,7 @@ function createAlanCodeHolderDriver(options) {
44256
44607
  conversationId: spec.conversationId
44257
44608
  },
44258
44609
  engineRoot,
44610
+ globalConfigDirectory,
44259
44611
  requestedModel: spec.model
44260
44612
  };
44261
44613
  const skills = options.installedSkills?.() ?? null;
@@ -44903,8 +45255,8 @@ var import_crypto18, import_promises27, FACTORY_API_VERSION, FACTORY_PROTOCOL_VE
44903
45255
  var init_droid = __esm({
44904
45256
  "../agent-core/dist/providers/droid.js"() {
44905
45257
  "use strict";
44906
- init_chunk_WD7O4DYQ();
44907
- init_chunk_OUEMTEUX();
45258
+ init_chunk_N2M5D7RS();
45259
+ init_chunk_RBQC7XZH();
44908
45260
  init_chunk_ZCTKXKYY();
44909
45261
  init_chunk_6VWVDJ2A();
44910
45262
  init_chunk_DLVRNIY5();
@@ -44949,7 +45301,10 @@ var init_droid = __esm({
44949
45301
  const notification = asRecord(params.notification);
44950
45302
  if (!notification) return [];
44951
45303
  const sessionId = asString(params.sessionId);
44952
- if (!sessionId || sessionId === this.#sessionId) return this.#read(notification);
45304
+ if (!sessionId || sessionId === this.#sessionId) {
45305
+ this.#noteContext(notification);
45306
+ return this.#read(notification);
45307
+ }
44953
45308
  const launcher = this.#memory.childLaunchers.get(sessionId);
44954
45309
  if (!launcher) return [];
44955
45310
  return this.#read(notification).map(
@@ -44959,6 +45314,14 @@ var init_droid = __esm({
44959
45314
  })
44960
45315
  );
44961
45316
  }
45317
+ /** Droid's own context figure: the last call's input, cache reads and output. */
45318
+ #noteContext(notification) {
45319
+ if (asString(notification.type) !== "session_token_usage_changed") return;
45320
+ const last = asRecord(notification.lastCallTokenUsage);
45321
+ if (!last) return;
45322
+ const tokens2 = (asFiniteNumber(last.inputTokens) ?? 0) + (asFiniteNumber(last.cacheReadTokens) ?? 0) + (asFiniteNumber(last.outputTokens) ?? 0);
45323
+ if (tokens2 > 0) this.#memory.contextTokens = tokens2;
45324
+ }
44962
45325
  #read(notification) {
44963
45326
  const type = asString(notification.type);
44964
45327
  if (SILENT2.has(type)) return [];
@@ -45033,6 +45396,7 @@ var init_droid = __esm({
45033
45396
  cacheCreationTokens: number4(usage?.cacheCreationTokens),
45034
45397
  numTurns: 1,
45035
45398
  ...duration3 === void 0 ? {} : { durationMs: duration3 },
45399
+ ...this.#memory.contextTokens === void 0 ? {} : { contextTokens: this.#memory.contextTokens },
45036
45400
  costUsd: 0
45037
45401
  },
45038
45402
  this.#memory.model ?? "droid"
@@ -45841,6 +46205,23 @@ function providerError(_grammar, frame) {
45841
46205
  function spellings(types, handle) {
45842
46206
  return types.map((type) => [type, handle]);
45843
46207
  }
46208
+ function stepTokens(stats) {
46209
+ return {
46210
+ inputTokens: firstNumber2(stats.input_tokens, stats.input),
46211
+ outputTokens: firstNumber2(stats.output_tokens) + firstNumber2(stats.thinking_tokens),
46212
+ cacheReadTokens: firstNumber2(stats.cache_read_tokens, stats.cached_input_tokens, stats.cached),
46213
+ cacheCreationTokens: 0
46214
+ };
46215
+ }
46216
+ function addStepTokens(total, step) {
46217
+ if (!total) return step;
46218
+ return {
46219
+ inputTokens: total.inputTokens + step.inputTokens,
46220
+ outputTokens: total.outputTokens + step.outputTokens,
46221
+ cacheReadTokens: total.cacheReadTokens + step.cacheReadTokens,
46222
+ cacheCreationTokens: total.cacheCreationTokens + step.cacheCreationTokens
46223
+ };
46224
+ }
45844
46225
  function firstNumber2(...values) {
45845
46226
  for (const value of values) {
45846
46227
  const number4 = asFiniteNumber(value);
@@ -46012,9 +46393,9 @@ var import_promises28, import_path13, import_fs9, import_path14, import_path15,
46012
46393
  var init_antigravity = __esm({
46013
46394
  "../agent-core/dist/providers/antigravity.js"() {
46014
46395
  "use strict";
46015
- init_chunk_D4TIXPWZ();
46016
- init_chunk_WD7O4DYQ();
46017
- init_chunk_OUEMTEUX();
46396
+ init_chunk_TFIO37PI();
46397
+ init_chunk_N2M5D7RS();
46398
+ init_chunk_RBQC7XZH();
46018
46399
  init_chunk_ZCTKXKYY();
46019
46400
  init_chunk_6VWVDJ2A();
46020
46401
  init_chunk_DLVRNIY5();
@@ -46372,6 +46753,11 @@ var init_antigravity = __esm({
46372
46753
  /** What `--conversation` takes: a frame's `conversation_id` wins over its `session_id`. */
46373
46754
  #conversationId;
46374
46755
  #forkReported = false;
46756
+ /** The conversation this turn runs in; a subagent's steps come under another id. */
46757
+ #rootConversation;
46758
+ /** The sum of this turn's own steps: the result's usage is the whole conversation's. */
46759
+ #stepSpend;
46760
+ #contextTokens;
46375
46761
  constructor(options) {
46376
46762
  this.#options = options;
46377
46763
  this.#conversationId = options.resumeId;
@@ -46418,7 +46804,9 @@ var init_antigravity = __esm({
46418
46804
  const type = asString(frame.type);
46419
46805
  if (!type) return [];
46420
46806
  this.#conversationId = antigravityString(frame, "conversation_id") ?? antigravityString(frame, "session_id") ?? this.#conversationId;
46807
+ this.#rootConversation ??= this.#conversationId;
46421
46808
  this.#track(type, frame);
46809
+ this.#noteStep(type, frame);
46422
46810
  const forked = this.#silentFork();
46423
46811
  if (SESSION_START_TYPES.has(type)) {
46424
46812
  return [
@@ -46433,6 +46821,29 @@ var init_antigravity = __esm({
46433
46821
  if (RESULT_TYPES.has(type)) return [...forked, ...this.#onResult(type, frame)];
46434
46822
  return [...forked, ...this.#transcripts?.read() ?? []];
46435
46823
  }
46824
+ /** A finished answer step of this conversation: one model call, with its own usage. */
46825
+ #noteStep(type, frame) {
46826
+ if (type !== "assistant_message" || asString(frame.state).toUpperCase() !== "DONE") return;
46827
+ const usage = asRecord(frame.usage);
46828
+ if (!usage) return;
46829
+ const conversation = antigravityString(frame, "conversation_id");
46830
+ if (conversation && this.#rootConversation && conversation !== this.#rootConversation) return;
46831
+ const step = stepTokens(usage);
46832
+ this.#stepSpend = addStepTokens(this.#stepSpend, step);
46833
+ const context = step.inputTokens + step.cacheReadTokens + step.outputTokens;
46834
+ if (context > 0) this.#contextTokens = context;
46835
+ }
46836
+ /**
46837
+ * agy's result usage is cumulative over the conversation, so a resumed turn's spend comes
46838
+ * from its steps; a first turn's result is its own.
46839
+ */
46840
+ #turnSpend(frame) {
46841
+ const steps = this.#stepSpend;
46842
+ this.#stepSpend = void 0;
46843
+ if (steps) return steps;
46844
+ if (this.#options.resumeId) return void 0;
46845
+ return stepTokens(asRecord(frame.usage) ?? asRecord(frame.stats) ?? frame);
46846
+ }
46436
46847
  #track(type, frame) {
46437
46848
  const transcripts = this.#transcripts;
46438
46849
  if (!transcripts) return;
@@ -46450,6 +46861,22 @@ var init_antigravity = __esm({
46450
46861
  this.#forkReported = true;
46451
46862
  return [noticeUpdate("warning", "session_resume_failed", RESUME_FORKED)];
46452
46863
  }
46864
+ #resultUsage(frame) {
46865
+ const spend = this.#turnSpend(frame);
46866
+ const contextTokens = this.#contextTokens;
46867
+ if (!spend && contextTokens === void 0) return [];
46868
+ const stats = asRecord(frame.usage) ?? asRecord(frame.stats) ?? frame;
46869
+ return [
46870
+ usageUpdate({
46871
+ model: formatAntigravityModelName(this.#model()),
46872
+ numTurns: Math.max(this.#iterations, 1),
46873
+ durationMs: asFiniteNumber(stats.duration_ms) ?? 0,
46874
+ ...spend,
46875
+ ...contextTokens === void 0 ? {} : { contextTokens },
46876
+ costUsd: 0
46877
+ })
46878
+ ];
46879
+ }
46453
46880
  #onResult(type, frame) {
46454
46881
  const updates = [];
46455
46882
  this.#iterations = Math.max(this.#iterations, asFiniteNumber(frame.num_turns) ?? 1);
@@ -46458,23 +46885,7 @@ var init_antigravity = __esm({
46458
46885
  updates.push(agentText(`antigravity-${this.#conversationId ?? "run"}-result`, resultText2));
46459
46886
  this.#resultShown = true;
46460
46887
  }
46461
- const stats = asRecord(frame.usage) ?? asRecord(frame.stats) ?? frame;
46462
- updates.push(
46463
- usageUpdate({
46464
- model: formatAntigravityModelName(this.#model()),
46465
- numTurns: Math.max(this.#iterations, 1),
46466
- durationMs: asFiniteNumber(stats.duration_ms) ?? 0,
46467
- inputTokens: firstNumber2(stats.input_tokens, stats.input),
46468
- outputTokens: firstNumber2(stats.output_tokens),
46469
- cacheReadTokens: firstNumber2(
46470
- stats.cache_read_tokens,
46471
- stats.cached_input_tokens,
46472
- stats.cached
46473
- ),
46474
- cacheCreationTokens: 0,
46475
- costUsd: 0
46476
- })
46477
- );
46888
+ updates.push(...this.#resultUsage(frame));
46478
46889
  const status = asString(frame.status).toLowerCase();
46479
46890
  const succeeded = !status || SUCCESSFUL_STATUSES.has(status);
46480
46891
  if (succeeded) {
@@ -46717,8 +47128,8 @@ var import_promises29, import_path16, import_crypto20, COMMAND_CODE_GRAMMAR_NAME
46717
47128
  var init_command_code = __esm({
46718
47129
  "../agent-core/dist/providers/command-code.js"() {
46719
47130
  "use strict";
46720
- init_chunk_WD7O4DYQ();
46721
- init_chunk_OUEMTEUX();
47131
+ init_chunk_N2M5D7RS();
47132
+ init_chunk_RBQC7XZH();
46722
47133
  init_chunk_ZCTKXKYY();
46723
47134
  init_chunk_6VWVDJ2A();
46724
47135
  init_chunk_DLVRNIY5();
@@ -47083,6 +47494,7 @@ var init_command_code = __esm({
47083
47494
  #streamed = false;
47084
47495
  #totals;
47085
47496
  #result;
47497
+ #contextTokens;
47086
47498
  constructor(options) {
47087
47499
  this.#options = options;
47088
47500
  if (options.resumeId) this.#grammar.sessionId = options.resumeId;
@@ -47125,6 +47537,8 @@ var init_command_code = __esm({
47125
47537
  #onEvent(event) {
47126
47538
  switch (commandCodeString(event.type)) {
47127
47539
  case "model_request_end":
47540
+ this.#noteContext(event.usage);
47541
+ return this.#usage(event.usage);
47128
47542
  case "turn_end":
47129
47543
  return this.#usage(event.usage);
47130
47544
  case "run_end": {
@@ -47176,7 +47590,28 @@ var init_command_code = __esm({
47176
47590
  durationMs: durationMs ?? previous?.durationMs ?? 0
47177
47591
  };
47178
47592
  this.#totals = totals;
47179
- return [usageUpdate({ model: this.#model(), numTurns: 1, ...totals, costUsd: 0 })];
47593
+ return [
47594
+ usageUpdate({
47595
+ model: this.#model(),
47596
+ numTurns: 1,
47597
+ ...totals,
47598
+ // Command Code's own cost estimate takes cache out of inputTokens, which counts it.
47599
+ inputTokens: Math.max(
47600
+ totals.inputTokens - totals.cacheReadTokens - totals.cacheCreationTokens,
47601
+ 0
47602
+ ),
47603
+ ...this.#contextTokens === void 0 ? {} : { contextTokens: this.#contextTokens },
47604
+ costUsd: 0
47605
+ })
47606
+ ];
47607
+ }
47608
+ /** One model call's prompt, cache included, plus its reply: what it left in the window. */
47609
+ #noteContext(usage) {
47610
+ const record2 = asRecord(usage);
47611
+ const input2 = asFiniteNumber(record2?.inputTokens) ?? asFiniteNumber(record2?.input_tokens);
47612
+ if (input2 === void 0 || input2 <= 0) return;
47613
+ const output2 = asFiniteNumber(record2?.outputTokens) ?? asFiniteNumber(record2?.output_tokens);
47614
+ this.#contextTokens = input2 + (output2 ?? 0);
47180
47615
  }
47181
47616
  };
47182
47617
  COMMAND_CODE_MAX_TURNS = 1e4;
@@ -48450,6 +48885,7 @@ function runtimePaths(stateDir) {
48450
48885
 
48451
48886
  // src/platform/process-memory.ts
48452
48887
  var import_node_child_process4 = require("child_process");
48888
+ var import_node_fs6 = require("fs");
48453
48889
  var import_promises12 = require("fs/promises");
48454
48890
  var import_node_os2 = require("os");
48455
48891
  var import_node_util3 = require("util");
@@ -48489,6 +48925,45 @@ async function readProcessRss(pid) {
48489
48925
  return null;
48490
48926
  }
48491
48927
  }
48928
+ function parseDarwinVmStat(output2) {
48929
+ const pageSize = Number(/page size of (\d+) bytes/.exec(output2)?.[1]);
48930
+ if (!Number.isFinite(pageSize) || pageSize <= 0) return null;
48931
+ const pages = (name) => {
48932
+ const match = new RegExp(`^Pages ${name}:\\s+(\\d+)\\.?$`, "m").exec(output2);
48933
+ return match ? Number(match[1]) : null;
48934
+ };
48935
+ const free = pages("free");
48936
+ if (free === null) return null;
48937
+ return (free + (pages("inactive") ?? 0) + (pages("speculative") ?? 0)) * pageSize;
48938
+ }
48939
+ function parseLinuxMemInfo(output2) {
48940
+ const kilobytes = /^MemAvailable:\s+(\d+)\s+kB$/m.exec(output2)?.[1];
48941
+ return kilobytes === void 0 ? null : Number(kilobytes) * 1024;
48942
+ }
48943
+ var CAPACITY_PROBE_TTL_MS = 2e3;
48944
+ var AvailableMemoryProbe = class {
48945
+ cached = null;
48946
+ read(now) {
48947
+ if (this.cached !== null && now - this.cached.at < CAPACITY_PROBE_TTL_MS) {
48948
+ return this.cached.bytes;
48949
+ }
48950
+ let bytes = null;
48951
+ try {
48952
+ if (process.platform === "darwin") {
48953
+ bytes = parseDarwinVmStat(
48954
+ (0, import_node_child_process4.execFileSync)("vm_stat", { encoding: "utf8", timeout: PROBE_TIMEOUT_MS })
48955
+ );
48956
+ } else if (process.platform === "linux") {
48957
+ bytes = parseLinuxMemInfo((0, import_node_fs6.readFileSync)("/proc/meminfo", "utf8"));
48958
+ }
48959
+ } catch {
48960
+ bytes = null;
48961
+ }
48962
+ this.cached = { at: now, bytes };
48963
+ return bytes;
48964
+ }
48965
+ };
48966
+ var availableMemoryProbe = new AvailableMemoryProbe();
48492
48967
  async function processMemoryRows() {
48493
48968
  if (process.platform === "win32") {
48494
48969
  const { stdout: stdout2 } = await execFileAsync3(
@@ -48589,7 +49064,7 @@ var systemExec = (request2) => new Promise((resolve8) => {
48589
49064
  init_alan_code();
48590
49065
 
48591
49066
  // src/capabilities/providers/commands.ts
48592
- var import_node_fs6 = require("fs");
49067
+ var import_node_fs7 = require("fs");
48593
49068
  var import_promises17 = require("fs/promises");
48594
49069
  var import_node_path9 = require("path");
48595
49070
  var PROVIDER_COMMANDS = [
@@ -48627,7 +49102,7 @@ function pathDelimiter(platform) {
48627
49102
  async function isRunnable(path, platform) {
48628
49103
  try {
48629
49104
  if (!(await (0, import_promises17.stat)(path)).isFile()) return false;
48630
- if (platform !== "win32") await (0, import_promises17.access)(path, import_node_fs6.constants.X_OK);
49105
+ if (platform !== "win32") await (0, import_promises17.access)(path, import_node_fs7.constants.X_OK);
48631
49106
  return true;
48632
49107
  } catch {
48633
49108
  return false;
@@ -49277,7 +49752,7 @@ async function inspectIndexedSkill(directory, contentHash) {
49277
49752
 
49278
49753
  // src/capabilities/skills/native-index.ts
49279
49754
  var import_node_crypto10 = require("crypto");
49280
- var import_node_fs7 = require("fs");
49755
+ var import_node_fs8 = require("fs");
49281
49756
  var import_promises21 = require("fs/promises");
49282
49757
  var import_node_path13 = require("path");
49283
49758
  var ALAN_SKILLS_PLUGIN_NAME = "alan";
@@ -49291,7 +49766,7 @@ var PLUGIN_MANIFEST = `${JSON.stringify(
49291
49766
  )}
49292
49767
  `;
49293
49768
  function installedSkillFolders(layout) {
49294
- return (0, import_node_fs7.existsSync)((0, import_node_path13.join)(layout.pluginDir, ".claude-plugin", "plugin.json")) ? { pluginDir: layout.pluginDir, skillsDir: layout.pluginSkillsDir } : null;
49769
+ return (0, import_node_fs8.existsSync)((0, import_node_path13.join)(layout.pluginDir, ".claude-plugin", "plugin.json")) ? { pluginDir: layout.pluginDir, skillsDir: layout.pluginSkillsDir } : null;
49295
49770
  }
49296
49771
 
49297
49772
  // src/capabilities/workspace/index.ts
@@ -49908,20 +50383,20 @@ async function prepareRunInputs(spec, { source, tmpDir, signal, skills = [] }) {
49908
50383
 
49909
50384
  // src/holder/serve.ts
49910
50385
  var import_node_crypto15 = require("crypto");
49911
- var import_node_fs11 = require("fs");
50386
+ var import_node_fs12 = require("fs");
49912
50387
  var import_node_net2 = require("net");
49913
50388
  var import_node_path29 = require("path");
49914
50389
  init_runtime_v2();
49915
50390
 
49916
50391
  // src/holder/admission.ts
49917
- var import_node_fs9 = require("fs");
50392
+ var import_node_fs10 = require("fs");
49918
50393
  var import_promises35 = require("fs/promises");
49919
50394
  var import_node_os6 = require("os");
49920
50395
  var import_node_path25 = require("path");
49921
50396
  init_constants();
49922
50397
 
49923
50398
  // ../shared/dist/node/local-workspace.js
49924
- var import_node_fs8 = require("fs");
50399
+ var import_node_fs9 = require("fs");
49925
50400
  var import_node_os5 = require("os");
49926
50401
  var import_node_path20 = require("path");
49927
50402
  function resolveAlanDefaultWorkspacePath(homeDirectory = (0, import_node_os5.homedir)()) {
@@ -50341,7 +50816,7 @@ async function inspectReadiness(path) {
50341
50816
  if (!(await (0, import_promises35.stat)(path)).isDirectory()) {
50342
50817
  return { ready: false, missing: true, message: MESSAGES.missing };
50343
50818
  }
50344
- await (0, import_promises35.access)(path, import_node_fs9.constants.R_OK | import_node_fs9.constants.W_OK | import_node_fs9.constants.X_OK);
50819
+ await (0, import_promises35.access)(path, import_node_fs10.constants.R_OK | import_node_fs10.constants.W_OK | import_node_fs10.constants.X_OK);
50345
50820
  return { ready: true };
50346
50821
  } catch (error62) {
50347
50822
  const code = errnoCode(error62) ?? "";
@@ -50386,7 +50861,7 @@ async function admitDefaultWorkspace(spec, context, skills) {
50386
50861
  const path = resolveAlanDefaultWorkspacePath(env.HOME || env.USERPROFILE || (0, import_node_os6.homedir)());
50387
50862
  try {
50388
50863
  await (0, import_promises35.mkdir)(path, { recursive: true, mode: 448 });
50389
- await (0, import_promises35.access)(path, import_node_fs9.constants.R_OK | import_node_fs9.constants.W_OK | import_node_fs9.constants.X_OK);
50864
+ await (0, import_promises35.access)(path, import_node_fs10.constants.R_OK | import_node_fs10.constants.W_OK | import_node_fs10.constants.X_OK);
50390
50865
  return { kind: "admitted", spec: { ...spec, projectPath: path }, skills };
50391
50866
  } catch (error62) {
50392
50867
  const code = errnoCode(error62);
@@ -50725,13 +51200,13 @@ function runEnded(input2) {
50725
51200
  var decoder = new TextDecoder();
50726
51201
 
50727
51202
  // src/run-log/writer.ts
50728
- var import_node_fs10 = require("fs");
51203
+ var import_node_fs11 = require("fs");
50729
51204
  var import_node_path28 = require("path");
50730
51205
  init_runtime_v2();
50731
51206
  function lastSeq(fd, size) {
50732
51207
  for (const length of tailWindows(size)) {
50733
51208
  const buffer = Buffer.alloc(length);
50734
- (0, import_node_fs10.readSync)(fd, buffer, 0, length, size - length);
51209
+ (0, import_node_fs11.readSync)(fd, buffer, 0, length, size - length);
50735
51210
  const last = lastLine(buffer.toString("utf8").trimEnd(), length === size);
50736
51211
  if (last === void 0) continue;
50737
51212
  if (last.length === 0) return 0;
@@ -50742,13 +51217,13 @@ function lastSeq(fd, size) {
50742
51217
  throw new RuntimeFault("record_too_large", "Run log tail record is larger than any record");
50743
51218
  }
50744
51219
  function openRunLog(path, clock) {
50745
- (0, import_node_fs10.mkdirSync)((0, import_node_path28.dirname)(path), { recursive: true, mode: 448 });
50746
- const fd = (0, import_node_fs10.openSync)(path, "a+", 384);
50747
- let size = (0, import_node_fs10.fstatSync)(fd).size;
51220
+ (0, import_node_fs11.mkdirSync)((0, import_node_path28.dirname)(path), { recursive: true, mode: 448 });
51221
+ const fd = (0, import_node_fs11.openSync)(path, "a+", 384);
51222
+ let size = (0, import_node_fs11.fstatSync)(fd).size;
50748
51223
  let seq = lastSeq(fd, size);
50749
51224
  let dirty = false;
50750
51225
  const sync = () => {
50751
- (0, import_node_fs10.fsyncSync)(fd);
51226
+ (0, import_node_fs11.fsyncSync)(fd);
50752
51227
  dirty = false;
50753
51228
  };
50754
51229
  return {
@@ -50762,7 +51237,7 @@ function openRunLog(path, clock) {
50762
51237
  };
50763
51238
  const line = Buffer.from(`${JSON.stringify(record2)}
50764
51239
  `, "utf8");
50765
- (0, import_node_fs10.writeSync)(fd, line);
51240
+ (0, import_node_fs11.writeSync)(fd, line);
50766
51241
  size += line.length;
50767
51242
  dirty = true;
50768
51243
  if (isRunLifecycleKind(update.sessionUpdate)) sync();
@@ -50774,7 +51249,7 @@ function openRunLog(path, clock) {
50774
51249
  },
50775
51250
  [Symbol.dispose]: () => {
50776
51251
  if (dirty) sync();
50777
- (0, import_node_fs10.closeSync)(fd);
51252
+ (0, import_node_fs11.closeSync)(fd);
50778
51253
  }
50779
51254
  };
50780
51255
  }
@@ -50837,20 +51312,17 @@ async function runWithInputs({ spec, skills }, context, sink, signal) {
50837
51312
  message: `Could not fetch this run's attachments or provider credential: ${error62 instanceof Error ? error62.message : String(error62)}`
50838
51313
  };
50839
51314
  }
50840
- const agentContext = await sessionContext;
50841
51315
  const prepared = __using(_stack, inputs, true);
50842
- const result = await context.driver.runTurn(
50843
- spec,
50844
- sink,
50845
- signal,
50846
- agentContext === void 0 ? prepared : {
50847
- ...prepared,
50848
- agentContext: {
50849
- full: agentContext.full,
50850
- ...agentContext.update ? { update: agentContext.update } : {}
51316
+ const result = await context.driver.runTurn(spec, sink, signal, {
51317
+ ...prepared,
51318
+ agentContext: sessionContext.then(
51319
+ (agentContext2) => agentContext2 === void 0 ? void 0 : {
51320
+ full: agentContext2.full,
51321
+ ...agentContext2.update ? { update: agentContext2.update } : {}
50851
51322
  }
50852
- }
50853
- );
51323
+ )
51324
+ });
51325
+ const agentContext = await sessionContext;
50854
51326
  if (agentContext !== void 0 && result.outcome !== "rejected") {
50855
51327
  await agentContext.save().catch((error62) => {
50856
51328
  context.log.warn("holder.agent_context_save_failed", { runId: spec.runId, error: error62 });
@@ -51218,7 +51690,7 @@ async function runHolder({
51218
51690
  for (const client of holder.clients) client.end();
51219
51691
  await new Promise((resolve8) => server.close(() => resolve8()));
51220
51692
  await statusWrites;
51221
- (0, import_node_fs11.rmSync)(launch.statusPath, { force: true });
51693
+ (0, import_node_fs12.rmSync)(launch.statusPath, { force: true });
51222
51694
  log.info("holder.suspended", { conversationId: launch.conversationId });
51223
51695
  } catch (_) {
51224
51696
  var _error = _, _hasError = true;
@@ -51229,6 +51701,7 @@ async function runHolder({
51229
51701
 
51230
51702
  // src/sessions/suspend-policy.ts
51231
51703
  var GIB = 1024 ** 3;
51704
+ var SESSION_MEMORY_CEILING_BYTES = 2.5 * GIB;
51232
51705
  var MEMORY_BUDGET_SHARE = 0.15;
51233
51706
  var MEMORY_BUDGET_MIN_BYTES = GIB;
51234
51707
  var MEMORY_BUDGET_MAX_BYTES = 4 * GIB;
@@ -51257,7 +51730,8 @@ var envSchema = external_exports.object({
51257
51730
  ALAN_RUNTIME_LOG_LEVEL: external_exports.enum(["debug", "info", "warn", "error"]).default("info"),
51258
51731
  ALAN_RUNTIME_SUSPEND_IDLE_MS: external_exports.coerce.number().int().positive().optional(),
51259
51732
  ALAN_RUNTIME_SUSPEND_CHECK_MS: external_exports.coerce.number().int().positive().default(3e4),
51260
- ALAN_RUNTIME_DESIRED_RESYNC_MS: external_exports.coerce.number().int().positive().default(6e5),
51733
+ // A two-minute conditional GET bounds recovery after a lost poke; unchanged state returns 304.
51734
+ ALAN_RUNTIME_DESIRED_RESYNC_MS: external_exports.coerce.number().int().positive().default(12e4),
51261
51735
  ALAN_MAX_ACTIVE_RUNS: external_exports.coerce.number().int().optional(),
51262
51736
  ALAN_RUNTIME_API_URL: external_exports.url().optional(),
51263
51737
  ALAN_RUNTIME_CREDENTIAL_STORE: external_exports.enum(CREDENTIAL_STORE_KINDS).optional(),