claude-use 11.39.0 → 11.40.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/README.md CHANGED
@@ -132,6 +132,7 @@ agent-shim model remove <name> [--yes]
132
132
  agent-shim model tier <tier> --ref <ref> | --clear
133
133
  agent-shim model price <ref> --input <usd> --output <usd> | --clear
134
134
  agent-shim model list [--json]
135
+ agent-shim model explain <name> # which member the virtual model's mode picks now, and why
135
136
  agent-shim provider remove <name> [--yes] [--json]
136
137
 
137
138
  agent-shim rule add <path> [--config-profile <profile>] [--identity <identity>] [--json]
package/dist/cli.cjs CHANGED
@@ -34636,7 +34636,7 @@ var init_package = __esm({
34636
34636
  "package.json"() {
34637
34637
  package_default = {
34638
34638
  name: "claude-use",
34639
- version: "11.39.0",
34639
+ version: "11.40.0",
34640
34640
  description: "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
34641
34641
  license: "MIT",
34642
34642
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -35948,6 +35948,7 @@ function createUsageStore(deps) {
35948
35948
  }
35949
35949
  fs26.appendFilePrivate(import_node_path26.default.join(paths.usageLogDir, segmentName(day, deps.pid)), `${JSON.stringify(record2)}
35950
35950
  `);
35951
+ deps.onRecord?.(record2);
35951
35952
  if (record2.identity !== void 0) {
35952
35953
  rewriteSnapshot(record2.identity, (current) => ({ ...current?.providers, [record2.provider]: foldProviderState(current?.providers[record2.provider], record2) }));
35953
35954
  }
@@ -115764,6 +115765,72 @@ function supervisedSessionOf(fs26, paths, sessionId, isRunning) {
115764
115765
  return void 0;
115765
115766
  }
115766
115767
 
115768
+ // src/selection/targetStore.ts
115769
+ init_read();
115770
+
115771
+ // src/selection/signals.ts
115772
+ function targetOf(record2) {
115773
+ return record2.model === void 0 ? void 0 : `${record2.provider}/${record2.model}`;
115774
+ }
115775
+ function median(values) {
115776
+ if (values.length === 0) {
115777
+ return void 0;
115778
+ }
115779
+ const sorted = [...values].sort((left, right) => left - right);
115780
+ const middle = Math.floor(sorted.length / 2);
115781
+ const above = sorted[middle];
115782
+ const below = sorted[middle - 1];
115783
+ return sorted.length % 2 === 0 && above !== void 0 && below !== void 0 ? (above + below) / 2 : sorted[middle];
115784
+ }
115785
+ var OBSERVATION_WINDOW = 20;
115786
+ function observeRecord(observations, record2) {
115787
+ const target = targetOf(record2);
115788
+ if (target === void 0) {
115789
+ return new Map(observations);
115790
+ }
115791
+ const kept = [...observations.get(target) ?? [], record2].slice(-OBSERVATION_WINDOW);
115792
+ return new Map(observations).set(target, kept);
115793
+ }
115794
+ function observationOf(records) {
115795
+ const completed = records.filter((record2) => record2.outcome === "completed");
115796
+ const latencies = completed.map((record2) => record2.latencyMs);
115797
+ const usage = records.flatMap((record2) => record2.usage === void 0 ? [] : [record2.usage]);
115798
+ const input2 = usage.reduce((sum, entry) => sum + (entry.inputTokens ?? 0), 0);
115799
+ const output2 = usage.reduce((sum, entry) => sum + (entry.outputTokens ?? 0), 0);
115800
+ const cacheRead = usage.reduce((sum, entry) => sum + (entry.cacheReadInputTokens ?? 0), 0);
115801
+ return {
115802
+ latencyMs: median(latencies),
115803
+ successRate: records.length === 0 ? void 0 : completed.length / records.length,
115804
+ tokenMix: input2 + output2 + cacheRead === 0 ? void 0 : { input: input2, output: output2, cacheRead }
115805
+ };
115806
+ }
115807
+ function blendedPricePerMTok(prices, mix) {
115808
+ const total = mix.input + mix.output + mix.cacheRead;
115809
+ if (total === 0) {
115810
+ return void 0;
115811
+ }
115812
+ return (prices.input * mix.input + prices.output * mix.output) / total;
115813
+ }
115814
+
115815
+ // src/selection/targetStore.ts
115816
+ var SEED_LOOKBACK_RECORDS = 500;
115817
+ function createTargetObservationStore(fs26, paths) {
115818
+ let observations = /* @__PURE__ */ new Map();
115819
+ const seeded = readUsageLog(fs26, paths.usageLogDir, {}).records.slice(-SEED_LOOKBACK_RECORDS);
115820
+ for (const record2 of seeded) {
115821
+ observations = observeRecord(observations, record2);
115822
+ }
115823
+ return {
115824
+ observe: (record2) => {
115825
+ observations = observeRecord(observations, record2);
115826
+ },
115827
+ observation: (target) => {
115828
+ const records = observations.get(target);
115829
+ return records === void 0 ? void 0 : observationOf(records);
115830
+ }
115831
+ };
115832
+ }
115833
+
115767
115834
  // src/update/commands.ts
115768
115835
  var import_node_fs14 = __toESM(require("node:fs"), 1);
115769
115836
  var import_node_os7 = __toESM(require("node:os"), 1);
@@ -131323,6 +131390,39 @@ function createPassthroughRoute(name, target) {
131323
131390
  // src/frontdoor/providerRoute.ts
131324
131391
  init_conditions();
131325
131392
  init_quotaFacts();
131393
+ init_modelsStore();
131394
+
131395
+ // src/selection/candidates.ts
131396
+ var WINDOW_PERIOD_HOURS = { fiveHour: 5, sevenDay: 168, extraUsage: 168 };
131397
+ function candidateOf(ref, order, facts, isCurrent) {
131398
+ const present = Object.entries(facts.quota ?? {}).map(([name, window]) => ({ name, ...window }));
131399
+ const available = present.every((window) => window.remaining > 0);
131400
+ const remainingAllowance = present.length === 0 ? void 0 : Math.min(...present.map((window) => window.remaining));
131401
+ const hoursToReset = present.length === 0 ? void 0 : Math.min(...present.map((window) => window.hoursUntilReset));
131402
+ const pressure = present.length === 0 ? void 0 : Math.max(
131403
+ ...present.map((window) => {
131404
+ const period = WINDOW_PERIOD_HOURS[window.name] ?? Number.NaN;
131405
+ return period > 0 && window.hoursUntilReset > 0 ? window.remaining / (window.hoursUntilReset / period) : Number.NaN;
131406
+ })
131407
+ );
131408
+ return {
131409
+ ref,
131410
+ order,
131411
+ available,
131412
+ ...remainingAllowance === void 0 ? {} : { remainingAllowance },
131413
+ ...hoursToReset === void 0 ? {} : { hoursToReset },
131414
+ ...pressure === void 0 || Number.isNaN(pressure) ? {} : { pressure },
131415
+ // Feasibility at the observed burn needs a burn rate no signal yet carries, so an available candidate counts as feasible and the run-dry projection waits on one.
131416
+ feasible: available,
131417
+ ...facts.observation?.latencyMs === void 0 ? {} : { latencyMs: facts.observation.latencyMs },
131418
+ ...facts.observation?.successRate === void 0 ? {} : { successRate: facts.observation.successRate },
131419
+ ...facts.price === void 0 || facts.observation?.tokenMix === void 0 ? {} : { pricePerMTok: blendedPricePerMTok(facts.price, facts.observation.tokenMix) },
131420
+ isCurrent
131421
+ };
131422
+ }
131423
+
131424
+ // src/frontdoor/providerRoute.ts
131425
+ init_engine();
131326
131426
  init_route();
131327
131427
  var import_node_stream3 = require("node:stream");
131328
131428
 
@@ -131412,22 +131512,43 @@ function scopeSessionProviderPath(request7) {
131412
131512
  }
131413
131513
  return { ...request7, url: `${PROVIDER_PATH_PREFIX}${encodeURIComponent(request7.session.provider)}${request7.url}` };
131414
131514
  }
131415
- function resolveModelTarget(model, models, includeUnqualified) {
131416
- if (models === void 0) {
131417
- return model.includes("/") && !model.startsWith("acct:") ? model.split("/")[0] : void 0;
131515
+ function resolveRoutedModel(model, providerName, session, includeUnqualified, deps, memory, rotations) {
131516
+ const models = deps.models?.();
131517
+ const qualified = model.includes("/") && !model.startsWith("acct:") ? model : void 0;
131518
+ if (qualified !== void 0) {
131519
+ const [provider2, ...rest2] = qualified.split("/");
131520
+ const named = rest2.join("/");
131521
+ return provider2 === void 0 || named === "" ? void 0 : { provider: provider2, model: named, ref: qualified };
131418
131522
  }
131419
- if (model.includes("/") && !model.startsWith("acct:")) {
131420
- return model.split("/")[0];
131523
+ const virtual = models?.virtual?.[model];
131524
+ if (virtual === void 0 || !includeUnqualified) {
131525
+ return void 0;
131421
131526
  }
131422
- if (!includeUnqualified) {
131527
+ const members2 = expandMembers(model, models).filter((member) => !member.startsWith("acct:") && !member.startsWith("family:"));
131528
+ if (members2.length === 0) {
131423
131529
  return void 0;
131424
131530
  }
131425
- const virtual = models.virtual?.[model];
131426
- const first = virtual?.members.find((member) => !member.startsWith("acct:") && !member.startsWith("family:"));
131427
- if (first === void 0) {
131531
+ const snapshot = deps.usageSnapshotOf?.(session.identity);
131532
+ const current = memory.get(session.sessionId ?? "");
131533
+ const candidates = members2.map((ref, order) => {
131534
+ const [provider2] = ref.split("/");
131535
+ const facts = quotaFactsOf(snapshot?.providers[provider2 ?? ""]?.rateLimit?.unified, Date.now());
131536
+ return candidateOf(ref, order, {
131537
+ quota: facts,
131538
+ ...deps.observations?.(ref) === void 0 ? {} : { observation: deps.observations(ref) },
131539
+ ...models?.prices?.[ref] === void 0 ? {} : { price: models.prices[ref] }
131540
+ }, ref === current);
131541
+ });
131542
+ const evaluated = candidates.map((candidate) => ({ candidate, capabilities: { vision: true, tools: true, thinking: true } }));
131543
+ const rotation = rotations.get(model) ?? 0;
131544
+ rotations.set(model, rotation + 1);
131545
+ const selection = selectMember(virtual.mode, evaluated, { rotation });
131546
+ if (selection.ref === void 0) {
131428
131547
  return void 0;
131429
131548
  }
131430
- return first.includes("/") ? first.split("/")[0] : resolveModelTarget(first, models, true);
131549
+ const [provider, ...rest] = selection.ref.split("/");
131550
+ const chosen = rest.join("/");
131551
+ return provider === void 0 || chosen === "" ? void 0 : { provider, model: chosen, ref: selection.ref };
131431
131552
  }
131432
131553
  function resolveAccountTarget(model, models) {
131433
131554
  if (model.startsWith("acct:")) {
@@ -131444,6 +131565,8 @@ function createProviderRouteResolver(deps) {
131444
131565
  const oauthRoute = createPassthroughRoute("anthropic", { baseUrl: `https://${CONNECT_INTERCEPT_HOST}:${String(HTTPS_PORT)}`, stripPrefix: void 0, headroomUpstream: void 0 });
131445
131566
  const antigravityQuotaSources = /* @__PURE__ */ new Map();
131446
131567
  const antigravityRoutingMemory = /* @__PURE__ */ new Map();
131568
+ const routingMemory = /* @__PURE__ */ new Map();
131569
+ const rotations = /* @__PURE__ */ new Map();
131447
131570
  const memoryFor = (provider) => {
131448
131571
  const existing = antigravityRoutingMemory.get(provider);
131449
131572
  if (existing !== void 0) {
@@ -131605,10 +131728,12 @@ function createProviderRouteResolver(deps) {
131605
131728
  }
131606
131729
  const routesByName = (isRouter || current.session.routeByName) && !isRcSelfHostPath(path65);
131607
131730
  if (routesByName) {
131608
- const scan2 = await scanRequestHead(current, false);
131609
- if (scan2.replayed !== void 0) {
131610
- replay = scan2.replayed;
131731
+ const scan2 = await scanRequestHead(current, true);
131732
+ if (scan2.replayed === void 0) {
131733
+ const resolution = resolve2(current);
131734
+ return resolution.ok && replay !== void 0 ? { ok: true, route: servingRewritten(resolution.route, { ...replay, url: current.url }), request: { ...replay, url: current.url } } : resolution.ok ? serveScoped(resolution) : resolution;
131611
131735
  }
131736
+ replay = scan2.replayed;
131612
131737
  const account = scan2.model === void 0 ? void 0 : resolveAccountTarget(scan2.model, deps.models?.());
131613
131738
  if (account !== void 0) {
131614
131739
  const sessionId = current.session.sessionId ?? "";
@@ -131619,18 +131744,29 @@ function createProviderRouteResolver(deps) {
131619
131744
  message: moved ? `model "${account.model}" runs under identity "${account.identity}"; this session is being moved there and will resume with it` : `model "${account.model}" runs under identity "${account.identity}", which needs a relaunch this session cannot make; start it there with: claude @${account.identity} --resume`
131620
131745
  };
131621
131746
  }
131622
- const target = scan2.model === void 0 ? void 0 : resolveModelTarget(scan2.model, deps.models?.(), isRouter || current.session.routeByName && providerName !== void 0);
131623
- if (target === providerName) {
131747
+ const routed = scan2.model === void 0 ? void 0 : resolveRoutedModel(scan2.model, providerName, current.session, isRouter || providerName !== void 0, deps, routingMemory, rotations);
131748
+ const requested = scan2.model;
131749
+ if (routed !== void 0) {
131750
+ routingMemory.set(current.session.sessionId ?? "", routed.ref);
131751
+ if (requested !== void 0 && routed.provider === providerName && routed.model === requested) {
131752
+ const resolution2 = resolve2(current);
131753
+ return resolution2.ok ? { ok: true, route: servingRewritten(resolution2.route, { ...replay, url: current.url }), request: { ...replay, url: current.url } } : resolution2;
131754
+ }
131755
+ if (requested !== void 0 && routed.model !== requested) {
131756
+ const rewritten = (scan2.text ?? "").replace(new RegExp('"model":\\s*"' + requested.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + '"'), '"model":"' + routed.model + '"');
131757
+ const headers = Object.fromEntries(Object.entries(replay.headers).filter(([name]) => name.toLowerCase() !== "content-length"));
131758
+ replay = { ...replay, headers, body: import_node_stream3.Readable.from([Buffer.from(rewritten, "utf8")]) };
131759
+ }
131760
+ if (routed.provider !== providerName) {
131761
+ const scopedPrefix = providerName === void 0 ? void 0 : `${PROVIDER_PATH_PREFIX}${encodeURIComponent(providerName)}`;
131762
+ const rest2 = scopedPrefix !== void 0 && path65.startsWith(scopedPrefix) ? path65.slice(scopedPrefix.length) : path65;
131763
+ const query2 = current.url.includes("?") ? current.url.slice(current.url.indexOf("?")) : "";
131764
+ const carried = replay;
131765
+ current = { ...current, url: `${PROVIDER_PATH_PREFIX}${encodeURIComponent(routed.provider)}${rest2}${query2}`, body: carried.body, headers: carried.headers };
131766
+ continue;
131767
+ }
131624
131768
  const resolution = resolve2(current);
131625
- return resolution.ok && replay !== void 0 ? { ok: true, route: servingRewritten(resolution.route, { ...replay, url: current.url }), request: { ...replay, url: current.url } } : resolution.ok ? serveScoped(resolution) : resolution;
131626
- }
131627
- if (target !== void 0) {
131628
- const scopedPrefix = providerName === void 0 ? void 0 : `${PROVIDER_PATH_PREFIX}${encodeURIComponent(providerName)}`;
131629
- const rest2 = scopedPrefix !== void 0 && path65.startsWith(scopedPrefix) ? path65.slice(scopedPrefix.length) : path65;
131630
- const query2 = current.url.includes("?") ? current.url.slice(current.url.indexOf("?")) : "";
131631
- const carried = scan2.replayed ?? current;
131632
- current = { ...current, url: `${PROVIDER_PATH_PREFIX}${encodeURIComponent(target)}${rest2}${query2}`, body: carried.body, headers: carried.headers };
131633
- continue;
131769
+ return resolution.ok ? { ok: true, route: servingRewritten(resolution.route, { ...replay, url: current.url }), request: { ...replay, url: current.url } } : resolution;
131634
131770
  }
131635
131771
  }
131636
131772
  if (routes === void 0 || routes.length === 0) {
@@ -134701,67 +134837,6 @@ function createRealQuotaRefresher(params) {
134701
134837
 
134702
134838
  // src/frontdoor/commands.ts
134703
134839
  init_store2();
134704
-
134705
- // src/selection/targetStore.ts
134706
- init_read();
134707
-
134708
- // src/selection/signals.ts
134709
- function targetOf(record2) {
134710
- return record2.model === void 0 ? void 0 : `${record2.provider}/${record2.model}`;
134711
- }
134712
- function median(values) {
134713
- if (values.length === 0) {
134714
- return void 0;
134715
- }
134716
- const sorted = [...values].sort((left, right) => left - right);
134717
- const middle = Math.floor(sorted.length / 2);
134718
- const above = sorted[middle];
134719
- const below = sorted[middle - 1];
134720
- return sorted.length % 2 === 0 && above !== void 0 && below !== void 0 ? (above + below) / 2 : sorted[middle];
134721
- }
134722
- var OBSERVATION_WINDOW = 20;
134723
- function observeRecord(observations, record2) {
134724
- const target = targetOf(record2);
134725
- if (target === void 0) {
134726
- return new Map(observations);
134727
- }
134728
- const kept = [...observations.get(target) ?? [], record2].slice(-OBSERVATION_WINDOW);
134729
- return new Map(observations).set(target, kept);
134730
- }
134731
- function observationOf(records) {
134732
- const completed = records.filter((record2) => record2.outcome === "completed");
134733
- const latencies = completed.map((record2) => record2.latencyMs);
134734
- const usage = records.flatMap((record2) => record2.usage === void 0 ? [] : [record2.usage]);
134735
- const input2 = usage.reduce((sum, entry) => sum + (entry.inputTokens ?? 0), 0);
134736
- const output2 = usage.reduce((sum, entry) => sum + (entry.outputTokens ?? 0), 0);
134737
- const cacheRead = usage.reduce((sum, entry) => sum + (entry.cacheReadInputTokens ?? 0), 0);
134738
- return {
134739
- latencyMs: median(latencies),
134740
- successRate: records.length === 0 ? void 0 : completed.length / records.length,
134741
- tokenMix: input2 + output2 + cacheRead === 0 ? void 0 : { input: input2, output: output2, cacheRead }
134742
- };
134743
- }
134744
-
134745
- // src/selection/targetStore.ts
134746
- var SEED_LOOKBACK_RECORDS = 500;
134747
- function createTargetObservationStore(fs26, paths) {
134748
- let observations = /* @__PURE__ */ new Map();
134749
- const seeded = readUsageLog(fs26, paths.usageLogDir, {}).records.slice(-SEED_LOOKBACK_RECORDS);
134750
- for (const record2 of seeded) {
134751
- observations = observeRecord(observations, record2);
134752
- }
134753
- return {
134754
- observe: (record2) => {
134755
- observations = observeRecord(observations, record2);
134756
- },
134757
- observation: (target) => {
134758
- const records = observations.get(target);
134759
- return records === void 0 ? void 0 : observationOf(records);
134760
- }
134761
- };
134762
- }
134763
-
134764
- // src/frontdoor/commands.ts
134765
134840
  function respawnInvocation(paths) {
134766
134841
  const env = {};
134767
134842
  for (const [name, value2] of Object.entries({ ...process.env, AGENT_SHIM_HOME: paths.root })) {
@@ -134846,6 +134921,7 @@ function realFrontDoorSupervisorPorts(paths) {
134846
134921
  appendLog(paths, `frontdoor ${String(process.pid)}: ${line}`);
134847
134922
  }
134848
134923
  });
134924
+ const observations = createTargetObservationStore(realFarmFs, paths);
134849
134925
  const routingSnapshots = /* @__PURE__ */ new Map();
134850
134926
  const rcControlToken = (0, import_node_crypto25.randomUUID)();
134851
134927
  const resolveRoute = rcObservingResolver(
@@ -134861,6 +134937,7 @@ function realFrontDoorSupervisorPorts(paths) {
134861
134937
  credentials: { ...realCredentialPort, cache: realCredentialCacheEnv(paths) },
134862
134938
  usageSnapshotOf: (identity) => identity === void 0 ? void 0 : routingSnapshots.get(identity) ?? readUsageSnapshot(realFarmFs, paths.usageSnapshotsDir, identity),
134863
134939
  // An `acct:` model member is served by relaunch: the door leaves a move request for the session's supervisor (found across every pool's registry, since the door does not know which pool launched the session) and answers the request with what is happening. A session nothing supervises gets the message naming the command to run instead.
134940
+ observations: (target) => observations.observation(target),
134864
134941
  accountMoves: (sessionId, to2, model) => {
134865
134942
  if (supervisedSessionOf(realFarmFs, paths, sessionId, realIsProcessRunning) === void 0) {
134866
134943
  return false;
@@ -134884,6 +134961,9 @@ function realFrontDoorSupervisorPorts(paths) {
134884
134961
  publish: (snapshot) => {
134885
134962
  routingSnapshots.set(snapshot.identity, snapshot);
134886
134963
  usagePublisher.publish(snapshot);
134964
+ },
134965
+ onRecord: (record2) => {
134966
+ observations.observe(record2);
134887
134967
  }
134888
134968
  });
134889
134969
  const quotaRefresher = createRealQuotaRefresher({ paths, store: usageStore, log });
@@ -135501,7 +135581,8 @@ function enrichStatuslinePayload(params) {
135501
135581
  sevenDayResetAt: void 0,
135502
135582
  providerQuotaWindows: [],
135503
135583
  quotaFamilies: [],
135504
- headroom: params.headroom
135584
+ headroom: params.headroom,
135585
+ routedTarget: params.routedTarget
135505
135586
  };
135506
135587
  if (params.snapshot !== void 0) {
135507
135588
  const scopedName = providerScopedState(params.snapshot, params.providerName, params.env.AGENT_SHIM_PROVIDER);
@@ -135575,6 +135656,9 @@ function providerScopedState(snapshot, providerName, providerDisplayName) {
135575
135656
  return void 0;
135576
135657
  }
135577
135658
 
135659
+ // src/statusline/commands.ts
135660
+ init_read();
135661
+
135578
135662
  // src/statusline/ansi.ts
135579
135663
  var ESCAPE_CHAR_CODE = 27;
135580
135664
  var ESCAPE = String.fromCharCode(ESCAPE_CHAR_CODE);
@@ -135866,6 +135950,9 @@ function renderStatuslineBlock(summary, view, terminalWidth, nowMs) {
135866
135950
  const account = [summary.providerAccountEmail, summary.providerPlan].filter((part) => part !== void 0);
135867
135951
  header.push(account.length > 0 ? `${summary.provider} \xB7 ${account.join(" \xB7 ")}` : summary.provider);
135868
135952
  }
135953
+ if (summary.routedTarget !== void 0) {
135954
+ header.push(`via ${summary.routedTarget}`);
135955
+ }
135869
135956
  const loginPlan = summary.provider === void 0 ? summary.loginPlan ?? accountPlanLabel(summary) : void 0;
135870
135957
  const loginOrgName = summary.loginOrganizationType === "claude_team" || summary.loginOrganizationType === "claude_enterprise" ? summary.loginOrganizationName : void 0;
135871
135958
  const loginParts = [summary.loginAccountEmail, loginOrgName, loginPlan].filter((part) => part !== void 0);
@@ -135969,6 +136056,7 @@ async function readAllStdin() {
135969
136056
  process.stdin.resume();
135970
136057
  });
135971
136058
  }
136059
+ var ROUTED_TARGET_LOOKBACK_MS = 36e5;
135972
136060
  function registerStatuslineCommand(program2, deps) {
135973
136061
  withExamples(
135974
136062
  program2.command("statusline").description("Serve as a statusline entrypoint: read the client's stdin payload, add the identity's live provider, account and usage windows under an agent_shim key, then run the renderer named in AGENT_SHIM_STATUSLINE_CMD or print the built-in line.").action(async () => {
@@ -136015,7 +136103,19 @@ function registerStatuslineCommand(program2, deps) {
136015
136103
  const target = headroomTargetOf(process.env, socketTarget === void 0 || socketTarget.refused !== void 0 ? void 0 : socketTarget.socketPath);
136016
136104
  const sessionId = headroomSessionIdOf(payload, process.env);
136017
136105
  const headroom = target === void 0 || sessionId === void 0 ? void 0 : await fetchHeadroomSessionStats(realHeadroomGet, target, sessionId);
136018
- const { payload: enriched, summary } = enrichStatuslinePayload({ payload, env: process.env, snapshot, account, providerName, nowMs, headroom });
136106
+ const sessionHeader = /x-agent-shim-session:\s*([A-Za-z0-9@._-]+)/i.exec(process.env.ANTHROPIC_CUSTOM_HEADERS ?? "")?.[1];
136107
+ let routedTarget;
136108
+ if (sessionHeader !== void 0) {
136109
+ try {
136110
+ const last = readUsageLog(realFarmFs, deps.paths.usageLogDir, { sinceMs: nowMs - ROUTED_TARGET_LOOKBACK_MS }).records.filter((record2) => record2.sessionId === sessionHeader).at(-1);
136111
+ if (last?.model !== void 0 && last.provider !== providerName) {
136112
+ routedTarget = `${last.provider}/${last.model}`;
136113
+ }
136114
+ } catch {
136115
+ routedTarget = void 0;
136116
+ }
136117
+ }
136118
+ const { payload: enriched, summary } = enrichStatuslinePayload({ payload, env: process.env, snapshot, account, providerName, nowMs, headroom, routedTarget });
136019
136119
  const renderer = process.env.AGENT_SHIM_STATUSLINE_CMD;
136020
136120
  if (renderer !== void 0 && renderer !== "") {
136021
136121
  const child = (0, import_node_child_process7.spawn)("/bin/sh", ["-c", renderer], { stdio: ["pipe", "inherit", "inherit"] });
@@ -147539,6 +147639,52 @@ function sameFamilyOtherVersion(a10, b) {
147539
147639
 
147540
147640
  // src/models.ts
147541
147641
  init_modelsStore();
147642
+ init_realPorts();
147643
+ init_read();
147644
+ init_quotaFacts();
147645
+ init_engine();
147646
+ function providerQuotaOf(paths) {
147647
+ const newest = /* @__PURE__ */ new Map();
147648
+ for (const name of realFarmFs.readdir(paths.usageSnapshotsDir)) {
147649
+ if (!name.endsWith(".json")) {
147650
+ continue;
147651
+ }
147652
+ const identity = name.slice(0, -".json".length);
147653
+ const snapshot = readUsageSnapshot(realFarmFs, paths.usageSnapshotsDir, identity);
147654
+ if (snapshot === void 0) {
147655
+ continue;
147656
+ }
147657
+ for (const provider of Object.keys(snapshot.providers)) {
147658
+ const known = newest.get(provider);
147659
+ if (known === void 0 || snapshot.updatedAt.localeCompare(known.updatedAt) > 0) {
147660
+ newest.set(provider, snapshot);
147661
+ }
147662
+ }
147663
+ }
147664
+ return (provider) => {
147665
+ const snapshot = newest.get(provider);
147666
+ return snapshot === void 0 ? {} : quotaFactsOf(snapshot.providers[provider]?.rateLimit?.unified, Date.now());
147667
+ };
147668
+ }
147669
+ function explainVirtualModel(paths, name) {
147670
+ const models = readModels(paths);
147671
+ const definition = models?.virtual?.[name];
147672
+ if (definition === void 0) {
147673
+ throw new UsageError(`No virtual model named "${name}".`);
147674
+ }
147675
+ const quotaOf = providerQuotaOf(paths);
147676
+ const observations = createTargetObservationStore(realFarmFs, paths);
147677
+ const candidates = expandMembers(name, models).filter((member) => !member.startsWith("acct:") && !member.startsWith("family:")).map((ref, order) => {
147678
+ const [provider] = ref.split("/");
147679
+ return candidateOf(ref, order, { quota: quotaOf(provider ?? ""), ...observations.observation(ref) === void 0 ? {} : { observation: observations.observation(ref) }, ...models?.prices?.[ref] === void 0 ? {} : { price: models.prices[ref] } }, false);
147680
+ });
147681
+ const evaluated = candidates.map((candidate) => ({ candidate, capabilities: { vision: true, tools: true, thinking: true } }));
147682
+ const selection = selectMember(definition.mode, evaluated, {});
147683
+ console.log(`${name} (${definition.mode}) chooses ${selection.ref ?? "nothing"}:`);
147684
+ for (const line of selection.reasons) {
147685
+ console.log(` ${line}`);
147686
+ }
147687
+ }
147542
147688
  function providerModels(paths) {
147543
147689
  return listProviders(paths).flatMap((entry) => {
147544
147690
  const catalogue = parseCatalogueCache(realFsPort.readFileUtf8(catalogueCachePath(paths, entry.name)));
@@ -147573,6 +147719,12 @@ function matchModels(models) {
147573
147719
  function registerModelsCommand(program2, deps) {
147574
147720
  const { paths } = deps;
147575
147721
  const modelsCommand = program2.command("model").description("Define and inspect the models the providers offer and the virtual models chosen among them.");
147722
+ withExamples(
147723
+ modelsCommand.command("explain <name>").description("Show which member a virtual model's mode picks over the live signals, and why each candidate stands where it does.").action((name) => {
147724
+ explainVirtualModel(paths, name);
147725
+ }),
147726
+ ["agent-shim model explain fast"]
147727
+ );
147576
147728
  withExamples(modelsCommand, ["agent-shim model match", "agent-shim model add fast --mode soonest-reset --member z/glm-5.3 --member m/MiniMax-M3"]);
147577
147729
  withExamples(
147578
147730
  modelsCommand.command("match").description("List every model every provider offers, grouped into the ones that are the same model across providers, with the pairs that are merely similar named beside them.").option("--json", "Print the match as JSON."),
package/dist/index.cjs CHANGED
@@ -3106,7 +3106,7 @@ var init_package = __esm({
3106
3106
  "package.json"() {
3107
3107
  package_default = {
3108
3108
  name: "claude-use",
3109
- version: "11.39.0",
3109
+ version: "11.40.0",
3110
3110
  description: "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
3111
3111
  license: "MIT",
3112
3112
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -6063,6 +6063,7 @@ function createUsageStore(deps) {
6063
6063
  }
6064
6064
  fs13.appendFilePrivate(import_node_path20.default.join(paths.usageLogDir, segmentName(day, deps.pid)), `${JSON.stringify(record)}
6065
6065
  `);
6066
+ deps.onRecord?.(record);
6066
6067
  if (record.identity !== void 0) {
6067
6068
  rewriteSnapshot(record.identity, (current) => ({ ...current?.providers, [record.provider]: foldProviderState(current?.providers[record.provider], record) }));
6068
6069
  }
package/dist/index.mjs CHANGED
@@ -3082,7 +3082,7 @@ var init_package = __esm({
3082
3082
  "package.json"() {
3083
3083
  package_default = {
3084
3084
  name: "claude-use",
3085
- version: "11.39.0",
3085
+ version: "11.40.0",
3086
3086
  description: "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
3087
3087
  license: "MIT",
3088
3088
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -6038,6 +6038,7 @@ function createUsageStore(deps) {
6038
6038
  }
6039
6039
  fs13.appendFilePrivate(path20.join(paths.usageLogDir, segmentName(day, deps.pid)), `${JSON.stringify(record)}
6040
6040
  `);
6041
+ deps.onRecord?.(record);
6041
6042
  if (record.identity !== void 0) {
6042
6043
  rewriteSnapshot(record.identity, (current) => ({ ...current?.providers, [record.provider]: foldProviderState(current?.providers[record.provider], record) }));
6043
6044
  }