@alan-ai-hq/agent-manager-linux-arm64 0.1.160 → 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 +775 -270
  2. package/alan-holder.cjs +657 -181
  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,
@@ -42514,8 +42806,22 @@ function codeModeChildUpdates(tool, metadata) {
42514
42806
  };
42515
42807
  });
42516
42808
  }
42809
+ function stepContextTokens(step, total) {
42810
+ const sum = step.inputTokens + step.outputTokens + step.cacheReadTokens + step.cacheCreationTokens;
42811
+ const tokens2 = total !== void 0 && total > 0 ? total : sum;
42812
+ return tokens2 > 0 ? tokens2 : void 0;
42813
+ }
42814
+ function addStepUsage(turn, step) {
42815
+ return {
42816
+ inputTokens: turn.inputTokens + step.inputTokens,
42817
+ outputTokens: turn.outputTokens + step.outputTokens,
42818
+ cacheReadTokens: turn.cacheReadTokens + step.cacheReadTokens,
42819
+ cacheCreationTokens: turn.cacheCreationTokens + step.cacheCreationTokens,
42820
+ costUsd: turn.costUsd === void 0 && step.costUsd === void 0 ? void 0 : (turn.costUsd ?? 0) + (step.costUsd ?? 0)
42821
+ };
42822
+ }
42517
42823
  function createOpenCodeSessionMemory() {
42518
- return { userMessageIds: /* @__PURE__ */ new Set() };
42824
+ return { userMessageIds: /* @__PURE__ */ new Set(), contextWindows: /* @__PURE__ */ new Map() };
42519
42825
  }
42520
42826
  function only(updates) {
42521
42827
  return { updates, actions: [] };
@@ -42848,12 +43154,12 @@ function openCodeTurnInput(run, context) {
42848
43154
  ...images.length ? { imagePaths: images.map((image) => image.path) } : {}
42849
43155
  };
42850
43156
  }
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;
43157
+ 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
43158
  var init_opencode = __esm({
42853
43159
  "../agent-core/dist/providers/opencode.js"() {
42854
43160
  "use strict";
42855
- init_chunk_WD7O4DYQ();
42856
- init_chunk_OUEMTEUX();
43161
+ init_chunk_N2M5D7RS();
43162
+ init_chunk_RBQC7XZH();
42857
43163
  init_chunk_ZCTKXKYY();
42858
43164
  init_chunk_6VWVDJ2A();
42859
43165
  init_chunk_DLVRNIY5();
@@ -43035,6 +43341,22 @@ var init_opencode = __esm({
43035
43341
  const providers = Array.isArray(body?.providers) ? body.providers : [];
43036
43342
  return providers.map((provider4) => asString(asRecord(provider4)?.id)).filter(Boolean);
43037
43343
  }
43344
+ /** `provider/model` \u2192 the model's context limit; 0 (a custom model's unknown) is left out. */
43345
+ async modelContextWindows() {
43346
+ const body = asRecord(await this.#call("provider list", "GET", "/config/providers"));
43347
+ const windows = /* @__PURE__ */ new Map();
43348
+ for (const provider4 of Array.isArray(body?.providers) ? body.providers : []) {
43349
+ const record2 = asRecord(provider4);
43350
+ const providerId = asString(record2?.id);
43351
+ for (const [modelId, model] of Object.entries(asRecord(record2?.models) ?? {})) {
43352
+ const limit = asFiniteNumber(asRecord(asRecord(model)?.limit)?.context);
43353
+ if (providerId && limit !== void 0 && limit > 0) {
43354
+ windows.set(`${providerId}/${modelId}`, limit);
43355
+ }
43356
+ }
43357
+ }
43358
+ return windows;
43359
+ }
43038
43360
  /** Asks emitted while disconnected must still get a reply. Older engines may lack these routes. */
43039
43361
  async pendingAsks() {
43040
43362
  const read = async (path, type) => {
@@ -43266,6 +43588,13 @@ var init_opencode = __esm({
43266
43588
  ["delete", "delete"],
43267
43589
  ["update", "modify"]
43268
43590
  ]);
43591
+ NO_USAGE = {
43592
+ inputTokens: 0,
43593
+ outputTokens: 0,
43594
+ cacheReadTokens: 0,
43595
+ cacheCreationTokens: 0,
43596
+ costUsd: void 0
43597
+ };
43269
43598
  PartReader = class {
43270
43599
  /** messageID \u2192 part ids in arrival order, so a multi-part message keeps its order. */
43271
43600
  #order = /* @__PURE__ */ new Map();
@@ -43275,6 +43604,7 @@ var init_opencode = __esm({
43275
43604
  /** To-do calls already sent as a plan; the running and completed frames repeat the input. */
43276
43605
  #planned = /* @__PURE__ */ new Set();
43277
43606
  #steps = /* @__PURE__ */ new Set();
43607
+ #turnUsage = NO_USAGE;
43278
43608
  #partIds = /* @__PURE__ */ new Set();
43279
43609
  #anonymous = 0;
43280
43610
  #retainedChars = 0;
@@ -43289,6 +43619,9 @@ var init_opencode = __esm({
43289
43619
  }
43290
43620
  /** `provider/model` from the assistant message; step-finish frames do not repeat it. */
43291
43621
  model;
43622
+ /** The model's context limit, when the server listed it. */
43623
+ contextWindow;
43624
+ #contextTokens;
43292
43625
  part(part, parentToolCallId) {
43293
43626
  const id = asString(part.id);
43294
43627
  if (id) this.#partIds.add(id);
@@ -43297,7 +43630,7 @@ var init_opencode = __esm({
43297
43630
  "protocol_violation",
43298
43631
  "Alan Code exceeded the retained event limit. Continue in a new turn."
43299
43632
  );
43300
- return withParent(this.#read(part), parentToolCallId);
43633
+ return withParent(this.#read(part, parentToolCallId !== void 0), parentToolCallId);
43301
43634
  }
43302
43635
  /** A delta names only its part; the role and message come from the part's opening snapshot. */
43303
43636
  delta(partId, field2, delta, parentToolCallId) {
@@ -43309,7 +43642,7 @@ var init_opencode = __esm({
43309
43642
  const update = role === "text" ? { sessionUpdate: "agent_message_chunk", messageId, content } : { sessionUpdate: "agent_thought_chunk", messageId: `${messageId}:reasoning`, content };
43310
43643
  return withParent([update], parentToolCallId);
43311
43644
  }
43312
- #read(part) {
43645
+ #read(part, child) {
43313
43646
  const type = asString(part.type);
43314
43647
  switch (type) {
43315
43648
  case "step-start":
@@ -43325,7 +43658,7 @@ var init_opencode = __esm({
43325
43658
  return this.#tool(part);
43326
43659
  case "step-finish":
43327
43660
  case "step_finish":
43328
- return this.#stepFinish(part);
43661
+ return this.#stepFinish(part, child);
43329
43662
  case "snapshot":
43330
43663
  case "patch":
43331
43664
  return [];
@@ -43391,6 +43724,31 @@ var init_opencode = __esm({
43391
43724
  }
43392
43725
  return updates;
43393
43726
  }
43727
+ #stepUsage(part, tokens2, child) {
43728
+ const cache = asRecord(tokens2.cache);
43729
+ const step = {
43730
+ inputTokens: asFiniteNumber(tokens2.input) ?? 0,
43731
+ // OpenCode counts reasoning apart from output, and cache apart from input.
43732
+ outputTokens: (asFiniteNumber(tokens2.output) ?? 0) + (asFiniteNumber(tokens2.reasoning) ?? 0),
43733
+ cacheReadTokens: asFiniteNumber(cache?.read) ?? 0,
43734
+ cacheCreationTokens: asFiniteNumber(cache?.write) ?? 0
43735
+ };
43736
+ if (!child) this.#contextTokens = stepContextTokens(step, asFiniteNumber(tokens2.total));
43737
+ this.#turnUsage = addStepUsage(this.#turnUsage, {
43738
+ ...step,
43739
+ costUsd: asFiniteNumber(part.cost)
43740
+ });
43741
+ const { costUsd, ...turnTokens } = this.#turnUsage;
43742
+ return usageUpdate(
43743
+ {
43744
+ ...turnTokens,
43745
+ ...costUsd === void 0 ? {} : { costUsd },
43746
+ ...this.#contextTokens === void 0 ? {} : { contextTokens: this.#contextTokens },
43747
+ ...this.contextWindow === void 0 ? {} : { contextSize: this.contextWindow }
43748
+ },
43749
+ this.model
43750
+ );
43751
+ }
43394
43752
  /** OpenCode's to-do list is the plan, sent once per call although every frame repeats it. */
43395
43753
  #plan(toolCallId, name, toolState) {
43396
43754
  const todos = asRecord(toolState?.input)?.todos;
@@ -43399,28 +43757,12 @@ var init_opencode = __esm({
43399
43757
  this.#planned.add(toolCallId);
43400
43758
  return [todoPlanUpdate(toolCallId, todos)];
43401
43759
  }
43402
- #stepFinish(part) {
43760
+ #stepFinish(part, child) {
43403
43761
  const id = asString(part.id);
43404
43762
  if (id && this.#steps.has(id)) return [];
43405
43763
  if (id) this.#steps.add(id);
43406
- const updates = [];
43407
43764
  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
- }
43765
+ const updates = tokens2 ? [this.#stepUsage(part, tokens2, child)] : [];
43424
43766
  const reason = asString(part.reason);
43425
43767
  if (reason === "stop") {
43426
43768
  updates.push({ sessionUpdate: "state_update", state: "idle", stopReason: "end_turn" });
@@ -43605,7 +43947,10 @@ var init_opencode = __esm({
43605
43947
  if (finish) this.#finish = finish;
43606
43948
  const provider4 = asString(info.providerID);
43607
43949
  const model = asString(info.modelID);
43608
- if (provider4 && model) this.#parts.model = `${provider4}/${model}`;
43950
+ if (provider4 && model) {
43951
+ this.#parts.model = `${provider4}/${model}`;
43952
+ this.#parts.contextWindow = this.#memory.contextWindows.get(this.#parts.model);
43953
+ }
43609
43954
  const error62 = asRecord(info.error);
43610
43955
  if (!error62 || isAbortError(error62) || this.#error) return [];
43611
43956
  return this.#fail(classifyOpenCodeError(error62, `${this.#engine.label} session error.`));
@@ -43810,6 +44155,9 @@ var init_opencode = __esm({
43810
44155
  /** Subscribes before the session exists, so `session.created` and early asks are seen. */
43811
44156
  async connect(client) {
43812
44157
  this.#client = client;
44158
+ client.modelContextWindows().then((windows) => {
44159
+ this.#memory.contextWindows = windows;
44160
+ }).catch(() => void 0);
43813
44161
  this.#events?.close();
43814
44162
  this.#events = await client.events({
43815
44163
  onEvent: (event) => {
@@ -44218,7 +44566,9 @@ function createAlanCodeHolderDriver(options) {
44218
44566
  });
44219
44567
  const env = options.cliEnvironment;
44220
44568
  const engine = resolveAlanCodeEngine({ env, platform, packaged: [] });
44221
- const engineRoot = alanCodeEngineRoot(env.HOME?.trim() || (0, import_node_os3.homedir)());
44569
+ const home = env.HOME?.trim() || (0, import_node_os3.homedir)();
44570
+ const engineRoot = alanCodeEngineRoot(home);
44571
+ const globalConfigDirectory = openCodeGlobalConfigDirectory(env, home);
44222
44572
  options.log.info("alan_code.engine", { command: engine.command, source: engine.source });
44223
44573
  const open4 = async (planned) => {
44224
44574
  if (planned.profile === void 0) throw refuseWithoutCredential();
@@ -44256,6 +44606,7 @@ function createAlanCodeHolderDriver(options) {
44256
44606
  conversationId: spec.conversationId
44257
44607
  },
44258
44608
  engineRoot,
44609
+ globalConfigDirectory,
44259
44610
  requestedModel: spec.model
44260
44611
  };
44261
44612
  const skills = options.installedSkills?.() ?? null;
@@ -44903,8 +45254,8 @@ var import_crypto18, import_promises27, FACTORY_API_VERSION, FACTORY_PROTOCOL_VE
44903
45254
  var init_droid = __esm({
44904
45255
  "../agent-core/dist/providers/droid.js"() {
44905
45256
  "use strict";
44906
- init_chunk_WD7O4DYQ();
44907
- init_chunk_OUEMTEUX();
45257
+ init_chunk_N2M5D7RS();
45258
+ init_chunk_RBQC7XZH();
44908
45259
  init_chunk_ZCTKXKYY();
44909
45260
  init_chunk_6VWVDJ2A();
44910
45261
  init_chunk_DLVRNIY5();
@@ -44949,7 +45300,10 @@ var init_droid = __esm({
44949
45300
  const notification = asRecord(params.notification);
44950
45301
  if (!notification) return [];
44951
45302
  const sessionId = asString(params.sessionId);
44952
- if (!sessionId || sessionId === this.#sessionId) return this.#read(notification);
45303
+ if (!sessionId || sessionId === this.#sessionId) {
45304
+ this.#noteContext(notification);
45305
+ return this.#read(notification);
45306
+ }
44953
45307
  const launcher = this.#memory.childLaunchers.get(sessionId);
44954
45308
  if (!launcher) return [];
44955
45309
  return this.#read(notification).map(
@@ -44959,6 +45313,14 @@ var init_droid = __esm({
44959
45313
  })
44960
45314
  );
44961
45315
  }
45316
+ /** Droid's own context figure: the last call's input, cache reads and output. */
45317
+ #noteContext(notification) {
45318
+ if (asString(notification.type) !== "session_token_usage_changed") return;
45319
+ const last = asRecord(notification.lastCallTokenUsage);
45320
+ if (!last) return;
45321
+ const tokens2 = (asFiniteNumber(last.inputTokens) ?? 0) + (asFiniteNumber(last.cacheReadTokens) ?? 0) + (asFiniteNumber(last.outputTokens) ?? 0);
45322
+ if (tokens2 > 0) this.#memory.contextTokens = tokens2;
45323
+ }
44962
45324
  #read(notification) {
44963
45325
  const type = asString(notification.type);
44964
45326
  if (SILENT2.has(type)) return [];
@@ -45033,6 +45395,7 @@ var init_droid = __esm({
45033
45395
  cacheCreationTokens: number4(usage?.cacheCreationTokens),
45034
45396
  numTurns: 1,
45035
45397
  ...duration3 === void 0 ? {} : { durationMs: duration3 },
45398
+ ...this.#memory.contextTokens === void 0 ? {} : { contextTokens: this.#memory.contextTokens },
45036
45399
  costUsd: 0
45037
45400
  },
45038
45401
  this.#memory.model ?? "droid"
@@ -45841,6 +46204,23 @@ function providerError(_grammar, frame) {
45841
46204
  function spellings(types, handle) {
45842
46205
  return types.map((type) => [type, handle]);
45843
46206
  }
46207
+ function stepTokens(stats) {
46208
+ return {
46209
+ inputTokens: firstNumber2(stats.input_tokens, stats.input),
46210
+ outputTokens: firstNumber2(stats.output_tokens) + firstNumber2(stats.thinking_tokens),
46211
+ cacheReadTokens: firstNumber2(stats.cache_read_tokens, stats.cached_input_tokens, stats.cached),
46212
+ cacheCreationTokens: 0
46213
+ };
46214
+ }
46215
+ function addStepTokens(total, step) {
46216
+ if (!total) return step;
46217
+ return {
46218
+ inputTokens: total.inputTokens + step.inputTokens,
46219
+ outputTokens: total.outputTokens + step.outputTokens,
46220
+ cacheReadTokens: total.cacheReadTokens + step.cacheReadTokens,
46221
+ cacheCreationTokens: total.cacheCreationTokens + step.cacheCreationTokens
46222
+ };
46223
+ }
45844
46224
  function firstNumber2(...values) {
45845
46225
  for (const value of values) {
45846
46226
  const number4 = asFiniteNumber(value);
@@ -46012,9 +46392,9 @@ var import_promises28, import_path13, import_fs9, import_path14, import_path15,
46012
46392
  var init_antigravity = __esm({
46013
46393
  "../agent-core/dist/providers/antigravity.js"() {
46014
46394
  "use strict";
46015
- init_chunk_D4TIXPWZ();
46016
- init_chunk_WD7O4DYQ();
46017
- init_chunk_OUEMTEUX();
46395
+ init_chunk_TFIO37PI();
46396
+ init_chunk_N2M5D7RS();
46397
+ init_chunk_RBQC7XZH();
46018
46398
  init_chunk_ZCTKXKYY();
46019
46399
  init_chunk_6VWVDJ2A();
46020
46400
  init_chunk_DLVRNIY5();
@@ -46372,6 +46752,11 @@ var init_antigravity = __esm({
46372
46752
  /** What `--conversation` takes: a frame's `conversation_id` wins over its `session_id`. */
46373
46753
  #conversationId;
46374
46754
  #forkReported = false;
46755
+ /** The conversation this turn runs in; a subagent's steps come under another id. */
46756
+ #rootConversation;
46757
+ /** The sum of this turn's own steps: the result's usage is the whole conversation's. */
46758
+ #stepSpend;
46759
+ #contextTokens;
46375
46760
  constructor(options) {
46376
46761
  this.#options = options;
46377
46762
  this.#conversationId = options.resumeId;
@@ -46418,7 +46803,9 @@ var init_antigravity = __esm({
46418
46803
  const type = asString(frame.type);
46419
46804
  if (!type) return [];
46420
46805
  this.#conversationId = antigravityString(frame, "conversation_id") ?? antigravityString(frame, "session_id") ?? this.#conversationId;
46806
+ this.#rootConversation ??= this.#conversationId;
46421
46807
  this.#track(type, frame);
46808
+ this.#noteStep(type, frame);
46422
46809
  const forked = this.#silentFork();
46423
46810
  if (SESSION_START_TYPES.has(type)) {
46424
46811
  return [
@@ -46433,6 +46820,29 @@ var init_antigravity = __esm({
46433
46820
  if (RESULT_TYPES.has(type)) return [...forked, ...this.#onResult(type, frame)];
46434
46821
  return [...forked, ...this.#transcripts?.read() ?? []];
46435
46822
  }
46823
+ /** A finished answer step of this conversation: one model call, with its own usage. */
46824
+ #noteStep(type, frame) {
46825
+ if (type !== "assistant_message" || asString(frame.state).toUpperCase() !== "DONE") return;
46826
+ const usage = asRecord(frame.usage);
46827
+ if (!usage) return;
46828
+ const conversation = antigravityString(frame, "conversation_id");
46829
+ if (conversation && this.#rootConversation && conversation !== this.#rootConversation) return;
46830
+ const step = stepTokens(usage);
46831
+ this.#stepSpend = addStepTokens(this.#stepSpend, step);
46832
+ const context = step.inputTokens + step.cacheReadTokens + step.outputTokens;
46833
+ if (context > 0) this.#contextTokens = context;
46834
+ }
46835
+ /**
46836
+ * agy's result usage is cumulative over the conversation, so a resumed turn's spend comes
46837
+ * from its steps; a first turn's result is its own.
46838
+ */
46839
+ #turnSpend(frame) {
46840
+ const steps = this.#stepSpend;
46841
+ this.#stepSpend = void 0;
46842
+ if (steps) return steps;
46843
+ if (this.#options.resumeId) return void 0;
46844
+ return stepTokens(asRecord(frame.usage) ?? asRecord(frame.stats) ?? frame);
46845
+ }
46436
46846
  #track(type, frame) {
46437
46847
  const transcripts = this.#transcripts;
46438
46848
  if (!transcripts) return;
@@ -46450,6 +46860,22 @@ var init_antigravity = __esm({
46450
46860
  this.#forkReported = true;
46451
46861
  return [noticeUpdate("warning", "session_resume_failed", RESUME_FORKED)];
46452
46862
  }
46863
+ #resultUsage(frame) {
46864
+ const spend = this.#turnSpend(frame);
46865
+ const contextTokens = this.#contextTokens;
46866
+ if (!spend && contextTokens === void 0) return [];
46867
+ const stats = asRecord(frame.usage) ?? asRecord(frame.stats) ?? frame;
46868
+ return [
46869
+ usageUpdate({
46870
+ model: formatAntigravityModelName(this.#model()),
46871
+ numTurns: Math.max(this.#iterations, 1),
46872
+ durationMs: asFiniteNumber(stats.duration_ms) ?? 0,
46873
+ ...spend,
46874
+ ...contextTokens === void 0 ? {} : { contextTokens },
46875
+ costUsd: 0
46876
+ })
46877
+ ];
46878
+ }
46453
46879
  #onResult(type, frame) {
46454
46880
  const updates = [];
46455
46881
  this.#iterations = Math.max(this.#iterations, asFiniteNumber(frame.num_turns) ?? 1);
@@ -46458,23 +46884,7 @@ var init_antigravity = __esm({
46458
46884
  updates.push(agentText(`antigravity-${this.#conversationId ?? "run"}-result`, resultText2));
46459
46885
  this.#resultShown = true;
46460
46886
  }
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
- );
46887
+ updates.push(...this.#resultUsage(frame));
46478
46888
  const status = asString(frame.status).toLowerCase();
46479
46889
  const succeeded = !status || SUCCESSFUL_STATUSES.has(status);
46480
46890
  if (succeeded) {
@@ -46717,8 +47127,8 @@ var import_promises29, import_path16, import_crypto20, COMMAND_CODE_GRAMMAR_NAME
46717
47127
  var init_command_code = __esm({
46718
47128
  "../agent-core/dist/providers/command-code.js"() {
46719
47129
  "use strict";
46720
- init_chunk_WD7O4DYQ();
46721
- init_chunk_OUEMTEUX();
47130
+ init_chunk_N2M5D7RS();
47131
+ init_chunk_RBQC7XZH();
46722
47132
  init_chunk_ZCTKXKYY();
46723
47133
  init_chunk_6VWVDJ2A();
46724
47134
  init_chunk_DLVRNIY5();
@@ -47083,6 +47493,7 @@ var init_command_code = __esm({
47083
47493
  #streamed = false;
47084
47494
  #totals;
47085
47495
  #result;
47496
+ #contextTokens;
47086
47497
  constructor(options) {
47087
47498
  this.#options = options;
47088
47499
  if (options.resumeId) this.#grammar.sessionId = options.resumeId;
@@ -47125,6 +47536,8 @@ var init_command_code = __esm({
47125
47536
  #onEvent(event) {
47126
47537
  switch (commandCodeString(event.type)) {
47127
47538
  case "model_request_end":
47539
+ this.#noteContext(event.usage);
47540
+ return this.#usage(event.usage);
47128
47541
  case "turn_end":
47129
47542
  return this.#usage(event.usage);
47130
47543
  case "run_end": {
@@ -47176,7 +47589,28 @@ var init_command_code = __esm({
47176
47589
  durationMs: durationMs ?? previous?.durationMs ?? 0
47177
47590
  };
47178
47591
  this.#totals = totals;
47179
- return [usageUpdate({ model: this.#model(), numTurns: 1, ...totals, costUsd: 0 })];
47592
+ return [
47593
+ usageUpdate({
47594
+ model: this.#model(),
47595
+ numTurns: 1,
47596
+ ...totals,
47597
+ // Command Code's own cost estimate takes cache out of inputTokens, which counts it.
47598
+ inputTokens: Math.max(
47599
+ totals.inputTokens - totals.cacheReadTokens - totals.cacheCreationTokens,
47600
+ 0
47601
+ ),
47602
+ ...this.#contextTokens === void 0 ? {} : { contextTokens: this.#contextTokens },
47603
+ costUsd: 0
47604
+ })
47605
+ ];
47606
+ }
47607
+ /** One model call's prompt, cache included, plus its reply: what it left in the window. */
47608
+ #noteContext(usage) {
47609
+ const record2 = asRecord(usage);
47610
+ const input2 = asFiniteNumber(record2?.inputTokens) ?? asFiniteNumber(record2?.input_tokens);
47611
+ if (input2 === void 0 || input2 <= 0) return;
47612
+ const output2 = asFiniteNumber(record2?.outputTokens) ?? asFiniteNumber(record2?.output_tokens);
47613
+ this.#contextTokens = input2 + (output2 ?? 0);
47180
47614
  }
47181
47615
  };
47182
47616
  COMMAND_CODE_MAX_TURNS = 1e4;
@@ -48450,6 +48884,7 @@ function runtimePaths(stateDir) {
48450
48884
 
48451
48885
  // src/platform/process-memory.ts
48452
48886
  var import_node_child_process4 = require("child_process");
48887
+ var import_node_fs6 = require("fs");
48453
48888
  var import_promises12 = require("fs/promises");
48454
48889
  var import_node_os2 = require("os");
48455
48890
  var import_node_util3 = require("util");
@@ -48489,6 +48924,45 @@ async function readProcessRss(pid) {
48489
48924
  return null;
48490
48925
  }
48491
48926
  }
48927
+ function parseDarwinVmStat(output2) {
48928
+ const pageSize = Number(/page size of (\d+) bytes/.exec(output2)?.[1]);
48929
+ if (!Number.isFinite(pageSize) || pageSize <= 0) return null;
48930
+ const pages = (name) => {
48931
+ const match = new RegExp(`^Pages ${name}:\\s+(\\d+)\\.?$`, "m").exec(output2);
48932
+ return match ? Number(match[1]) : null;
48933
+ };
48934
+ const free = pages("free");
48935
+ if (free === null) return null;
48936
+ return (free + (pages("inactive") ?? 0) + (pages("speculative") ?? 0)) * pageSize;
48937
+ }
48938
+ function parseLinuxMemInfo(output2) {
48939
+ const kilobytes = /^MemAvailable:\s+(\d+)\s+kB$/m.exec(output2)?.[1];
48940
+ return kilobytes === void 0 ? null : Number(kilobytes) * 1024;
48941
+ }
48942
+ var CAPACITY_PROBE_TTL_MS = 2e3;
48943
+ var AvailableMemoryProbe = class {
48944
+ cached = null;
48945
+ read(now) {
48946
+ if (this.cached !== null && now - this.cached.at < CAPACITY_PROBE_TTL_MS) {
48947
+ return this.cached.bytes;
48948
+ }
48949
+ let bytes = null;
48950
+ try {
48951
+ if (process.platform === "darwin") {
48952
+ bytes = parseDarwinVmStat(
48953
+ (0, import_node_child_process4.execFileSync)("vm_stat", { encoding: "utf8", timeout: PROBE_TIMEOUT_MS })
48954
+ );
48955
+ } else if (process.platform === "linux") {
48956
+ bytes = parseLinuxMemInfo((0, import_node_fs6.readFileSync)("/proc/meminfo", "utf8"));
48957
+ }
48958
+ } catch {
48959
+ bytes = null;
48960
+ }
48961
+ this.cached = { at: now, bytes };
48962
+ return bytes;
48963
+ }
48964
+ };
48965
+ var availableMemoryProbe = new AvailableMemoryProbe();
48492
48966
  async function processMemoryRows() {
48493
48967
  if (process.platform === "win32") {
48494
48968
  const { stdout: stdout2 } = await execFileAsync3(
@@ -48589,7 +49063,7 @@ var systemExec = (request2) => new Promise((resolve8) => {
48589
49063
  init_alan_code();
48590
49064
 
48591
49065
  // src/capabilities/providers/commands.ts
48592
- var import_node_fs6 = require("fs");
49066
+ var import_node_fs7 = require("fs");
48593
49067
  var import_promises17 = require("fs/promises");
48594
49068
  var import_node_path9 = require("path");
48595
49069
  var PROVIDER_COMMANDS = [
@@ -48627,7 +49101,7 @@ function pathDelimiter(platform) {
48627
49101
  async function isRunnable(path, platform) {
48628
49102
  try {
48629
49103
  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);
49104
+ if (platform !== "win32") await (0, import_promises17.access)(path, import_node_fs7.constants.X_OK);
48631
49105
  return true;
48632
49106
  } catch {
48633
49107
  return false;
@@ -49277,7 +49751,7 @@ async function inspectIndexedSkill(directory, contentHash) {
49277
49751
 
49278
49752
  // src/capabilities/skills/native-index.ts
49279
49753
  var import_node_crypto10 = require("crypto");
49280
- var import_node_fs7 = require("fs");
49754
+ var import_node_fs8 = require("fs");
49281
49755
  var import_promises21 = require("fs/promises");
49282
49756
  var import_node_path13 = require("path");
49283
49757
  var ALAN_SKILLS_PLUGIN_NAME = "alan";
@@ -49291,7 +49765,7 @@ var PLUGIN_MANIFEST = `${JSON.stringify(
49291
49765
  )}
49292
49766
  `;
49293
49767
  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;
49768
+ 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
49769
  }
49296
49770
 
49297
49771
  // src/capabilities/workspace/index.ts
@@ -49908,20 +50382,20 @@ async function prepareRunInputs(spec, { source, tmpDir, signal, skills = [] }) {
49908
50382
 
49909
50383
  // src/holder/serve.ts
49910
50384
  var import_node_crypto15 = require("crypto");
49911
- var import_node_fs11 = require("fs");
50385
+ var import_node_fs12 = require("fs");
49912
50386
  var import_node_net2 = require("net");
49913
50387
  var import_node_path29 = require("path");
49914
50388
  init_runtime_v2();
49915
50389
 
49916
50390
  // src/holder/admission.ts
49917
- var import_node_fs9 = require("fs");
50391
+ var import_node_fs10 = require("fs");
49918
50392
  var import_promises35 = require("fs/promises");
49919
50393
  var import_node_os6 = require("os");
49920
50394
  var import_node_path25 = require("path");
49921
50395
  init_constants();
49922
50396
 
49923
50397
  // ../shared/dist/node/local-workspace.js
49924
- var import_node_fs8 = require("fs");
50398
+ var import_node_fs9 = require("fs");
49925
50399
  var import_node_os5 = require("os");
49926
50400
  var import_node_path20 = require("path");
49927
50401
  function resolveAlanDefaultWorkspacePath(homeDirectory = (0, import_node_os5.homedir)()) {
@@ -50341,7 +50815,7 @@ async function inspectReadiness(path) {
50341
50815
  if (!(await (0, import_promises35.stat)(path)).isDirectory()) {
50342
50816
  return { ready: false, missing: true, message: MESSAGES.missing };
50343
50817
  }
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);
50818
+ 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
50819
  return { ready: true };
50346
50820
  } catch (error62) {
50347
50821
  const code = errnoCode(error62) ?? "";
@@ -50386,7 +50860,7 @@ async function admitDefaultWorkspace(spec, context, skills) {
50386
50860
  const path = resolveAlanDefaultWorkspacePath(env.HOME || env.USERPROFILE || (0, import_node_os6.homedir)());
50387
50861
  try {
50388
50862
  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);
50863
+ 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
50864
  return { kind: "admitted", spec: { ...spec, projectPath: path }, skills };
50391
50865
  } catch (error62) {
50392
50866
  const code = errnoCode(error62);
@@ -50725,13 +51199,13 @@ function runEnded(input2) {
50725
51199
  var decoder = new TextDecoder();
50726
51200
 
50727
51201
  // src/run-log/writer.ts
50728
- var import_node_fs10 = require("fs");
51202
+ var import_node_fs11 = require("fs");
50729
51203
  var import_node_path28 = require("path");
50730
51204
  init_runtime_v2();
50731
51205
  function lastSeq(fd, size) {
50732
51206
  for (const length of tailWindows(size)) {
50733
51207
  const buffer = Buffer.alloc(length);
50734
- (0, import_node_fs10.readSync)(fd, buffer, 0, length, size - length);
51208
+ (0, import_node_fs11.readSync)(fd, buffer, 0, length, size - length);
50735
51209
  const last = lastLine(buffer.toString("utf8").trimEnd(), length === size);
50736
51210
  if (last === void 0) continue;
50737
51211
  if (last.length === 0) return 0;
@@ -50742,13 +51216,13 @@ function lastSeq(fd, size) {
50742
51216
  throw new RuntimeFault("record_too_large", "Run log tail record is larger than any record");
50743
51217
  }
50744
51218
  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;
51219
+ (0, import_node_fs11.mkdirSync)((0, import_node_path28.dirname)(path), { recursive: true, mode: 448 });
51220
+ const fd = (0, import_node_fs11.openSync)(path, "a+", 384);
51221
+ let size = (0, import_node_fs11.fstatSync)(fd).size;
50748
51222
  let seq = lastSeq(fd, size);
50749
51223
  let dirty = false;
50750
51224
  const sync = () => {
50751
- (0, import_node_fs10.fsyncSync)(fd);
51225
+ (0, import_node_fs11.fsyncSync)(fd);
50752
51226
  dirty = false;
50753
51227
  };
50754
51228
  return {
@@ -50762,7 +51236,7 @@ function openRunLog(path, clock) {
50762
51236
  };
50763
51237
  const line = Buffer.from(`${JSON.stringify(record2)}
50764
51238
  `, "utf8");
50765
- (0, import_node_fs10.writeSync)(fd, line);
51239
+ (0, import_node_fs11.writeSync)(fd, line);
50766
51240
  size += line.length;
50767
51241
  dirty = true;
50768
51242
  if (isRunLifecycleKind(update.sessionUpdate)) sync();
@@ -50774,7 +51248,7 @@ function openRunLog(path, clock) {
50774
51248
  },
50775
51249
  [Symbol.dispose]: () => {
50776
51250
  if (dirty) sync();
50777
- (0, import_node_fs10.closeSync)(fd);
51251
+ (0, import_node_fs11.closeSync)(fd);
50778
51252
  }
50779
51253
  };
50780
51254
  }
@@ -51218,7 +51692,7 @@ async function runHolder({
51218
51692
  for (const client of holder.clients) client.end();
51219
51693
  await new Promise((resolve8) => server.close(() => resolve8()));
51220
51694
  await statusWrites;
51221
- (0, import_node_fs11.rmSync)(launch.statusPath, { force: true });
51695
+ (0, import_node_fs12.rmSync)(launch.statusPath, { force: true });
51222
51696
  log.info("holder.suspended", { conversationId: launch.conversationId });
51223
51697
  } catch (_) {
51224
51698
  var _error = _, _hasError = true;
@@ -51229,6 +51703,7 @@ async function runHolder({
51229
51703
 
51230
51704
  // src/sessions/suspend-policy.ts
51231
51705
  var GIB = 1024 ** 3;
51706
+ var SESSION_MEMORY_CEILING_BYTES = 2.5 * GIB;
51232
51707
  var MEMORY_BUDGET_SHARE = 0.15;
51233
51708
  var MEMORY_BUDGET_MIN_BYTES = GIB;
51234
51709
  var MEMORY_BUDGET_MAX_BYTES = 4 * GIB;
@@ -51257,7 +51732,8 @@ var envSchema = external_exports.object({
51257
51732
  ALAN_RUNTIME_LOG_LEVEL: external_exports.enum(["debug", "info", "warn", "error"]).default("info"),
51258
51733
  ALAN_RUNTIME_SUSPEND_IDLE_MS: external_exports.coerce.number().int().positive().optional(),
51259
51734
  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),
51735
+ // A two-minute conditional GET bounds recovery after a lost poke; unchanged state returns 304.
51736
+ ALAN_RUNTIME_DESIRED_RESYNC_MS: external_exports.coerce.number().int().positive().default(12e4),
51261
51737
  ALAN_MAX_ACTIVE_RUNS: external_exports.coerce.number().int().optional(),
51262
51738
  ALAN_RUNTIME_API_URL: external_exports.url().optional(),
51263
51739
  ALAN_RUNTIME_CREDENTIAL_STORE: external_exports.enum(CREDENTIAL_STORE_KINDS).optional(),