@workerdeck/core 2.8.0 → 2.10.0

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.
package/build/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { createRequire } from "node:module";
2
2
  import { createHash, randomUUID } from "node:crypto";
3
3
  import { getSessionInfo, getSessionMessages, listSessions, query } from "@anthropic-ai/claude-agent-sdk";
4
- import { CHECKLIST_TEXT_MAX, ENGINE_CAPABILITIES, PROTOCOL_VERSION, SUBAGENT_HISTORY, TOOL_RESULT_HEAD_CHARS, contextReading, imagePartRef, parseTodoWriteInput, replayCoalesceKey, replayRetains, sanitizeToolTitle, snapshotRetains, transcriptActivity, transcriptContent, transcriptProse } from "@workerdeck/protocol";
4
+ import { CHECKLIST_TEXT_MAX, ENGINE_CAPABILITIES, PROTOCOL_VERSION, SUBAGENT_HISTORY, TOOL_RESULT_HEAD_CHARS, addTokenUsage, byModelTotalTokens, canonicalModel, contextReading, costOfByModel, emptyTokenUsage, imagePartRef, mergeByModel, parseTodoWriteInput, replayCoalesceKey, replayRetains, sanitizeToolTitle, snapshotRetains, tokenUsageFromWire, totalTokens, transcriptActivity, transcriptContent, transcriptProse } from "@workerdeck/protocol";
5
5
  import { ToolLoopAgent, generateText, isStepCount, tool } from "ai";
6
6
  import { execFile, spawn } from "node:child_process";
7
7
  import { appendFileSync, existsSync, mkdirSync, readFileSync, realpathSync, rmSync, statSync, writeFileSync } from "node:fs";
@@ -273,6 +273,18 @@ function parseUnifiedDiff(diff, path) {
273
273
  }
274
274
  //#endregion
275
275
  //#region src/lib/normalize.ts
276
+ function byModelFromSdk(modelUsage) {
277
+ if (!modelUsage) return;
278
+ const out = {};
279
+ for (const [model, entry] of Object.entries(modelUsage)) out[entry.canonicalModel ?? canonicalModel(model)] = {
280
+ ...emptyTokenUsage(),
281
+ input: Math.max(0, entry.inputTokens ?? 0),
282
+ output: Math.max(0, entry.outputTokens ?? 0),
283
+ cacheWrite5m: Math.max(0, entry.cacheCreationInputTokens ?? 0),
284
+ cacheRead: Math.max(0, entry.cacheReadInputTokens ?? 0)
285
+ };
286
+ return Object.keys(out).length === 0 ? void 0 : out;
287
+ }
276
288
  const FAMILY_ORDER = [
277
289
  "fable",
278
290
  "opus",
@@ -445,7 +457,8 @@ function normalizeSdkMessage(msg) {
445
457
  totalCostUsd: msg.total_cost_usd,
446
458
  result: msg.subtype === "success" ? msg.result : void 0,
447
459
  errors: msg.subtype === "success" ? void 0 : msg.errors,
448
- usage: msg.usage
460
+ usage: msg.usage,
461
+ usageByModel: byModelFromSdk(msg.modelUsage)
449
462
  };
450
463
  case "conversation_reset": return {
451
464
  type: "conversation_reset",
@@ -480,6 +493,157 @@ function resolveApprovalTimeoutMs(session, fallback) {
480
493
  return value === void 0 || value === null || value <= 0 ? void 0 : value;
481
494
  }
482
495
  //#endregion
496
+ //#region src/lib/cost-ledger.ts
497
+ function emptyBucket() {
498
+ return {
499
+ byModel: {},
500
+ reportedUsd: void 0
501
+ };
502
+ }
503
+ function bucketOf(figures) {
504
+ return {
505
+ byModel: figures.byModel ?? {},
506
+ reportedUsd: figures.reportedCostUsd
507
+ };
508
+ }
509
+ function figuresOf(bucket) {
510
+ return {
511
+ byModel: Object.keys(bucket.byModel).length === 0 ? void 0 : bucket.byModel,
512
+ reportedCostUsd: bucket.reportedUsd
513
+ };
514
+ }
515
+ function addBuckets(into, add) {
516
+ const reportedUsd = into.reportedUsd === void 0 && add.reportedUsd === void 0 ? void 0 : (into.reportedUsd ?? 0) + (add.reportedUsd ?? 0);
517
+ return {
518
+ byModel: mergeByModel(into.byModel, add.byModel),
519
+ reportedUsd
520
+ };
521
+ }
522
+ function subtractUsage(from, part) {
523
+ return {
524
+ input: Math.max(0, from.input - part.input),
525
+ output: Math.max(0, from.output - part.output),
526
+ cacheWrite5m: Math.max(0, from.cacheWrite5m - part.cacheWrite5m),
527
+ cacheWrite1h: Math.max(0, from.cacheWrite1h - part.cacheWrite1h),
528
+ cacheRead: Math.max(0, from.cacheRead - part.cacheRead)
529
+ };
530
+ }
531
+ function subtractBuckets(from, part) {
532
+ const byModel = {};
533
+ for (const [model, usage] of Object.entries(from.byModel)) {
534
+ const taken = part.byModel[model];
535
+ const rest = taken ? subtractUsage(usage, taken) : usage;
536
+ if (totalTokens(rest) > 0) byModel[model] = rest;
537
+ }
538
+ return {
539
+ byModel,
540
+ reportedUsd: from.reportedUsd === void 0 ? void 0 : Math.max(0, from.reportedUsd - (part.reportedUsd ?? 0))
541
+ };
542
+ }
543
+ function isEmpty(bucket) {
544
+ return byModelTotalTokens(bucket.byModel) === 0 && !((bucket.reportedUsd ?? 0) > 0);
545
+ }
546
+ function canonicalByModel(byModel) {
547
+ const out = {};
548
+ for (const [model, usage] of Object.entries(byModel)) {
549
+ const key = canonicalModel(model);
550
+ out[key] = addTokenUsage(out[key] ?? emptyTokenUsage(), usage);
551
+ }
552
+ return out;
553
+ }
554
+ function coversUsage(have, need) {
555
+ return have.input >= need.input && have.output >= need.output && have.cacheWrite5m >= need.cacheWrite5m && have.cacheWrite1h >= need.cacheWrite1h && have.cacheRead >= need.cacheRead;
556
+ }
557
+ function covers(reading, baseline) {
558
+ let compared = false;
559
+ if (baseline.reportedUsd !== void 0 && reading.reportedUsd !== void 0) {
560
+ if (reading.reportedUsd < baseline.reportedUsd) return false;
561
+ compared = true;
562
+ }
563
+ if (byModelTotalTokens(reading.byModel) > 0 && byModelTotalTokens(baseline.byModel) > 0) {
564
+ const have = canonicalByModel(reading.byModel);
565
+ for (const [model, need] of Object.entries(canonicalByModel(baseline.byModel))) {
566
+ if (totalTokens(need) === 0) continue;
567
+ const got = have[model];
568
+ if (!got || !coversUsage(got, need)) return false;
569
+ }
570
+ compared = true;
571
+ }
572
+ return compared;
573
+ }
574
+ var CostLedger = class {
575
+ #carried = emptyBucket();
576
+ #pending;
577
+ #current = emptyBucket();
578
+ carry(state) {
579
+ if (!state) return;
580
+ this.#carried = addBuckets(this.#carried, bucketOf(state));
581
+ }
582
+ carryUnlessRestored(state) {
583
+ if (!state) return;
584
+ const whole = bucketOf(state);
585
+ const lifetime = state.lifetime ? bucketOf(state.lifetime) : whole;
586
+ if (state.lifetime) this.#carried = addBuckets(this.#carried, subtractBuckets(whole, lifetime));
587
+ this.#pending = addBuckets(this.#pending ?? emptyBucket(), lifetime);
588
+ }
589
+ observeCumulative(byModel, reportedCostUsd) {
590
+ const reading = {
591
+ byModel: byModel ?? {},
592
+ reportedUsd: reportedCostUsd
593
+ };
594
+ if (this.#pending && !isEmpty(reading)) {
595
+ if (!covers(reading, this.#pending)) this.#carried = addBuckets(this.#carried, this.#pending);
596
+ this.#pending = void 0;
597
+ }
598
+ if (byModel !== void 0) this.#current = {
599
+ ...this.#current,
600
+ byModel
601
+ };
602
+ if (reportedCostUsd !== void 0) this.#current = {
603
+ ...this.#current,
604
+ reportedUsd: reportedCostUsd
605
+ };
606
+ }
607
+ observeDelta(byModel) {
608
+ this.#current = {
609
+ ...this.#current,
610
+ byModel: mergeByModel(this.#current.byModel, byModel)
611
+ };
612
+ }
613
+ rollover() {
614
+ this.#carried = addBuckets(this.#carried, this.#lifetime());
615
+ this.#pending = void 0;
616
+ this.#current = emptyBucket();
617
+ }
618
+ get byModel() {
619
+ return figuresOf(this.#total()).byModel;
620
+ }
621
+ get breakdown() {
622
+ return costOfByModel(this.byModel ?? {});
623
+ }
624
+ get costUsd() {
625
+ const byModel = this.byModel;
626
+ if (!byModel) return;
627
+ const cost = costOfByModel(byModel);
628
+ return cost.unpriced ? void 0 : cost.total;
629
+ }
630
+ get reportedCostUsd() {
631
+ return this.#total().reportedUsd;
632
+ }
633
+ snapshot() {
634
+ return {
635
+ ...figuresOf(this.#total()),
636
+ lifetime: figuresOf(this.#lifetime())
637
+ };
638
+ }
639
+ #lifetime() {
640
+ return addBuckets(this.#pending ?? emptyBucket(), this.#current);
641
+ }
642
+ #total() {
643
+ return addBuckets(this.#carried, this.#lifetime());
644
+ }
645
+ };
646
+ //#endregion
483
647
  //#region src/lib/event-log.ts
484
648
  var EventLog = class {
485
649
  #events = [];
@@ -904,6 +1068,7 @@ function toolUseBlocks(content) {
904
1068
  }
905
1069
  //#endregion
906
1070
  //#region src/engines/claude/runner.ts
1071
+ const USAGE_REFRESH_MIN_MS = 6e4;
907
1072
  var SessionRunner = class {
908
1073
  id;
909
1074
  createdAt;
@@ -920,7 +1085,7 @@ var SessionRunner = class {
920
1085
  #pending = /* @__PURE__ */ new Map();
921
1086
  #turnOverWhileBlocked = false;
922
1087
  #subagents = new SubagentTracker();
923
- #totalCostUsd;
1088
+ #cost = new CostLedger();
924
1089
  #numTurns;
925
1090
  #input = new InputQueue();
926
1091
  #pendingLocalCommands = [];
@@ -929,8 +1094,11 @@ var SessionRunner = class {
929
1094
  #idleWhileCompacting = false;
930
1095
  #query;
931
1096
  #capabilitiesEmitted = false;
1097
+ #models;
1098
+ #defaultModel;
932
1099
  #subscriptionType;
933
1100
  #engineTitle;
1101
+ #lastRateLimitPoll = 0;
934
1102
  #started = false;
935
1103
  #closed = false;
936
1104
  #runPromise;
@@ -982,7 +1150,9 @@ var SessionRunner = class {
982
1150
  meta: this.#config.meta,
983
1151
  scope: this.#config.scope,
984
1152
  title: sessionTitle(this.#config, this.#engineTitle),
985
- totalCostUsd: this.#totalCostUsd,
1153
+ totalCostUsd: this.#cost.reportedCostUsd,
1154
+ costUsd: this.#cost.costUsd,
1155
+ usageByModel: this.#cost.byModel,
986
1156
  numTurns: this.#numTurns,
987
1157
  lastActivityAt: this.#log.lastActivityAt
988
1158
  };
@@ -990,6 +1160,12 @@ var SessionRunner = class {
990
1160
  setTitle(title) {
991
1161
  this.#config = withTitle(this.#config, title);
992
1162
  }
1163
+ carryCost(state) {
1164
+ this.#cost.carryUnlessRestored(state);
1165
+ }
1166
+ costState() {
1167
+ return this.#cost.snapshot();
1168
+ }
993
1169
  start() {
994
1170
  if (this.#started) return this.#runPromise;
995
1171
  this.#started = true;
@@ -1254,6 +1430,10 @@ var SessionRunner = class {
1254
1430
  else if (msg.state === "running") this.#setStatus("running");
1255
1431
  return;
1256
1432
  }
1433
+ if (msg.type === "system" && msg.subtype === "commands_changed") {
1434
+ if (this.#capabilitiesEmitted && !this.#closed) this.#emitCapabilities(msg.commands);
1435
+ return;
1436
+ }
1257
1437
  if (msg.type === "system" && msg.subtype === "status") this.#handleCompactionStatus(msg);
1258
1438
  if (msg.type === "system" && msg.subtype === "compact_boundary") {
1259
1439
  const meta = msg.compact_metadata;
@@ -1269,6 +1449,7 @@ var SessionRunner = class {
1269
1449
  if (body) {
1270
1450
  this.#emit(body);
1271
1451
  if (body.type === "conversation_reset") {
1452
+ this.#cost.rollover();
1272
1453
  this.#pendingLocalCommands = [];
1273
1454
  if (body.sdkSessionId) this.#sdkSessionId = body.sdkSessionId;
1274
1455
  this.#fetchContextUsage();
@@ -1276,7 +1457,10 @@ var SessionRunner = class {
1276
1457
  if (body.type === "turn_result") {
1277
1458
  this.#compactionTurns += 1;
1278
1459
  if (this.#compactionTurns > 1) this.#settleCompaction();
1279
- this.#totalCostUsd = body.totalCostUsd;
1460
+ this.#cost.observeCumulative(body.usageByModel, body.totalCostUsd);
1461
+ body.totalCostUsd = this.#cost.reportedCostUsd ?? body.totalCostUsd;
1462
+ body.usageByModel = this.#cost.byModel;
1463
+ body.costUsd = this.#cost.costUsd;
1280
1464
  this.#numTurns = body.numTurns;
1281
1465
  if (this.#pending.size === 0) this.#setStatus("idle");
1282
1466
  else this.#turnOverWhileBlocked = true;
@@ -1330,19 +1514,24 @@ var SessionRunner = class {
1330
1514
  const [models, commands] = await Promise.all([query.supportedModels(), query.supportedCommands()]);
1331
1515
  if (this.#closed || this.#capabilitiesEmitted) return;
1332
1516
  this.#capabilitiesEmitted = true;
1333
- this.#emit({
1334
- type: "capabilities",
1335
- models: modelOptionsFromSdk(models),
1336
- defaultModel: defaultModelFromSdk(models),
1337
- commands: commands.map((c) => ({
1338
- name: c.name,
1339
- description: c.description,
1340
- argumentHint: c.argumentHint,
1341
- aliases: c.aliases
1342
- }))
1343
- });
1517
+ this.#models = modelOptionsFromSdk(models);
1518
+ this.#defaultModel = defaultModelFromSdk(models);
1519
+ this.#emitCapabilities(commands);
1344
1520
  } catch {}
1345
1521
  }
1522
+ #emitCapabilities(commands) {
1523
+ this.#emit({
1524
+ type: "capabilities",
1525
+ models: this.#models ?? [],
1526
+ defaultModel: this.#defaultModel,
1527
+ commands: commands.map((c) => ({
1528
+ name: c.name,
1529
+ description: c.description,
1530
+ argumentHint: c.argumentHint,
1531
+ aliases: c.aliases
1532
+ }))
1533
+ });
1534
+ }
1346
1535
  async #fetchEngineTitle() {
1347
1536
  if (hostTitle(this.#config.meta)) return;
1348
1537
  const sdkSessionId = this.#sdkSessionId;
@@ -1378,7 +1567,12 @@ var SessionRunner = class {
1378
1567
  });
1379
1568
  } catch {}
1380
1569
  }
1570
+ async refreshUsage(minIntervalMs = USAGE_REFRESH_MIN_MS) {
1571
+ if (Date.now() - this.#lastRateLimitPoll < minIntervalMs) return;
1572
+ await this.#fetchRateLimits();
1573
+ }
1381
1574
  async #fetchRateLimits() {
1575
+ this.#lastRateLimitPoll = Date.now();
1382
1576
  const query = this.#query;
1383
1577
  const fetchUsage = query?.usage_EXPERIMENTAL_MAY_CHANGE_DO_NOT_RELY_ON_THIS_API_YET;
1384
1578
  if (typeof fetchUsage !== "function") return;
@@ -1569,12 +1763,7 @@ var AiSdkRunner = class {
1569
1763
  #abort;
1570
1764
  #turnAccum;
1571
1765
  #numTurns = 0;
1572
- #totalUsage = {
1573
- input: 0,
1574
- output: 0,
1575
- cacheWrite: 0,
1576
- cacheRead: 0
1577
- };
1766
+ #cost = new CostLedger();
1578
1767
  #started = false;
1579
1768
  #closed = false;
1580
1769
  #parked = false;
@@ -1598,10 +1787,15 @@ var AiSdkRunner = class {
1598
1787
  this.#log.restore(snapshot.events, snapshot.seq, state.lastActivityAt);
1599
1788
  this.#messages = [...state.messages];
1600
1789
  this.#pendingLocalCommands = [...state.pendingLocalCommands ?? []];
1601
- for (const call of state.pendingToolCalls) this.#pendingToolCalls.set(call.toolCallId, call);
1790
+ for (const call of state.pendingToolCalls) {
1791
+ const legacy = call.deferred;
1792
+ this.#pendingToolCalls.set(call.toolCallId, legacy === void 0 ? call : {
1793
+ ...call,
1794
+ parkable: call.parkable ?? legacy
1795
+ });
1796
+ }
1602
1797
  this.#dispatched = new Set(state.dispatched);
1603
1798
  this.#numTurns = state.numTurns;
1604
- this.#totalUsage = { ...state.totalUsage };
1605
1799
  this.#turnAccum = state.turnAccum ? { ...state.turnAccum } : void 0;
1606
1800
  if (this.#turnAccum && state.parkedAt !== void 0) this.#turnAccum.startedAt += Date.now() - state.parkedAt;
1607
1801
  this.#permissionMode = state.permissionMode;
@@ -1654,9 +1848,20 @@ var AiSdkRunner = class {
1654
1848
  scope: this.#config.scope,
1655
1849
  title: sessionTitle(this.#config),
1656
1850
  numTurns: this.#numTurns || void 0,
1851
+ costUsd: this.#cost.costUsd,
1852
+ usageByModel: this.#cost.byModel,
1657
1853
  lastActivityAt: this.#log.lastActivityAt
1658
1854
  };
1659
1855
  }
1856
+ carryCost(state) {
1857
+ this.#cost.carry(state);
1858
+ }
1859
+ costState() {
1860
+ return this.#cost.snapshot();
1861
+ }
1862
+ #turnByModel(accum) {
1863
+ return { [this.#modelId() ?? "unknown"]: tokenUsageFromWire(turnUsage(accum)) };
1864
+ }
1660
1865
  start() {
1661
1866
  if (this.#started) return this.#turnChain;
1662
1867
  this.#started = true;
@@ -1694,7 +1899,6 @@ var AiSdkRunner = class {
1694
1899
  pendingToolCalls: [...this.#pendingToolCalls.values()],
1695
1900
  dispatched: [...this.#dispatched],
1696
1901
  numTurns: this.#numTurns,
1697
- totalUsage: { ...this.#totalUsage },
1698
1902
  turnAccum: this.#turnAccum ? { ...this.#turnAccum } : void 0,
1699
1903
  permissionMode: this.#permissionMode,
1700
1904
  model: this.#modelAlias,
@@ -2072,14 +2276,14 @@ var AiSdkRunner = class {
2072
2276
  signal: this.#abort?.signal
2073
2277
  };
2074
2278
  const profile = executor.describe?.(toolCall) ?? {};
2075
- call.deferred = profile.deferred === true ? true : void 0;
2279
+ call.parkable = profile.deferred === true ? true : void 0;
2076
2280
  call.expiresAt = profile.timeoutMs === void 0 ? void 0 : Date.now() + profile.timeoutMs;
2077
2281
  this.#emit({
2078
2282
  type: "execution_dispatched",
2079
2283
  executionId: call.toolCallId,
2080
2284
  toolName: call.toolName,
2081
2285
  backend: profile.backend ?? this.#config.executionBackend ?? "server",
2082
- deferred: call.deferred,
2286
+ deferred: call.parkable,
2083
2287
  expiresAt: call.expiresAt
2084
2288
  });
2085
2289
  const promise = executor.dispatch(toolCall).then((dispatch) => {
@@ -2092,7 +2296,7 @@ var AiSdkRunner = class {
2092
2296
  });
2093
2297
  });
2094
2298
  return {
2095
- deferred: call.deferred === true,
2299
+ deferred: call.parkable === true,
2096
2300
  promise
2097
2301
  };
2098
2302
  }
@@ -2102,7 +2306,7 @@ var AiSdkRunner = class {
2102
2306
  }
2103
2307
  #restingOnDeferred() {
2104
2308
  if (this.#pendingToolCalls.size === 0) return false;
2105
- for (const call of this.#pendingToolCalls.values()) if (call.deferred !== true) return false;
2309
+ for (const call of this.#pendingToolCalls.values()) if (call.parkable !== true) return false;
2106
2310
  return true;
2107
2311
  }
2108
2312
  #applyExecutionResult(executionId, result) {
@@ -2340,10 +2544,8 @@ var AiSdkRunner = class {
2340
2544
  cacheRead: 0
2341
2545
  };
2342
2546
  this.#numTurns += 1;
2343
- this.#totalUsage.input += accum.input;
2344
- this.#totalUsage.output += accum.output;
2345
- this.#totalUsage.cacheWrite += accum.cacheWrite;
2346
- this.#totalUsage.cacheRead += accum.cacheRead;
2547
+ const byModel = this.#turnByModel(accum);
2548
+ this.#cost.observeDelta(byModel);
2347
2549
  this.#emit({
2348
2550
  type: "turn_result",
2349
2551
  subtype: "success",
@@ -2352,7 +2554,9 @@ var AiSdkRunner = class {
2352
2554
  numTurns: this.#numTurns,
2353
2555
  totalCostUsd: 0,
2354
2556
  result: text,
2355
- usage: turnUsage(accum)
2557
+ usage: turnUsage(accum),
2558
+ usageByModel: this.#cost.byModel,
2559
+ costUsd: this.#cost.costUsd
2356
2560
  });
2357
2561
  this.#turnAccum = void 0;
2358
2562
  this.#setStatus("idle");
@@ -3999,6 +4203,29 @@ function skillInfo(skill) {
3999
4203
  enabled: skill.enabled !== false
4000
4204
  };
4001
4205
  }
4206
+ const SKILL_MENTION = /(^|[^A-Za-z0-9_$-])\$([a-z0-9][a-z0-9-]*)(?![A-Za-z0-9_-])/g;
4207
+ function withSkillItems(input, paths) {
4208
+ const present = new Set(input.flatMap((item) => item.type === "skill" ? [item.name] : []));
4209
+ const added = [];
4210
+ for (const item of input) {
4211
+ if (item.type !== "text") continue;
4212
+ for (const match of item.text.matchAll(SKILL_MENTION)) {
4213
+ const name = match[2];
4214
+ const path = paths.get(name);
4215
+ if (path === void 0 || present.has(name)) continue;
4216
+ present.add(name);
4217
+ added.push({
4218
+ type: "skill",
4219
+ name,
4220
+ path
4221
+ });
4222
+ }
4223
+ }
4224
+ return added.length > 0 ? [...input, ...added] : [...input];
4225
+ }
4226
+ function mentionsSkill(input) {
4227
+ return input.some((item) => item.type === "text" && /(^|[^A-Za-z0-9_$-])\$[a-z0-9]/.test(item.text));
4228
+ }
4002
4229
  function mcpStatusOf(authStatus, update, hasTools) {
4003
4230
  if (update?.status === "failed") return update.failureReason === "reauthenticationRequired" ? "needs-auth" : "failed";
4004
4231
  if (update?.status === "cancelled") return "failed";
@@ -4227,7 +4454,7 @@ var CodexRunner = class {
4227
4454
  #workspaceWrite;
4228
4455
  #threadLoaded = false;
4229
4456
  #numTurns = 0;
4230
- #totalCostUsd;
4457
+ #cost = new CostLedger();
4231
4458
  #started = false;
4232
4459
  #closed = false;
4233
4460
  #imageDir;
@@ -4237,6 +4464,7 @@ var CodexRunner = class {
4237
4464
  #replayingHistory = false;
4238
4465
  #skillsFingerprint;
4239
4466
  #skillsRefresh;
4467
+ #skillPaths = /* @__PURE__ */ new Map();
4240
4468
  #producedPaths = /* @__PURE__ */ new Set();
4241
4469
  #mcpStatus = /* @__PURE__ */ new Map();
4242
4470
  #agents = new CodexAgentTracker();
@@ -4294,7 +4522,9 @@ var CodexRunner = class {
4294
4522
  meta: this.#config.meta,
4295
4523
  scope: this.#config.scope,
4296
4524
  title: sessionTitle(this.#config),
4297
- totalCostUsd: this.#totalCostUsd,
4525
+ totalCostUsd: this.#cost.reportedCostUsd,
4526
+ costUsd: this.#cost.costUsd,
4527
+ usageByModel: this.#cost.byModel,
4298
4528
  numTurns: this.#numTurns || void 0,
4299
4529
  lastActivityAt: this.#log.lastActivityAt,
4300
4530
  subagents: this.#agents.list(),
@@ -4304,6 +4534,12 @@ var CodexRunner = class {
4304
4534
  setTitle(title) {
4305
4535
  this.#config = withTitle(this.#config, title);
4306
4536
  }
4537
+ carryCost(state) {
4538
+ this.#cost.carry(state);
4539
+ }
4540
+ costState() {
4541
+ return this.#cost.snapshot();
4542
+ }
4307
4543
  start() {
4308
4544
  if (this.#started) return this.#turnChain;
4309
4545
  this.#started = true;
@@ -4460,7 +4696,7 @@ var CodexRunner = class {
4460
4696
  type: "text",
4461
4697
  text: context
4462
4698
  });
4463
- return parts;
4699
+ return withSkillItems(parts, this.#skillPaths);
4464
4700
  }
4465
4701
  queueLocalCommand(result) {
4466
4702
  if (this.#closed) throw new Error("session is closed");
@@ -4692,11 +4928,14 @@ var CodexRunner = class {
4692
4928
  const entries = Array.isArray(result?.data) ? result.data : [];
4693
4929
  const seen = /* @__PURE__ */ new Set();
4694
4930
  const skills = [];
4931
+ const paths = /* @__PURE__ */ new Map();
4695
4932
  for (const entry of entries) for (const skill of entry?.skills ?? []) {
4696
4933
  if (typeof skill?.name !== "string" || seen.has(skill.name)) continue;
4697
4934
  seen.add(skill.name);
4698
4935
  skills.push(skillInfo(skill));
4936
+ if (typeof skill.path === "string" && skill.path) paths.set(skill.name, skill.path);
4699
4937
  }
4938
+ this.#skillPaths = paths;
4700
4939
  skills.sort((a, b) => a.name.localeCompare(b.name));
4701
4940
  const fingerprint = JSON.stringify(skills);
4702
4941
  if (fingerprint === this.#skillsFingerprint) return;
@@ -4848,6 +5087,10 @@ var CodexRunner = class {
4848
5087
  this.#activeTurn = active;
4849
5088
  try {
4850
5089
  const connection = await this.#ensureThread();
5090
+ if (mentionsSkill(turn.input)) {
5091
+ await this.#skillsRefresh;
5092
+ turn.input = withSkillItems(turn.input, this.#skillPaths);
5093
+ }
4851
5094
  const params = {
4852
5095
  threadId: this.#sdkSessionId,
4853
5096
  input: turn.input,
@@ -5395,23 +5638,27 @@ var CodexRunner = class {
5395
5638
  message: "Turn ended"
5396
5639
  }, "policy");
5397
5640
  this.#numTurns += 1;
5398
- this.#totalCostUsd = 0;
5399
5641
  const usage = active.sawUsage ? active.usage : void 0;
5642
+ const wire = usage ? {
5643
+ input_tokens: Math.max(0, usage.inputTokens - usage.cachedInputTokens),
5644
+ output_tokens: usage.outputTokens + usage.reasoningOutputTokens,
5645
+ cache_creation_input_tokens: usage.cacheWriteInputTokens ?? 0,
5646
+ cache_read_input_tokens: usage.cachedInputTokens
5647
+ } : void 0;
5648
+ const turnByModel = wire ? { [this.#model ?? this.#resolvedModel ?? "unknown"]: tokenUsageFromWire(wire) } : void 0;
5649
+ if (turnByModel) this.#cost.observeDelta(turnByModel);
5400
5650
  this.#emit({
5401
5651
  type: "turn_result",
5402
5652
  subtype: kind === "success" ? "success" : "error_during_execution",
5403
5653
  isError: kind !== "success",
5404
5654
  durationMs: Date.now() - startedAt,
5405
5655
  numTurns: this.#numTurns,
5406
- totalCostUsd: 0,
5656
+ totalCostUsd: this.#cost.reportedCostUsd ?? 0,
5407
5657
  result: kind === "success" ? active.finalText ?? "" : void 0,
5408
5658
  errors,
5409
- usage: usage ? {
5410
- input_tokens: Math.max(0, usage.inputTokens - usage.cachedInputTokens),
5411
- output_tokens: usage.outputTokens + usage.reasoningOutputTokens,
5412
- cache_creation_input_tokens: usage.cacheWriteInputTokens ?? 0,
5413
- cache_read_input_tokens: usage.cachedInputTokens
5414
- } : void 0
5659
+ usage: wire,
5660
+ usageByModel: this.#cost.byModel,
5661
+ costUsd: this.#cost.costUsd
5415
5662
  });
5416
5663
  this.#emitContextUsage(active);
5417
5664
  this.#setStatus("idle");
@@ -5783,6 +6030,6 @@ function getEngineAdapter(engine) {
5783
6030
  return ADAPTERS[engine ?? "claude"];
5784
6031
  }
5785
6032
  //#endregion
5786
- export { AiSdkRunner, BrowserBridgeExecutor, CLAUDE_CATALOG, CODEX_CATALOG, CodexRunner, DeferredExecutor, InputQueue, JsonRpcError, JsonRpcStdioConnection, PendingRequestRegistry, QuickJsExecutor, SUPPORTED_ATTACHMENT_TYPES, SessionRunner, attachmentContentBlocks, attachmentKind, attachmentRef, checkClaudeAuth, claudeAdapter, codexAdapter, connectAppServer, connectMcpTools, createEngineSession, createToolContext, createWebFetch, getEngineAdapter, htmlToMarkdown, isHostAllowed, isPrivateAddress, listCodexSessions, localCommandContext, localCommandTranscript, mcpStatusInfo, modelOptionsFromSdk, normalizeMediaType, normalizeSdkMessage, providerAdapter, replaySlice, resolveBundledClaudeExecutable, resolveBundledCodexExecutable, toApiMessage, toExecutionResult, truncateResultBlocks, withHostTools, withMcpTools };
6033
+ export { AiSdkRunner, BrowserBridgeExecutor, CLAUDE_CATALOG, CODEX_CATALOG, CodexRunner, CostLedger, DeferredExecutor, InputQueue, JsonRpcError, JsonRpcStdioConnection, PendingRequestRegistry, QuickJsExecutor, SUPPORTED_ATTACHMENT_TYPES, SessionRunner, attachmentContentBlocks, attachmentKind, attachmentRef, checkClaudeAuth, claudeAdapter, codexAdapter, connectAppServer, connectMcpTools, createEngineSession, createToolContext, createWebFetch, getEngineAdapter, htmlToMarkdown, isHostAllowed, isPrivateAddress, listCodexSessions, localCommandContext, localCommandTranscript, mcpStatusInfo, modelOptionsFromSdk, normalizeMediaType, normalizeSdkMessage, providerAdapter, replaySlice, resolveBundledClaudeExecutable, resolveBundledCodexExecutable, toApiMessage, toExecutionResult, truncateResultBlocks, withHostTools, withMcpTools };
5787
6034
 
5788
6035
  //# sourceMappingURL=index.mjs.map